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