@agether/sdk 1.5.5 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +97 -226
- package/dist/index.d.mts +9 -16
- package/dist/index.d.ts +9 -16
- package/dist/index.js +93 -222
- package/dist/index.mjs +93 -222
- package/package.json +6 -2
- package/dist/MorphoClient-AV27HBOF.mjs +0 -6
- package/dist/X402Client-PY4FOTQC.mjs +0 -6
- package/dist/chunk-OMCWZ3VN.mjs +0 -840
- package/dist/chunk-PTXYOTCG.mjs +0 -257
- package/dist/cli.d.mts +0 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.mjs +0 -680
package/dist/chunk-OMCWZ3VN.mjs
DELETED
|
@@ -1,840 +0,0 @@
|
|
|
1
|
-
// src/clients/MorphoClient.ts
|
|
2
|
-
import { ethers, Contract } from "ethers";
|
|
3
|
-
import axios from "axios";
|
|
4
|
-
|
|
5
|
-
// src/types/index.ts
|
|
6
|
-
var ChainId = /* @__PURE__ */ ((ChainId2) => {
|
|
7
|
-
ChainId2[ChainId2["Ethereum"] = 1] = "Ethereum";
|
|
8
|
-
ChainId2[ChainId2["Base"] = 8453] = "Base";
|
|
9
|
-
ChainId2[ChainId2["BaseSepolia"] = 84532] = "BaseSepolia";
|
|
10
|
-
ChainId2[ChainId2["Sepolia"] = 11155111] = "Sepolia";
|
|
11
|
-
ChainId2[ChainId2["Hardhat"] = 31337] = "Hardhat";
|
|
12
|
-
return ChainId2;
|
|
13
|
-
})(ChainId || {});
|
|
14
|
-
var AgetherError = class extends Error {
|
|
15
|
-
constructor(message, code, details) {
|
|
16
|
-
super(message);
|
|
17
|
-
this.code = code;
|
|
18
|
-
this.details = details;
|
|
19
|
-
this.name = "AgetherError";
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
var InsufficientBalanceError = class extends AgetherError {
|
|
23
|
-
constructor(available, required) {
|
|
24
|
-
super(
|
|
25
|
-
`Insufficient balance: available ${available}, required ${required}`,
|
|
26
|
-
"INSUFFICIENT_BALANCE",
|
|
27
|
-
{ available: available.toString(), required: required.toString() }
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
var ScoringRejectedError = class extends AgetherError {
|
|
32
|
-
constructor(riskScore, reason) {
|
|
33
|
-
super(
|
|
34
|
-
`Scoring rejected: risk score ${riskScore}${reason ? `, ${reason}` : ""}`,
|
|
35
|
-
"SCORING_REJECTED",
|
|
36
|
-
{ riskScore, reason }
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
var AgentNotApprovedError = class extends AgetherError {
|
|
41
|
-
constructor(agentId) {
|
|
42
|
-
super(
|
|
43
|
-
`Agent ${agentId} is not KYA-approved. Submit code for validation first.`,
|
|
44
|
-
"AGENT_NOT_APPROVED",
|
|
45
|
-
{ agentId: agentId.toString() }
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
// src/utils/abis.ts
|
|
51
|
-
var IDENTITY_REGISTRY_ABI = [
|
|
52
|
-
"function ownerOf(uint256 agentId) view returns (address)",
|
|
53
|
-
"function balanceOf(address owner) view returns (uint256)",
|
|
54
|
-
"function totalSupply() view returns (uint256)",
|
|
55
|
-
"function exists(uint256 agentId) view returns (bool)",
|
|
56
|
-
"function register() returns (uint256 agentId)",
|
|
57
|
-
"event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)"
|
|
58
|
-
];
|
|
59
|
-
var ACCOUNT_FACTORY_ABI = [
|
|
60
|
-
"function getAccount(uint256 agentId) view returns (address)",
|
|
61
|
-
"function accountExists(uint256 agentId) view returns (bool)",
|
|
62
|
-
"function predictAddress(uint256 agentId) view returns (address)",
|
|
63
|
-
"function totalAccounts() view returns (uint256)",
|
|
64
|
-
"function getAgentId(address account) view returns (uint256)",
|
|
65
|
-
"function createAccount(uint256 agentId) returns (address account)",
|
|
66
|
-
"event AccountCreated(uint256 indexed agentId, address indexed account, address indexed owner)"
|
|
67
|
-
];
|
|
68
|
-
var AGENT_ACCOUNT_ABI = [
|
|
69
|
-
"function agentId() view returns (uint256)",
|
|
70
|
-
"function owner() view returns (address)",
|
|
71
|
-
"function factory() view returns (address)",
|
|
72
|
-
"function validationRegistry() view returns (address)",
|
|
73
|
-
"function identityRegistry() view returns (address)",
|
|
74
|
-
"function balanceOf(address token) view returns (uint256)",
|
|
75
|
-
"function ethBalance() view returns (uint256)",
|
|
76
|
-
"function execute(address target, uint256 value, bytes data) payable returns (bytes)",
|
|
77
|
-
"function executeBatch(address[] targets, uint256[] values, bytes[] datas) payable returns (bytes[])",
|
|
78
|
-
"function fund(address token, uint256 amount)",
|
|
79
|
-
"function withdraw(address token, uint256 amount, address to)",
|
|
80
|
-
"function withdrawETH(uint256 amount, address to)",
|
|
81
|
-
"function isValidSignature(bytes32 hash, bytes signature) view returns (bytes4)"
|
|
82
|
-
];
|
|
83
|
-
var AGENT_REPUTATION_ABI = [
|
|
84
|
-
"function getCreditScore(uint256 agentId) view returns (uint256)",
|
|
85
|
-
"function getAttestation(uint256 agentId) view returns (tuple(uint256 score, uint256 timestamp, address signer))",
|
|
86
|
-
"function isScoreFresh(uint256 agentId) view returns (bool fresh, uint256 age)",
|
|
87
|
-
"function isEligible(uint256 agentId, uint256 minScore) view returns (bool eligible, uint256 currentScore)",
|
|
88
|
-
"function oracleSigner() view returns (address)",
|
|
89
|
-
"function submitScore(uint256 agentId, uint256 score_, uint256 timestamp_, bytes signature)",
|
|
90
|
-
"function setOracleSigner(address signer_)",
|
|
91
|
-
"event ScoreUpdated(uint256 indexed agentId, uint256 score, uint256 timestamp, address signer)"
|
|
92
|
-
];
|
|
93
|
-
var VALIDATION_REGISTRY_ABI = [
|
|
94
|
-
"function isAgentCodeApproved(uint256 agentId) view returns (bool)",
|
|
95
|
-
"function isAgentCodeApprovedForTag(uint256 agentId, string tag) view returns (bool)",
|
|
96
|
-
"function getAgentValidations(uint256 agentId) view returns (bytes32[])",
|
|
97
|
-
"function getValidation(bytes32 requestHash) view returns (tuple(address validatorAddress, uint256 agentId, string requestURI, uint8 response, string responseURI, bytes32 responseHash, string tag, uint256 requestedAt, uint256 respondedAt, bool hasResponse))"
|
|
98
|
-
];
|
|
99
|
-
var MORPHO_BLUE_ABI = [
|
|
100
|
-
// Supply & Withdraw (lending side)
|
|
101
|
-
"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)",
|
|
102
|
-
"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)",
|
|
103
|
-
// Collateral
|
|
104
|
-
"function supplyCollateral(tuple(address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, address onBehalf, bytes data)",
|
|
105
|
-
"function withdrawCollateral(tuple(address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, address onBehalf, address receiver)",
|
|
106
|
-
// Borrow & Repay
|
|
107
|
-
"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)",
|
|
108
|
-
"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)",
|
|
109
|
-
// Authorization
|
|
110
|
-
"function setAuthorization(address authorized, bool newIsAuthorized)",
|
|
111
|
-
"function isAuthorized(address authorizer, address authorized) view returns (bool)",
|
|
112
|
-
// Views
|
|
113
|
-
"function position(bytes32 id, address user) view returns (uint256 supplyShares, uint128 borrowShares, uint128 collateral)",
|
|
114
|
-
"function market(bytes32 id) view returns (uint128 totalSupplyAssets, uint128 totalSupplyShares, uint128 totalBorrowAssets, uint128 totalBorrowShares, uint128 lastUpdate, uint128 fee)",
|
|
115
|
-
"function idToMarketParams(bytes32 id) view returns (tuple(address loanToken, address collateralToken, address oracle, address irm, uint256 lltv))"
|
|
116
|
-
];
|
|
117
|
-
var ERC20_ABI = [
|
|
118
|
-
"function balanceOf(address account) view returns (uint256)",
|
|
119
|
-
"function allowance(address owner, address spender) view returns (uint256)",
|
|
120
|
-
"function approve(address spender, uint256 amount) returns (bool)",
|
|
121
|
-
"function transfer(address to, uint256 amount) returns (bool)",
|
|
122
|
-
"function transferFrom(address from, address to, uint256 amount) returns (bool)",
|
|
123
|
-
"function decimals() view returns (uint8)",
|
|
124
|
-
"function symbol() view returns (string)",
|
|
125
|
-
"function name() view returns (string)"
|
|
126
|
-
];
|
|
127
|
-
|
|
128
|
-
// src/utils/config.ts
|
|
129
|
-
var CONTRACT_ADDRESSES = {
|
|
130
|
-
[1 /* Ethereum */]: {
|
|
131
|
-
accountFactory: "0x0000000000000000000000000000000000000000",
|
|
132
|
-
validationRegistry: "0x0000000000000000000000000000000000000000",
|
|
133
|
-
agentReputation: "0x0000000000000000000000000000000000000000",
|
|
134
|
-
usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
135
|
-
identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
|
|
136
|
-
morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb"
|
|
137
|
-
},
|
|
138
|
-
[8453 /* Base */]: {
|
|
139
|
-
accountFactory: "0x7D5D56416bAEA06a9DCBe3092eF335724C6320a0",
|
|
140
|
-
validationRegistry: "0xd196C32D2149270F56E209ba7aEE67CE9ceD2001",
|
|
141
|
-
agentReputation: "0x65c9cA1211809D3CF3A2707558198eb2b2bE623c",
|
|
142
|
-
usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
143
|
-
identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
|
|
144
|
-
morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb"
|
|
145
|
-
},
|
|
146
|
-
[84532 /* BaseSepolia */]: {
|
|
147
|
-
accountFactory: "0x0000000000000000000000000000000000000000",
|
|
148
|
-
validationRegistry: "0x0000000000000000000000000000000000000000",
|
|
149
|
-
agentReputation: "0x0000000000000000000000000000000000000000",
|
|
150
|
-
usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
151
|
-
identityRegistry: "0x8004A818BFB912233c491871b3d84c89A494BD9e",
|
|
152
|
-
morphoBlue: "0x0000000000000000000000000000000000000000"
|
|
153
|
-
},
|
|
154
|
-
[11155111 /* Sepolia */]: {
|
|
155
|
-
accountFactory: "0x0000000000000000000000000000000000000000",
|
|
156
|
-
validationRegistry: "0x0000000000000000000000000000000000000000",
|
|
157
|
-
agentReputation: "0x0000000000000000000000000000000000000000",
|
|
158
|
-
usdc: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
|
|
159
|
-
identityRegistry: "0x8004A818BFB912233c491871b3d84c89A494BD9e",
|
|
160
|
-
morphoBlue: "0x0000000000000000000000000000000000000000"
|
|
161
|
-
},
|
|
162
|
-
[31337 /* Hardhat */]: {
|
|
163
|
-
accountFactory: "0x0000000000000000000000000000000000000000",
|
|
164
|
-
validationRegistry: "0x0000000000000000000000000000000000000000",
|
|
165
|
-
agentReputation: "0x0000000000000000000000000000000000000000",
|
|
166
|
-
usdc: "0x56d4d6aEe0278c5Df2FA23Ecb32eC146C9446FDf",
|
|
167
|
-
identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
|
|
168
|
-
morphoBlue: "0x0000000000000000000000000000000000000000"
|
|
169
|
-
}
|
|
170
|
-
};
|
|
171
|
-
var RPC_URLS = {
|
|
172
|
-
[1 /* Ethereum */]: "https://ethereum-rpc.publicnode.com",
|
|
173
|
-
[8453 /* Base */]: "https://base-rpc.publicnode.com",
|
|
174
|
-
[84532 /* BaseSepolia */]: "https://sepolia.base.org",
|
|
175
|
-
[11155111 /* Sepolia */]: "https://rpc.sepolia.org",
|
|
176
|
-
[31337 /* Hardhat */]: "http://127.0.0.1:8545"
|
|
177
|
-
};
|
|
178
|
-
var SCORING_ENDPOINTS = {
|
|
179
|
-
[1 /* Ethereum */]: "https://scoring.agether.ai/v1",
|
|
180
|
-
[8453 /* Base */]: "http://95.179.189.214:3001",
|
|
181
|
-
[84532 /* BaseSepolia */]: "http://95.179.189.214:3001",
|
|
182
|
-
[11155111 /* Sepolia */]: "https://scoring-testnet.agether.ai/v1",
|
|
183
|
-
[31337 /* Hardhat */]: "http://127.0.0.1:3001"
|
|
184
|
-
};
|
|
185
|
-
function getDefaultConfig(chainId) {
|
|
186
|
-
return {
|
|
187
|
-
chainId,
|
|
188
|
-
rpcUrl: RPC_URLS[chainId],
|
|
189
|
-
contracts: CONTRACT_ADDRESSES[chainId],
|
|
190
|
-
scoringEndpoint: SCORING_ENDPOINTS[chainId]
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
function createConfig(chainId, options) {
|
|
194
|
-
const defaultConfig = getDefaultConfig(chainId);
|
|
195
|
-
return {
|
|
196
|
-
...defaultConfig,
|
|
197
|
-
...options,
|
|
198
|
-
contracts: {
|
|
199
|
-
...defaultConfig.contracts,
|
|
200
|
-
...options?.contracts
|
|
201
|
-
}
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// src/clients/MorphoClient.ts
|
|
206
|
-
var BASE_COLLATERALS = {
|
|
207
|
-
WETH: { address: "0x4200000000000000000000000000000000000006", symbol: "WETH", decimals: 18 },
|
|
208
|
-
wstETH: { address: "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452", symbol: "wstETH", decimals: 18 },
|
|
209
|
-
cbETH: { address: "0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22", symbol: "cbETH", decimals: 18 }
|
|
210
|
-
};
|
|
211
|
-
var MORPHO_API_URL = "https://api.morpho.org/graphql";
|
|
212
|
-
var morphoIface = new ethers.Interface(MORPHO_BLUE_ABI);
|
|
213
|
-
var erc20Iface = new ethers.Interface(ERC20_ABI);
|
|
214
|
-
var MorphoClient = class {
|
|
215
|
-
constructor(config) {
|
|
216
|
-
this._marketCache = /* @__PURE__ */ new Map();
|
|
217
|
-
this._discoveredAt = 0;
|
|
218
|
-
const chainId = config.chainId ?? 8453 /* Base */;
|
|
219
|
-
const defaultCfg = getDefaultConfig(chainId);
|
|
220
|
-
this.config = defaultCfg;
|
|
221
|
-
this.agentId = config.agentId;
|
|
222
|
-
this.provider = new ethers.JsonRpcProvider(config.rpcUrl || defaultCfg.rpcUrl);
|
|
223
|
-
this.wallet = new ethers.Wallet(config.privateKey, this.provider);
|
|
224
|
-
const addrs = { ...defaultCfg.contracts, ...config.contracts };
|
|
225
|
-
this.accountFactory = new Contract(addrs.accountFactory, ACCOUNT_FACTORY_ABI, this.wallet);
|
|
226
|
-
this.morphoBlue = new Contract(addrs.morphoBlue, MORPHO_BLUE_ABI, this.provider);
|
|
227
|
-
this.agentReputation = new Contract(addrs.agentReputation, AGENT_REPUTATION_ABI, this.wallet);
|
|
228
|
-
this.identityRegistry = new Contract(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this.wallet);
|
|
229
|
-
}
|
|
230
|
-
// ════════════════════════════════════════════════════════
|
|
231
|
-
// Account Management
|
|
232
|
-
// ════════════════════════════════════════════════════════
|
|
233
|
-
/** Resolve the AgentAccount address (cached). */
|
|
234
|
-
async getAccountAddress() {
|
|
235
|
-
if (this._accountAddress) return this._accountAddress;
|
|
236
|
-
if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
|
|
237
|
-
const addr = await this.accountFactory.getAccount(BigInt(this.agentId));
|
|
238
|
-
if (addr === ethers.ZeroAddress) {
|
|
239
|
-
throw new AgetherError("No AgentAccount found. Call register() first.", "NO_ACCOUNT");
|
|
240
|
-
}
|
|
241
|
-
this._accountAddress = addr;
|
|
242
|
-
return addr;
|
|
243
|
-
}
|
|
244
|
-
getAgentId() {
|
|
245
|
-
if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
|
|
246
|
-
return this.agentId;
|
|
247
|
-
}
|
|
248
|
-
getWalletAddress() {
|
|
249
|
-
return this.wallet.address;
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* Register: create ERC-8004 identity + AgentAccount in one flow.
|
|
253
|
-
* If already registered, returns existing state.
|
|
254
|
-
*/
|
|
255
|
-
async register(_name) {
|
|
256
|
-
const eoaAddr = this.wallet.address;
|
|
257
|
-
if (this.agentId) {
|
|
258
|
-
const exists = await this.accountFactory.accountExists(BigInt(this.agentId));
|
|
259
|
-
if (exists) {
|
|
260
|
-
const acct = await this.accountFactory.getAccount(BigInt(this.agentId));
|
|
261
|
-
this._accountAddress = acct;
|
|
262
|
-
return { agentId: this.agentId, address: eoaAddr, agentAccount: acct, alreadyRegistered: true };
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
const balance = await this.identityRegistry.balanceOf(eoaAddr);
|
|
266
|
-
let agentId;
|
|
267
|
-
if (balance > 0n && this.agentId) {
|
|
268
|
-
agentId = BigInt(this.agentId);
|
|
269
|
-
} else if (balance > 0n) {
|
|
270
|
-
throw new AgetherError(
|
|
271
|
-
"Wallet already has an ERC-8004 identity but agentId is unknown. Pass agentId in config.",
|
|
272
|
-
"AGENT_ID_UNKNOWN"
|
|
273
|
-
);
|
|
274
|
-
} else {
|
|
275
|
-
const regTx = await this.identityRegistry.register();
|
|
276
|
-
const regReceipt = await regTx.wait();
|
|
277
|
-
agentId = 0n;
|
|
278
|
-
for (const log of regReceipt.logs) {
|
|
279
|
-
try {
|
|
280
|
-
const parsed = this.identityRegistry.interface.parseLog({ topics: log.topics, data: log.data });
|
|
281
|
-
if (parsed?.name === "Transfer") {
|
|
282
|
-
agentId = parsed.args[2];
|
|
283
|
-
break;
|
|
284
|
-
}
|
|
285
|
-
} catch {
|
|
286
|
-
continue;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
if (agentId === 0n) throw new AgetherError("Failed to parse agentId from registration", "PARSE_ERROR");
|
|
290
|
-
}
|
|
291
|
-
this.agentId = agentId.toString();
|
|
292
|
-
const acctExists = await this.accountFactory.accountExists(agentId);
|
|
293
|
-
let txHash;
|
|
294
|
-
if (!acctExists) {
|
|
295
|
-
const tx = await this.accountFactory.createAccount(agentId);
|
|
296
|
-
const receipt = await tx.wait();
|
|
297
|
-
txHash = receipt.hash;
|
|
298
|
-
}
|
|
299
|
-
const acctAddr = await this.accountFactory.getAccount(agentId);
|
|
300
|
-
this._accountAddress = acctAddr;
|
|
301
|
-
return {
|
|
302
|
-
agentId: this.agentId,
|
|
303
|
-
address: eoaAddr,
|
|
304
|
-
agentAccount: acctAddr,
|
|
305
|
-
alreadyRegistered: acctExists,
|
|
306
|
-
tx: txHash
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
/** Get ETH / USDC balances for EOA and AgentAccount. */
|
|
310
|
-
async getBalances() {
|
|
311
|
-
const eoaAddr = this.wallet.address;
|
|
312
|
-
const usdc = new Contract(this.config.contracts.usdc, ERC20_ABI, this.provider);
|
|
313
|
-
const ethBal = await this.provider.getBalance(eoaAddr);
|
|
314
|
-
const usdcBal = await usdc.balanceOf(eoaAddr);
|
|
315
|
-
const result = {
|
|
316
|
-
agentId: this.agentId || "?",
|
|
317
|
-
address: eoaAddr,
|
|
318
|
-
eth: ethers.formatEther(ethBal),
|
|
319
|
-
usdc: ethers.formatUnits(usdcBal, 6)
|
|
320
|
-
};
|
|
321
|
-
try {
|
|
322
|
-
const acctAddr = await this.getAccountAddress();
|
|
323
|
-
const acctEth = await this.provider.getBalance(acctAddr);
|
|
324
|
-
const acctUsdc = await usdc.balanceOf(acctAddr);
|
|
325
|
-
result.agentAccount = {
|
|
326
|
-
address: acctAddr,
|
|
327
|
-
eth: ethers.formatEther(acctEth),
|
|
328
|
-
usdc: ethers.formatUnits(acctUsdc, 6)
|
|
329
|
-
};
|
|
330
|
-
} catch {
|
|
331
|
-
}
|
|
332
|
-
return result;
|
|
333
|
-
}
|
|
334
|
-
/** Transfer USDC from EOA to AgentAccount. */
|
|
335
|
-
async fundAccount(usdcAmount) {
|
|
336
|
-
const acctAddr = await this.getAccountAddress();
|
|
337
|
-
const usdc = new Contract(this.config.contracts.usdc, ERC20_ABI, this.wallet);
|
|
338
|
-
const amount = ethers.parseUnits(usdcAmount, 6);
|
|
339
|
-
const tx = await usdc.transfer(acctAddr, amount);
|
|
340
|
-
const receipt = await tx.wait();
|
|
341
|
-
return { tx: receipt.hash, amount: usdcAmount, agentAccount: acctAddr };
|
|
342
|
-
}
|
|
343
|
-
// ════════════════════════════════════════════════════════
|
|
344
|
-
// Market Discovery (Morpho GraphQL API)
|
|
345
|
-
// ════════════════════════════════════════════════════════
|
|
346
|
-
/**
|
|
347
|
-
* Fetch USDC borrow markets on Base from Morpho API.
|
|
348
|
-
* Caches results for 5 minutes.
|
|
349
|
-
*/
|
|
350
|
-
async getMarkets(forceRefresh = false) {
|
|
351
|
-
if (!forceRefresh && this._discoveredMarkets && Date.now() - this._discoveredAt < 3e5) {
|
|
352
|
-
return this._discoveredMarkets;
|
|
353
|
-
}
|
|
354
|
-
const chainId = this.config.chainId;
|
|
355
|
-
const usdcAddr = this.config.contracts.usdc.toLowerCase();
|
|
356
|
-
const query = `{
|
|
357
|
-
markets(
|
|
358
|
-
first: 50
|
|
359
|
-
orderBy: SupplyAssetsUsd
|
|
360
|
-
orderDirection: Desc
|
|
361
|
-
where: { chainId_in: [${chainId}], loanAssetAddress_in: ["${usdcAddr}"] }
|
|
362
|
-
) {
|
|
363
|
-
items {
|
|
364
|
-
uniqueKey
|
|
365
|
-
lltv
|
|
366
|
-
oracleAddress
|
|
367
|
-
irmAddress
|
|
368
|
-
loanAsset { address symbol decimals }
|
|
369
|
-
collateralAsset { address symbol decimals }
|
|
370
|
-
state {
|
|
371
|
-
borrowAssets
|
|
372
|
-
supplyAssets
|
|
373
|
-
utilization
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
}`;
|
|
378
|
-
try {
|
|
379
|
-
const resp = await axios.post(MORPHO_API_URL, { query }, { timeout: 1e4 });
|
|
380
|
-
const items = resp.data?.data?.markets?.items ?? [];
|
|
381
|
-
this._discoveredMarkets = items.map((m) => ({
|
|
382
|
-
uniqueKey: m.uniqueKey,
|
|
383
|
-
loanAsset: m.loanAsset,
|
|
384
|
-
collateralAsset: m.collateralAsset ?? { address: ethers.ZeroAddress, symbol: "N/A", decimals: 0 },
|
|
385
|
-
oracle: m.oracleAddress,
|
|
386
|
-
irm: m.irmAddress,
|
|
387
|
-
lltv: BigInt(m.lltv),
|
|
388
|
-
totalSupplyAssets: BigInt(m.state?.supplyAssets ?? "0"),
|
|
389
|
-
totalBorrowAssets: BigInt(m.state?.borrowAssets ?? "0"),
|
|
390
|
-
utilization: m.state?.utilization ? Number(m.state.utilization) : 0
|
|
391
|
-
}));
|
|
392
|
-
this._discoveredAt = Date.now();
|
|
393
|
-
for (const mi of this._discoveredMarkets) {
|
|
394
|
-
if (mi.collateralAsset.address !== ethers.ZeroAddress) {
|
|
395
|
-
this._marketCache.set(mi.collateralAsset.address.toLowerCase(), {
|
|
396
|
-
loanToken: mi.loanAsset.address,
|
|
397
|
-
collateralToken: mi.collateralAsset.address,
|
|
398
|
-
oracle: mi.oracle,
|
|
399
|
-
irm: mi.irm,
|
|
400
|
-
lltv: mi.lltv
|
|
401
|
-
});
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
return this._discoveredMarkets;
|
|
405
|
-
} catch {
|
|
406
|
-
return this._discoveredMarkets ?? [];
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
/**
|
|
410
|
-
* Get MarketParams for a collateral token.
|
|
411
|
-
* Tries cache → API → on-chain idToMarketParams.
|
|
412
|
-
*/
|
|
413
|
-
async findMarketForCollateral(collateralSymbolOrAddress) {
|
|
414
|
-
const colInfo = BASE_COLLATERALS[collateralSymbolOrAddress];
|
|
415
|
-
const colAddr = (colInfo?.address ?? collateralSymbolOrAddress).toLowerCase();
|
|
416
|
-
const cached = this._marketCache.get(colAddr);
|
|
417
|
-
if (cached) return cached;
|
|
418
|
-
await this.getMarkets();
|
|
419
|
-
const fromApi = this._marketCache.get(colAddr);
|
|
420
|
-
if (fromApi) return fromApi;
|
|
421
|
-
throw new AgetherError(
|
|
422
|
-
`No Morpho market found for collateral ${collateralSymbolOrAddress}`,
|
|
423
|
-
"MARKET_NOT_FOUND"
|
|
424
|
-
);
|
|
425
|
-
}
|
|
426
|
-
/** Read MarketParams on-chain by market ID (bytes32). */
|
|
427
|
-
async getMarketParams(marketId) {
|
|
428
|
-
const result = await this.morphoBlue.idToMarketParams(marketId);
|
|
429
|
-
return {
|
|
430
|
-
loanToken: result.loanToken,
|
|
431
|
-
collateralToken: result.collateralToken,
|
|
432
|
-
oracle: result.oracle,
|
|
433
|
-
irm: result.irm,
|
|
434
|
-
lltv: result.lltv
|
|
435
|
-
};
|
|
436
|
-
}
|
|
437
|
-
// ════════════════════════════════════════════════════════
|
|
438
|
-
// Position Reads
|
|
439
|
-
// ════════════════════════════════════════════════════════
|
|
440
|
-
/** Read on-chain position for a specific market. */
|
|
441
|
-
async getPosition(marketId) {
|
|
442
|
-
const acctAddr = await this.getAccountAddress();
|
|
443
|
-
const pos = await this.morphoBlue.position(marketId, acctAddr);
|
|
444
|
-
return {
|
|
445
|
-
supplyShares: pos.supplyShares,
|
|
446
|
-
borrowShares: pos.borrowShares,
|
|
447
|
-
collateral: pos.collateral
|
|
448
|
-
};
|
|
449
|
-
}
|
|
450
|
-
/**
|
|
451
|
-
* Full status: positions across all discovered markets.
|
|
452
|
-
*/
|
|
453
|
-
async getStatus() {
|
|
454
|
-
const acctAddr = await this.getAccountAddress();
|
|
455
|
-
const markets = await this.getMarkets();
|
|
456
|
-
const positions = [];
|
|
457
|
-
let totalDebt = 0n;
|
|
458
|
-
for (const m of markets) {
|
|
459
|
-
if (!m.collateralAsset || m.collateralAsset.address === ethers.ZeroAddress) continue;
|
|
460
|
-
try {
|
|
461
|
-
const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
|
|
462
|
-
if (pos.collateral === 0n && pos.borrowShares === 0n && pos.supplyShares === 0n) continue;
|
|
463
|
-
let debt = 0n;
|
|
464
|
-
if (pos.borrowShares > 0n) {
|
|
465
|
-
try {
|
|
466
|
-
const mkt = await this.morphoBlue.market(m.uniqueKey);
|
|
467
|
-
const totalBorrowShares = BigInt(mkt.totalBorrowShares);
|
|
468
|
-
const totalBorrowAssets = BigInt(mkt.totalBorrowAssets);
|
|
469
|
-
debt = totalBorrowShares > 0n ? BigInt(pos.borrowShares) * totalBorrowAssets / totalBorrowShares : 0n;
|
|
470
|
-
totalDebt += debt;
|
|
471
|
-
} catch {
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
positions.push({
|
|
475
|
-
marketId: m.uniqueKey,
|
|
476
|
-
collateralToken: m.collateralAsset.symbol,
|
|
477
|
-
collateral: ethers.formatUnits(pos.collateral, m.collateralAsset.decimals),
|
|
478
|
-
borrowShares: pos.borrowShares.toString(),
|
|
479
|
-
supplyShares: pos.supplyShares.toString(),
|
|
480
|
-
debt: ethers.formatUnits(debt, 6)
|
|
481
|
-
});
|
|
482
|
-
} catch {
|
|
483
|
-
continue;
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
return {
|
|
487
|
-
agentId: this.agentId || "?",
|
|
488
|
-
agentAccount: acctAddr,
|
|
489
|
-
totalDebt: ethers.formatUnits(totalDebt, 6),
|
|
490
|
-
positions
|
|
491
|
-
};
|
|
492
|
-
}
|
|
493
|
-
// ════════════════════════════════════════════════════════
|
|
494
|
-
// Lending Operations (all via AgentAccount.executeBatch)
|
|
495
|
-
// ════════════════════════════════════════════════════════
|
|
496
|
-
/**
|
|
497
|
-
* Deposit collateral into Morpho Blue.
|
|
498
|
-
*
|
|
499
|
-
* Flow:
|
|
500
|
-
* 1. EOA transfers collateral to AgentAccount
|
|
501
|
-
* 2. AgentAccount.executeBatch:
|
|
502
|
-
* [collateral.approve(MorphoBlue), Morpho.supplyCollateral(params)]
|
|
503
|
-
*/
|
|
504
|
-
async supplyCollateral(tokenSymbol, amount, marketParams) {
|
|
505
|
-
const acctAddr = await this.getAccountAddress();
|
|
506
|
-
const colInfo = BASE_COLLATERALS[tokenSymbol];
|
|
507
|
-
if (!colInfo) throw new AgetherError(`Unknown collateral: ${tokenSymbol}`, "UNKNOWN_COLLATERAL");
|
|
508
|
-
const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
|
|
509
|
-
const weiAmount = ethers.parseUnits(amount, colInfo.decimals);
|
|
510
|
-
const morphoAddr = this.config.contracts.morphoBlue;
|
|
511
|
-
const colToken = new Contract(colInfo.address, ERC20_ABI, this.wallet);
|
|
512
|
-
const transferTx = await colToken.transfer(acctAddr, weiAmount);
|
|
513
|
-
await transferTx.wait();
|
|
514
|
-
const targets = [colInfo.address, morphoAddr];
|
|
515
|
-
const values = [0n, 0n];
|
|
516
|
-
const datas = [
|
|
517
|
-
erc20Iface.encodeFunctionData("approve", [morphoAddr, weiAmount]),
|
|
518
|
-
morphoIface.encodeFunctionData("supplyCollateral", [
|
|
519
|
-
this._toTuple(params),
|
|
520
|
-
weiAmount,
|
|
521
|
-
acctAddr,
|
|
522
|
-
"0x"
|
|
523
|
-
])
|
|
524
|
-
];
|
|
525
|
-
const receipt = await this.batch(targets, values, datas);
|
|
526
|
-
return {
|
|
527
|
-
tx: receipt.hash,
|
|
528
|
-
collateralToken: tokenSymbol,
|
|
529
|
-
amount,
|
|
530
|
-
agentAccount: acctAddr
|
|
531
|
-
};
|
|
532
|
-
}
|
|
533
|
-
/**
|
|
534
|
-
* Borrow USDC against existing collateral.
|
|
535
|
-
*
|
|
536
|
-
* AgentAccount.execute: Morpho.borrow(params, amount, 0, account, account)
|
|
537
|
-
*
|
|
538
|
-
* @param usdcAmount - USDC amount (e.g. '100')
|
|
539
|
-
* @param tokenSymbol - collateral symbol to identify which market (default: first with collateral)
|
|
540
|
-
*/
|
|
541
|
-
async borrow(usdcAmount, tokenSymbol, marketParams) {
|
|
542
|
-
const acctAddr = await this.getAccountAddress();
|
|
543
|
-
const amount = ethers.parseUnits(usdcAmount, 6);
|
|
544
|
-
const morphoAddr = this.config.contracts.morphoBlue;
|
|
545
|
-
let params;
|
|
546
|
-
let usedToken = tokenSymbol || "WETH";
|
|
547
|
-
if (marketParams) {
|
|
548
|
-
params = marketParams;
|
|
549
|
-
} else if (tokenSymbol) {
|
|
550
|
-
params = await this.findMarketForCollateral(tokenSymbol);
|
|
551
|
-
} else {
|
|
552
|
-
const { params: p, symbol } = await this._findActiveMarket();
|
|
553
|
-
params = p;
|
|
554
|
-
usedToken = symbol;
|
|
555
|
-
}
|
|
556
|
-
const data = morphoIface.encodeFunctionData("borrow", [
|
|
557
|
-
this._toTuple(params),
|
|
558
|
-
amount,
|
|
559
|
-
0n,
|
|
560
|
-
acctAddr,
|
|
561
|
-
acctAddr
|
|
562
|
-
]);
|
|
563
|
-
const receipt = await this.exec(morphoAddr, data);
|
|
564
|
-
return {
|
|
565
|
-
tx: receipt.hash,
|
|
566
|
-
amount: usdcAmount,
|
|
567
|
-
collateralToken: usedToken,
|
|
568
|
-
agentAccount: acctAddr
|
|
569
|
-
};
|
|
570
|
-
}
|
|
571
|
-
/**
|
|
572
|
-
* Deposit collateral AND borrow USDC in one batched transaction.
|
|
573
|
-
*
|
|
574
|
-
* AgentAccount.executeBatch:
|
|
575
|
-
* [collateral.approve, Morpho.supplyCollateral, Morpho.borrow]
|
|
576
|
-
*
|
|
577
|
-
* The collateral must be transferred to AgentAccount first.
|
|
578
|
-
*/
|
|
579
|
-
async depositAndBorrow(tokenSymbol, collateralAmount, borrowUsdcAmount, marketParams) {
|
|
580
|
-
const acctAddr = await this.getAccountAddress();
|
|
581
|
-
const colInfo = BASE_COLLATERALS[tokenSymbol];
|
|
582
|
-
if (!colInfo) throw new AgetherError(`Unknown collateral: ${tokenSymbol}`, "UNKNOWN_COLLATERAL");
|
|
583
|
-
const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
|
|
584
|
-
const colWei = ethers.parseUnits(collateralAmount, colInfo.decimals);
|
|
585
|
-
const borrowWei = ethers.parseUnits(borrowUsdcAmount, 6);
|
|
586
|
-
const morphoAddr = this.config.contracts.morphoBlue;
|
|
587
|
-
const colToken = new Contract(colInfo.address, ERC20_ABI, this.wallet);
|
|
588
|
-
const transferTx = await colToken.transfer(acctAddr, colWei);
|
|
589
|
-
await transferTx.wait();
|
|
590
|
-
const targets = [colInfo.address, morphoAddr, morphoAddr];
|
|
591
|
-
const values = [0n, 0n, 0n];
|
|
592
|
-
const datas = [
|
|
593
|
-
erc20Iface.encodeFunctionData("approve", [morphoAddr, colWei]),
|
|
594
|
-
morphoIface.encodeFunctionData("supplyCollateral", [
|
|
595
|
-
this._toTuple(params),
|
|
596
|
-
colWei,
|
|
597
|
-
acctAddr,
|
|
598
|
-
"0x"
|
|
599
|
-
]),
|
|
600
|
-
morphoIface.encodeFunctionData("borrow", [
|
|
601
|
-
this._toTuple(params),
|
|
602
|
-
borrowWei,
|
|
603
|
-
0n,
|
|
604
|
-
acctAddr,
|
|
605
|
-
acctAddr
|
|
606
|
-
])
|
|
607
|
-
];
|
|
608
|
-
const receipt = await this.batch(targets, values, datas);
|
|
609
|
-
return {
|
|
610
|
-
tx: receipt.hash,
|
|
611
|
-
collateralToken: tokenSymbol,
|
|
612
|
-
collateralAmount,
|
|
613
|
-
borrowAmount: borrowUsdcAmount,
|
|
614
|
-
agentAccount: acctAddr
|
|
615
|
-
};
|
|
616
|
-
}
|
|
617
|
-
/**
|
|
618
|
-
* Repay borrowed USDC from AgentAccount.
|
|
619
|
-
*
|
|
620
|
-
* AgentAccount.executeBatch:
|
|
621
|
-
* [USDC.approve(MorphoBlue), Morpho.repay(params)]
|
|
622
|
-
*/
|
|
623
|
-
async repay(usdcAmount, tokenSymbol, marketParams) {
|
|
624
|
-
const acctAddr = await this.getAccountAddress();
|
|
625
|
-
const amount = ethers.parseUnits(usdcAmount, 6);
|
|
626
|
-
const morphoAddr = this.config.contracts.morphoBlue;
|
|
627
|
-
const usdcAddr = this.config.contracts.usdc;
|
|
628
|
-
let params;
|
|
629
|
-
if (marketParams) {
|
|
630
|
-
params = marketParams;
|
|
631
|
-
} else if (tokenSymbol) {
|
|
632
|
-
params = await this.findMarketForCollateral(tokenSymbol);
|
|
633
|
-
} else {
|
|
634
|
-
const { params: p } = await this._findActiveMarket();
|
|
635
|
-
params = p;
|
|
636
|
-
}
|
|
637
|
-
const targets = [usdcAddr, morphoAddr];
|
|
638
|
-
const values = [0n, 0n];
|
|
639
|
-
const datas = [
|
|
640
|
-
erc20Iface.encodeFunctionData("approve", [morphoAddr, amount]),
|
|
641
|
-
morphoIface.encodeFunctionData("repay", [
|
|
642
|
-
this._toTuple(params),
|
|
643
|
-
amount,
|
|
644
|
-
0n,
|
|
645
|
-
acctAddr,
|
|
646
|
-
"0x"
|
|
647
|
-
])
|
|
648
|
-
];
|
|
649
|
-
const receipt = await this.batch(targets, values, datas);
|
|
650
|
-
let remainingDebt = "0";
|
|
651
|
-
try {
|
|
652
|
-
const status = await this.getStatus();
|
|
653
|
-
remainingDebt = status.totalDebt;
|
|
654
|
-
} catch {
|
|
655
|
-
}
|
|
656
|
-
return { tx: receipt.hash, amount: usdcAmount, remainingDebt };
|
|
657
|
-
}
|
|
658
|
-
/**
|
|
659
|
-
* Withdraw collateral from Morpho Blue.
|
|
660
|
-
*
|
|
661
|
-
* AgentAccount.execute: Morpho.withdrawCollateral(params, amount, account, receiver)
|
|
662
|
-
*
|
|
663
|
-
* @param receiver - defaults to EOA wallet
|
|
664
|
-
*/
|
|
665
|
-
async withdrawCollateral(tokenSymbol, amount, marketParams, receiver) {
|
|
666
|
-
const acctAddr = await this.getAccountAddress();
|
|
667
|
-
const colInfo = BASE_COLLATERALS[tokenSymbol];
|
|
668
|
-
if (!colInfo) throw new AgetherError(`Unknown collateral: ${tokenSymbol}`, "UNKNOWN_COLLATERAL");
|
|
669
|
-
const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
|
|
670
|
-
const morphoAddr = this.config.contracts.morphoBlue;
|
|
671
|
-
const dest = receiver || this.wallet.address;
|
|
672
|
-
let weiAmount;
|
|
673
|
-
if (amount === "all") {
|
|
674
|
-
const markets = await this.getMarkets();
|
|
675
|
-
const market = markets.find(
|
|
676
|
-
(m) => m.collateralAsset.address.toLowerCase() === colInfo.address.toLowerCase()
|
|
677
|
-
);
|
|
678
|
-
if (!market) throw new AgetherError("Market not found", "MARKET_NOT_FOUND");
|
|
679
|
-
const pos = await this.morphoBlue.position(market.uniqueKey, acctAddr);
|
|
680
|
-
weiAmount = pos.collateral;
|
|
681
|
-
if (weiAmount === 0n) throw new AgetherError("No collateral to withdraw", "NO_COLLATERAL");
|
|
682
|
-
} else {
|
|
683
|
-
weiAmount = ethers.parseUnits(amount, colInfo.decimals);
|
|
684
|
-
}
|
|
685
|
-
const data = morphoIface.encodeFunctionData("withdrawCollateral", [
|
|
686
|
-
this._toTuple(params),
|
|
687
|
-
weiAmount,
|
|
688
|
-
acctAddr,
|
|
689
|
-
dest
|
|
690
|
-
]);
|
|
691
|
-
const receipt = await this.exec(morphoAddr, data);
|
|
692
|
-
let remainingCollateral = "0";
|
|
693
|
-
try {
|
|
694
|
-
const markets = await this.getMarkets();
|
|
695
|
-
const market = markets.find(
|
|
696
|
-
(m) => m.collateralAsset.address.toLowerCase() === colInfo.address.toLowerCase()
|
|
697
|
-
);
|
|
698
|
-
if (market) {
|
|
699
|
-
const pos = await this.morphoBlue.position(market.uniqueKey, acctAddr);
|
|
700
|
-
remainingCollateral = ethers.formatUnits(pos.collateral, colInfo.decimals);
|
|
701
|
-
}
|
|
702
|
-
} catch {
|
|
703
|
-
}
|
|
704
|
-
return {
|
|
705
|
-
tx: receipt.hash,
|
|
706
|
-
token: tokenSymbol,
|
|
707
|
-
amount: amount === "all" ? ethers.formatUnits(weiAmount, colInfo.decimals) : amount,
|
|
708
|
-
remainingCollateral,
|
|
709
|
-
destination: dest
|
|
710
|
-
};
|
|
711
|
-
}
|
|
712
|
-
/**
|
|
713
|
-
* Sponsor: transfer collateral to another agent's AgentAccount.
|
|
714
|
-
* (The agent must then supplyCollateral themselves via their own account.)
|
|
715
|
-
*/
|
|
716
|
-
async sponsor(target, tokenSymbol, amount) {
|
|
717
|
-
const colInfo = BASE_COLLATERALS[tokenSymbol];
|
|
718
|
-
if (!colInfo) throw new AgetherError(`Unknown collateral: ${tokenSymbol}`, "UNKNOWN_COLLATERAL");
|
|
719
|
-
let targetAddr;
|
|
720
|
-
if (target.address) {
|
|
721
|
-
targetAddr = target.address;
|
|
722
|
-
} else if (target.agentId) {
|
|
723
|
-
targetAddr = await this.accountFactory.getAccount(BigInt(target.agentId));
|
|
724
|
-
if (targetAddr === ethers.ZeroAddress) throw new AgetherError("Target agent has no account", "NO_ACCOUNT");
|
|
725
|
-
} else {
|
|
726
|
-
throw new AgetherError("Provide agentId or address", "INVALID_TARGET");
|
|
727
|
-
}
|
|
728
|
-
const weiAmount = ethers.parseUnits(amount, colInfo.decimals);
|
|
729
|
-
const colToken = new Contract(colInfo.address, ERC20_ABI, this.wallet);
|
|
730
|
-
const tx = await colToken.transfer(targetAddr, weiAmount);
|
|
731
|
-
const receipt = await tx.wait();
|
|
732
|
-
return { tx: receipt.hash, targetAccount: targetAddr, targetAgentId: target.agentId };
|
|
733
|
-
}
|
|
734
|
-
// ════════════════════════════════════════════════════════
|
|
735
|
-
// Reputation (AgentReputation contract)
|
|
736
|
-
// ════════════════════════════════════════════════════════
|
|
737
|
-
async getCreditScore() {
|
|
738
|
-
if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
|
|
739
|
-
return this.agentReputation.getCreditScore(BigInt(this.agentId));
|
|
740
|
-
}
|
|
741
|
-
async getAttestation() {
|
|
742
|
-
if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
|
|
743
|
-
const att = await this.agentReputation.getAttestation(BigInt(this.agentId));
|
|
744
|
-
return { score: att.score, timestamp: att.timestamp, signer: att.signer };
|
|
745
|
-
}
|
|
746
|
-
async isEligible(minScore = 500n) {
|
|
747
|
-
if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
|
|
748
|
-
const [eligible, currentScore] = await this.agentReputation.isEligible(BigInt(this.agentId), minScore);
|
|
749
|
-
return { eligible, currentScore };
|
|
750
|
-
}
|
|
751
|
-
async isScoreFresh() {
|
|
752
|
-
if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
|
|
753
|
-
const [fresh, age] = await this.agentReputation.isScoreFresh(BigInt(this.agentId));
|
|
754
|
-
return { fresh, age };
|
|
755
|
-
}
|
|
756
|
-
// ════════════════════════════════════════════════════════
|
|
757
|
-
// Internal Helpers
|
|
758
|
-
// ════════════════════════════════════════════════════════
|
|
759
|
-
/**
|
|
760
|
-
* Execute a single call via AgentAccount.execute.
|
|
761
|
-
*/
|
|
762
|
-
async exec(target, data, value = 0n) {
|
|
763
|
-
const acctAddr = await this.getAccountAddress();
|
|
764
|
-
const account = new Contract(acctAddr, AGENT_ACCOUNT_ABI, this.wallet);
|
|
765
|
-
let gasLimit;
|
|
766
|
-
try {
|
|
767
|
-
const estimate = await account.execute.estimateGas(target, value, data);
|
|
768
|
-
gasLimit = estimate * 130n / 100n;
|
|
769
|
-
} catch {
|
|
770
|
-
gasLimit = 500000n;
|
|
771
|
-
}
|
|
772
|
-
const tx = await account.execute(target, value, data, { gasLimit });
|
|
773
|
-
return tx.wait();
|
|
774
|
-
}
|
|
775
|
-
/**
|
|
776
|
-
* Execute multiple calls via AgentAccount.executeBatch.
|
|
777
|
-
*/
|
|
778
|
-
async batch(targets, values, datas) {
|
|
779
|
-
const acctAddr = await this.getAccountAddress();
|
|
780
|
-
const account = new Contract(acctAddr, AGENT_ACCOUNT_ABI, this.wallet);
|
|
781
|
-
let gasLimit;
|
|
782
|
-
try {
|
|
783
|
-
const estimate = await account.executeBatch.estimateGas(targets, values, datas);
|
|
784
|
-
gasLimit = estimate * 130n / 100n;
|
|
785
|
-
} catch {
|
|
786
|
-
gasLimit = 800000n;
|
|
787
|
-
}
|
|
788
|
-
const tx = await account.executeBatch(targets, values, datas, { gasLimit });
|
|
789
|
-
return tx.wait();
|
|
790
|
-
}
|
|
791
|
-
/** Convert MorphoMarketParams to Solidity tuple. */
|
|
792
|
-
_toTuple(p) {
|
|
793
|
-
return [p.loanToken, p.collateralToken, p.oracle, p.irm, p.lltv];
|
|
794
|
-
}
|
|
795
|
-
/** Find the first market where the agent has collateral deposited. */
|
|
796
|
-
async _findActiveMarket() {
|
|
797
|
-
const acctAddr = await this.getAccountAddress();
|
|
798
|
-
const markets = await this.getMarkets();
|
|
799
|
-
for (const m of markets) {
|
|
800
|
-
if (!m.collateralAsset || m.collateralAsset.address === ethers.ZeroAddress) continue;
|
|
801
|
-
try {
|
|
802
|
-
const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
|
|
803
|
-
if (pos.collateral > 0n) {
|
|
804
|
-
return {
|
|
805
|
-
params: {
|
|
806
|
-
loanToken: m.loanAsset.address,
|
|
807
|
-
collateralToken: m.collateralAsset.address,
|
|
808
|
-
oracle: m.oracle,
|
|
809
|
-
irm: m.irm,
|
|
810
|
-
lltv: m.lltv
|
|
811
|
-
},
|
|
812
|
-
symbol: m.collateralAsset.symbol
|
|
813
|
-
};
|
|
814
|
-
}
|
|
815
|
-
} catch {
|
|
816
|
-
continue;
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
const params = await this.findMarketForCollateral("WETH");
|
|
820
|
-
return { params, symbol: "WETH" };
|
|
821
|
-
}
|
|
822
|
-
};
|
|
823
|
-
|
|
824
|
-
export {
|
|
825
|
-
ChainId,
|
|
826
|
-
AgetherError,
|
|
827
|
-
InsufficientBalanceError,
|
|
828
|
-
ScoringRejectedError,
|
|
829
|
-
AgentNotApprovedError,
|
|
830
|
-
IDENTITY_REGISTRY_ABI,
|
|
831
|
-
ACCOUNT_FACTORY_ABI,
|
|
832
|
-
AGENT_ACCOUNT_ABI,
|
|
833
|
-
AGENT_REPUTATION_ABI,
|
|
834
|
-
VALIDATION_REGISTRY_ABI,
|
|
835
|
-
MORPHO_BLUE_ABI,
|
|
836
|
-
ERC20_ABI,
|
|
837
|
-
getDefaultConfig,
|
|
838
|
-
createConfig,
|
|
839
|
-
MorphoClient
|
|
840
|
-
};
|