@agether/sdk 1.0.0

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