@agether/sdk 1.4.1 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -30,6 +30,807 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
30
  mod
31
31
  ));
32
32
 
33
+ // src/types/index.ts
34
+ var AgetherError;
35
+ var init_types = __esm({
36
+ "src/types/index.ts"() {
37
+ "use strict";
38
+ AgetherError = class extends Error {
39
+ constructor(message, code, details) {
40
+ super(message);
41
+ this.code = code;
42
+ this.details = details;
43
+ this.name = "AgetherError";
44
+ }
45
+ };
46
+ }
47
+ });
48
+
49
+ // src/utils/abis.ts
50
+ var IDENTITY_REGISTRY_ABI, ACCOUNT_FACTORY_ABI, AGENT_ACCOUNT_ABI, AGENT_REPUTATION_ABI, MORPHO_BLUE_ABI, ERC20_ABI;
51
+ var init_abis = __esm({
52
+ "src/utils/abis.ts"() {
53
+ "use strict";
54
+ IDENTITY_REGISTRY_ABI = [
55
+ "function ownerOf(uint256 agentId) view returns (address)",
56
+ "function balanceOf(address owner) view returns (uint256)",
57
+ "function totalSupply() view returns (uint256)",
58
+ "function exists(uint256 agentId) view returns (bool)",
59
+ "function register() returns (uint256 agentId)",
60
+ "event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)"
61
+ ];
62
+ ACCOUNT_FACTORY_ABI = [
63
+ "function getAccount(uint256 agentId) view returns (address)",
64
+ "function accountExists(uint256 agentId) view returns (bool)",
65
+ "function predictAddress(uint256 agentId) view returns (address)",
66
+ "function totalAccounts() view returns (uint256)",
67
+ "function getAgentId(address account) view returns (uint256)",
68
+ "function createAccount(uint256 agentId) returns (address account)",
69
+ "event AccountCreated(uint256 indexed agentId, address indexed account, address indexed owner)"
70
+ ];
71
+ AGENT_ACCOUNT_ABI = [
72
+ "function agentId() view returns (uint256)",
73
+ "function owner() view returns (address)",
74
+ "function factory() view returns (address)",
75
+ "function validationRegistry() view returns (address)",
76
+ "function identityRegistry() view returns (address)",
77
+ "function balanceOf(address token) view returns (uint256)",
78
+ "function ethBalance() view returns (uint256)",
79
+ "function execute(address target, uint256 value, bytes data) payable returns (bytes)",
80
+ "function executeBatch(address[] targets, uint256[] values, bytes[] datas) payable returns (bytes[])",
81
+ "function fund(address token, uint256 amount)",
82
+ "function withdraw(address token, uint256 amount, address to)",
83
+ "function withdrawETH(uint256 amount, address to)",
84
+ "function isValidSignature(bytes32 hash, bytes signature) view returns (bytes4)"
85
+ ];
86
+ AGENT_REPUTATION_ABI = [
87
+ "function getCreditScore(uint256 agentId) view returns (uint256)",
88
+ "function getAttestation(uint256 agentId) view returns (tuple(uint256 score, uint256 timestamp, address signer))",
89
+ "function isScoreFresh(uint256 agentId) view returns (bool fresh, uint256 age)",
90
+ "function isEligible(uint256 agentId, uint256 minScore) view returns (bool eligible, uint256 currentScore)",
91
+ "function oracleSigner() view returns (address)",
92
+ "function submitScore(uint256 agentId, uint256 score_, uint256 timestamp_, bytes signature)",
93
+ "function setOracleSigner(address signer_)",
94
+ "event ScoreUpdated(uint256 indexed agentId, uint256 score, uint256 timestamp, address signer)"
95
+ ];
96
+ MORPHO_BLUE_ABI = [
97
+ // Supply & Withdraw (lending side)
98
+ "function supply(tuple(address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, uint256 shares, address onBehalf, bytes data) returns (uint256 assetsSupplied, uint256 sharesSupplied)",
99
+ "function withdraw(tuple(address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, uint256 shares, address onBehalf, address receiver) returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn)",
100
+ // Collateral
101
+ "function supplyCollateral(tuple(address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, address onBehalf, bytes data)",
102
+ "function withdrawCollateral(tuple(address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, address onBehalf, address receiver)",
103
+ // Borrow & Repay
104
+ "function borrow(tuple(address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, uint256 shares, address onBehalf, address receiver) returns (uint256 assetsBorrowed, uint256 sharesBorrowed)",
105
+ "function repay(tuple(address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, uint256 shares, address onBehalf, bytes data) returns (uint256 assetsRepaid, uint256 sharesRepaid)",
106
+ // Authorization
107
+ "function setAuthorization(address authorized, bool newIsAuthorized)",
108
+ "function isAuthorized(address authorizer, address authorized) view returns (bool)",
109
+ // Views
110
+ "function position(bytes32 id, address user) view returns (uint256 supplyShares, uint128 borrowShares, uint128 collateral)",
111
+ "function market(bytes32 id) view returns (uint128 totalSupplyAssets, uint128 totalSupplyShares, uint128 totalBorrowAssets, uint128 totalBorrowShares, uint128 lastUpdate, uint128 fee)",
112
+ "function idToMarketParams(bytes32 id) view returns (tuple(address loanToken, address collateralToken, address oracle, address irm, uint256 lltv))"
113
+ ];
114
+ ERC20_ABI = [
115
+ "function balanceOf(address account) view returns (uint256)",
116
+ "function allowance(address owner, address spender) view returns (uint256)",
117
+ "function approve(address spender, uint256 amount) returns (bool)",
118
+ "function transfer(address to, uint256 amount) returns (bool)",
119
+ "function transferFrom(address from, address to, uint256 amount) returns (bool)",
120
+ "function decimals() view returns (uint8)",
121
+ "function symbol() view returns (string)",
122
+ "function name() view returns (string)"
123
+ ];
124
+ }
125
+ });
126
+
127
+ // src/utils/config.ts
128
+ function getDefaultConfig(chainId) {
129
+ return {
130
+ chainId,
131
+ rpcUrl: RPC_URLS[chainId],
132
+ contracts: CONTRACT_ADDRESSES[chainId],
133
+ scoringEndpoint: SCORING_ENDPOINTS[chainId]
134
+ };
135
+ }
136
+ var CONTRACT_ADDRESSES, RPC_URLS, SCORING_ENDPOINTS;
137
+ var init_config = __esm({
138
+ "src/utils/config.ts"() {
139
+ "use strict";
140
+ init_types();
141
+ CONTRACT_ADDRESSES = {
142
+ [1 /* Ethereum */]: {
143
+ accountFactory: "0x0000000000000000000000000000000000000000",
144
+ validationRegistry: "0x0000000000000000000000000000000000000000",
145
+ agentReputation: "0x0000000000000000000000000000000000000000",
146
+ usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
147
+ identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
148
+ morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb"
149
+ },
150
+ [8453 /* Base */]: {
151
+ accountFactory: "0x7D5D56416bAEA06a9DCBe3092eF335724C6320a0",
152
+ validationRegistry: "0xd196C32D2149270F56E209ba7aEE67CE9ceD2001",
153
+ agentReputation: "0x65c9cA1211809D3CF3A2707558198eb2b2bE623c",
154
+ usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
155
+ identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
156
+ morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb"
157
+ },
158
+ [84532 /* BaseSepolia */]: {
159
+ accountFactory: "0x0000000000000000000000000000000000000000",
160
+ validationRegistry: "0x0000000000000000000000000000000000000000",
161
+ agentReputation: "0x0000000000000000000000000000000000000000",
162
+ usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
163
+ identityRegistry: "0x8004A818BFB912233c491871b3d84c89A494BD9e",
164
+ morphoBlue: "0x0000000000000000000000000000000000000000"
165
+ },
166
+ [11155111 /* Sepolia */]: {
167
+ accountFactory: "0x0000000000000000000000000000000000000000",
168
+ validationRegistry: "0x0000000000000000000000000000000000000000",
169
+ agentReputation: "0x0000000000000000000000000000000000000000",
170
+ usdc: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
171
+ identityRegistry: "0x8004A818BFB912233c491871b3d84c89A494BD9e",
172
+ morphoBlue: "0x0000000000000000000000000000000000000000"
173
+ },
174
+ [31337 /* Hardhat */]: {
175
+ accountFactory: "0x0000000000000000000000000000000000000000",
176
+ validationRegistry: "0x0000000000000000000000000000000000000000",
177
+ agentReputation: "0x0000000000000000000000000000000000000000",
178
+ usdc: "0x56d4d6aEe0278c5Df2FA23Ecb32eC146C9446FDf",
179
+ identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
180
+ morphoBlue: "0x0000000000000000000000000000000000000000"
181
+ }
182
+ };
183
+ RPC_URLS = {
184
+ [1 /* Ethereum */]: "https://ethereum-rpc.publicnode.com",
185
+ [8453 /* Base */]: "https://base-rpc.publicnode.com",
186
+ [84532 /* BaseSepolia */]: "https://sepolia.base.org",
187
+ [11155111 /* Sepolia */]: "https://rpc.sepolia.org",
188
+ [31337 /* Hardhat */]: "http://127.0.0.1:8545"
189
+ };
190
+ SCORING_ENDPOINTS = {
191
+ [1 /* Ethereum */]: "https://scoring.agether.ai/v1",
192
+ [8453 /* Base */]: "http://95.179.189.214:3001",
193
+ [84532 /* BaseSepolia */]: "http://95.179.189.214:3001",
194
+ [11155111 /* Sepolia */]: "https://scoring-testnet.agether.ai/v1",
195
+ [31337 /* Hardhat */]: "http://127.0.0.1:3001"
196
+ };
197
+ }
198
+ });
199
+
200
+ // src/clients/MorphoClient.ts
201
+ var MorphoClient_exports = {};
202
+ __export(MorphoClient_exports, {
203
+ MorphoClient: () => MorphoClient
204
+ });
205
+ var import_ethers, import_axios, BASE_COLLATERALS, MORPHO_API_URL, morphoIface, erc20Iface, MorphoClient;
206
+ var init_MorphoClient = __esm({
207
+ "src/clients/MorphoClient.ts"() {
208
+ "use strict";
209
+ import_ethers = require("ethers");
210
+ import_axios = __toESM(require("axios"));
211
+ init_types();
212
+ init_abis();
213
+ init_config();
214
+ BASE_COLLATERALS = {
215
+ WETH: { address: "0x4200000000000000000000000000000000000006", symbol: "WETH", decimals: 18 },
216
+ wstETH: { address: "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452", symbol: "wstETH", decimals: 18 },
217
+ cbETH: { address: "0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22", symbol: "cbETH", decimals: 18 }
218
+ };
219
+ MORPHO_API_URL = "https://api.morpho.org/graphql";
220
+ morphoIface = new import_ethers.ethers.Interface(MORPHO_BLUE_ABI);
221
+ erc20Iface = new import_ethers.ethers.Interface(ERC20_ABI);
222
+ MorphoClient = class {
223
+ constructor(config) {
224
+ this._marketCache = /* @__PURE__ */ new Map();
225
+ this._discoveredAt = 0;
226
+ const chainId = config.chainId ?? 8453 /* Base */;
227
+ const defaultCfg = getDefaultConfig(chainId);
228
+ this.config = defaultCfg;
229
+ this.agentId = config.agentId;
230
+ this.provider = new import_ethers.ethers.JsonRpcProvider(config.rpcUrl || defaultCfg.rpcUrl);
231
+ this.wallet = new import_ethers.ethers.Wallet(config.privateKey, this.provider);
232
+ const addrs = { ...defaultCfg.contracts, ...config.contracts };
233
+ this.accountFactory = new import_ethers.Contract(addrs.accountFactory, ACCOUNT_FACTORY_ABI, this.wallet);
234
+ this.morphoBlue = new import_ethers.Contract(addrs.morphoBlue, MORPHO_BLUE_ABI, this.provider);
235
+ this.agentReputation = new import_ethers.Contract(addrs.agentReputation, AGENT_REPUTATION_ABI, this.provider);
236
+ this.identityRegistry = new import_ethers.Contract(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this.provider);
237
+ }
238
+ // ════════════════════════════════════════════════════════
239
+ // Account Management
240
+ // ════════════════════════════════════════════════════════
241
+ /** Resolve the AgentAccount address (cached). */
242
+ async getAccountAddress() {
243
+ if (this._accountAddress) return this._accountAddress;
244
+ if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
245
+ const addr = await this.accountFactory.getAccount(BigInt(this.agentId));
246
+ if (addr === import_ethers.ethers.ZeroAddress) {
247
+ throw new AgetherError("No AgentAccount found. Call register() first.", "NO_ACCOUNT");
248
+ }
249
+ this._accountAddress = addr;
250
+ return addr;
251
+ }
252
+ getAgentId() {
253
+ if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
254
+ return this.agentId;
255
+ }
256
+ getWalletAddress() {
257
+ return this.wallet.address;
258
+ }
259
+ /**
260
+ * Register: create ERC-8004 identity + AgentAccount in one flow.
261
+ * If already registered, returns existing state.
262
+ */
263
+ async register(_name) {
264
+ const eoaAddr = this.wallet.address;
265
+ if (this.agentId) {
266
+ const exists = await this.accountFactory.accountExists(BigInt(this.agentId));
267
+ if (exists) {
268
+ const acct = await this.accountFactory.getAccount(BigInt(this.agentId));
269
+ this._accountAddress = acct;
270
+ return { agentId: this.agentId, address: eoaAddr, agentAccount: acct, alreadyRegistered: true };
271
+ }
272
+ }
273
+ const balance = await this.identityRegistry.balanceOf(eoaAddr);
274
+ let agentId;
275
+ if (balance > 0n && this.agentId) {
276
+ agentId = BigInt(this.agentId);
277
+ } else if (balance > 0n) {
278
+ throw new AgetherError(
279
+ "Wallet already has an ERC-8004 identity but agentId is unknown. Pass agentId in config.",
280
+ "AGENT_ID_UNKNOWN"
281
+ );
282
+ } else {
283
+ const regTx = await this.identityRegistry.register();
284
+ const regReceipt = await regTx.wait();
285
+ agentId = 0n;
286
+ for (const log of regReceipt.logs) {
287
+ try {
288
+ const parsed = this.identityRegistry.interface.parseLog({ topics: log.topics, data: log.data });
289
+ if (parsed?.name === "Transfer") {
290
+ agentId = parsed.args[2];
291
+ break;
292
+ }
293
+ } catch {
294
+ continue;
295
+ }
296
+ }
297
+ if (agentId === 0n) throw new AgetherError("Failed to parse agentId from registration", "PARSE_ERROR");
298
+ }
299
+ this.agentId = agentId.toString();
300
+ const acctExists = await this.accountFactory.accountExists(agentId);
301
+ let txHash;
302
+ if (!acctExists) {
303
+ const tx = await this.accountFactory.createAccount(agentId);
304
+ const receipt = await tx.wait();
305
+ txHash = receipt.hash;
306
+ }
307
+ const acctAddr = await this.accountFactory.getAccount(agentId);
308
+ this._accountAddress = acctAddr;
309
+ return {
310
+ agentId: this.agentId,
311
+ address: eoaAddr,
312
+ agentAccount: acctAddr,
313
+ alreadyRegistered: acctExists,
314
+ tx: txHash
315
+ };
316
+ }
317
+ /** Get ETH / USDC balances for EOA and AgentAccount. */
318
+ async getBalances() {
319
+ const eoaAddr = this.wallet.address;
320
+ const usdc = new import_ethers.Contract(this.config.contracts.usdc, ERC20_ABI, this.provider);
321
+ const ethBal = await this.provider.getBalance(eoaAddr);
322
+ const usdcBal = await usdc.balanceOf(eoaAddr);
323
+ const result = {
324
+ agentId: this.agentId || "?",
325
+ address: eoaAddr,
326
+ eth: import_ethers.ethers.formatEther(ethBal),
327
+ usdc: import_ethers.ethers.formatUnits(usdcBal, 6)
328
+ };
329
+ try {
330
+ const acctAddr = await this.getAccountAddress();
331
+ const acctEth = await this.provider.getBalance(acctAddr);
332
+ const acctUsdc = await usdc.balanceOf(acctAddr);
333
+ result.agentAccount = {
334
+ address: acctAddr,
335
+ eth: import_ethers.ethers.formatEther(acctEth),
336
+ usdc: import_ethers.ethers.formatUnits(acctUsdc, 6)
337
+ };
338
+ } catch {
339
+ }
340
+ return result;
341
+ }
342
+ /** Transfer USDC from EOA to AgentAccount. */
343
+ async fundAccount(usdcAmount) {
344
+ const acctAddr = await this.getAccountAddress();
345
+ const usdc = new import_ethers.Contract(this.config.contracts.usdc, ERC20_ABI, this.wallet);
346
+ const amount = import_ethers.ethers.parseUnits(usdcAmount, 6);
347
+ const tx = await usdc.transfer(acctAddr, amount);
348
+ const receipt = await tx.wait();
349
+ return { tx: receipt.hash, amount: usdcAmount, agentAccount: acctAddr };
350
+ }
351
+ // ════════════════════════════════════════════════════════
352
+ // Market Discovery (Morpho GraphQL API)
353
+ // ════════════════════════════════════════════════════════
354
+ /**
355
+ * Fetch USDC borrow markets on Base from Morpho API.
356
+ * Caches results for 5 minutes.
357
+ */
358
+ async getMarkets(forceRefresh = false) {
359
+ if (!forceRefresh && this._discoveredMarkets && Date.now() - this._discoveredAt < 3e5) {
360
+ return this._discoveredMarkets;
361
+ }
362
+ const chainId = this.config.chainId;
363
+ const usdcAddr = this.config.contracts.usdc.toLowerCase();
364
+ const query = `{
365
+ markets(
366
+ first: 50
367
+ orderBy: SupplyAssetsUsd
368
+ orderDirection: Desc
369
+ where: { chainId_in: [${chainId}], loanAssetAddress_in: ["${usdcAddr}"] }
370
+ ) {
371
+ items {
372
+ uniqueKey
373
+ lltv
374
+ oracleAddress
375
+ irmAddress
376
+ loanAsset { address symbol decimals }
377
+ collateralAsset { address symbol decimals }
378
+ state {
379
+ borrowAssets
380
+ supplyAssets
381
+ utilization
382
+ }
383
+ }
384
+ }
385
+ }`;
386
+ try {
387
+ const resp = await import_axios.default.post(MORPHO_API_URL, { query }, { timeout: 1e4 });
388
+ const items = resp.data?.data?.markets?.items ?? [];
389
+ this._discoveredMarkets = items.map((m) => ({
390
+ uniqueKey: m.uniqueKey,
391
+ loanAsset: m.loanAsset,
392
+ collateralAsset: m.collateralAsset ?? { address: import_ethers.ethers.ZeroAddress, symbol: "N/A", decimals: 0 },
393
+ oracle: m.oracleAddress,
394
+ irm: m.irmAddress,
395
+ lltv: BigInt(m.lltv),
396
+ totalSupplyAssets: BigInt(m.state?.supplyAssets ?? "0"),
397
+ totalBorrowAssets: BigInt(m.state?.borrowAssets ?? "0"),
398
+ utilization: m.state?.utilization ? Number(m.state.utilization) : 0
399
+ }));
400
+ this._discoveredAt = Date.now();
401
+ for (const mi of this._discoveredMarkets) {
402
+ if (mi.collateralAsset.address !== import_ethers.ethers.ZeroAddress) {
403
+ this._marketCache.set(mi.collateralAsset.address.toLowerCase(), {
404
+ loanToken: mi.loanAsset.address,
405
+ collateralToken: mi.collateralAsset.address,
406
+ oracle: mi.oracle,
407
+ irm: mi.irm,
408
+ lltv: mi.lltv
409
+ });
410
+ }
411
+ }
412
+ return this._discoveredMarkets;
413
+ } catch {
414
+ return this._discoveredMarkets ?? [];
415
+ }
416
+ }
417
+ /**
418
+ * Get MarketParams for a collateral token.
419
+ * Tries cache → API → on-chain idToMarketParams.
420
+ */
421
+ async findMarketForCollateral(collateralSymbolOrAddress) {
422
+ const colInfo = BASE_COLLATERALS[collateralSymbolOrAddress];
423
+ const colAddr = (colInfo?.address ?? collateralSymbolOrAddress).toLowerCase();
424
+ const cached = this._marketCache.get(colAddr);
425
+ if (cached) return cached;
426
+ await this.getMarkets();
427
+ const fromApi = this._marketCache.get(colAddr);
428
+ if (fromApi) return fromApi;
429
+ throw new AgetherError(
430
+ `No Morpho market found for collateral ${collateralSymbolOrAddress}`,
431
+ "MARKET_NOT_FOUND"
432
+ );
433
+ }
434
+ /** Read MarketParams on-chain by market ID (bytes32). */
435
+ async getMarketParams(marketId) {
436
+ const result = await this.morphoBlue.idToMarketParams(marketId);
437
+ return {
438
+ loanToken: result.loanToken,
439
+ collateralToken: result.collateralToken,
440
+ oracle: result.oracle,
441
+ irm: result.irm,
442
+ lltv: result.lltv
443
+ };
444
+ }
445
+ // ════════════════════════════════════════════════════════
446
+ // Position Reads
447
+ // ════════════════════════════════════════════════════════
448
+ /** Read on-chain position for a specific market. */
449
+ async getPosition(marketId) {
450
+ const acctAddr = await this.getAccountAddress();
451
+ const pos = await this.morphoBlue.position(marketId, acctAddr);
452
+ return {
453
+ supplyShares: pos.supplyShares,
454
+ borrowShares: pos.borrowShares,
455
+ collateral: pos.collateral
456
+ };
457
+ }
458
+ /**
459
+ * Full status: positions across all discovered markets.
460
+ */
461
+ async getStatus() {
462
+ const acctAddr = await this.getAccountAddress();
463
+ const markets = await this.getMarkets();
464
+ const positions = [];
465
+ let totalDebt = 0n;
466
+ for (const m of markets) {
467
+ if (!m.collateralAsset || m.collateralAsset.address === import_ethers.ethers.ZeroAddress) continue;
468
+ try {
469
+ const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
470
+ if (pos.collateral === 0n && pos.borrowShares === 0n && pos.supplyShares === 0n) continue;
471
+ let debt = 0n;
472
+ if (pos.borrowShares > 0n) {
473
+ try {
474
+ const mkt = await this.morphoBlue.market(m.uniqueKey);
475
+ const totalBorrowShares = BigInt(mkt.totalBorrowShares);
476
+ const totalBorrowAssets = BigInt(mkt.totalBorrowAssets);
477
+ debt = totalBorrowShares > 0n ? BigInt(pos.borrowShares) * totalBorrowAssets / totalBorrowShares : 0n;
478
+ totalDebt += debt;
479
+ } catch {
480
+ }
481
+ }
482
+ positions.push({
483
+ marketId: m.uniqueKey,
484
+ collateralToken: m.collateralAsset.symbol,
485
+ collateral: import_ethers.ethers.formatUnits(pos.collateral, m.collateralAsset.decimals),
486
+ borrowShares: pos.borrowShares.toString(),
487
+ supplyShares: pos.supplyShares.toString(),
488
+ debt: import_ethers.ethers.formatUnits(debt, 6)
489
+ });
490
+ } catch {
491
+ continue;
492
+ }
493
+ }
494
+ return {
495
+ agentId: this.agentId || "?",
496
+ agentAccount: acctAddr,
497
+ totalDebt: import_ethers.ethers.formatUnits(totalDebt, 6),
498
+ positions
499
+ };
500
+ }
501
+ // ════════════════════════════════════════════════════════
502
+ // Lending Operations (all via AgentAccount.executeBatch)
503
+ // ════════════════════════════════════════════════════════
504
+ /**
505
+ * Deposit collateral into Morpho Blue.
506
+ *
507
+ * Flow:
508
+ * 1. EOA transfers collateral to AgentAccount
509
+ * 2. AgentAccount.executeBatch:
510
+ * [collateral.approve(MorphoBlue), Morpho.supplyCollateral(params)]
511
+ */
512
+ async supplyCollateral(tokenSymbol, amount, marketParams) {
513
+ const acctAddr = await this.getAccountAddress();
514
+ const colInfo = BASE_COLLATERALS[tokenSymbol];
515
+ if (!colInfo) throw new AgetherError(`Unknown collateral: ${tokenSymbol}`, "UNKNOWN_COLLATERAL");
516
+ const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
517
+ const weiAmount = import_ethers.ethers.parseUnits(amount, colInfo.decimals);
518
+ const morphoAddr = this.config.contracts.morphoBlue;
519
+ const colToken = new import_ethers.Contract(colInfo.address, ERC20_ABI, this.wallet);
520
+ const transferTx = await colToken.transfer(acctAddr, weiAmount);
521
+ await transferTx.wait();
522
+ const targets = [colInfo.address, morphoAddr];
523
+ const values = [0n, 0n];
524
+ const datas = [
525
+ erc20Iface.encodeFunctionData("approve", [morphoAddr, weiAmount]),
526
+ morphoIface.encodeFunctionData("supplyCollateral", [
527
+ this._toTuple(params),
528
+ weiAmount,
529
+ acctAddr,
530
+ "0x"
531
+ ])
532
+ ];
533
+ const receipt = await this.batch(targets, values, datas);
534
+ return {
535
+ tx: receipt.hash,
536
+ collateralToken: tokenSymbol,
537
+ amount,
538
+ agentAccount: acctAddr
539
+ };
540
+ }
541
+ /**
542
+ * Borrow USDC against existing collateral.
543
+ *
544
+ * AgentAccount.execute: Morpho.borrow(params, amount, 0, account, account)
545
+ *
546
+ * @param usdcAmount - USDC amount (e.g. '100')
547
+ * @param tokenSymbol - collateral symbol to identify which market (default: first with collateral)
548
+ */
549
+ async borrow(usdcAmount, tokenSymbol, marketParams) {
550
+ const acctAddr = await this.getAccountAddress();
551
+ const amount = import_ethers.ethers.parseUnits(usdcAmount, 6);
552
+ const morphoAddr = this.config.contracts.morphoBlue;
553
+ let params;
554
+ let usedToken = tokenSymbol || "WETH";
555
+ if (marketParams) {
556
+ params = marketParams;
557
+ } else if (tokenSymbol) {
558
+ params = await this.findMarketForCollateral(tokenSymbol);
559
+ } else {
560
+ const { params: p, symbol } = await this._findActiveMarket();
561
+ params = p;
562
+ usedToken = symbol;
563
+ }
564
+ const data = morphoIface.encodeFunctionData("borrow", [
565
+ this._toTuple(params),
566
+ amount,
567
+ 0n,
568
+ acctAddr,
569
+ acctAddr
570
+ ]);
571
+ const receipt = await this.exec(morphoAddr, data);
572
+ return {
573
+ tx: receipt.hash,
574
+ amount: usdcAmount,
575
+ collateralToken: usedToken,
576
+ agentAccount: acctAddr
577
+ };
578
+ }
579
+ /**
580
+ * Deposit collateral AND borrow USDC in one batched transaction.
581
+ *
582
+ * AgentAccount.executeBatch:
583
+ * [collateral.approve, Morpho.supplyCollateral, Morpho.borrow]
584
+ *
585
+ * The collateral must be transferred to AgentAccount first.
586
+ */
587
+ async depositAndBorrow(tokenSymbol, collateralAmount, borrowUsdcAmount, marketParams) {
588
+ const acctAddr = await this.getAccountAddress();
589
+ const colInfo = BASE_COLLATERALS[tokenSymbol];
590
+ if (!colInfo) throw new AgetherError(`Unknown collateral: ${tokenSymbol}`, "UNKNOWN_COLLATERAL");
591
+ const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
592
+ const colWei = import_ethers.ethers.parseUnits(collateralAmount, colInfo.decimals);
593
+ const borrowWei = import_ethers.ethers.parseUnits(borrowUsdcAmount, 6);
594
+ const morphoAddr = this.config.contracts.morphoBlue;
595
+ const colToken = new import_ethers.Contract(colInfo.address, ERC20_ABI, this.wallet);
596
+ const transferTx = await colToken.transfer(acctAddr, colWei);
597
+ await transferTx.wait();
598
+ const targets = [colInfo.address, morphoAddr, morphoAddr];
599
+ const values = [0n, 0n, 0n];
600
+ const datas = [
601
+ erc20Iface.encodeFunctionData("approve", [morphoAddr, colWei]),
602
+ morphoIface.encodeFunctionData("supplyCollateral", [
603
+ this._toTuple(params),
604
+ colWei,
605
+ acctAddr,
606
+ "0x"
607
+ ]),
608
+ morphoIface.encodeFunctionData("borrow", [
609
+ this._toTuple(params),
610
+ borrowWei,
611
+ 0n,
612
+ acctAddr,
613
+ acctAddr
614
+ ])
615
+ ];
616
+ const receipt = await this.batch(targets, values, datas);
617
+ return {
618
+ tx: receipt.hash,
619
+ collateralToken: tokenSymbol,
620
+ collateralAmount,
621
+ borrowAmount: borrowUsdcAmount,
622
+ agentAccount: acctAddr
623
+ };
624
+ }
625
+ /**
626
+ * Repay borrowed USDC from AgentAccount.
627
+ *
628
+ * AgentAccount.executeBatch:
629
+ * [USDC.approve(MorphoBlue), Morpho.repay(params)]
630
+ */
631
+ async repay(usdcAmount, tokenSymbol, marketParams) {
632
+ const acctAddr = await this.getAccountAddress();
633
+ const amount = import_ethers.ethers.parseUnits(usdcAmount, 6);
634
+ const morphoAddr = this.config.contracts.morphoBlue;
635
+ const usdcAddr = this.config.contracts.usdc;
636
+ let params;
637
+ if (marketParams) {
638
+ params = marketParams;
639
+ } else if (tokenSymbol) {
640
+ params = await this.findMarketForCollateral(tokenSymbol);
641
+ } else {
642
+ const { params: p } = await this._findActiveMarket();
643
+ params = p;
644
+ }
645
+ const targets = [usdcAddr, morphoAddr];
646
+ const values = [0n, 0n];
647
+ const datas = [
648
+ erc20Iface.encodeFunctionData("approve", [morphoAddr, amount]),
649
+ morphoIface.encodeFunctionData("repay", [
650
+ this._toTuple(params),
651
+ amount,
652
+ 0n,
653
+ acctAddr,
654
+ "0x"
655
+ ])
656
+ ];
657
+ const receipt = await this.batch(targets, values, datas);
658
+ let remainingDebt = "0";
659
+ try {
660
+ const status = await this.getStatus();
661
+ remainingDebt = status.totalDebt;
662
+ } catch {
663
+ }
664
+ return { tx: receipt.hash, amount: usdcAmount, remainingDebt };
665
+ }
666
+ /**
667
+ * Withdraw collateral from Morpho Blue.
668
+ *
669
+ * AgentAccount.execute: Morpho.withdrawCollateral(params, amount, account, receiver)
670
+ *
671
+ * @param receiver - defaults to EOA wallet
672
+ */
673
+ async withdrawCollateral(tokenSymbol, amount, marketParams, receiver) {
674
+ const acctAddr = await this.getAccountAddress();
675
+ const colInfo = BASE_COLLATERALS[tokenSymbol];
676
+ if (!colInfo) throw new AgetherError(`Unknown collateral: ${tokenSymbol}`, "UNKNOWN_COLLATERAL");
677
+ const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
678
+ const morphoAddr = this.config.contracts.morphoBlue;
679
+ const dest = receiver || this.wallet.address;
680
+ let weiAmount;
681
+ if (amount === "all") {
682
+ const markets = await this.getMarkets();
683
+ const market = markets.find(
684
+ (m) => m.collateralAsset.address.toLowerCase() === colInfo.address.toLowerCase()
685
+ );
686
+ if (!market) throw new AgetherError("Market not found", "MARKET_NOT_FOUND");
687
+ const pos = await this.morphoBlue.position(market.uniqueKey, acctAddr);
688
+ weiAmount = pos.collateral;
689
+ if (weiAmount === 0n) throw new AgetherError("No collateral to withdraw", "NO_COLLATERAL");
690
+ } else {
691
+ weiAmount = import_ethers.ethers.parseUnits(amount, colInfo.decimals);
692
+ }
693
+ const data = morphoIface.encodeFunctionData("withdrawCollateral", [
694
+ this._toTuple(params),
695
+ weiAmount,
696
+ acctAddr,
697
+ dest
698
+ ]);
699
+ const receipt = await this.exec(morphoAddr, data);
700
+ let remainingCollateral = "0";
701
+ try {
702
+ const markets = await this.getMarkets();
703
+ const market = markets.find(
704
+ (m) => m.collateralAsset.address.toLowerCase() === colInfo.address.toLowerCase()
705
+ );
706
+ if (market) {
707
+ const pos = await this.morphoBlue.position(market.uniqueKey, acctAddr);
708
+ remainingCollateral = import_ethers.ethers.formatUnits(pos.collateral, colInfo.decimals);
709
+ }
710
+ } catch {
711
+ }
712
+ return {
713
+ tx: receipt.hash,
714
+ token: tokenSymbol,
715
+ amount: amount === "all" ? import_ethers.ethers.formatUnits(weiAmount, colInfo.decimals) : amount,
716
+ remainingCollateral,
717
+ destination: dest
718
+ };
719
+ }
720
+ /**
721
+ * Sponsor: transfer collateral to another agent's AgentAccount.
722
+ * (The agent must then supplyCollateral themselves via their own account.)
723
+ */
724
+ async sponsor(target, tokenSymbol, amount) {
725
+ const colInfo = BASE_COLLATERALS[tokenSymbol];
726
+ if (!colInfo) throw new AgetherError(`Unknown collateral: ${tokenSymbol}`, "UNKNOWN_COLLATERAL");
727
+ let targetAddr;
728
+ if (target.address) {
729
+ targetAddr = target.address;
730
+ } else if (target.agentId) {
731
+ targetAddr = await this.accountFactory.getAccount(BigInt(target.agentId));
732
+ if (targetAddr === import_ethers.ethers.ZeroAddress) throw new AgetherError("Target agent has no account", "NO_ACCOUNT");
733
+ } else {
734
+ throw new AgetherError("Provide agentId or address", "INVALID_TARGET");
735
+ }
736
+ const weiAmount = import_ethers.ethers.parseUnits(amount, colInfo.decimals);
737
+ const colToken = new import_ethers.Contract(colInfo.address, ERC20_ABI, this.wallet);
738
+ const tx = await colToken.transfer(targetAddr, weiAmount);
739
+ const receipt = await tx.wait();
740
+ return { tx: receipt.hash, targetAccount: targetAddr, targetAgentId: target.agentId };
741
+ }
742
+ // ════════════════════════════════════════════════════════
743
+ // Reputation (AgentReputation contract)
744
+ // ════════════════════════════════════════════════════════
745
+ async getCreditScore() {
746
+ if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
747
+ return this.agentReputation.getCreditScore(BigInt(this.agentId));
748
+ }
749
+ async getAttestation() {
750
+ if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
751
+ const att = await this.agentReputation.getAttestation(BigInt(this.agentId));
752
+ return { score: att.score, timestamp: att.timestamp, signer: att.signer };
753
+ }
754
+ async isEligible(minScore = 500n) {
755
+ if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
756
+ const [eligible, currentScore] = await this.agentReputation.isEligible(BigInt(this.agentId), minScore);
757
+ return { eligible, currentScore };
758
+ }
759
+ async isScoreFresh() {
760
+ if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
761
+ const [fresh, age] = await this.agentReputation.isScoreFresh(BigInt(this.agentId));
762
+ return { fresh, age };
763
+ }
764
+ // ════════════════════════════════════════════════════════
765
+ // Internal Helpers
766
+ // ════════════════════════════════════════════════════════
767
+ /**
768
+ * Execute a single call via AgentAccount.execute.
769
+ */
770
+ async exec(target, data, value = 0n) {
771
+ const acctAddr = await this.getAccountAddress();
772
+ const account = new import_ethers.Contract(acctAddr, AGENT_ACCOUNT_ABI, this.wallet);
773
+ let gasLimit;
774
+ try {
775
+ const estimate = await account.execute.estimateGas(target, value, data);
776
+ gasLimit = estimate * 130n / 100n;
777
+ } catch {
778
+ gasLimit = 500000n;
779
+ }
780
+ const tx = await account.execute(target, value, data, { gasLimit });
781
+ return tx.wait();
782
+ }
783
+ /**
784
+ * Execute multiple calls via AgentAccount.executeBatch.
785
+ */
786
+ async batch(targets, values, datas) {
787
+ const acctAddr = await this.getAccountAddress();
788
+ const account = new import_ethers.Contract(acctAddr, AGENT_ACCOUNT_ABI, this.wallet);
789
+ let gasLimit;
790
+ try {
791
+ const estimate = await account.executeBatch.estimateGas(targets, values, datas);
792
+ gasLimit = estimate * 130n / 100n;
793
+ } catch {
794
+ gasLimit = 800000n;
795
+ }
796
+ const tx = await account.executeBatch(targets, values, datas, { gasLimit });
797
+ return tx.wait();
798
+ }
799
+ /** Convert MorphoMarketParams to Solidity tuple. */
800
+ _toTuple(p) {
801
+ return [p.loanToken, p.collateralToken, p.oracle, p.irm, p.lltv];
802
+ }
803
+ /** Find the first market where the agent has collateral deposited. */
804
+ async _findActiveMarket() {
805
+ const acctAddr = await this.getAccountAddress();
806
+ const markets = await this.getMarkets();
807
+ for (const m of markets) {
808
+ if (!m.collateralAsset || m.collateralAsset.address === import_ethers.ethers.ZeroAddress) continue;
809
+ try {
810
+ const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
811
+ if (pos.collateral > 0n) {
812
+ return {
813
+ params: {
814
+ loanToken: m.loanAsset.address,
815
+ collateralToken: m.collateralAsset.address,
816
+ oracle: m.oracle,
817
+ irm: m.irm,
818
+ lltv: m.lltv
819
+ },
820
+ symbol: m.collateralAsset.symbol
821
+ };
822
+ }
823
+ } catch {
824
+ continue;
825
+ }
826
+ }
827
+ const params = await this.findMarketForCollateral("WETH");
828
+ return { params, symbol: "WETH" };
829
+ }
830
+ };
831
+ }
832
+ });
833
+
33
834
  // src/clients/X402Client.ts
34
835
  var X402Client_exports = {};
35
836
  __export(X402Client_exports, {
@@ -39,11 +840,11 @@ function chainIdFromNetwork(network) {
39
840
  const m = network.match(/^eip155:(\d+)$/);
40
841
  return m ? Number(m[1]) : 1;
41
842
  }
42
- var import_ethers, USDC_DOMAINS, X402Client;
843
+ var import_ethers2, USDC_DOMAINS, X402Client;
43
844
  var init_X402Client = __esm({
44
845
  "src/clients/X402Client.ts"() {
45
846
  "use strict";
46
- import_ethers = require("ethers");
847
+ import_ethers2 = require("ethers");
47
848
  USDC_DOMAINS = {
48
849
  "eip155:1": { name: "USD Coin", version: "2", address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" },
49
850
  "eip155:8453": { name: "USD Coin", version: "2", address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" },
@@ -51,11 +852,11 @@ var init_X402Client = __esm({
51
852
  "eip155:42161": { name: "USD Coin", version: "2", address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831" },
52
853
  "eip155:10": { name: "USD Coin", version: "2", address: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85" }
53
854
  };
54
- X402Client = class _X402Client {
855
+ X402Client = class {
55
856
  constructor(config) {
56
857
  this.config = config;
57
- const provider = new import_ethers.ethers.JsonRpcProvider(config.rpcUrl);
58
- this.wallet = new import_ethers.ethers.Wallet(config.privateKey, provider);
858
+ const provider = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
859
+ this.wallet = new import_ethers2.ethers.Wallet(config.privateKey, provider);
59
860
  }
60
861
  async get(url, opts) {
61
862
  return this.request(url, { ...opts, method: "GET" });
@@ -100,9 +901,6 @@ var init_X402Client = __esm({
100
901
  console.log(` amount : ${requirements.amount} (atomic)`);
101
902
  console.log(` asset : ${requirements.asset}`);
102
903
  console.log(` payTo : ${requirements.payTo}`);
103
- if (this.config.autoDraw && this.config.accountAddress && this.config.morphoCreditAddress) {
104
- await this.ensureBalance(BigInt(requirements.amount));
105
- }
106
904
  console.log(" [3/4] Signing EIP-3009 transferWithAuthorization\u2026");
107
905
  const paymentPayload = await this.buildPaymentPayload(requirements, resource, url);
108
906
  const paymentB64 = Buffer.from(JSON.stringify(paymentPayload)).toString("base64");
@@ -198,7 +996,7 @@ var init_X402Client = __esm({
198
996
  const now = Math.floor(Date.now() / 1e3);
199
997
  const validAfter = String(now - 60);
200
998
  const validBefore = String(now + (reqs.maxTimeoutSeconds || 300));
201
- const nonce = import_ethers.ethers.hexlify(import_ethers.ethers.randomBytes(32));
999
+ const nonce = import_ethers2.ethers.hexlify(import_ethers2.ethers.randomBytes(32));
202
1000
  const chainId = chainIdFromNetwork(reqs.network);
203
1001
  const usdcDomain = USDC_DOMAINS[reqs.network] || USDC_DOMAINS["eip155:1"];
204
1002
  const payerAddress = this.config.accountAddress || this.wallet.address;
@@ -263,73 +1061,6 @@ var init_X402Client = __esm({
263
1061
  }
264
1062
  };
265
1063
  }
266
- static {
267
- // ──────────── Auto-draw (Flow 9) ────────────
268
- //
269
- // When autoDraw is enabled and the AgentAccount has insufficient USDC,
270
- // automatically borrow from Morpho credit line to cover the payment.
271
- this.MORPHO_DRAW_ABI = [
272
- "function drawWithCollateral(address collateralToken, uint256 amount)",
273
- "function getPosition(address account, address collateralToken) view returns (tuple(uint256 collateralAmount, uint256 borrowedAmount, uint256 borrowShares, bool isActive))"
274
- ];
275
- }
276
- static {
277
- this.AGENT_ACCOUNT_EXEC_ABI = [
278
- "function execute(address target, uint256 value, bytes data) payable returns (bytes)"
279
- ];
280
- }
281
- static {
282
- this.ERC20_BALANCE_ABI = [
283
- "function balanceOf(address) view returns (uint256)"
284
- ];
285
- }
286
- static {
287
- this.AUTO_DRAW_COLLATERALS = [
288
- "0x4200000000000000000000000000000000000006",
289
- // WETH
290
- "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452",
291
- // wstETH
292
- "0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22"
293
- // cbETH
294
- ];
295
- }
296
- async ensureBalance(requiredAmount) {
297
- const accountAddr = this.config.accountAddress;
298
- const morphoAddr = this.config.morphoCreditAddress;
299
- const provider = this.wallet.provider;
300
- const usdcAddr = USDC_DOMAINS["eip155:8453"]?.address || USDC_DOMAINS["eip155:1"].address;
301
- const usdc = new import_ethers.ethers.Contract(usdcAddr, _X402Client.ERC20_BALANCE_ABI, provider);
302
- const balance = await usdc.balanceOf(accountAddr);
303
- const needed = requiredAmount + requiredAmount / 10n;
304
- if (balance >= needed) return;
305
- const deficit = needed - balance;
306
- const minDraw = import_ethers.ethers.parseUnits("10", 6);
307
- const drawAmount = deficit > minDraw ? deficit : minDraw;
308
- console.log(` [auto-draw] USDC balance $${import_ethers.ethers.formatUnits(balance, 6)} < needed $${import_ethers.ethers.formatUnits(needed, 6)}`);
309
- const morpho = new import_ethers.ethers.Contract(morphoAddr, _X402Client.MORPHO_DRAW_ABI, provider);
310
- let collateralAddr = null;
311
- for (const addr of _X402Client.AUTO_DRAW_COLLATERALS) {
312
- try {
313
- const pos = await morpho.getPosition(accountAddr, addr);
314
- if (pos.collateralAmount > 0n) {
315
- collateralAddr = addr;
316
- break;
317
- }
318
- } catch {
319
- continue;
320
- }
321
- }
322
- if (!collateralAddr) {
323
- throw new Error("autoDraw failed: no collateral deposited in Morpho. Deposit collateral first.");
324
- }
325
- const account = new import_ethers.ethers.Contract(accountAddr, _X402Client.AGENT_ACCOUNT_EXEC_ABI, this.wallet);
326
- const morphoIface = new import_ethers.ethers.Interface(_X402Client.MORPHO_DRAW_ABI);
327
- const calldata = morphoIface.encodeFunctionData("drawWithCollateral", [collateralAddr, drawAmount]);
328
- console.log(` [auto-draw] Borrowing $${import_ethers.ethers.formatUnits(drawAmount, 6)} from Morpho...`);
329
- const tx = await account.execute(morphoAddr, 0, calldata);
330
- await tx.wait();
331
- console.log(` [auto-draw] \u2713 Borrowed (tx: ${tx.hash.slice(0, 14)}\u2026)`);
332
- }
333
1064
  // ──────────── Risk check via our backend ────────────
334
1065
  async riskCheck(paymentPayload, reqs) {
335
1066
  try {
@@ -365,7 +1096,7 @@ var init_X402Client = __esm({
365
1096
  });
366
1097
 
367
1098
  // src/cli.ts
368
- var import_ethers2 = require("ethers");
1099
+ var import_ethers3 = require("ethers");
369
1100
  var fs = __toESM(require("fs"));
370
1101
  var path = __toESM(require("path"));
371
1102
  var os = __toESM(require("os"));
@@ -383,11 +1114,17 @@ function loadConfig() {
383
1114
  }
384
1115
  function saveConfig(config) {
385
1116
  const dir = path.dirname(CONFIG_PATH);
386
- if (!fs.existsSync(dir)) {
387
- fs.mkdirSync(dir, { recursive: true });
388
- }
1117
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
389
1118
  fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
390
1119
  }
1120
+ function requireConfig() {
1121
+ const config = loadConfig();
1122
+ if (!config) {
1123
+ console.error("\u274C Not initialized. Run: agether init <private-key>");
1124
+ process.exit(1);
1125
+ }
1126
+ return config;
1127
+ }
391
1128
  async function waitForTx(tx, retries = 5) {
392
1129
  for (let attempt = 1; attempt <= retries; attempt++) {
393
1130
  try {
@@ -401,176 +1138,119 @@ async function waitForTx(tx, retries = 5) {
401
1138
  }
402
1139
  throw new Error("Failed to get transaction receipt after retries");
403
1140
  }
404
- function requireConfig() {
405
- const config = loadConfig();
406
- if (!config) {
407
- console.error("\u274C Not initialized. Run: agether init <private-key>");
408
- process.exit(1);
409
- }
410
- return config;
411
- }
412
- function getSigner(config) {
413
- const provider = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
414
- return new import_ethers2.ethers.Wallet(config.privateKey, provider);
415
- }
416
- function getFreshSigner(config) {
417
- const provider = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
418
- return new import_ethers2.ethers.Wallet(config.privateKey, provider);
1141
+ async function getMorphoClient(config) {
1142
+ const { MorphoClient: MorphoClient2 } = await Promise.resolve().then(() => (init_MorphoClient(), MorphoClient_exports));
1143
+ return new MorphoClient2({
1144
+ privateKey: config.privateKey,
1145
+ rpcUrl: config.rpcUrl,
1146
+ agentId: config.agentId !== "0" ? config.agentId : void 0
1147
+ });
419
1148
  }
420
- async function apiGet(backendUrl, endpoint) {
421
- const res = await fetch(`${backendUrl}${endpoint}`);
422
- return res.json();
1149
+ async function getX402Client(config) {
1150
+ const { X402Client: X402Client2 } = await Promise.resolve().then(() => (init_X402Client(), X402Client_exports));
1151
+ let accountAddress;
1152
+ try {
1153
+ const mc = await getMorphoClient(config);
1154
+ accountAddress = await mc.getAccountAddress();
1155
+ } catch {
1156
+ }
1157
+ return new X402Client2({
1158
+ privateKey: config.privateKey,
1159
+ rpcUrl: config.rpcUrl,
1160
+ backendUrl: config.backendUrl,
1161
+ agentId: config.agentId,
1162
+ accountAddress
1163
+ });
423
1164
  }
424
1165
  var ERC8004_ABI = [
425
1166
  "function register(string agentURI) external returns (uint256 agentId)",
426
1167
  "function register() external returns (uint256 agentId)",
427
1168
  "function ownerOf(uint256 tokenId) view returns (address)",
428
1169
  "function balanceOf(address owner) view returns (uint256)",
429
- "event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)",
430
- "event Registered(uint256 indexed agentId, string agentURI, address indexed owner)"
1170
+ "event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)"
431
1171
  ];
432
- var ACCOUNT_FACTORY_ABI = [
1172
+ var ACCOUNT_FACTORY_ABI2 = [
433
1173
  "function getAccount(uint256 agentId) view returns (address)",
434
1174
  "function accountExists(uint256 agentId) view returns (bool)",
435
- "function predictAddress(uint256 agentId) view returns (address)",
436
- "function totalAccounts() view returns (uint256)",
437
1175
  "function createAccount(uint256 agentId) returns (address account)",
438
1176
  "event AccountCreated(uint256 indexed agentId, address indexed account, address indexed owner)"
439
1177
  ];
440
- var AGENT_ACCOUNT_ABI = [
441
- "function agentId() view returns (uint256)",
442
- "function owner() view returns (address)",
443
- "function balanceOf(address token) view returns (uint256)",
444
- "function ethBalance() view returns (uint256)",
445
- "function execute(address target, uint256 value, bytes data) payable returns (bytes)",
446
- "function drawCredit(address creditProvider, uint256 amount)",
447
- "function repayCredit(address creditProvider, uint256 amount)",
448
- "function fund(address token, uint256 amount)",
449
- "function withdraw(address token, uint256 amount, address to)"
450
- ];
451
- var MORPHO_CREDIT_ABI = [
452
- "function depositCollateral(address collateralToken, uint256 amount)",
453
- "function depositCollateralFor(address onBehalf, address collateralToken, uint256 amount)",
454
- "function withdrawCollateral(address collateralToken, uint256 amount)",
455
- "function drawWithCollateral(address collateralToken, uint256 amount)",
456
- "function repayWithCollateral(address collateralToken, uint256 amount)",
457
- "function getPosition(address account, address collateralToken) view returns (tuple(uint256 collateralAmount, uint256 borrowedAmount, uint256 borrowShares, bool isActive))",
458
- "function getSupportedCollaterals() view returns (address[])",
459
- "function asset() view returns (address)",
460
- "function getCreditInfo(address account) view returns (tuple(uint256 limit, uint256 used, uint256 available, uint256 accruedInterest, uint256 aprBps, bool isActive, bool requiresCollateral))",
461
- "function getTotalDebt(address account) view returns (uint256)",
462
- "function maxDrawable(address account) view returns (uint256)"
463
- ];
464
- var REPUTATION_CREDIT_ABI = [
465
- "function asset() view returns (address)",
466
- "function isEligible(address account) view returns (bool)",
467
- "function getCreditInfo(address account) view returns (tuple(uint256 limit, uint256 used, uint256 available, uint256 accruedInterest, uint256 aprBps, bool isActive, bool requiresCollateral))",
468
- "function getTotalDebt(address account) view returns (uint256)",
469
- "function maxDrawable(address account) view returns (uint256)",
470
- "function applyForCredit(address account, uint256 requestedLimit)",
471
- "function getCreditLineStatus(address account) view returns (uint8)",
472
- "function getCreditLineDetails(address account) view returns (uint256 agentId, uint256 limit, uint256 used, uint256 aprBps, uint256 accruedInterest, uint256 requestedLimit, uint256 createdAt, uint256 lastActivityAt, uint8 status)",
473
- "function getAgentAccount(uint256 agentId) view returns (address)",
474
- "function previewScoredLimit(uint256 agentId) view returns (uint256 limit, uint256 score, bool eligible)",
475
- "function dailyDrawLimit() view returns (uint256)",
476
- "function totalBorrowed() view returns (uint256)",
477
- "event CreditApplied(uint256 indexed creditLineId, uint256 indexed agentId, uint256 requestedLimit)"
478
- ];
479
1178
  var VALIDATION_REGISTRY_ABI = [
480
- "function isAgentCodeApproved(uint256 agentId) view returns (bool)",
481
- "function getAgentValidations(uint256 agentId) view returns (bytes32[])"
482
- ];
483
- var ERC20_ABI = [
484
- "function balanceOf(address account) view returns (uint256)",
485
- "function approve(address spender, uint256 amount) external returns (bool)",
486
- "function allowance(address owner, address spender) view returns (uint256)",
487
- "function decimals() view returns (uint8)",
488
- "function symbol() view returns (string)"
1179
+ "function isAgentCodeApproved(uint256 agentId) view returns (bool)"
489
1180
  ];
490
1181
  var MOCK_ERC20_ABI = [
491
1182
  "function mint(address to, uint256 amount) external"
492
1183
  ];
493
- var STATUS_NAMES = {
494
- 0: "None",
495
- 1: "Pending",
496
- 2: "Active",
497
- 3: "Frozen",
498
- 4: "Closed",
499
- 5: "Defaulted"
500
- };
501
- function getCollateralInfo(chainId) {
502
- if (chainId === 8453 || chainId === 84532) {
503
- return {
504
- WETH: { address: "0x4200000000000000000000000000000000000006", decimals: 18 },
505
- wstETH: { address: "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452", decimals: 18 },
506
- cbETH: { address: "0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22", decimals: 18 }
507
- };
508
- }
509
- return {
510
- WETH: { address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", decimals: 18 },
511
- wstETH: { address: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", decimals: 18 }
512
- };
1184
+ async function apiGet(backendUrl, endpoint) {
1185
+ const res = await fetch(`${backendUrl}${endpoint}`);
1186
+ return res.json();
1187
+ }
1188
+ function decodeError(error) {
1189
+ const msg = error?.message || String(error);
1190
+ if (msg.includes("CodeNotApproved")) return "Agent code not approved. Complete KYA first.";
1191
+ if (msg.includes("0xda04aecc") || msg.includes("ExceedsMaxLtv"))
1192
+ return "ExceedsMaxLtv \u2014 collateral too low for this borrow amount.";
1193
+ if (msg.includes("0xfeca99cb") || msg.includes("ExecutionFailed"))
1194
+ return "ExecutionFailed \u2014 the inner contract call reverted.";
1195
+ if (msg.includes("0xa920ef9f"))
1196
+ return "PositionNotActive \u2014 no collateral deposited for this token.";
1197
+ if (msg.length > 200) return msg.slice(0, 200) + "...";
1198
+ return msg;
513
1199
  }
514
1200
  async function cmdInit(privateKey, agentId) {
515
1201
  const rpcUrl = process.env.AGETHER_RPC_URL || DEFAULT_RPC;
516
1202
  const backendUrl = process.env.AGETHER_BACKEND_URL || DEFAULT_BACKEND;
517
1203
  let wallet;
518
1204
  try {
519
- wallet = new import_ethers2.ethers.Wallet(privateKey);
1205
+ wallet = new import_ethers3.ethers.Wallet(privateKey);
520
1206
  } catch {
521
1207
  console.error("\u274C Invalid private key");
522
1208
  process.exit(1);
523
1209
  }
524
- const config = {
525
- privateKey,
526
- agentId: agentId || "0",
527
- rpcUrl,
528
- backendUrl
529
- };
1210
+ const config = { privateKey, agentId: agentId || "0", rpcUrl, backendUrl };
530
1211
  saveConfig(config);
531
- console.log(`\u2705 Initialized Agether CLI`);
1212
+ console.log("\u2705 Initialized Agether CLI");
532
1213
  console.log(` Address: ${wallet.address}`);
533
1214
  console.log(` RPC: ${rpcUrl}`);
534
1215
  console.log(` Backend: ${backendUrl}`);
535
1216
  console.log(` Config: ${CONFIG_PATH}`);
536
1217
  }
537
- async function cmdRegister(name, _codeUrl) {
1218
+ async function cmdRegister(name) {
538
1219
  const config = requireConfig();
539
- const signer = getSigner(config);
540
- const wallet = new import_ethers2.ethers.Wallet(config.privateKey);
541
- const agentName = name || `Agent-${wallet.address.slice(0, 8)}`;
1220
+ const provider = new import_ethers3.ethers.JsonRpcProvider(config.rpcUrl);
1221
+ const signer = new import_ethers3.ethers.Wallet(config.privateKey, provider);
1222
+ const agentName = name || `Agent-${signer.address.slice(0, 8)}`;
542
1223
  console.log(`\u{1F916} Registering agent: ${agentName}
543
1224
  `);
544
- console.log(` Wallet: ${wallet.address}`);
545
- console.log("\n [1/5] Fetching contract addresses...");
546
- let status;
1225
+ console.log(` Wallet: ${signer.address}`);
1226
+ console.log("\n [1/4] Fetching contract addresses...");
1227
+ let contracts;
547
1228
  try {
548
- status = await apiGet(config.backendUrl, "/status");
549
- if (!status.contracts?.agentRegistry) {
550
- console.error(" \u274C Backend not configured with agentRegistry");
551
- process.exit(1);
552
- }
553
- console.log(` \u2713 ChainId: ${status.chainId}`);
554
- console.log(` \u2713 Registry: ${status.contracts.agentRegistry}`);
1229
+ const statusResp = await apiGet(config.backendUrl, "/status");
1230
+ contracts = statusResp.contracts || {};
1231
+ console.log(" \u2713 Backend OK");
555
1232
  } catch (e) {
556
1233
  console.error(` \u274C Failed to reach backend: ${e.message}`);
557
1234
  process.exit(1);
558
1235
  }
559
- console.log(" [2/5] Registering on ERC-8004 IdentityRegistry...");
560
- const agentRegistry = new import_ethers2.ethers.Contract(
561
- status.contracts.agentRegistry,
562
- ERC8004_ABI,
563
- signer
564
- );
1236
+ const registryAddr = contracts.agentRegistry || contracts.identityRegistry;
1237
+ const factoryAddr = contracts.accountFactory;
1238
+ const validationAddr = contracts.validationRegistry;
1239
+ if (!registryAddr || !factoryAddr) {
1240
+ console.error(" \u274C Backend missing agentRegistry or accountFactory");
1241
+ process.exit(1);
1242
+ }
1243
+ console.log(" [2/4] Registering on ERC-8004 IdentityRegistry...");
1244
+ const agentRegistry = new import_ethers3.ethers.Contract(registryAddr, ERC8004_ABI, signer);
565
1245
  let agentId;
566
1246
  if (config.agentId && config.agentId !== "0") {
567
1247
  agentId = BigInt(config.agentId);
568
1248
  try {
569
1249
  const owner = await agentRegistry.ownerOf(agentId);
570
- if (owner.toLowerCase() === wallet.address.toLowerCase()) {
571
- console.log(` \u2713 Already registered as Agent #${agentId}, skipping mint`);
1250
+ if (owner.toLowerCase() === signer.address.toLowerCase()) {
1251
+ console.log(` \u2713 Already registered as Agent #${agentId}`);
572
1252
  } else {
573
- console.error(" \u274C agentId in config does not belong to this wallet");
1253
+ console.error(" \u274C agentId does not belong to this wallet");
574
1254
  process.exit(1);
575
1255
  }
576
1256
  } catch {
@@ -578,1551 +1258,325 @@ async function cmdRegister(name, _codeUrl) {
578
1258
  process.exit(1);
579
1259
  }
580
1260
  } else {
581
- const existingBalance = await agentRegistry.balanceOf(wallet.address);
1261
+ const existingBalance = await agentRegistry.balanceOf(signer.address);
582
1262
  if (existingBalance > 0n) {
583
- console.log(` \u26A0 Wallet already owns ${existingBalance} ERC-8004 token(s), minting another`);
1263
+ console.log(` \u26A0 Wallet already owns ${existingBalance} token(s), minting another`);
584
1264
  }
585
1265
  try {
586
1266
  const registrationFile = JSON.stringify({
587
1267
  type: "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
588
1268
  name: agentName,
589
1269
  description: "AI agent registered via Agether CLI",
590
- active: true,
591
- registrations: [{
592
- agentId: 0,
593
- agentRegistry: `eip155:${status.chainId}:${status.contracts.agentRegistry}`
594
- }]
1270
+ active: true
595
1271
  });
596
1272
  const agentURI = `data:application/json;base64,${Buffer.from(registrationFile).toString("base64")}`;
597
1273
  const tx = await agentRegistry["register(string)"](agentURI);
598
1274
  const receipt = await waitForTx(tx);
599
- const transferTopic = import_ethers2.ethers.id("Transfer(address,address,uint256)");
600
- const transferLog = receipt.logs.find(
601
- (log) => log.topics[0] === transferTopic
602
- );
1275
+ const transferTopic = import_ethers3.ethers.id("Transfer(address,address,uint256)");
1276
+ const transferLog = receipt.logs.find((log) => log.topics[0] === transferTopic);
603
1277
  if (transferLog && transferLog.topics.length >= 4) {
604
1278
  agentId = BigInt(transferLog.topics[3]);
605
1279
  } else {
606
- const registeredTopic = import_ethers2.ethers.id("Registered(uint256,string,address)");
607
- const registeredLog = receipt.logs.find(
608
- (log) => log.topics[0] === registeredTopic
609
- );
610
- if (registeredLog && registeredLog.topics.length >= 2) {
611
- agentId = BigInt(registeredLog.topics[1]);
612
- } else {
613
- console.error(" \u274C Could not parse agentId from receipt");
614
- console.error(" Logs:", receipt.logs.length);
615
- process.exit(1);
616
- }
617
- }
618
- const owner = await agentRegistry.ownerOf(agentId);
619
- if (owner.toLowerCase() !== wallet.address.toLowerCase()) {
620
- console.error(` \u274C Ownership mismatch: expected ${wallet.address}, got ${owner}`);
1280
+ console.error(" \u274C Could not parse agentId from receipt");
621
1281
  process.exit(1);
622
1282
  }
623
- console.log(` \u2713 Agent #${agentId} registered on ERC-8004`);
1283
+ console.log(` \u2713 Agent #${agentId} registered`);
624
1284
  console.log(` TX: ${tx.hash}`);
625
1285
  config.agentId = agentId.toString();
626
1286
  saveConfig(config);
627
1287
  } catch (e) {
628
- if (e.message?.includes("already") || e.message?.includes("exists") || e.message?.includes("execution reverted")) {
629
- console.log(" Already registered on ERC-8004, looking up existing agentId...");
630
- const balance = await agentRegistry.balanceOf(wallet.address);
1288
+ if (config.agentId && config.agentId !== "0") {
1289
+ agentId = BigInt(config.agentId);
1290
+ console.log(` Using existing Agent #${agentId}`);
1291
+ } else {
1292
+ const balance = await agentRegistry.balanceOf(signer.address);
631
1293
  if (balance > 0n) {
632
- if (config.agentId && config.agentId !== "0") {
633
- agentId = BigInt(config.agentId);
634
- const owner = await agentRegistry.ownerOf(agentId);
635
- if (owner.toLowerCase() === wallet.address.toLowerCase()) {
636
- console.log(` \u2713 Using existing Agent #${agentId}`);
637
- } else {
638
- console.error(" \u274C agentId in config does not belong to this wallet");
639
- process.exit(1);
640
- }
641
- } else {
642
- console.error(` Wallet owns ${balance} ERC-8004 tokens but agentId unknown.`);
643
- console.error(" Set manually: agether init <pk> --agent-id <id>");
644
- process.exit(1);
645
- }
1294
+ console.error(` Wallet owns ${balance} token(s) but agentId unknown.`);
1295
+ console.error(" Set manually: agether init <pk> --agent-id <id>");
646
1296
  } else {
647
- console.error(` \u274C No agentId in config. Re-register or set manually.`);
648
- process.exit(1);
1297
+ console.error(` \u274C Registration failed: ${e.message}`);
649
1298
  }
650
- } else {
651
- console.error(` \u274C Failed: ${e.message}`);
652
1299
  process.exit(1);
653
1300
  }
654
1301
  }
655
1302
  }
656
- const network = await new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl).getNetwork();
1303
+ const network = await provider.getNetwork();
657
1304
  const chainId = Number(network.chainId);
658
1305
  if (chainId === 31337 || chainId === 1) {
659
- if (status.contracts?.usdc) {
660
- console.log(" [3/5] Minting test USDC (Hardhat fork)...");
661
- const deployerPk = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
662
- const provider = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
663
- const deployer = new import_ethers2.ethers.Wallet(deployerPk, provider);
664
- const usdc = new import_ethers2.ethers.Contract(status.contracts.usdc, MOCK_ERC20_ABI, deployer);
1306
+ console.log(" [3/4] Minting test USDC (Hardhat fork)...");
1307
+ const deployerPk = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
1308
+ const deployer = new import_ethers3.ethers.Wallet(deployerPk, provider);
1309
+ const usdcAddr = contracts.usdc;
1310
+ if (usdcAddr) {
665
1311
  try {
666
- const mintAmount = BigInt(5e10);
667
- const tx = await usdc.mint(wallet.address, mintAmount);
1312
+ const usdc = new import_ethers3.ethers.Contract(usdcAddr, MOCK_ERC20_ABI, deployer);
1313
+ const tx = await usdc.mint(signer.address, BigInt(5e10));
668
1314
  await waitForTx(tx);
669
- console.log(` \u2713 Minted $${Number(mintAmount) / 1e6} USDC`);
670
- } catch (e) {
671
- console.log(` \u26A0 Mint failed: ${e.message?.slice(0, 80)}`);
1315
+ console.log(" \u2713 Minted $50,000 USDC");
1316
+ } catch {
1317
+ console.log(" \u26A0 Mint failed (probably real network)");
672
1318
  }
673
1319
  }
674
1320
  } else {
675
- console.log(" [3/5] Skipping USDC mint (real network \u2014 fund wallet manually)");
1321
+ console.log(" [3/4] Skipping USDC mint (real network)");
676
1322
  }
677
- console.log(" [4/5] Creating AgentAccount (smart wallet)...");
678
- if (status.contracts?.accountFactory) {
679
- const accountFactory = new import_ethers2.ethers.Contract(
680
- status.contracts.accountFactory,
681
- ACCOUNT_FACTORY_ABI,
682
- signer
683
- );
1323
+ console.log(" [4/4] Creating AgentAccount...");
1324
+ if (factoryAddr) {
1325
+ const factory = new import_ethers3.ethers.Contract(factoryAddr, ACCOUNT_FACTORY_ABI2, signer);
684
1326
  try {
685
- const exists = await accountFactory.accountExists(agentId);
1327
+ const exists = await factory.accountExists(agentId);
686
1328
  if (exists) {
687
- const accountAddr = await accountFactory.getAccount(agentId);
688
- console.log(` Already exists: ${accountAddr}`);
1329
+ const addr = await factory.getAccount(agentId);
1330
+ console.log(` Already exists: ${addr}`);
689
1331
  } else {
690
- const tx = await accountFactory.createAccount(agentId);
1332
+ const tx = await factory.createAccount(agentId);
691
1333
  await waitForTx(tx);
692
- const accountAddr = await accountFactory.getAccount(agentId);
693
- console.log(` \u2713 Account created: ${accountAddr}`);
1334
+ const addr = await factory.getAccount(agentId);
1335
+ console.log(` \u2713 Created: ${addr}`);
694
1336
  console.log(` TX: ${tx.hash}`);
695
1337
  }
696
1338
  } catch (e) {
697
1339
  console.error(` \u274C Failed: ${e.message}`);
698
1340
  }
699
- } else {
700
- console.log(" \u26A0 No accountFactory configured");
701
1341
  }
702
- console.log(" [5/5] Checking KYA status (ValidationRegistry)...");
703
- if (status.contracts?.validationRegistry) {
704
- const validationRegistry = new import_ethers2.ethers.Contract(
705
- status.contracts.validationRegistry,
706
- VALIDATION_REGISTRY_ABI,
707
- signer
708
- );
1342
+ if (validationAddr) {
1343
+ const vr = new import_ethers3.ethers.Contract(validationAddr, VALIDATION_REGISTRY_ABI, provider);
709
1344
  try {
710
- const approved = await validationRegistry.isAgentCodeApproved(agentId);
711
- console.log(` Code approved: ${approved ? "\u2705 Yes" : "\u23F3 Pending"}`);
1345
+ const approved = await vr.isAgentCodeApproved(agentId);
1346
+ console.log(`
1347
+ KYA Status: ${approved ? "\u2705 Approved" : "\u23F3 Pending"}`);
712
1348
  } catch {
713
- console.log(" \u26A0 Could not check validation status");
1349
+ console.log("\n KYA Status: \u26A0 Could not check");
714
1350
  }
715
- } else {
716
- console.log(" \u26A0 No validationRegistry configured");
717
- }
718
- console.log("\n \u{1F4CA} Fetching initial credit scores...");
719
- try {
720
- const scoreRes = await fetch(`${config.backendUrl}/credit/score/${agentId}`);
721
- const score = await scoreRes.json();
722
- if (score.error) {
723
- console.log(" \u26A0 Could not fetch scores (agent not yet indexed)");
724
- } else {
725
- console.log("");
726
- console.log(" Credit Score Summary:");
727
- console.log(` Bayesian Score: ${score.bayesianScore}/1000`);
728
- console.log(` Internal Score: ${score.internalScore}/1000`);
729
- console.log(` External Score: ${score.externalScore}/1000 (Cred Protocol)`);
730
- console.log(` Confidence: ${(score.confidence * 100).toFixed(0)}%`);
731
- console.log("");
732
- console.log(" ChainRisk Subscores (5-factor model):");
733
- if (score.subscores) {
734
- console.log(` Historical (35%): ${score.subscores.historical?.score || "N/A"} - ${score.subscores.historical?.description || ""}`);
735
- console.log(` Current Risk (25%):${score.subscores.currentRisk?.score || "N/A"} - ${score.subscores.currentRisk?.description || ""}`);
736
- console.log(` Utilization (15%): ${score.subscores.utilization?.score || "N/A"} - ${score.subscores.utilization?.description || ""}`);
737
- console.log(` On-chain TX (15%): ${score.subscores.onChainTx?.score || "N/A"} - ${score.subscores.onChainTx?.description || ""}`);
738
- console.log(` New Credit (10%): ${score.subscores.newCredit?.score || "N/A"} - ${score.subscores.newCredit?.description || ""}`);
739
- }
740
- }
741
- } catch {
742
- console.log(" \u26A0 Could not reach backend for scores");
743
1351
  }
744
1352
  console.log(`
745
- \u2705 Agent #${agentId} registered on ERC-8004!`);
1353
+ \u2705 Agent #${agentId} ready!`);
746
1354
  console.log(` Config: ${CONFIG_PATH}`);
747
- console.log("");
748
- console.log(" Next steps:");
749
- console.log(" 1. Wait for Admin to approve code (KYA audit) at /test");
750
- console.log(" 2. Apply for credit: agether apply --limit 5000");
751
- console.log(" 3. After approval, deposit collateral if required");
752
- console.log(" 4. Draw funds: agether draw --amount 1000");
1355
+ console.log("\n Next steps:");
1356
+ console.log(" agether balance");
1357
+ console.log(" agether deposit --amount 0.05 --token WETH");
1358
+ console.log(" agether borrow --amount 100");
753
1359
  }
754
- async function cmdApply(limitUsd) {
1360
+ async function cmdBalance() {
755
1361
  const config = requireConfig();
756
- const signer = getSigner(config);
757
- const agentId = BigInt(config.agentId);
758
- if (agentId === 0n) {
759
- console.error("\u274C No agentId. Run: agether register");
760
- process.exit(1);
761
- }
762
- console.log(`\u{1F4CB} Applying for $${limitUsd} credit line (Agent #${agentId})...
1362
+ const mc = await getMorphoClient(config);
1363
+ const balances = await mc.getBalances();
1364
+ console.log(`
1365
+ \u{1F4B0} Agent #${balances.agentId} Balances
763
1366
  `);
764
- const status = await apiGet(config.backendUrl, "/status");
765
- const reputationCreditAddr = status.contracts?.reputationCredit;
766
- const accountFactoryAddr = status.contracts?.accountFactory;
767
- if (!reputationCreditAddr || !accountFactoryAddr) {
768
- console.error("\u274C Backend not configured (missing reputationCredit or accountFactory)");
769
- process.exit(1);
770
- }
771
- const provider = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
772
- const accountFactory = new import_ethers2.ethers.Contract(accountFactoryAddr, ACCOUNT_FACTORY_ABI, provider);
773
- const reputationCredit = new import_ethers2.ethers.Contract(reputationCreditAddr, REPUTATION_CREDIT_ABI, signer);
774
- const accountExists = await accountFactory.accountExists(agentId);
775
- if (!accountExists) {
776
- console.error(" \u274C No AgentAccount. Run: agether register");
777
- process.exit(1);
1367
+ console.log(` EOA: ${balances.address}`);
1368
+ console.log(` ETH: ${parseFloat(balances.eth).toFixed(6)}`);
1369
+ console.log(` USDC: $${parseFloat(balances.usdc).toFixed(2)}`);
1370
+ if (balances.agentAccount) {
1371
+ console.log(`
1372
+ AgentAccount: ${balances.agentAccount.address}`);
1373
+ console.log(` ETH: ${parseFloat(balances.agentAccount.eth).toFixed(6)}`);
1374
+ console.log(` USDC: $${parseFloat(balances.agentAccount.usdc).toFixed(2)}`);
778
1375
  }
779
- const accountAddr = await accountFactory.getAccount(agentId);
780
- const statusCode = await reputationCredit.getCreditLineStatus(accountAddr);
781
- if (Number(statusCode) !== 0) {
782
- console.log(` \u26A0 Agent #${agentId} already has a credit line`);
783
- console.log(` Status: ${STATUS_NAMES[Number(statusCode)] || statusCode}`);
784
- const data = await reputationCredit.getCreditLineDetails(accountAddr);
785
- console.log(` Limit: $${(Number(data[1]) / 1e6).toFixed(2)}`);
1376
+ }
1377
+ async function cmdStatus() {
1378
+ const config = requireConfig();
1379
+ const mc = await getMorphoClient(config);
1380
+ console.log("\n\u{1F4CA} Morpho Positions\n");
1381
+ const status = await mc.getStatus();
1382
+ console.log(` Agent #${status.agentId}`);
1383
+ console.log(` Account: ${status.agentAccount}`);
1384
+ console.log(` Total Debt: $${parseFloat(status.totalDebt).toFixed(2)}`);
1385
+ if (status.positions.length === 0) {
1386
+ console.log("\n No active positions. Deposit collateral first:");
1387
+ console.log(" agether deposit --amount 0.05 --token WETH");
786
1388
  return;
787
1389
  }
788
- console.log(" [1/2] Evaluating credit application...");
789
- const limitRaw = import_ethers2.ethers.parseUnits(limitUsd.toString(), 6);
790
- let evaluation;
791
- try {
792
- const res = await fetch(`${config.backendUrl}/credit/evaluate`, {
793
- method: "POST",
794
- headers: { "Content-Type": "application/json" },
795
- body: JSON.stringify({
796
- agentId: agentId.toString(),
797
- requestedLimit: limitRaw.toString()
798
- })
799
- });
800
- evaluation = await res.json();
801
- } catch (e) {
802
- console.error(` \u274C Evaluation failed: ${e.message}`);
803
- process.exit(1);
804
- }
805
- console.log("");
806
- console.log(" \u{1F4CA} Evaluation Results:");
807
- console.log(` Approved: ${evaluation.approved ? "\u2705 Yes" : "\u274C No"}`);
808
- console.log(` Credit Limit: $${(Number(evaluation.limit) / 1e6).toFixed(2)}`);
809
- console.log(` APR: ${evaluation.aprBps / 100}%`);
810
- console.log(` Risk Score: ${evaluation.riskScore}/100`);
811
- console.log(` Bayesian Score: ${evaluation.bayesianScore}/1000`);
812
- console.log(` Confidence: ${((evaluation.confidence || 0) * 100).toFixed(0)}%`);
813
- if (!evaluation.approved) {
814
- console.log("");
815
- console.log(` \u274C Reason: ${evaluation.reason}`);
816
- process.exit(1);
1390
+ console.log("\n \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
1391
+ console.log(" \u2502 Token \u2502 Collateral \u2502 Debt (USDC) \u2502");
1392
+ console.log(" \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
1393
+ for (const p of status.positions) {
1394
+ const tok = p.collateralToken.padEnd(9);
1395
+ const col = parseFloat(p.collateral).toFixed(6).padStart(16);
1396
+ const debt = ("$" + parseFloat(p.debt).toFixed(2)).padStart(16);
1397
+ console.log(` \u2502 ${tok} \u2502 ${col} \u2502 ${debt} \u2502`);
817
1398
  }
818
- console.log("");
819
- console.log(" [2/2] Submitting application on-chain...");
1399
+ console.log(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
820
1400
  try {
821
- const tx = await reputationCredit.applyForCredit(accountAddr, limitRaw);
822
- await tx.wait();
823
- console.log(` \u2713 TX: ${tx.hash}`);
1401
+ const score = await mc.getCreditScore();
1402
+ const { fresh, age } = await mc.isScoreFresh();
1403
+ const ageHrs = Number(age) / 3600;
824
1404
  console.log(`
825
- \u2705 Credit application submitted (Pending)`);
826
- console.log(" Next steps:");
827
- console.log(" 1. Wait for admin to process your application");
828
- console.log(" 2. After approval, draw: agether draw --amount <usd>");
829
- } catch (e) {
830
- console.error(` \u274C ${decodeError(e)}`);
831
- }
832
- }
833
- async function cmdDraw(amountUsd) {
834
- const config = requireConfig();
835
- const signer = getSigner(config);
836
- const agentId = BigInt(config.agentId);
837
- const walletAddress = await signer.getAddress();
838
- console.log(`\u{1F4B8} Drawing $${amountUsd} (Agent #${agentId})...
839
- `);
840
- const status = await apiGet(config.backendUrl, "/status");
841
- const reputationCreditAddr = status.contracts?.reputationCredit;
842
- const accountFactoryAddr = status.contracts?.accountFactory;
843
- const provider = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
844
- const accountFactory = new import_ethers2.ethers.Contract(accountFactoryAddr, ACCOUNT_FACTORY_ABI, provider);
845
- const accountAddr = await accountFactory.getAccount(agentId);
846
- if (accountAddr === import_ethers2.ethers.ZeroAddress) {
847
- console.error(" \u274C No AgentAccount. Run: agether register");
848
- process.exit(1);
849
- }
850
- const agentAccount = new import_ethers2.ethers.Contract(accountAddr, AGENT_ACCOUNT_ABI, provider);
851
- const owner = await agentAccount.owner();
852
- if (owner.toLowerCase() !== walletAddress.toLowerCase()) {
853
- console.error(" \u274C WALLET MISMATCH!");
854
- console.error(` Your wallet: ${walletAddress}`);
855
- console.error(` Agent owner: ${owner}`);
856
- process.exit(1);
857
- }
858
- const reputationCredit = new import_ethers2.ethers.Contract(reputationCreditAddr, REPUTATION_CREDIT_ABI, provider);
859
- const creditStatus = await reputationCredit.getCreditLineStatus(accountAddr);
860
- if (Number(creditStatus) !== 2) {
861
- console.error(` \u274C Credit line not active (status: ${STATUS_NAMES[Number(creditStatus)] || creditStatus})`);
862
- process.exit(1);
863
- }
864
- const available = await reputationCredit.maxDrawable(accountAddr);
865
- const drawAmount = import_ethers2.ethers.parseUnits(amountUsd.toString(), 6);
866
- console.log(` Account: ${accountAddr}`);
867
- console.log(` Available: $${(Number(available) / 1e6).toFixed(2)}`);
868
- console.log(` Drawing: $${amountUsd}`);
869
- if (drawAmount > available) {
870
- console.error(` \u274C Exceeds available credit`);
871
- process.exit(1);
872
- }
873
- console.log("\n Signing draw transaction...");
874
- try {
875
- const account = new import_ethers2.ethers.Contract(accountAddr, AGENT_ACCOUNT_ABI, signer);
876
- const tx = await account.drawCredit(reputationCreditAddr, drawAmount);
877
- await tx.wait();
878
- console.log(`
879
- \u2705 Drew $${amountUsd}`);
880
- console.log(` TX: ${tx.hash}`);
881
- const newAvailable = await reputationCredit.maxDrawable(accountAddr);
882
- console.log(` Remaining credit: $${(Number(newAvailable) / 1e6).toFixed(2)}`);
883
- } catch (e) {
884
- console.error(` \u274C ${decodeError(e)}`);
885
- }
886
- }
887
- async function cmdRepay(amountUsd) {
888
- const config = requireConfig();
889
- const signer = getSigner(config);
890
- const agentId = BigInt(config.agentId);
891
- console.log(`\u{1F4B0} Repaying $${amountUsd} (Agent #${agentId})...
892
- `);
893
- const status = await apiGet(config.backendUrl, "/status");
894
- const reputationCreditAddr = status.contracts?.reputationCredit;
895
- const morphoCreditAddr = status.contracts?.morphoCredit;
896
- const accountFactoryAddr = status.contracts?.accountFactory;
897
- const usdcAddr = status.contracts?.usdc;
898
- const provider = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
899
- const accountFactory = new import_ethers2.ethers.Contract(accountFactoryAddr, ACCOUNT_FACTORY_ABI, provider);
900
- const accountAddr = await accountFactory.getAccount(agentId);
901
- if (accountAddr === import_ethers2.ethers.ZeroAddress) {
902
- console.error(" \u274C No AgentAccount found");
903
- process.exit(1);
904
- }
905
- if (morphoCreditAddr) {
906
- const morphoCredit = new import_ethers2.ethers.Contract(morphoCreditAddr, MORPHO_CREDIT_ABI, provider);
907
- const COLLATERALS = getCollateralInfo(Number((await provider.getNetwork()).chainId));
908
- for (const [symbol, info] of Object.entries(COLLATERALS)) {
909
- const pos = await morphoCredit.getPosition(accountAddr, info.address);
910
- if (pos.borrowedAmount > 0n) {
911
- console.log(` \u26A0 Agent has Morpho debt ($${import_ethers2.ethers.formatUnits(pos.borrowedAmount, 6)} via ${symbol})`);
912
- console.log(` \u2192 Redirecting to morpho-repay...
913
- `);
914
- return cmdMorphoRepay(amountUsd.toString());
915
- }
916
- }
917
- }
918
- const reputationCredit = new import_ethers2.ethers.Contract(reputationCreditAddr, REPUTATION_CREDIT_ABI, provider);
919
- const totalDebt = await reputationCredit.getTotalDebt(accountAddr);
920
- if (totalDebt === 0n) {
921
- console.log(" \u2705 Nothing to repay \u2014 debt is zero");
922
- return;
923
- }
924
- let repayAmount = import_ethers2.ethers.parseUnits(amountUsd.toString(), 6);
925
- if (repayAmount > totalDebt) {
926
- repayAmount = totalDebt;
927
- console.log(` \u26A0 Capped to total debt: $${(Number(totalDebt) / 1e6).toFixed(2)}`);
928
- }
929
- console.log(` Account: ${accountAddr}`);
930
- console.log(` Total debt: $${(Number(totalDebt) / 1e6).toFixed(2)}`);
931
- console.log(` Repaying: $${(Number(repayAmount) / 1e6).toFixed(2)}`);
932
- const usdc = new import_ethers2.ethers.Contract(usdcAddr, ERC20_ABI, signer);
933
- console.log("\n [1/3] Approving USDC...");
934
- try {
935
- const approveTx = await usdc.approve(accountAddr, repayAmount);
936
- await approveTx.wait();
937
- console.log(" \u2713 Approved");
938
- } catch (e) {
939
- console.error(` \u274C Approve failed: ${e.message}`);
940
- process.exit(1);
941
- }
942
- console.log(" [2/3] Funding AgentAccount...");
943
- const freshSigner = getFreshSigner(config);
944
- const agentAccount = new import_ethers2.ethers.Contract(accountAddr, AGENT_ACCOUNT_ABI, freshSigner);
945
- try {
946
- const fundTx = await agentAccount.fund(usdcAddr, repayAmount);
947
- await fundTx.wait();
948
- console.log(" \u2713 Funded");
949
- } catch (e) {
950
- console.error(` \u274C Fund failed: ${e.message}`);
951
- process.exit(1);
952
- }
953
- console.log(" [3/3] Repaying...");
954
- const freshSigner2 = getFreshSigner(config);
955
- const agentAccount2 = new import_ethers2.ethers.Contract(accountAddr, AGENT_ACCOUNT_ABI, freshSigner2);
956
- try {
957
- const tx = await agentAccount2.repayCredit(reputationCreditAddr, repayAmount);
958
- await tx.wait();
959
- console.log(`
960
- \u2705 Repaid $${(Number(repayAmount) / 1e6).toFixed(2)}`);
961
- console.log(` TX: ${tx.hash}`);
962
- const newDebt = await reputationCredit.getTotalDebt(accountAddr);
963
- console.log(` Remaining debt: $${(Number(newDebt) / 1e6).toFixed(2)}`);
964
- } catch (e) {
965
- console.error(` \u274C ${decodeError(e)}`);
966
- }
967
- }
968
- async function cmdStatus() {
969
- const config = requireConfig();
970
- const agentId = BigInt(config.agentId || "0");
971
- if (agentId === 0n) {
972
- const signer = getSigner(config);
973
- console.log(`\u{1F4CA} Wallet Status (not registered yet)
974
- `);
975
- console.log(` Wallet: ${signer.address}`);
976
- try {
977
- const provider2 = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
978
- const balance = await provider2.getBalance(signer.address);
979
- console.log(` ETH: ${import_ethers2.ethers.formatEther(balance)}`);
980
- } catch {
981
- console.log(" ETH: (could not read)");
982
- }
983
- console.log(`
984
- Run: agether register <name>`);
985
- return;
986
- }
987
- console.log(`\u{1F4CA} Agent #${agentId} Status
988
- `);
989
- const status = await apiGet(config.backendUrl, "/status");
990
- const provider = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
991
- const accountFactory = new import_ethers2.ethers.Contract(
992
- status.contracts.accountFactory,
993
- ACCOUNT_FACTORY_ABI,
994
- provider
995
- );
996
- const accountAddr = await accountFactory.getAccount(agentId);
997
- if (accountAddr === import_ethers2.ethers.ZeroAddress) {
998
- console.log(" No AgentAccount found. Run: agether register");
999
- return;
1000
- }
1001
- const reputationCredit = new import_ethers2.ethers.Contract(
1002
- status.contracts.reputationCredit,
1003
- REPUTATION_CREDIT_ABI,
1004
- provider
1005
- );
1006
- const creditStatus = await reputationCredit.getCreditLineStatus(accountAddr);
1007
- if (Number(creditStatus) === 0) {
1008
- console.log(" No credit line found. Run: agether apply --limit <amount>");
1009
- return;
1010
- }
1011
- const data = await reputationCredit.getCreditLineDetails(accountAddr);
1012
- const totalDebt = await reputationCredit.getTotalDebt(accountAddr);
1013
- const available = await reputationCredit.maxDrawable(accountAddr);
1014
- const limit = Number(data[1]) / 1e6;
1015
- const used = Number(data[2]) / 1e6;
1016
- const interest = Number(data[4]) / 1e6;
1017
- console.log(` Account: ${accountAddr}`);
1018
- console.log(` Status: ${STATUS_NAMES[Number(data[8])] || data[8]}`);
1019
- console.log(` Limit: $${limit.toFixed(2)}`);
1020
- console.log(` Used: $${used.toFixed(2)}`);
1021
- console.log(` Interest: $${interest.toFixed(2)}`);
1022
- console.log(` Total Debt: $${(Number(totalDebt) / 1e6).toFixed(2)}`);
1023
- console.log(` Available: $${(Number(available) / 1e6).toFixed(2)}`);
1024
- console.log(` APR: ${Number(data[3]) / 100}%`);
1025
- console.log(` Requested Limit: $${(Number(data[5]) / 1e6).toFixed(2)}`);
1026
- console.log(` Created: ${new Date(Number(data[6]) * 1e3).toISOString()}`);
1027
- console.log(` Last Activity: ${new Date(Number(data[7]) * 1e3).toISOString()}`);
1028
- }
1029
- async function cmdScore() {
1030
- const config = requireConfig();
1031
- console.log(`\u{1F4C8} Agent #${config.agentId} Score
1032
- `);
1033
- try {
1034
- const score = await apiGet(config.backendUrl, `/credit/score/${config.agentId}`);
1035
- console.log(` Bayesian Score: ${score.bayesianScore?.toFixed(0) || "N/A"}`);
1036
- console.log(` Confidence: ${((score.confidence || 0) * 100).toFixed(1)}%`);
1037
- if (score.subscores) {
1038
- console.log("");
1039
- console.log(" Subscores:");
1040
- console.log(` Historical: ${score.subscores.historical?.score?.toFixed(0) || "N/A"}`);
1041
- console.log(` Current Risk: ${score.subscores.currentRisk?.score?.toFixed(0) || "N/A"}`);
1042
- console.log(` Utilization: ${score.subscores.utilization?.score?.toFixed(0) || "N/A"}`);
1043
- console.log(` On-chain TX: ${score.subscores.onChainTx?.score?.toFixed(0) || "N/A"}`);
1044
- console.log(` New Credit: ${score.subscores.newCredit?.score?.toFixed(0) || "N/A"}`);
1045
- }
1046
- } catch (e) {
1047
- console.error(`\u274C Failed: ${e.message}`);
1048
- }
1049
- }
1050
- async function cmdBalance() {
1051
- const config = requireConfig();
1052
- const wallet = new import_ethers2.ethers.Wallet(config.privateKey);
1053
- const provider = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
1054
- console.log(`\u{1F4B0} Agent #${config.agentId} Balances
1055
- `);
1056
- console.log(` Address: ${wallet.address}`);
1057
- const ethBal = await provider.getBalance(wallet.address);
1058
- console.log(` ETH: ${import_ethers2.ethers.formatEther(ethBal)}`);
1059
- try {
1060
- const status = await apiGet(config.backendUrl, "/status");
1061
- if (status.contracts?.usdc) {
1062
- const usdc = new import_ethers2.ethers.Contract(status.contracts.usdc, ERC20_ABI, provider);
1063
- const usdcBal = await usdc.balanceOf(wallet.address);
1064
- console.log(` USDC: $${(Number(usdcBal) / 1e6).toFixed(2)}`);
1065
- }
1405
+ Credit Score: ${score} ${fresh ? "\u2705" : `\u26A0\uFE0F stale (${ageHrs.toFixed(1)}h old)`}`);
1066
1406
  } catch {
1067
- console.log(" USDC: (could not read)");
1407
+ console.log("\n Credit Score: not yet computed");
1068
1408
  }
1069
1409
  }
1070
- async function cmdCollateral(_amountUsd) {
1071
- console.log("\u26A0\uFE0F Collateral deposit is not needed in v2.");
1072
- console.log(" ReputationCredit is undercollateralized (LP-funded).");
1073
- console.log(" For overcollateralized credit, use MorphoCredit.");
1074
- }
1075
- function decodeError(error) {
1076
- const msg = error?.message || String(error);
1077
- if (msg.includes("CodeNotApproved")) return "Agent code not approved. Complete KYA first.";
1078
- if (msg.includes("DailyLimitExceeded")) return "Daily draw limit exceeded. Try smaller amount or wait.";
1079
- if (msg.includes("CollateralRequired")) return "Collateral required. Run: agether collateral --amount <usd>";
1080
- if (msg.includes("ExceedsAvailable")) return "Amount exceeds available credit.";
1081
- if (msg.includes("NotAgentOwner")) return "Wallet is not the owner of this agentId.";
1082
- if (msg.includes("AlreadyHasCreditLine")) return "Agent already has a credit line.";
1083
- if (msg.includes("BelowMinimum")) return "Amount below minimum ($100).";
1084
- if (msg.includes("AboveMaximum")) return "Amount above maximum ($100,000).";
1085
- if (msg.includes("InsufficientLiquidity")) return "Vault has insufficient liquidity.";
1086
- if (msg.includes("Undercollateralized")) return "Position is undercollateralized.";
1087
- if (msg.includes("AgentDefaulted")) return "Agent has defaulted. Cannot use protocol.";
1088
- if (msg.includes("InvalidCreditStatus")) return "Credit line is not in the required status.";
1089
- if (msg.length > 200) return msg.slice(0, 200) + "...";
1090
- return msg;
1091
- }
1092
- async function cmdMorphoCompare(amountUsd) {
1410
+ async function cmdScore() {
1093
1411
  const config = requireConfig();
1094
- const signer = getSigner(config);
1095
- const address = await signer.getAddress();
1096
1412
  console.log(`
1097
- \u{1F4CA} Comparing credit options for $${amountUsd}...
1413
+ \u{1F4C8} Agent #${config.agentId} Score
1098
1414
  `);
1099
- console.log(` Wallet: ${address}`);
1100
1415
  try {
1101
- const balRes = await fetch(`${config.backendUrl}/morpho/balances/${address}`);
1102
- const balances = await balRes.json();
1103
- console.log("\n\u{1F4B0} Your Available Assets:");
1104
- console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
1105
- console.log("\u2502 Token \u2502 Balance \u2502 Value USD \u2502");
1106
- console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
1107
- for (const [token, info] of Object.entries(balances.balances)) {
1108
- const bal = parseFloat(info.balanceFormatted);
1109
- if (bal > 0 || token === "USDC") {
1110
- const balStr = bal.toFixed(token === "USDC" ? 2 : 4).padStart(14);
1111
- const valStr = `$${parseFloat(info.valueUsd).toLocaleString()}`.padStart(13);
1112
- console.log(`\u2502 ${token.padEnd(11)} \u2502 ${balStr} \u2502 ${valStr} \u2502`);
1113
- }
1114
- }
1115
- console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
1116
- const res = await fetch(`${config.backendUrl}/morpho/compare`, {
1117
- method: "POST",
1118
- headers: { "Content-Type": "application/json" },
1119
- body: JSON.stringify({
1120
- agentId: config.agentId,
1121
- amount: import_ethers2.ethers.parseUnits(amountUsd.toString(), 6).toString()
1122
- })
1123
- });
1124
- await res.json();
1125
- let estimates = {};
1126
- try {
1127
- const estRes = await fetch(`${config.backendUrl}/morpho/estimate/${amountUsd}`);
1128
- const estData = await estRes.json();
1129
- estimates = estData.estimates || {};
1130
- } catch {
1131
- }
1132
- const opts = balances.creditOptions || {};
1133
- const canMorphoWETH = opts.morphoWETH?.available && parseFloat(opts.morphoWETH?.maxBorrow || "0") >= amountUsd;
1134
- const canMorphoWstETH = opts.morphoWstETH?.available && parseFloat(opts.morphoWstETH?.maxBorrow || "0") >= amountUsd;
1135
- const canMorpho = canMorphoWETH || canMorphoWstETH;
1136
- console.log("\n\u{1F4CB} Credit Options for $" + amountUsd.toLocaleString() + ":");
1137
- console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
1138
- for (const [symbol, est] of Object.entries(estimates)) {
1139
- const optKey = `morpho${symbol}`;
1140
- const canAfford = opts[optKey]?.available && parseFloat(opts[optKey]?.maxBorrow || "0") >= amountUsd;
1141
- const price = parseFloat(est.priceUsd || 0);
1142
- const needed = parseFloat(est.minCollateral || 0);
1143
- const neededUsd = parseFloat(est.minCollateralUsd || 0);
1144
- if (canAfford) {
1145
- console.log(`\u2502 \u2705 MORPHO with ${symbol} (Overcollateralized)`.padEnd(71) + "\u2502");
1146
- console.log(`\u2502 Need: ~${needed.toFixed(6)} ${symbol} ($${neededUsd.toFixed(2)}) at $${price.toFixed(0)}/${symbol} (120%)`.padEnd(71) + "\u2502");
1147
- console.log(`\u2502 \u2713 Instant \u2713 No limits \u2713 Borrow from Morpho Blue pool`.padEnd(71) + "\u2502");
1148
- } else if (price > 0) {
1149
- console.log(`\u2502 \u26A0\uFE0F MORPHO with ${symbol} \u2014 need ${needed.toFixed(6)} ${symbol} ($${neededUsd.toFixed(2)})`.padEnd(71) + "\u2502");
1150
- const have = parseFloat(balances.balances?.[symbol]?.valueUsd || "0");
1151
- console.log(`\u2502 Have: $${have.toFixed(2)} ${symbol} | Need: $${neededUsd.toFixed(2)}`.padEnd(71) + "\u2502");
1152
- }
1153
- }
1154
- if (Object.keys(estimates).length === 0) {
1155
- console.log("\u2502 \u26A0\uFE0F Could not fetch oracle prices from backend".padEnd(71) + "\u2502");
1156
- }
1157
- console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
1158
- if (canMorpho) {
1159
- const bestToken = canMorphoWETH ? "WETH" : "wstETH";
1160
- const bestEst = estimates[bestToken];
1161
- const needed = bestEst ? parseFloat(bestEst.minCollateral) : amountUsd * 1.2 / 2600;
1162
- const depositAmount = (needed * 1.05).toFixed(6);
1163
- console.log("\n\u{1F4A1} Recommended:");
1164
- console.log(` agether morpho-deposit --amount ${depositAmount} --token ${bestToken}`);
1165
- console.log(` agether morpho-borrow --amount ${amountUsd}`);
1416
+ const data = await apiGet(config.backendUrl, `/score/${config.agentId}/current`);
1417
+ if (data.score !== void 0) {
1418
+ console.log(` On-chain Score: ${data.score}`);
1419
+ console.log(` Timestamp: ${data.timestamp ? new Date(Number(data.timestamp) * 1e3).toISOString() : "N/A"}`);
1420
+ console.log(` Signer: ${data.signer || "N/A"}`);
1421
+ console.log(` Fresh: ${data.fresh ? "\u2705" : "\u26A0\uFE0F stale"}`);
1166
1422
  } else {
1167
- console.log("\n\u274C Cannot borrow $" + amountUsd.toLocaleString());
1168
- console.log(" You need more collateral. Options:");
1169
- console.log(" \u2022 Wrap ETH to WETH for Morpho credit");
1170
- if (estimates["WETH"]) {
1171
- console.log(` \u2022 Minimum: ${estimates["WETH"].minCollateral} WETH ($${estimates["WETH"].minCollateralUsd})`);
1172
- }
1173
- }
1174
- } catch (e) {
1175
- console.error(`\u274C Failed to compare: ${e.message}`);
1176
- }
1177
- }
1178
- async function cmdMorphoBalances() {
1179
- const config = requireConfig();
1180
- const signer = getSigner(config);
1181
- const address = await signer.getAddress();
1182
- console.log(`
1183
- \u{1F4B0} Token Balances & Credit Capacity
1184
- `);
1185
- console.log(` Wallet: ${address}`);
1186
- try {
1187
- const res = await fetch(`${config.backendUrl}/morpho/balances/${address}`);
1188
- const data = await res.json();
1189
- console.log("\n\u{1F4CA} Your Balances:");
1190
- console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
1191
- console.log("\u2502 Token \u2502 Balance \u2502 Value USD \u2502");
1192
- console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
1193
- for (const [token, info] of Object.entries(data.balances)) {
1194
- const bal = parseFloat(info.balanceFormatted);
1195
- const balStr = bal.toFixed(token === "USDC" ? 2 : 6).padStart(18);
1196
- const valStr = `$${parseFloat(info.valueUsd).toLocaleString()}`.padStart(15);
1197
- console.log(`\u2502 ${token.padEnd(11)} \u2502 ${balStr} \u2502 ${valStr} \u2502`);
1198
- }
1199
- console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
1200
- console.log(`\u2502 TOTAL \u2502 \u2502 $${parseFloat(data.totalValueUsd).toLocaleString().padStart(13)} \u2502`);
1201
- console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
1202
- console.log("\n\u{1F4B3} Max Credit Capacity:");
1203
- console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
1204
- console.log("\u2502 Option \u2502 Max Borrow \u2502 Status \u2502");
1205
- console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
1206
- const opts = data.creditOptions || {};
1207
- const rows = [
1208
- ["Morpho WETH", opts.morphoWETH?.maxBorrow || "0", opts.morphoWETH?.available || false],
1209
- ["Morpho wstETH", opts.morphoWstETH?.maxBorrow || "0", opts.morphoWstETH?.available || false],
1210
- ["Morpho WBTC", opts.morphoWBTC?.maxBorrow || "0", opts.morphoWBTC?.available || false]
1211
- ];
1212
- for (const [name, max, avail] of rows) {
1213
- const nameStr = name.padEnd(29);
1214
- const maxStr = `$${parseFloat(max).toLocaleString()}`.padStart(15);
1215
- const statusStr = avail ? "\u2705" : "\u274C";
1216
- console.log(`\u2502 ${nameStr} \u2502 ${maxStr} \u2502 ${statusStr} \u2502`);
1217
- }
1218
- console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
1219
- } catch (e) {
1220
- console.error(`\u274C Failed to fetch balances: ${e.message}`);
1221
- }
1222
- }
1223
- async function cmdMorphoMarkets() {
1224
- const config = requireConfig();
1225
- console.log("\n\u{1F4C8} Supported Morpho Markets\n");
1226
- try {
1227
- const data = await apiGet(config.backendUrl, "/morpho/markets");
1228
- console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
1229
- console.log("\u2502 Collateral \u2502 Loan \u2502 Status \u2502");
1230
- console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
1231
- for (const m of data.markets) {
1232
- const collat = m.collateralToken.padEnd(11);
1233
- const loan = (m.loanToken || "USDC").padEnd(6);
1234
- const status = m.status === "active" ? "\u2705 Active" : "\u274C Inactive";
1235
- console.log(`\u2502 ${collat} \u2502 ${loan} \u2502 ${status} \u2502`);
1423
+ console.log(" No score on-chain yet.");
1236
1424
  }
1237
- console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
1238
- } catch (e) {
1239
- console.error(`\u274C Failed to fetch markets: ${e.message}`);
1240
- }
1241
- }
1242
- async function cmdMorphoOpen(collateralToken) {
1243
- const config = requireConfig();
1244
- console.log(`
1245
- \u{1F3E6} Setting up Morpho credit with ${collateralToken} collateral...
1246
- `);
1247
- if (config.agentId === "0") {
1248
- console.error("\u274C Register agent first: agether register");
1249
- process.exit(1);
1250
- }
1251
- const status = await apiGet(config.backendUrl, "/status");
1252
- const morphoCreditAddr = status.contracts?.morphoCredit;
1253
- if (!morphoCreditAddr) {
1254
- console.error("\u274C MorphoCredit not deployed");
1255
- process.exit(1);
1256
- }
1257
- const provider = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
1258
- const signer = new import_ethers2.ethers.Wallet(config.privateKey, provider);
1259
- const net = await provider.getNetwork();
1260
- const cid = Number(net.chainId);
1261
- const COLLATERAL_ADDRESSES = cid === 8453 || cid === 84532 ? {
1262
- WETH: "0x4200000000000000000000000000000000000006",
1263
- wstETH: "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452",
1264
- cbETH: "0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22"
1265
- } : {
1266
- WETH: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
1267
- wstETH: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
1268
- };
1269
- const collateralAddr = COLLATERAL_ADDRESSES[collateralToken];
1270
- if (!collateralAddr) {
1271
- console.error(`\u274C Unsupported collateral: ${collateralToken}`);
1272
- console.log(" Supported:", Object.keys(COLLATERAL_ADDRESSES).join(", "));
1273
- process.exit(1);
1274
- }
1275
- const morphoCredit = new import_ethers2.ethers.Contract(morphoCreditAddr, MORPHO_CREDIT_ABI, signer);
1276
- const position = await morphoCredit.getPosition(signer.address, collateralAddr);
1277
- if (position.isActive) {
1278
- console.log(`\u2713 Position already active with ${import_ethers2.ethers.formatEther(position.collateralAmount)} ${collateralToken}`);
1279
- console.log(` Borrowed: $${import_ethers2.ethers.formatUnits(position.borrowedAmount, 6)}`);
1280
- } else {
1281
- console.log(` No existing position for ${collateralToken}`);
1425
+ } catch {
1426
+ console.log(" Could not fetch current score.");
1282
1427
  }
1283
- console.log(`
1284
- \u2705 Ready for Morpho credit with ${collateralToken}!`);
1285
- console.log(`
1286
- Deposit collateral directly:
1287
- `);
1288
- console.log(` agether morpho-deposit --amount 0.1 --token ${collateralToken}`);
1289
- console.log(`
1290
- This will:`);
1291
- console.log(` 1. Approve MorphoCredit to pull ${collateralToken} from your EOA`);
1292
- console.log(` 2. Deposit collateral to Morpho Blue via MorphoCredit`);
1293
- console.log(` 3. You can then borrow: agether morpho-borrow --amount 100`);
1428
+ console.log("\n To compute a fresh score (x402-gated, costs USDC):");
1429
+ console.log(` agether x402 ${config.backendUrl}/score/${config.agentId}`);
1294
1430
  }
1295
- async function cmdMorphoDeposit(amountStr, tokenSymbol) {
1431
+ async function cmdMarkets() {
1296
1432
  const config = requireConfig();
1297
- console.log(`
1298
- \u{1F4B0} Depositing ${amountStr} ${tokenSymbol} as collateral via MorphoCredit...
1299
- `);
1300
- if (config.agentId === "0") {
1301
- console.error("\u274C Register agent first: agether register");
1302
- process.exit(1);
1303
- }
1304
- const status = await apiGet(config.backendUrl, "/status");
1305
- const morphoCreditAddr = status.contracts?.morphoCredit;
1306
- const accountFactoryAddr = status.contracts?.accountFactory;
1307
- if (!morphoCreditAddr) {
1308
- console.error("\u274C MorphoCredit not deployed");
1309
- process.exit(1);
1310
- }
1311
- if (!accountFactoryAddr) {
1312
- console.error("\u274C AccountFactory not deployed");
1313
- process.exit(1);
1314
- }
1315
- const provider = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
1316
- const net = await provider.getNetwork();
1317
- const COLLATERAL_INFO = getCollateralInfo(Number(net.chainId));
1318
- const tokenInfo = COLLATERAL_INFO[tokenSymbol];
1319
- if (!tokenInfo) {
1320
- console.error(`\u274C Unsupported token: ${tokenSymbol}`);
1321
- console.log(" Supported:", Object.keys(COLLATERAL_INFO).join(", "));
1322
- process.exit(1);
1323
- }
1324
- const signer = new import_ethers2.ethers.Wallet(config.privateKey, provider);
1325
- const amount = import_ethers2.ethers.parseUnits(amountStr, tokenInfo.decimals);
1326
- const factory = new import_ethers2.ethers.Contract(accountFactoryAddr, ACCOUNT_FACTORY_ABI, signer);
1327
- const accountExists = await factory.accountExists(config.agentId);
1328
- if (!accountExists) {
1329
- console.error("\u274C No AgentAccount. Create one first: agether wallet-create");
1330
- process.exit(1);
1331
- }
1332
- const accountAddr = await factory.getAccount(config.agentId);
1333
- console.log(` AgentAccount: ${accountAddr}`);
1334
- const token = new import_ethers2.ethers.Contract(tokenInfo.address, [
1335
- "function approve(address spender, uint256 amount) returns (bool)",
1336
- "function balanceOf(address) view returns (uint256)"
1337
- ], signer);
1338
- const balance = await token.balanceOf(signer.address);
1339
- if (balance < amount) {
1340
- console.error(`\u274C Insufficient ${tokenSymbol} balance`);
1341
- console.log(` Have: ${import_ethers2.ethers.formatUnits(balance, tokenInfo.decimals)} ${tokenSymbol}`);
1342
- console.log(` Need: ${amountStr} ${tokenSymbol}`);
1343
- process.exit(1);
1344
- }
1345
- console.log(`Step 1/3: Approving ${tokenSymbol} for MorphoCredit...`);
1346
- const approveTx = await token.approve(morphoCreditAddr, amount);
1347
- await approveTx.wait();
1348
- console.log(` \u2713 Approved`);
1349
- const signer2 = new import_ethers2.ethers.Wallet(config.privateKey, new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl));
1350
- const morphoCredit = new import_ethers2.ethers.Contract(morphoCreditAddr, MORPHO_CREDIT_ABI, signer2);
1351
- console.log(`Step 2/3: Depositing collateral for AgentAccount...`);
1352
- try {
1353
- const depositTx = await morphoCredit.depositCollateralFor(accountAddr, tokenInfo.address, amount);
1354
- await depositTx.wait();
1355
- console.log(` \u2713 Deposited`);
1356
- } catch (e) {
1357
- console.error(`\u274C Deposit failed: ${decodeError(e)}`);
1358
- process.exit(1);
1359
- }
1360
- const signer3 = new import_ethers2.ethers.Wallet(config.privateKey, new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl));
1361
- const account = new import_ethers2.ethers.Contract(accountAddr, [
1362
- ...AGENT_ACCOUNT_ABI,
1363
- "function approveCreditProvider(address creditProvider)"
1364
- ], signer3);
1365
- console.log(`Step 3/3: Approving MorphoCredit as credit provider...`);
1366
- try {
1367
- const approveCpTx = await account.approveCreditProvider(morphoCreditAddr);
1368
- await approveCpTx.wait();
1369
- console.log(` \u2713 Approved`);
1370
- } catch (e) {
1371
- console.log(` \u2713 Already approved`);
1433
+ const mc = await getMorphoClient(config);
1434
+ console.log("\n\u{1F4C8} Morpho Blue Markets (Base USDC)\n");
1435
+ const markets = await mc.getMarkets();
1436
+ if (markets.length === 0) {
1437
+ console.log(" No markets found. API may be unavailable.");
1438
+ return;
1372
1439
  }
1373
- const morphoCreditView = new import_ethers2.ethers.Contract(morphoCreditAddr, MORPHO_CREDIT_ABI, provider);
1374
- const position = await morphoCreditView.getPosition(accountAddr, tokenInfo.address);
1375
- console.log(`
1376
- \u2705 Deposited ${amountStr} ${tokenSymbol} as Morpho collateral`);
1377
- console.log(` Position tracked under: ${accountAddr} (AgentAccount)`);
1378
- console.log(` Total collateral: ${import_ethers2.ethers.formatUnits(position.collateralAmount, tokenInfo.decimals)} ${tokenSymbol}`);
1379
- console.log(`
1380
- \u{1F4B5} You can now borrow USDC:`);
1381
- console.log(` agether morpho-borrow --amount 100`);
1440
+ console.log(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
1441
+ console.log(" \u2502 Collateral \u2502 LLTV \u2502 Util % \u2502 Supply (USDC) \u2502");
1442
+ console.log(" \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
1443
+ for (const m of markets.slice(0, 15)) {
1444
+ const col = (m.collateralAsset?.symbol || "N/A").padEnd(13);
1445
+ const lltv = (Number(m.lltv) / 1e18 * 100).toFixed(0).padStart(6) + "%";
1446
+ const util = (m.utilization * 100).toFixed(1).padStart(8) + "%";
1447
+ const supply = ("$" + (Number(m.totalSupplyAssets) / 1e6).toLocaleString()).padStart(16);
1448
+ console.log(` \u2502 ${col} \u2502 ${lltv} \u2502 ${util} \u2502 ${supply} \u2502`);
1449
+ }
1450
+ console.log(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
1382
1451
  }
1383
- async function cmdMorphoBorrow(amountUsd) {
1452
+ async function cmdDeposit(amount, token) {
1384
1453
  const config = requireConfig();
1454
+ const mc = await getMorphoClient(config);
1385
1455
  console.log(`
1386
- \u{1F4B8} Borrowing $${amountUsd} USDC via AgentAccount \u2192 MorphoCredit...
1456
+ \u{1F4B0} Depositing ${amount} ${token} as collateral...
1387
1457
  `);
1388
- if (config.agentId === "0") {
1389
- console.error("\u274C Register agent first: agether register");
1390
- process.exit(1);
1391
- }
1392
- const status = await apiGet(config.backendUrl, "/status");
1393
- const morphoCreditAddr = status.contracts?.morphoCredit;
1394
- const accountFactoryAddr = status.contracts?.accountFactory;
1395
- const usdcAddr = status.contracts?.usdc;
1396
- if (!morphoCreditAddr || !accountFactoryAddr) {
1397
- console.error("\u274C Contracts not deployed");
1398
- process.exit(1);
1399
- }
1400
- const provider = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
1401
- const signer = new import_ethers2.ethers.Wallet(config.privateKey, provider);
1402
- const factory = new import_ethers2.ethers.Contract(accountFactoryAddr, ACCOUNT_FACTORY_ABI, signer);
1403
- const accountAddr = await factory.getAccount(config.agentId);
1404
- if (accountAddr === import_ethers2.ethers.ZeroAddress) {
1405
- console.error("\u274C No AgentAccount. Create one first: agether wallet-create");
1406
- process.exit(1);
1407
- }
1408
- console.log(` AgentAccount: ${accountAddr}`);
1409
- const morphoCredit = new import_ethers2.ethers.Contract(morphoCreditAddr, MORPHO_CREDIT_ABI, provider);
1410
- const COLLATERALS = getCollateralInfo(Number((await provider.getNetwork()).chainId));
1411
- let activeCollateral = null;
1412
- for (const [symbol, info] of Object.entries(COLLATERALS)) {
1413
- const pos = await morphoCredit.getPosition(accountAddr, info.address);
1414
- if (pos.collateralAmount > 0n) {
1415
- activeCollateral = symbol;
1416
- console.log(` Position: ${import_ethers2.ethers.formatEther(pos.collateralAmount)} ${symbol}`);
1417
- console.log(` Current debt: $${import_ethers2.ethers.formatUnits(pos.borrowedAmount, 6)}`);
1418
- break;
1419
- }
1420
- }
1421
- if (!activeCollateral) {
1422
- console.error("\u274C No collateral deposited for AgentAccount");
1423
- console.log(" Deposit first: agether morpho-deposit --amount 0.1 --token WETH");
1424
- process.exit(1);
1425
- }
1426
- const collateralAddr = COLLATERALS[activeCollateral].address;
1427
- const amountWei = import_ethers2.ethers.parseUnits(amountUsd, 6);
1428
1458
  try {
1429
- const account = new import_ethers2.ethers.Contract(accountAddr, AGENT_ACCOUNT_ABI, signer);
1430
- const morphoIface = new import_ethers2.ethers.Interface(MORPHO_CREDIT_ABI);
1431
- const borrowCalldata = morphoIface.encodeFunctionData("drawWithCollateral", [collateralAddr, amountWei]);
1432
- console.log(` Borrowing $${amountUsd} USDC via drawWithCollateral(${activeCollateral})...`);
1433
- const tx = await account.execute(morphoCreditAddr, 0, borrowCalldata);
1434
- await waitForTx(tx);
1435
- const usdc = new import_ethers2.ethers.Contract(usdcAddr, ERC20_ABI, provider);
1436
- const accountUsdcBalance = await usdc.balanceOf(accountAddr);
1437
- console.log(`
1438
- \u2705 Borrowed $${amountUsd} USDC`);
1439
- console.log(` TX: ${tx.hash}`);
1440
- console.log(` AgentAccount USDC: $${import_ethers2.ethers.formatUnits(accountUsdcBalance, 6)}`);
1441
- console.log(`
1442
- USDC is in your AgentAccount \u2014 ready for x402 payments`);
1459
+ const result = await mc.supplyCollateral(token, amount);
1460
+ console.log(`\u2705 Deposited ${amount} ${token}`);
1461
+ console.log(` AgentAccount: ${result.agentAccount}`);
1462
+ console.log(` TX: ${result.tx}`);
1443
1463
  } catch (e) {
1444
1464
  console.error(`\u274C ${decodeError(e)}`);
1445
1465
  }
1446
1466
  }
1447
- async function cmdMorphoWithdraw(amountStr, tokenSymbol) {
1467
+ async function cmdBorrow(amount, token) {
1448
1468
  const config = requireConfig();
1469
+ const mc = await getMorphoClient(config);
1449
1470
  console.log(`
1450
- \u{1F3E7} Withdrawing ${amountStr} ${tokenSymbol} collateral from Morpho...
1471
+ \u{1F4B8} Borrowing $${amount} USDC...
1451
1472
  `);
1452
- if (config.agentId === "0") {
1453
- console.error("\u274C Register agent first: agether register");
1454
- process.exit(1);
1455
- }
1456
- const status = await apiGet(config.backendUrl, "/status");
1457
- const morphoCreditAddr = status.contracts?.morphoCredit;
1458
- const accountFactoryAddr = status.contracts?.accountFactory;
1459
- if (!morphoCreditAddr || !accountFactoryAddr) {
1460
- console.error("\u274C Contracts not deployed");
1461
- process.exit(1);
1462
- }
1463
- const provider = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
1464
- const net = await provider.getNetwork();
1465
- const COLLATERALS = getCollateralInfo(Number(net.chainId));
1466
- const tokenInfo = COLLATERALS[tokenSymbol];
1467
- if (!tokenInfo) {
1468
- console.error(`\u274C Unsupported token: ${tokenSymbol}`);
1469
- console.log(" Supported:", Object.keys(COLLATERALS).join(", "));
1470
- process.exit(1);
1471
- }
1472
- const signer = new import_ethers2.ethers.Wallet(config.privateKey, provider);
1473
- const amount = import_ethers2.ethers.parseUnits(amountStr, tokenInfo.decimals);
1474
- const factory = new import_ethers2.ethers.Contract(accountFactoryAddr, ACCOUNT_FACTORY_ABI, signer);
1475
- const accountAddr = await factory.getAccount(config.agentId);
1476
- if (accountAddr === import_ethers2.ethers.ZeroAddress) {
1477
- console.error("\u274C No AgentAccount");
1478
- process.exit(1);
1479
- }
1480
- console.log(` AgentAccount: ${accountAddr}`);
1481
- const morphoCredit = new import_ethers2.ethers.Contract(morphoCreditAddr, MORPHO_CREDIT_ABI, provider);
1482
- const pos = await morphoCredit.getPosition(accountAddr, tokenInfo.address);
1483
- console.log(` Collateral: ${import_ethers2.ethers.formatUnits(pos.collateralAmount, tokenInfo.decimals)} ${tokenSymbol}`);
1484
- console.log(` Debt: $${import_ethers2.ethers.formatUnits(pos.borrowedAmount, 6)}`);
1485
- if (pos.collateralAmount === 0n) {
1486
- console.error(`\u274C No ${tokenSymbol} collateral deposited`);
1487
- process.exit(1);
1488
- }
1489
- const withdrawAmount = amountStr.toLowerCase() === "all" ? pos.collateralAmount : amount;
1490
- if (withdrawAmount > pos.collateralAmount) {
1491
- console.error(`\u274C Cannot withdraw more than deposited`);
1492
- console.log(` Max: ${import_ethers2.ethers.formatUnits(pos.collateralAmount, tokenInfo.decimals)} ${tokenSymbol}`);
1493
- process.exit(1);
1494
- }
1495
1473
  try {
1496
- const account = new import_ethers2.ethers.Contract(accountAddr, AGENT_ACCOUNT_ABI, signer);
1497
- const morphoIface = new import_ethers2.ethers.Interface(MORPHO_CREDIT_ABI);
1498
- console.log(` Step 1/2: Withdrawing from Morpho...`);
1499
- const withdrawCalldata = morphoIface.encodeFunctionData("withdrawCollateral", [tokenInfo.address, withdrawAmount]);
1500
- const tx1 = await account.execute(morphoCreditAddr, 0, withdrawCalldata);
1501
- await waitForTx(tx1);
1502
- console.log(` \u2713 Collateral withdrawn to AgentAccount`);
1503
- console.log(` Step 2/2: Transferring to EOA wallet...`);
1504
- const tx2 = await account.withdraw(tokenInfo.address, withdrawAmount, signer.address);
1505
- await waitForTx(tx2);
1506
- console.log(` \u2713 Sent to ${signer.address}`);
1507
- const newPos = await morphoCredit.getPosition(accountAddr, tokenInfo.address);
1508
- console.log(`
1509
- \u2705 Withdrew ${import_ethers2.ethers.formatUnits(withdrawAmount, tokenInfo.decimals)} ${tokenSymbol} to EOA`);
1510
- console.log(` Remaining collateral: ${import_ethers2.ethers.formatUnits(newPos.collateralAmount, tokenInfo.decimals)} ${tokenSymbol}`);
1511
- console.log(` Remaining debt: $${import_ethers2.ethers.formatUnits(newPos.borrowedAmount, 6)}`);
1512
- console.log(` TX: ${tx1.hash}`);
1474
+ const result = await mc.borrow(amount, token);
1475
+ console.log(`\u2705 Borrowed $${amount} USDC`);
1476
+ console.log(` Collateral: ${result.collateralToken}`);
1477
+ console.log(` AgentAccount: ${result.agentAccount}`);
1478
+ console.log(` TX: ${result.tx}`);
1513
1479
  } catch (e) {
1514
1480
  console.error(`\u274C ${decodeError(e)}`);
1515
1481
  }
1516
1482
  }
1517
- async function cmdMorphoRepay(amountUsd) {
1483
+ async function cmdDepositAndBorrow(collateralAmount, token, borrowAmount) {
1518
1484
  const config = requireConfig();
1485
+ const mc = await getMorphoClient(config);
1519
1486
  console.log(`
1520
- \u{1F4B3} Repaying $${amountUsd} USDC via AgentAccount \u2192 MorphoCredit...
1487
+ \uFFFD\uFFFD Depositing ${collateralAmount} ${token} + Borrowing $${borrowAmount}...
1521
1488
  `);
1522
- if (config.agentId === "0") {
1523
- console.error("\u274C Register agent first: agether register");
1524
- process.exit(1);
1525
- }
1526
- const status = await apiGet(config.backendUrl, "/status");
1527
- const morphoCreditAddr = status.contracts?.morphoCredit;
1528
- const accountFactoryAddr = status.contracts?.accountFactory;
1529
- const usdcAddr = status.contracts?.usdc;
1530
- if (!morphoCreditAddr || !accountFactoryAddr) {
1531
- console.error("\u274C Contracts not deployed");
1532
- process.exit(1);
1533
- }
1534
- const provider = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
1535
- const signer = new import_ethers2.ethers.Wallet(config.privateKey, provider);
1536
- const factory = new import_ethers2.ethers.Contract(accountFactoryAddr, ACCOUNT_FACTORY_ABI, signer);
1537
- const accountAddr = await factory.getAccount(config.agentId);
1538
- if (accountAddr === import_ethers2.ethers.ZeroAddress) {
1539
- console.error("\u274C No AgentAccount");
1540
- process.exit(1);
1541
- }
1542
- console.log(` AgentAccount: ${accountAddr}`);
1543
- const morphoCredit = new import_ethers2.ethers.Contract(morphoCreditAddr, MORPHO_CREDIT_ABI, provider);
1544
- const COLLATERALS = getCollateralInfo(Number((await provider.getNetwork()).chainId));
1545
- let hasDebt = false;
1546
- let activeCollateral = null;
1547
- for (const [symbol, info] of Object.entries(COLLATERALS)) {
1548
- const pos = await morphoCredit.getPosition(accountAddr, info.address);
1549
- if (pos.borrowedAmount > 0n) {
1550
- hasDebt = true;
1551
- activeCollateral = symbol;
1552
- console.log(` Position: ${import_ethers2.ethers.formatEther(pos.collateralAmount)} ${symbol}`);
1553
- console.log(` Current debt: $${import_ethers2.ethers.formatUnits(pos.borrowedAmount, 6)}`);
1554
- break;
1555
- }
1556
- }
1557
- if (!hasDebt || !activeCollateral) {
1558
- console.error("\u274C No Morpho debt to repay");
1559
- process.exit(1);
1560
- }
1561
- const collateralAddr = COLLATERALS[activeCollateral].address;
1562
- const amountWei = import_ethers2.ethers.parseUnits(amountUsd, 6);
1563
- const usdc = new import_ethers2.ethers.Contract(usdcAddr, ERC20_ABI, provider);
1564
- const accountUsdcBalance = await usdc.balanceOf(accountAddr);
1565
- if (accountUsdcBalance < amountWei) {
1566
- console.error(`\u274C Insufficient USDC in AgentAccount`);
1567
- console.log(` Have: $${import_ethers2.ethers.formatUnits(accountUsdcBalance, 6)}`);
1568
- console.log(` Need: $${amountUsd}`);
1569
- process.exit(1);
1570
- }
1571
1489
  try {
1572
- const account = new import_ethers2.ethers.Contract(accountAddr, AGENT_ACCOUNT_ABI, signer);
1573
- const erc20Iface = new import_ethers2.ethers.Interface(ERC20_ABI);
1574
- const approveCalldata = erc20Iface.encodeFunctionData("approve", [morphoCreditAddr, amountWei]);
1575
- console.log(` Approving $${amountUsd} USDC for MorphoCredit...`);
1576
- const approveTx = await account.execute(usdcAddr, 0, approveCalldata);
1577
- await waitForTx(approveTx);
1578
- const morphoIface = new import_ethers2.ethers.Interface(MORPHO_CREDIT_ABI);
1579
- const repayCalldata = morphoIface.encodeFunctionData("repayWithCollateral", [collateralAddr, amountWei]);
1580
- console.log(` Repaying $${amountUsd} USDC via repayWithCollateral(${activeCollateral})...`);
1581
- const tx = await account.execute(morphoCreditAddr, 0, repayCalldata);
1582
- await waitForTx(tx);
1583
- const totalDebt = await morphoCredit.getTotalDebt(accountAddr);
1584
- console.log(`
1585
- \u2705 Repaid $${amountUsd} to Morpho`);
1586
- console.log(` TX: ${tx.hash}`);
1587
- console.log(` Remaining debt: $${import_ethers2.ethers.formatUnits(totalDebt, 6)}`);
1490
+ const result = await mc.depositAndBorrow(token, collateralAmount, borrowAmount);
1491
+ console.log(`\u2705 Deposited ${collateralAmount} ${token} & Borrowed $${borrowAmount} USDC`);
1492
+ console.log(` AgentAccount: ${result.agentAccount}`);
1493
+ console.log(` TX: ${result.tx}`);
1588
1494
  } catch (e) {
1589
1495
  console.error(`\u274C ${decodeError(e)}`);
1590
1496
  }
1591
1497
  }
1592
- async function cmdMorphoDepositAndBorrow(amountStr, tokenSymbol, borrowUsd) {
1498
+ async function cmdRepay(amount, token) {
1593
1499
  const config = requireConfig();
1500
+ const mc = await getMorphoClient(config);
1594
1501
  console.log(`
1595
- \u{1F4B0} Deposit ${amountStr} ${tokenSymbol} + Borrow $${borrowUsd} USDC...
1502
+ \u{1F4B3} Repaying $${amount} USDC...
1596
1503
  `);
1597
- if (config.agentId === "0") {
1598
- console.error("\u274C Register agent first: agether register");
1599
- process.exit(1);
1600
- }
1601
- const status = await apiGet(config.backendUrl, "/status");
1602
- const morphoCreditAddr = status.contracts?.morphoCredit;
1603
- const accountFactoryAddr = status.contracts?.accountFactory;
1604
- const usdcAddr = status.contracts?.usdc;
1605
- if (!morphoCreditAddr || !accountFactoryAddr) {
1606
- console.error("\u274C Contracts not deployed");
1607
- process.exit(1);
1608
- }
1609
- const provider = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
1610
- const net = await provider.getNetwork();
1611
- const COLLATERAL_INFO = getCollateralInfo(Number(net.chainId));
1612
- const tokenInfo = COLLATERAL_INFO[tokenSymbol];
1613
- if (!tokenInfo) {
1614
- console.error(`\u274C Unsupported token: ${tokenSymbol}. Supported: ${Object.keys(COLLATERAL_INFO).join(", ")}`);
1615
- process.exit(1);
1616
- }
1617
- const signer = new import_ethers2.ethers.Wallet(config.privateKey, provider);
1618
- const collateralWei = import_ethers2.ethers.parseUnits(amountStr, tokenInfo.decimals);
1619
- const borrowWei = import_ethers2.ethers.parseUnits(borrowUsd, 6);
1620
- const factory = new import_ethers2.ethers.Contract(accountFactoryAddr, ACCOUNT_FACTORY_ABI, signer);
1621
- const accountAddr = await factory.getAccount(config.agentId);
1622
- if (accountAddr === import_ethers2.ethers.ZeroAddress) {
1623
- console.error("\u274C No AgentAccount. Create one first: agether wallet-create");
1624
- process.exit(1);
1625
- }
1626
- console.log(` AgentAccount: ${accountAddr}`);
1627
- const token = new import_ethers2.ethers.Contract(tokenInfo.address, ERC20_ABI, signer);
1628
- const balance = await token.balanceOf(signer.address);
1629
- if (balance < collateralWei) {
1630
- console.error(`\u274C Insufficient ${tokenSymbol}: have ${import_ethers2.ethers.formatUnits(balance, tokenInfo.decimals)}, need ${amountStr}`);
1631
- process.exit(1);
1632
- }
1633
1504
  try {
1634
- console.log(`Step 1/4: Approving ${tokenSymbol}...`);
1635
- const approveTx = await token.approve(morphoCreditAddr, collateralWei);
1636
- await approveTx.wait();
1637
- console.log(` \u2713 Approved`);
1638
- console.log(`Step 2/4: Depositing collateral...`);
1639
- const signer2 = getFreshSigner(config);
1640
- const morpho = new import_ethers2.ethers.Contract(morphoCreditAddr, MORPHO_CREDIT_ABI, signer2);
1641
- const depositTx = await morpho.depositCollateralFor(accountAddr, tokenInfo.address, collateralWei);
1642
- await depositTx.wait();
1643
- console.log(` \u2713 Deposited`);
1644
- console.log(`Step 3/4: Approving credit provider...`);
1645
- const signer3 = getFreshSigner(config);
1646
- const account = new import_ethers2.ethers.Contract(accountAddr, [
1647
- ...AGENT_ACCOUNT_ABI,
1648
- "function approveCreditProvider(address creditProvider)"
1649
- ], signer3);
1650
- try {
1651
- const cpTx = await account.approveCreditProvider(morphoCreditAddr);
1652
- await cpTx.wait();
1653
- console.log(` \u2713 Approved`);
1654
- } catch {
1655
- console.log(` \u2713 Already approved`);
1656
- }
1657
- console.log(`Step 4/4: Borrowing $${borrowUsd} USDC...`);
1658
- const signer4 = getFreshSigner(config);
1659
- const account4 = new import_ethers2.ethers.Contract(accountAddr, AGENT_ACCOUNT_ABI, signer4);
1660
- const morphoIface = new import_ethers2.ethers.Interface(MORPHO_CREDIT_ABI);
1661
- const borrowCalldata = morphoIface.encodeFunctionData("drawWithCollateral", [tokenInfo.address, borrowWei]);
1662
- const borrowTx = await account4.execute(morphoCreditAddr, 0, borrowCalldata);
1663
- await waitForTx(borrowTx);
1664
- const morphoView = new import_ethers2.ethers.Contract(morphoCreditAddr, MORPHO_CREDIT_ABI, provider);
1665
- const pos = await morphoView.getPosition(accountAddr, tokenInfo.address);
1666
- const totalDebt = await morphoView.getTotalDebt(accountAddr);
1667
- const usdc = new import_ethers2.ethers.Contract(usdcAddr, ERC20_ABI, provider);
1668
- const accUsdcBal = await usdc.balanceOf(accountAddr);
1669
- console.log(`
1670
- \u2705 Deposited ${amountStr} ${tokenSymbol} + Borrowed $${borrowUsd}`);
1671
- console.log(` Deposit TX: ${depositTx.hash}`);
1672
- console.log(` Borrow TX: ${borrowTx.hash}`);
1673
- console.log(` Collateral: ${import_ethers2.ethers.formatUnits(pos.collateralAmount, tokenInfo.decimals)} ${tokenSymbol}`);
1674
- console.log(` Total debt: $${import_ethers2.ethers.formatUnits(totalDebt, 6)}`);
1675
- console.log(` AgentAccount USDC: $${import_ethers2.ethers.formatUnits(accUsdcBal, 6)}`);
1676
- console.log(`
1677
- USDC is in your AgentAccount \u2014 ready for x402 payments`);
1505
+ const result = await mc.repay(amount, token);
1506
+ console.log(`\u2705 Repaid $${amount}`);
1507
+ console.log(` Remaining debt: $${parseFloat(result.remainingDebt).toFixed(2)}`);
1508
+ console.log(` TX: ${result.tx}`);
1678
1509
  } catch (e) {
1679
1510
  console.error(`\u274C ${decodeError(e)}`);
1680
1511
  }
1681
1512
  }
1682
- async function cmdMorphoSponsor(amountStr, tokenSymbol, targetAgentId, targetAddress, borrowUsd) {
1513
+ async function cmdWithdraw(amount, token) {
1683
1514
  const config = requireConfig();
1684
- const targetDesc = targetAgentId ? `agent #${targetAgentId}` : targetAddress;
1515
+ const mc = await getMorphoClient(config);
1685
1516
  console.log(`
1686
- \u{1F91D} Sponsoring ${targetDesc}: ${amountStr} ${tokenSymbol}${borrowUsd ? ` + borrow $${borrowUsd}` : ""}...
1517
+ \u{1F4E4} Withdrawing ${amount} ${token}...
1687
1518
  `);
1688
- if (!targetAgentId && !targetAddress) {
1689
- console.error("\u274C Provide --agent-id or --address");
1690
- process.exit(1);
1691
- }
1692
- const status = await apiGet(config.backendUrl, "/status");
1693
- const morphoCreditAddr = status.contracts?.morphoCredit;
1694
- const accountFactoryAddr = status.contracts?.accountFactory;
1695
- if (!morphoCreditAddr || !accountFactoryAddr) {
1696
- console.error("\u274C Contracts not deployed");
1697
- process.exit(1);
1698
- }
1699
- const provider = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
1700
- const net = await provider.getNetwork();
1701
- const COLLATERAL_INFO = getCollateralInfo(Number(net.chainId));
1702
- const tokenInfo = COLLATERAL_INFO[tokenSymbol];
1703
- if (!tokenInfo) {
1704
- console.error(`\u274C Unsupported token: ${tokenSymbol}. Supported: ${Object.keys(COLLATERAL_INFO).join(", ")}`);
1705
- process.exit(1);
1706
- }
1707
- const signer = new import_ethers2.ethers.Wallet(config.privateKey, provider);
1708
- const collateralWei = import_ethers2.ethers.parseUnits(amountStr, tokenInfo.decimals);
1709
- let accountAddr;
1710
- if (targetAddress) {
1711
- accountAddr = targetAddress;
1712
- } else {
1713
- const factory = new import_ethers2.ethers.Contract(accountFactoryAddr, ACCOUNT_FACTORY_ABI, signer);
1714
- accountAddr = await factory.getAccount(targetAgentId);
1715
- if (accountAddr === import_ethers2.ethers.ZeroAddress) {
1716
- console.error(`\u274C No AgentAccount for agent #${targetAgentId}`);
1717
- process.exit(1);
1718
- }
1719
- }
1720
- console.log(` Target AgentAccount: ${accountAddr}`);
1721
- const token = new import_ethers2.ethers.Contract(tokenInfo.address, ERC20_ABI, signer);
1722
- const balance = await token.balanceOf(signer.address);
1723
- if (balance < collateralWei) {
1724
- console.error(`\u274C Insufficient ${tokenSymbol}: have ${import_ethers2.ethers.formatUnits(balance, tokenInfo.decimals)}, need ${amountStr}`);
1725
- process.exit(1);
1726
- }
1727
1519
  try {
1728
- console.log(`Step 1/2: Approving + Depositing ${tokenSymbol} for target...`);
1729
- const approveTx = await token.approve(morphoCreditAddr, collateralWei);
1730
- await approveTx.wait();
1731
- const signer2 = getFreshSigner(config);
1732
- const morpho = new import_ethers2.ethers.Contract(morphoCreditAddr, MORPHO_CREDIT_ABI, signer2);
1733
- const depositTx = await morpho.depositCollateralFor(accountAddr, tokenInfo.address, collateralWei);
1734
- await depositTx.wait();
1735
- console.log(` \u2713 Deposited ${amountStr} ${tokenSymbol} for ${targetDesc}`);
1736
- if (borrowUsd) {
1737
- console.log(`Step 2/2: Borrowing $${borrowUsd} for target...`);
1738
- const signer3 = getFreshSigner(config);
1739
- const account = new import_ethers2.ethers.Contract(accountAddr, [
1740
- ...AGENT_ACCOUNT_ABI,
1741
- "function approveCreditProvider(address creditProvider)"
1742
- ], signer3);
1743
- try {
1744
- const cpTx = await account.approveCreditProvider(morphoCreditAddr);
1745
- await cpTx.wait();
1746
- } catch {
1747
- }
1748
- const borrowWei = import_ethers2.ethers.parseUnits(borrowUsd, 6);
1749
- const signer4 = getFreshSigner(config);
1750
- const account4 = new import_ethers2.ethers.Contract(accountAddr, AGENT_ACCOUNT_ABI, signer4);
1751
- const morphoIface = new import_ethers2.ethers.Interface(MORPHO_CREDIT_ABI);
1752
- const calldata = morphoIface.encodeFunctionData("drawWithCollateral", [tokenInfo.address, borrowWei]);
1753
- try {
1754
- const borrowTx = await account4.execute(morphoCreditAddr, 0, calldata);
1755
- await waitForTx(borrowTx);
1756
- console.log(` \u2713 Borrowed $${borrowUsd} for target (TX: ${borrowTx.hash})`);
1757
- } catch (e) {
1758
- console.log(` \u26A0 Borrow failed (you may not own this AgentAccount): ${decodeError(e)}`);
1759
- }
1760
- }
1761
- const morphoView = new import_ethers2.ethers.Contract(morphoCreditAddr, MORPHO_CREDIT_ABI, provider);
1762
- const pos = await morphoView.getPosition(accountAddr, tokenInfo.address);
1763
- console.log(`
1764
- \u2705 Sponsored ${targetDesc}`);
1765
- console.log(` Deposit TX: ${depositTx.hash}`);
1766
- console.log(` Collateral: ${import_ethers2.ethers.formatUnits(pos.collateralAmount, tokenInfo.decimals)} ${tokenSymbol}`);
1767
- console.log(` Debt: $${import_ethers2.ethers.formatUnits(pos.borrowedAmount, 6)}`);
1520
+ const result = await mc.withdrawCollateral(token, amount);
1521
+ console.log(`\u2705 Withdrew ${result.amount} ${token}`);
1522
+ console.log(` Remaining collateral: ${result.remainingCollateral}`);
1523
+ console.log(` Destination: ${result.destination}`);
1524
+ console.log(` TX: ${result.tx}`);
1768
1525
  } catch (e) {
1769
1526
  console.error(`\u274C ${decodeError(e)}`);
1770
1527
  }
1771
1528
  }
1772
- async function cmdMorphoStatus() {
1773
- const config = requireConfig();
1774
- console.log("\n\u{1F4CA} Morpho Credit Status\n");
1775
- if (config.agentId === "0") {
1776
- console.error("\u274C Register agent first: agether register");
1777
- process.exit(1);
1778
- }
1779
- try {
1780
- const status = await apiGet(config.backendUrl, "/status");
1781
- const morphoCreditAddr = status.contracts?.morphoCredit;
1782
- const accountFactoryAddr = status.contracts?.accountFactory;
1783
- if (!morphoCreditAddr || !accountFactoryAddr) {
1784
- console.error("\u274C Contracts not deployed");
1785
- process.exit(1);
1786
- }
1787
- const provider = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
1788
- const morphoCredit = new import_ethers2.ethers.Contract(morphoCreditAddr, MORPHO_CREDIT_ABI, provider);
1789
- const factory = new import_ethers2.ethers.Contract(accountFactoryAddr, ACCOUNT_FACTORY_ABI, provider);
1790
- const accountAddr = await factory.getAccount(config.agentId);
1791
- if (accountAddr === import_ethers2.ethers.ZeroAddress) {
1792
- console.log("\u274C No AgentAccount. Create one: agether wallet-create");
1793
- return;
1794
- }
1795
- console.log(` AgentAccount: ${accountAddr}
1796
- `);
1797
- const COLLATERALS = getCollateralInfo(Number((await provider.getNetwork()).chainId));
1798
- let hasPositions = false;
1799
- for (const [symbol, info] of Object.entries(COLLATERALS)) {
1800
- const pos = await morphoCredit.getPosition(accountAddr, info.address);
1801
- if (pos.isActive || pos.collateralAmount > 0n) {
1802
- hasPositions = true;
1803
- console.log(`Position: ${symbol}`);
1804
- console.log(` Collateral: ${import_ethers2.ethers.formatUnits(pos.collateralAmount, info.decimals)} ${symbol}`);
1805
- console.log(` Borrowed: $${import_ethers2.ethers.formatUnits(pos.borrowedAmount, 6)}`);
1806
- console.log(` Status: ${pos.isActive ? "\u2705 Active" : "\u274C Inactive"}`);
1807
- console.log("");
1808
- }
1809
- }
1810
- if (!hasPositions) {
1811
- console.log("No Morpho credit positions found.");
1812
- console.log("\nTo open one:");
1813
- console.log(" agether morpho-deposit --amount 0.1 --token WETH");
1814
- }
1815
- } catch (e) {
1816
- console.error(`\u274C Failed to fetch status: ${e.message}`);
1817
- }
1818
- }
1819
- async function cmdUnifiedStatus() {
1820
- const config = requireConfig();
1821
- console.log("\n\u{1F4CA} All Credit Lines (Unified View)\n");
1822
- if (config.agentId === "0") {
1823
- console.error("\u274C Register agent first: agether register");
1824
- process.exit(1);
1825
- }
1826
- try {
1827
- const data = await apiGet(config.backendUrl, `/morpho/unified/agent/${config.agentId}`);
1828
- if (data.creditLines.length === 0) {
1829
- console.log("No credit lines found.");
1830
- console.log("\nTo get credit:");
1831
- console.log(" agether apply --limit 5000 # Undercollateralized (80%)");
1832
- console.log(" agether morpho-open --collateral WETH # Overcollateralized (120%)");
1833
- return;
1834
- }
1835
- console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
1836
- console.log("\u2502 ID \u2502 Type \u2502 Borrowed \u2502 Available \u2502 Health \u2502");
1837
- console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
1838
- for (const cl of data.creditLines) {
1839
- const id = cl.id.toString().padEnd(4);
1840
- const type = cl.creditType === "undercollateralized" ? "Undercollat (80%)".padEnd(21) : `Morpho ${cl.collateralSymbol} (120%)`.padEnd(21);
1841
- const borrowed = `$${(parseFloat(cl.borrowed) / 1e6).toFixed(2)}`.padEnd(10);
1842
- const available = `$${(parseFloat(cl.available) / 1e6).toFixed(2)}`.padEnd(10);
1843
- const health = cl.healthFactor === "Infinity" ? "\u221E" : parseFloat(cl.healthFactor).toFixed(2);
1844
- console.log(`\u2502 ${id}\u2502 ${type}\u2502 ${borrowed} \u2502 ${available} \u2502 ${health.padEnd(10)} \u2502`);
1845
- }
1846
- console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
1847
- console.log(`
1848
- \u{1F4C8} Summary:`);
1849
- console.log(` Total Borrowed: $${(parseFloat(data.summary.totalBorrowed) / 1e6).toFixed(2)}`);
1850
- console.log(` Total Available: $${(parseFloat(data.summary.totalAvailable) / 1e6).toFixed(2)}`);
1851
- console.log(` Total Collateral: $${(parseFloat(data.summary.totalCollateralUsd) / 1e6).toFixed(2)}`);
1852
- } catch (e) {
1853
- console.error(`\u274C Failed to fetch status: ${e.message}`);
1854
- }
1855
- }
1856
- async function cmdWalletCreate() {
1857
- const config = requireConfig();
1858
- const signer = getSigner(config);
1859
- console.log("\n\u{1F4BC} Creating Agent Account\n");
1860
- let status;
1861
- try {
1862
- status = await apiGet(config.backendUrl, "/status");
1863
- if (!status.contracts?.accountFactory) {
1864
- console.error("\u274C Backend not configured with accountFactory");
1865
- process.exit(1);
1866
- }
1867
- } catch (e) {
1868
- console.error(`\u274C Failed to reach backend: ${e.message}`);
1869
- process.exit(1);
1870
- }
1871
- const factory = new import_ethers2.ethers.Contract(
1872
- status.contracts.accountFactory,
1873
- ACCOUNT_FACTORY_ABI,
1874
- signer
1875
- );
1876
- const agentId = BigInt(config.agentId);
1877
- const exists = await factory.accountExists(agentId);
1878
- if (exists) {
1879
- const accountAddr2 = await factory.getAccount(agentId);
1880
- console.log(`\u2713 Account already exists: ${accountAddr2}`);
1881
- return;
1882
- }
1883
- console.log(` Agent ID: ${agentId}`);
1884
- console.log(` Factory: ${status.contracts.accountFactory}`);
1885
- console.log(" Creating account...");
1886
- const tx = await factory.createAccount(agentId);
1887
- console.log(` TX: ${tx.hash}`);
1888
- const receipt = await tx.wait();
1889
- console.log(` \u2713 Confirmed in block ${receipt.blockNumber}`);
1890
- const accountAddr = await factory.getAccount(agentId);
1891
- console.log(`
1892
- \u2705 Account created: ${accountAddr}`);
1893
- console.log("\nNext steps:");
1894
- console.log(" 1. Fund the account: agether wallet-fund --amount 1000");
1895
- console.log(" 2. Draw credit: agether wallet-draw --amount 500");
1896
- console.log(" 3. Check status: agether wallet-status");
1897
- }
1898
- async function cmdWalletStatus() {
1529
+ async function cmdSponsor(amount, token, agentId, address) {
1899
1530
  const config = requireConfig();
1900
- const signer = getSigner(config);
1901
- console.log("\n\u{1F4BC} Agent Account Status\n");
1902
- let status;
1903
- try {
1904
- status = await apiGet(config.backendUrl, "/status");
1905
- if (!status.contracts?.accountFactory) {
1906
- console.error("\u274C Backend not configured with accountFactory");
1907
- process.exit(1);
1908
- }
1909
- } catch (e) {
1910
- console.error(`\u274C Failed to reach backend: ${e.message}`);
1911
- process.exit(1);
1912
- }
1913
- const factory = new import_ethers2.ethers.Contract(
1914
- status.contracts.accountFactory,
1915
- ACCOUNT_FACTORY_ABI,
1916
- signer
1917
- );
1918
- const agentId = BigInt(config.agentId);
1919
- const exists = await factory.accountExists(agentId);
1920
- if (!exists) {
1921
- console.log("\u274C No account found for this agent");
1922
- console.log(" Create one with: agether wallet-create");
1923
- return;
1924
- }
1925
- const accountAddr = await factory.getAccount(agentId);
1926
- const account = new import_ethers2.ethers.Contract(accountAddr, AGENT_ACCOUNT_ABI, signer);
1927
- const usdcAddr = status.contracts.usdc;
1928
- const usdc = new import_ethers2.ethers.Contract(usdcAddr, ERC20_ABI, signer);
1929
- const [owner, usdcBalance, ethBal] = await Promise.all([
1930
- account.owner(),
1931
- usdc.balanceOf(accountAddr),
1932
- signer.provider.getBalance(accountAddr)
1933
- ]);
1934
- console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
1935
- console.log(`\u2502 Account: ${accountAddr.slice(0, 20)}... \u2502`);
1936
- console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
1937
- console.log(`\u2502 Agent ID: ${config.agentId.padStart(10)}`);
1938
- console.log(`\u2502 Owner: ${owner.slice(0, 20)}...`);
1939
- console.log(`\u2502 ETH Balance: ${import_ethers2.ethers.formatEther(ethBal).padStart(10)} ETH`);
1940
- console.log(`\u2502 USDC Balance: $${import_ethers2.ethers.formatUnits(usdcBalance, 6).padStart(10)}`);
1941
- console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
1942
- }
1943
- async function cmdWalletDraw(amount) {
1944
- const config = requireConfig();
1945
- const signer = getSigner(config);
1531
+ const mc = await getMorphoClient(config);
1532
+ const target = agentId ? { agentId } : { address };
1946
1533
  console.log(`
1947
- \u{1F4B8} Drawing $${amount} from Credit Line via AgentAccount
1534
+ \u{1F381} Sponsoring ${amount} ${token} to ${agentId || address}...
1948
1535
  `);
1949
- let status;
1950
1536
  try {
1951
- status = await apiGet(config.backendUrl, "/status");
1952
- if (!status.contracts?.accountFactory) {
1953
- console.error("\u274C Backend not configured with accountFactory");
1954
- process.exit(1);
1955
- }
1537
+ const result = await mc.sponsor(target, token, amount);
1538
+ console.log(`\u2705 Sponsored ${amount} ${token}`);
1539
+ console.log(` Target: ${result.targetAccount}`);
1540
+ console.log(` TX: ${result.tx}`);
1956
1541
  } catch (e) {
1957
- console.error(`\u274C Failed to reach backend: ${e.message}`);
1958
- process.exit(1);
1959
- }
1960
- const factory = new import_ethers2.ethers.Contract(
1961
- status.contracts.accountFactory,
1962
- ACCOUNT_FACTORY_ABI,
1963
- signer
1964
- );
1965
- const agentId = BigInt(config.agentId);
1966
- const accountAddr = await factory.getAccount(agentId);
1967
- if (accountAddr === import_ethers2.ethers.ZeroAddress) {
1968
- console.log("\u274C No account found. Create one first: agether wallet-create");
1969
- return;
1970
- }
1971
- const account = new import_ethers2.ethers.Contract(accountAddr, AGENT_ACCOUNT_ABI, signer);
1972
- const amountWei = import_ethers2.ethers.parseUnits(amount.toString(), 6);
1973
- const creditProvider = status.contracts.reputationCredit;
1974
- console.log(` Account: ${accountAddr}`);
1975
- console.log(` Amount: $${amount} USDC`);
1976
- console.log(" Drawing from credit line...");
1977
- const tx = await account.drawCredit(creditProvider, amountWei);
1978
- console.log(` TX: ${tx.hash}`);
1979
- const receipt = await tx.wait();
1980
- console.log(` \u2713 Confirmed in block ${receipt.blockNumber}`);
1981
- const usdc = new import_ethers2.ethers.Contract(status.contracts.usdc, ERC20_ABI, signer);
1982
- const newBalance = await usdc.balanceOf(accountAddr);
1983
- console.log(`
1984
- \u2705 Drew $${amount}. Account USDC balance: $${import_ethers2.ethers.formatUnits(newBalance, 6)}`);
1985
- }
1986
- async function cmdWalletRepay(amount) {
1987
- const config = requireConfig();
1988
- const signer = getSigner(config);
1989
- console.log(`
1990
- \u{1F4B0} Repaying $${amount} to Credit Line from AgentAccount
1991
- `);
1992
- let status;
1993
- try {
1994
- status = await apiGet(config.backendUrl, "/status");
1995
- if (!status.contracts?.accountFactory) {
1996
- console.error("\u274C Backend not configured with accountFactory");
1997
- process.exit(1);
1998
- }
1999
- } catch (e) {
2000
- console.error(`\u274C Failed to reach backend: ${e.message}`);
2001
- process.exit(1);
2002
- }
2003
- const factory = new import_ethers2.ethers.Contract(
2004
- status.contracts.accountFactory,
2005
- ACCOUNT_FACTORY_ABI,
2006
- signer
2007
- );
2008
- const agentId = BigInt(config.agentId);
2009
- const accountAddr = await factory.getAccount(agentId);
2010
- if (accountAddr === import_ethers2.ethers.ZeroAddress) {
2011
- console.log("\u274C No account found. Create one first: agether wallet-create");
2012
- return;
1542
+ console.error(`\u274C ${decodeError(e)}`);
2013
1543
  }
2014
- const account = new import_ethers2.ethers.Contract(accountAddr, AGENT_ACCOUNT_ABI, signer);
2015
- const amountWei = import_ethers2.ethers.parseUnits(amount.toString(), 6);
2016
- const creditProvider = status.contracts.reputationCredit;
2017
- console.log(` Account: ${accountAddr}`);
2018
- console.log(` Amount: $${amount} USDC`);
2019
- console.log(" Repaying to credit line...");
2020
- const tx = await account.repayCredit(creditProvider, amountWei);
2021
- console.log(` TX: ${tx.hash}`);
2022
- const receipt = await tx.wait();
2023
- console.log(` \u2713 Confirmed in block ${receipt.blockNumber}`);
2024
- console.log(`
2025
- \u2705 Repaid $${amount}.`);
2026
1544
  }
2027
- async function cmdWalletFund(amount) {
1545
+ async function cmdFund(amount) {
2028
1546
  const config = requireConfig();
2029
- const signer = getSigner(config);
1547
+ const mc = await getMorphoClient(config);
2030
1548
  console.log(`
2031
- \u{1F4B5} Funding Account with $${amount} USDC
1549
+ \u{1F4B5} Funding AgentAccount with $${amount} USDC...
2032
1550
  `);
2033
- let status;
2034
1551
  try {
2035
- status = await apiGet(config.backendUrl, "/status");
2036
- if (!status.contracts?.accountFactory || !status.contracts?.usdc) {
2037
- console.error("\u274C Backend not configured with required contracts");
2038
- process.exit(1);
2039
- }
1552
+ const result = await mc.fundAccount(amount);
1553
+ console.log(`\u2705 Funded $${amount} USDC`);
1554
+ console.log(` AgentAccount: ${result.agentAccount}`);
1555
+ console.log(` TX: ${result.tx}`);
2040
1556
  } catch (e) {
2041
- console.error(`\u274C Failed to reach backend: ${e.message}`);
2042
- process.exit(1);
2043
- }
2044
- const factory = new import_ethers2.ethers.Contract(
2045
- status.contracts.accountFactory,
2046
- ACCOUNT_FACTORY_ABI,
2047
- signer
2048
- );
2049
- const agentId = BigInt(config.agentId);
2050
- const accountAddr = await factory.getAccount(agentId);
2051
- if (accountAddr === import_ethers2.ethers.ZeroAddress) {
2052
- console.log("\u274C No account found. Create one first: agether wallet-create");
2053
- return;
1557
+ console.error(`\u274C ${decodeError(e)}`);
2054
1558
  }
2055
- const usdc = new import_ethers2.ethers.Contract(status.contracts.usdc, ERC20_ABI, signer);
2056
- const amountWei = import_ethers2.ethers.parseUnits(amount.toString(), 6);
2057
- console.log(` From: ${signer.address}`);
2058
- console.log(` To: ${accountAddr}`);
2059
- console.log(` Amount: $${amount} USDC`);
2060
- console.log(" Approving USDC...");
2061
- const approveTx = await usdc.approve(accountAddr, amountWei);
2062
- await approveTx.wait();
2063
- const freshSigner = getFreshSigner(config);
2064
- const account = new import_ethers2.ethers.Contract(accountAddr, AGENT_ACCOUNT_ABI, freshSigner);
2065
- console.log(" Funding account...");
2066
- const tx = await account.fund(status.contracts.usdc, amountWei);
2067
- console.log(` TX: ${tx.hash}`);
2068
- const receipt = await tx.wait();
2069
- console.log(` \u2713 Confirmed in block ${receipt.blockNumber}`);
2070
- const usdcContract = new import_ethers2.ethers.Contract(status.contracts.usdc, ERC20_ABI, signer);
2071
- const newBalance = await usdcContract.balanceOf(accountAddr);
2072
- console.log(`
2073
- \u2705 Funded. Account USDC balance: $${import_ethers2.ethers.formatUnits(newBalance, 6)}`);
2074
1559
  }
2075
- async function cmdX402Call(url, method = "GET", body, autoDraw = false) {
1560
+ async function cmdX402Call(url, method = "GET", body) {
2076
1561
  const config = requireConfig();
2077
1562
  console.log("\n\u{1F510} x402 Paid API Call\n");
2078
- if (autoDraw) console.log(" \u26A1 Auto-draw enabled: will borrow from Morpho if USDC insufficient");
2079
- let accountAddress;
2080
- let morphoCreditAddress;
2081
- try {
2082
- const status = await apiGet(config.backendUrl, "/status");
2083
- const factoryAddr = status.contracts?.accountFactory;
2084
- morphoCreditAddress = status.contracts?.morphoCredit;
2085
- if (factoryAddr && config.agentId) {
2086
- const provider = new import_ethers2.ethers.JsonRpcProvider(config.rpcUrl);
2087
- const factory = new import_ethers2.ethers.Contract(factoryAddr, ACCOUNT_FACTORY_ABI, provider);
2088
- const addr = await factory.getAccount(config.agentId);
2089
- if (addr !== import_ethers2.ethers.ZeroAddress) {
2090
- accountAddress = addr;
2091
- console.log(` AgentAccount: ${addr}`);
2092
- }
2093
- }
2094
- } catch {
2095
- }
2096
- const { X402Client: X402Client2 } = await Promise.resolve().then(() => (init_X402Client(), X402Client_exports));
2097
- const client = new X402Client2({
2098
- privateKey: config.privateKey,
2099
- rpcUrl: config.rpcUrl,
2100
- backendUrl: config.backendUrl,
2101
- agentId: config.agentId,
2102
- accountAddress,
2103
- autoDraw,
2104
- morphoCreditAddress
2105
- });
2106
- console.log(` Wallet: ${new import_ethers2.ethers.Wallet(config.privateKey).address}`);
1563
+ const x402 = await getX402Client(config);
1564
+ console.log(` Wallet: ${new import_ethers3.ethers.Wallet(config.privateKey).address}`);
2107
1565
  console.log(`
2108
- \u{1F4E1} Calling: ${method} ${url}`);
2109
- if (body) {
2110
- console.log(`\u{1F4E6} Body: ${body}`);
2111
- }
1566
+ \u{1F4E1} ${method} ${url}`);
1567
+ if (body) console.log(`\u{1F4E6} Body: ${body}`);
2112
1568
  try {
2113
1569
  let result;
2114
1570
  if (method === "POST" && body) {
2115
- result = await client.post(url, JSON.parse(body));
1571
+ result = await x402.post(url, JSON.parse(body));
2116
1572
  } else {
2117
- result = await client.get(url);
1573
+ result = await x402.get(url);
2118
1574
  }
2119
1575
  if (result.success) {
2120
1576
  console.log("\n\u2705 Success!");
2121
1577
  if (result.paymentInfo) {
2122
1578
  console.log(`\u{1F4B0} Paid: ${result.paymentInfo.amount} ${result.paymentInfo.asset} on ${result.paymentInfo.network}`);
2123
- if (result.paymentInfo.txHash) {
2124
- console.log(`\u{1F4DC} TX: ${result.paymentInfo.txHash}`);
2125
- }
1579
+ if (result.paymentInfo.txHash) console.log(`\u{1F4DC} TX: ${result.paymentInfo.txHash}`);
2126
1580
  }
2127
1581
  console.log("\n\u{1F4C4} Response:");
2128
1582
  console.log(JSON.stringify(result.data, null, 2));
@@ -2136,88 +1590,46 @@ async function cmdX402Call(url, method = "GET", body, autoDraw = false) {
2136
1590
  }
2137
1591
  function cmdHelp() {
2138
1592
  console.log(`
2139
- \u{1F3E6} Agether CLI \u2014 On-Chain Credit for AI Agents
1593
+ \u{1F3E6} Agether CLI \u2014 Direct Morpho Blue Credit for AI Agents
2140
1594
 
2141
1595
  USAGE:
2142
1596
  agether <command> [options]
2143
1597
 
2144
- COMMANDS (Undercollateralized - 80% collateral, reputation-based):
1598
+ SETUP:
2145
1599
  init <private-key> [--agent-id <id>] Initialize with private key
2146
- register [--name <n>] [--code-url <u>] Register on ERC-8004 + code audit
2147
- apply --limit <usd> Apply for credit line (needs scoring)
2148
- collateral --amount <usd> Deposit USDC collateral
2149
- draw --amount <usd> Draw funds (daily limits apply)
2150
- repay --amount <usd> Repay debt
2151
- status Show credit line status
2152
- score Show credit score
2153
- balance Show ETH + USDC balances
1600
+ register [--name <n>] Register ERC-8004 + create AgentAccount
2154
1601
 
2155
- COMMANDS (Morpho - 120% collateral, instant approval):
2156
- morpho-compare --amount <usd> Compare both credit options (checks balances!)
2157
- morpho-balances Show all token balances & available credit
2158
- morpho-markets List supported Morpho markets
2159
- morpho-open --collateral <token> Open Morpho credit line (WETH/wstETH/WBTC)
2160
- morpho-deposit --amount <n> --token <t> Deposit collateral (e.g. 0.5 WETH)
2161
- morpho-deposit-and-borrow --amount <n> --token <t> --borrow <usd> Deposit + borrow in one go
2162
- morpho-borrow --amount <usd> Borrow USDC against collateral
2163
- morpho-repay --amount <usd> Repay borrowed USDC
2164
- morpho-withdraw --amount <n> --token <t> Withdraw collateral to EOA (e.g. 0.05 WETH or "all")
2165
- morpho-sponsor --amount <n> --token <t> --agent-id <id> [--borrow <usd>] Sponsor another agent
2166
- morpho-sponsor --amount <n> --token <t> --address <addr> [--borrow <usd>] Sponsor by address
2167
- morpho-status Show Morpho credit lines
2168
- unified-status Show ALL credit lines (both types)
1602
+ INFO:
1603
+ balance Check ETH + USDC balances
1604
+ status Show Morpho positions & credit score
1605
+ score Get credit score
1606
+ markets List Morpho Blue USDC markets
2169
1607
 
2170
- COMMANDS (Agent Wallet - Per-agent execution wallet):
2171
- wallet-create Create isolated wallet for your agent
2172
- wallet-status Show wallet status & balances
2173
- wallet-fund --amount <usd> Fund wallet with USDC
2174
- wallet-draw --amount <usd> Draw from credit line into wallet
2175
- wallet-repay --amount <usd> Repay credit line from wallet
1608
+ MORPHO LENDING:
1609
+ deposit --amount <n> --token <t> Deposit collateral (WETH, wstETH, cbETH)
1610
+ borrow --amount <usd> [--token <t>] Borrow USDC against collateral
1611
+ deposit-and-borrow --amount <n> --token <t> --borrow <usd>
1612
+ Deposit + borrow in one batched tx
1613
+ repay --amount <usd> [--token <t>] Repay borrowed USDC
1614
+ withdraw --amount <n> --token <t> Withdraw collateral (use 'all' for max)
1615
+ sponsor --amount <n> --token <t> --agent-id <id> Send collateral to another agent
1616
+ fund --amount <usd> Transfer USDC from EOA to AgentAccount
2176
1617
 
2177
- COMMANDS (x402 - Paid API Calls):
2178
- x402 <url> [--method GET|POST] [--body <json>] [--auto-draw] Make a paid API call using credit
1618
+ x402 PAYMENTS:
1619
+ x402 <url> [--method GET|POST] [--body <json>] Make a paid API call
2179
1620
 
2180
1621
  ENVIRONMENT:
2181
- AGETHER_RPC_URL RPC endpoint (default: https://mainnet.base.org)
2182
- AGETHER_BACKEND_URL Backend URL (default: http://95.179.189.214:3001)
2183
-
2184
- COMPARISON:
2185
- \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
2186
- \u2502 UNDERCOLLATERALIZED \u2502 MORPHO-BACKED \u2502
2187
- \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524
2188
- \u2502 80% collateral \u2502 120% collateral \u2502
2189
- \u2502 Requires scoring \u2502 Instant approval \u2502
2190
- \u2502 Daily limits \u2502 No limits \u2502
2191
- \u2502 ~12% APR \u2502 ~5% APR \u2502
2192
- \u2502 Builds reputation \u2502 No reputation \u2502
2193
- \u2502 Can graduate to 0% \u2502 Collateral always required \u2502
2194
- \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
2195
-
2196
- EXAMPLE FLOWS:
1622
+ AGETHER_RPC_URL RPC endpoint (default: ${DEFAULT_RPC})
1623
+ AGETHER_BACKEND_URL Backend URL (default: ${DEFAULT_BACKEND})
2197
1624
 
2198
- Undercollateralized (recommended for agents building reputation):
2199
- agether init 0xYOUR_PRIVATE_KEY
2200
- agether register --name "MyAgent"
2201
- agether apply --limit 5000 # Wait for approval
2202
- agether collateral --amount 4000 # 80% of limit
2203
- agether draw --amount 1000
2204
- agether repay --amount 500
2205
-
2206
- Morpho-backed (instant, for new agents or large amounts):
2207
- agether init 0xYOUR_PRIVATE_KEY
2208
- agether register --name "MyAgent"
2209
- agether morpho-open --collateral WETH
2210
- agether morpho-deposit --amount 0.01 --token WETH # ~$25 collateral
2211
- agether morpho-borrow --amount 10 # Borrow $10 USDC
2212
- agether morpho-repay --amount 10 # Repay when done
2213
-
2214
- Agent Wallet (isolated execution wallet with x402 support):
2215
- agether init 0xYOUR_PRIVATE_KEY
2216
- agether register --name "MyAgent"
2217
- agether wallet-create # Deploy isolated wallet
2218
- agether wallet-fund --amount 100 # Pre-fund wallet
2219
- agether wallet-draw --amount 500 # Draw from credit line
2220
- agether wallet-status # Check balances
1625
+ EXAMPLE FLOW:
1626
+ agether init 0xYOUR_PRIVATE_KEY
1627
+ agether register --name "MyAgent"
1628
+ agether deposit --amount 0.05 --token WETH # ~$125 collateral
1629
+ agether borrow --amount 50 # Borrow $50 USDC
1630
+ agether status # Check positions
1631
+ agether repay --amount 50 # Repay when done
1632
+ agether withdraw --amount all --token WETH # Withdraw collateral
2221
1633
  `);
2222
1634
  }
2223
1635
  function parseArgs(args) {
@@ -2253,35 +1665,10 @@ async function main() {
2253
1665
  await cmdInit(positional[0], options["agent-id"]);
2254
1666
  break;
2255
1667
  case "register":
2256
- await cmdRegister(options.name, options["code-url"]);
1668
+ await cmdRegister(options.name);
2257
1669
  break;
2258
- case "apply":
2259
- if (!options.limit) {
2260
- console.error("\u274C --limit required");
2261
- process.exit(1);
2262
- }
2263
- await cmdApply(parseFloat(options.limit));
2264
- break;
2265
- case "draw":
2266
- if (!options.amount) {
2267
- console.error("\u274C --amount required");
2268
- process.exit(1);
2269
- }
2270
- await cmdDraw(parseFloat(options.amount));
2271
- break;
2272
- case "repay":
2273
- if (!options.amount) {
2274
- console.error("\u274C --amount required");
2275
- process.exit(1);
2276
- }
2277
- await cmdRepay(parseFloat(options.amount));
2278
- break;
2279
- case "collateral":
2280
- if (!options.amount) {
2281
- console.error("\u274C --amount required");
2282
- process.exit(1);
2283
- }
2284
- await cmdCollateral(parseFloat(options.amount));
1670
+ case "balance":
1671
+ await cmdBalance();
2285
1672
  break;
2286
1673
  case "status":
2287
1674
  await cmdStatus();
@@ -2289,94 +1676,75 @@ async function main() {
2289
1676
  case "score":
2290
1677
  await cmdScore();
2291
1678
  break;
2292
- case "balance":
2293
- await cmdBalance();
2294
- break;
2295
- case "morpho-compare":
2296
- if (!options.amount) {
2297
- console.error("\u274C --amount required");
2298
- process.exit(1);
2299
- }
2300
- await cmdMorphoCompare(parseFloat(options.amount));
2301
- break;
2302
- case "morpho-balances":
2303
- await cmdMorphoBalances();
2304
- break;
2305
- case "morpho-markets":
2306
- await cmdMorphoMarkets();
2307
- break;
2308
- case "morpho-open":
2309
- if (!options.collateral) {
2310
- console.error("\u274C --collateral required (WETH, wstETH, or WBTC)");
2311
- process.exit(1);
2312
- }
2313
- await cmdMorphoOpen(options.collateral);
1679
+ case "markets":
1680
+ await cmdMarkets();
2314
1681
  break;
2315
- case "morpho-deposit":
1682
+ case "deposit":
2316
1683
  if (!options.amount || !options.token) {
2317
1684
  console.error("\u274C --amount and --token required");
2318
- console.error(" agether morpho-deposit --amount 0.5 --token WETH");
1685
+ console.error(" agether deposit --amount 0.05 --token WETH");
2319
1686
  process.exit(1);
2320
1687
  }
2321
- await cmdMorphoDeposit(options.amount, options.token);
1688
+ await cmdDeposit(options.amount, options.token);
2322
1689
  break;
2323
- case "morpho-borrow":
1690
+ case "borrow":
2324
1691
  if (!options.amount) {
2325
1692
  console.error("\u274C --amount required (in USD)");
2326
- console.error(" agether morpho-borrow --amount 100");
1693
+ console.error(" agether borrow --amount 100");
2327
1694
  process.exit(1);
2328
1695
  }
2329
- await cmdMorphoBorrow(options.amount);
1696
+ await cmdBorrow(options.amount, options.token);
2330
1697
  break;
2331
- case "morpho-repay":
1698
+ case "deposit-and-borrow":
1699
+ if (!options.amount || !options.token || !options.borrow) {
1700
+ console.error("\u274C --amount, --token, and --borrow required");
1701
+ console.error(" agether deposit-and-borrow --amount 0.05 --token WETH --borrow 100");
1702
+ process.exit(1);
1703
+ }
1704
+ await cmdDepositAndBorrow(
1705
+ options.amount,
1706
+ options.token,
1707
+ options.borrow
1708
+ );
1709
+ break;
1710
+ case "repay":
2332
1711
  if (!options.amount) {
2333
- console.error("\u274C --amount required (in USD)");
2334
- console.error(" agether morpho-repay --amount 50");
1712
+ console.error("\u274C --amount required");
2335
1713
  process.exit(1);
2336
1714
  }
2337
- await cmdMorphoRepay(options.amount);
1715
+ await cmdRepay(options.amount, options.token);
2338
1716
  break;
2339
- case "morpho-withdraw":
1717
+ case "withdraw":
2340
1718
  if (!options.amount || !options.token) {
2341
1719
  console.error("\u274C --amount and --token required");
2342
- console.error(" agether morpho-withdraw --amount 0.05 --token WETH");
2343
- console.error(" agether morpho-withdraw --amount all --token WETH");
1720
+ console.error(" agether withdraw --amount 0.05 --token WETH");
1721
+ console.error(" agether withdraw --amount all --token WETH");
2344
1722
  process.exit(1);
2345
1723
  }
2346
- await cmdMorphoWithdraw(options.amount, options.token);
2347
- break;
2348
- case "morpho-status":
2349
- await cmdMorphoStatus();
2350
- break;
2351
- case "unified-status":
2352
- await cmdUnifiedStatus();
1724
+ await cmdWithdraw(options.amount, options.token);
2353
1725
  break;
2354
- case "wallet-create":
2355
- await cmdWalletCreate();
2356
- break;
2357
- case "wallet-status":
2358
- await cmdWalletStatus();
2359
- break;
2360
- case "wallet-draw":
2361
- if (!options.amount) {
2362
- console.error("\u274C --amount required");
1726
+ case "sponsor":
1727
+ if (!options.amount || !options.token) {
1728
+ console.error("\u274C --amount and --token required, plus --agent-id or --address");
2363
1729
  process.exit(1);
2364
1730
  }
2365
- await cmdWalletDraw(parseFloat(options.amount));
2366
- break;
2367
- case "wallet-repay":
2368
- if (!options.amount) {
2369
- console.error("\u274C --amount required");
1731
+ if (!options["agent-id"] && !options.address) {
1732
+ console.error("\u274C --agent-id or --address required");
2370
1733
  process.exit(1);
2371
1734
  }
2372
- await cmdWalletRepay(parseFloat(options.amount));
1735
+ await cmdSponsor(
1736
+ options.amount,
1737
+ options.token,
1738
+ options["agent-id"],
1739
+ options.address
1740
+ );
2373
1741
  break;
2374
- case "wallet-fund":
1742
+ case "fund":
2375
1743
  if (!options.amount) {
2376
- console.error("\u274C --amount required");
1744
+ console.error("\u274C --amount required (USDC)");
2377
1745
  process.exit(1);
2378
1746
  }
2379
- await cmdWalletFund(parseFloat(options.amount));
1747
+ await cmdFund(options.amount);
2380
1748
  break;
2381
1749
  case "x402":
2382
1750
  if (!positional[0]) {
@@ -2386,39 +1754,7 @@ async function main() {
2386
1754
  await cmdX402Call(
2387
1755
  positional[0],
2388
1756
  options.method || "GET",
2389
- options.body,
2390
- !!options["auto-draw"]
2391
- );
2392
- break;
2393
- case "morpho-deposit-and-borrow":
2394
- if (!options.amount || !options.token || !options.borrow) {
2395
- console.error("\u274C --amount, --token, and --borrow required");
2396
- console.error(" agether morpho-deposit-and-borrow --amount 0.01 --token WETH --borrow 10");
2397
- process.exit(1);
2398
- }
2399
- await cmdMorphoDepositAndBorrow(
2400
- options.amount,
2401
- options.token,
2402
- options.borrow
2403
- );
2404
- break;
2405
- case "morpho-sponsor":
2406
- if (!options.amount || !options.token) {
2407
- console.error("\u274C --amount and --token required, plus --agent-id or --address");
2408
- console.error(" agether morpho-sponsor --amount 0.01 --token WETH --agent-id 17676");
2409
- console.error(" agether morpho-sponsor --amount 0.01 --token WETH --address 0x... --borrow 50");
2410
- process.exit(1);
2411
- }
2412
- if (!options["agent-id"] && !options.address) {
2413
- console.error("\u274C --agent-id or --address required");
2414
- process.exit(1);
2415
- }
2416
- await cmdMorphoSponsor(
2417
- options.amount,
2418
- options.token,
2419
- options["agent-id"],
2420
- options.address,
2421
- options.borrow
1757
+ options.body
2422
1758
  );
2423
1759
  break;
2424
1760
  case "help":