@agether/sdk 1.5.0 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/MorphoClient-3UAKN2VR.mjs +6 -0
- package/dist/X402Client-PY4FOTQC.mjs +6 -0
- package/dist/chunk-GAFDBPDW.mjs +835 -0
- package/dist/chunk-PTXYOTCG.mjs +257 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +3 -8
- package/dist/cli.mjs +680 -0
- package/dist/index.js +3 -8
- package/dist/index.mjs +31 -1089
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,207 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
};
|
|
21
|
-
var InsufficientBalanceError = class extends AgetherError {
|
|
22
|
-
constructor(available, required) {
|
|
23
|
-
super(
|
|
24
|
-
`Insufficient balance: available ${available}, required ${required}`,
|
|
25
|
-
"INSUFFICIENT_BALANCE",
|
|
26
|
-
{ available: available.toString(), required: required.toString() }
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
var ScoringRejectedError = class extends AgetherError {
|
|
31
|
-
constructor(riskScore, reason) {
|
|
32
|
-
super(
|
|
33
|
-
`Scoring rejected: risk score ${riskScore}${reason ? `, ${reason}` : ""}`,
|
|
34
|
-
"SCORING_REJECTED",
|
|
35
|
-
{ riskScore, reason }
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
var AgentNotApprovedError = class extends AgetherError {
|
|
40
|
-
constructor(agentId) {
|
|
41
|
-
super(
|
|
42
|
-
`Agent ${agentId} is not KYA-approved. Submit code for validation first.`,
|
|
43
|
-
"AGENT_NOT_APPROVED",
|
|
44
|
-
{ agentId: agentId.toString() }
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
// src/utils/abis.ts
|
|
50
|
-
var IDENTITY_REGISTRY_ABI = [
|
|
51
|
-
"function ownerOf(uint256 agentId) view returns (address)",
|
|
52
|
-
"function balanceOf(address owner) view returns (uint256)",
|
|
53
|
-
"function totalSupply() view returns (uint256)",
|
|
54
|
-
"function exists(uint256 agentId) view returns (bool)",
|
|
55
|
-
"function register() returns (uint256 agentId)",
|
|
56
|
-
"event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)"
|
|
57
|
-
];
|
|
58
|
-
var ACCOUNT_FACTORY_ABI = [
|
|
59
|
-
"function getAccount(uint256 agentId) view returns (address)",
|
|
60
|
-
"function accountExists(uint256 agentId) view returns (bool)",
|
|
61
|
-
"function predictAddress(uint256 agentId) view returns (address)",
|
|
62
|
-
"function totalAccounts() view returns (uint256)",
|
|
63
|
-
"function getAgentId(address account) view returns (uint256)",
|
|
64
|
-
"function createAccount(uint256 agentId) returns (address account)",
|
|
65
|
-
"event AccountCreated(uint256 indexed agentId, address indexed account, address indexed owner)"
|
|
66
|
-
];
|
|
67
|
-
var AGENT_ACCOUNT_ABI = [
|
|
68
|
-
"function agentId() view returns (uint256)",
|
|
69
|
-
"function owner() view returns (address)",
|
|
70
|
-
"function factory() view returns (address)",
|
|
71
|
-
"function validationRegistry() view returns (address)",
|
|
72
|
-
"function identityRegistry() view returns (address)",
|
|
73
|
-
"function balanceOf(address token) view returns (uint256)",
|
|
74
|
-
"function ethBalance() view returns (uint256)",
|
|
75
|
-
"function execute(address target, uint256 value, bytes data) payable returns (bytes)",
|
|
76
|
-
"function executeBatch(address[] targets, uint256[] values, bytes[] datas) payable returns (bytes[])",
|
|
77
|
-
"function fund(address token, uint256 amount)",
|
|
78
|
-
"function withdraw(address token, uint256 amount, address to)",
|
|
79
|
-
"function withdrawETH(uint256 amount, address to)",
|
|
80
|
-
"function isValidSignature(bytes32 hash, bytes signature) view returns (bytes4)"
|
|
81
|
-
];
|
|
82
|
-
var AGENT_REPUTATION_ABI = [
|
|
83
|
-
"function getCreditScore(uint256 agentId) view returns (uint256)",
|
|
84
|
-
"function getAttestation(uint256 agentId) view returns (tuple(uint256 score, uint256 timestamp, address signer))",
|
|
85
|
-
"function isScoreFresh(uint256 agentId) view returns (bool fresh, uint256 age)",
|
|
86
|
-
"function isEligible(uint256 agentId, uint256 minScore) view returns (bool eligible, uint256 currentScore)",
|
|
87
|
-
"function oracleSigner() view returns (address)",
|
|
88
|
-
"function submitScore(uint256 agentId, uint256 score_, uint256 timestamp_, bytes signature)",
|
|
89
|
-
"function setOracleSigner(address signer_)",
|
|
90
|
-
"event ScoreUpdated(uint256 indexed agentId, uint256 score, uint256 timestamp, address signer)"
|
|
91
|
-
];
|
|
92
|
-
var VALIDATION_REGISTRY_ABI = [
|
|
93
|
-
"function isAgentCodeApproved(uint256 agentId) view returns (bool)",
|
|
94
|
-
"function isAgentCodeApprovedForTag(uint256 agentId, string tag) view returns (bool)",
|
|
95
|
-
"function getAgentValidations(uint256 agentId) view returns (bytes32[])",
|
|
96
|
-
"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))"
|
|
97
|
-
];
|
|
98
|
-
var MORPHO_BLUE_ABI = [
|
|
99
|
-
// Supply & Withdraw (lending side)
|
|
100
|
-
"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)",
|
|
101
|
-
"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)",
|
|
102
|
-
// Collateral
|
|
103
|
-
"function supplyCollateral(tuple(address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, address onBehalf, bytes data)",
|
|
104
|
-
"function withdrawCollateral(tuple(address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, address onBehalf, address receiver)",
|
|
105
|
-
// Borrow & Repay
|
|
106
|
-
"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)",
|
|
107
|
-
"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)",
|
|
108
|
-
// Authorization
|
|
109
|
-
"function setAuthorization(address authorized, bool newIsAuthorized)",
|
|
110
|
-
"function isAuthorized(address authorizer, address authorized) view returns (bool)",
|
|
111
|
-
// Views
|
|
112
|
-
"function position(bytes32 id, address user) view returns (uint256 supplyShares, uint128 borrowShares, uint128 collateral)",
|
|
113
|
-
"function market(bytes32 id) view returns (uint128 totalSupplyAssets, uint128 totalSupplyShares, uint128 totalBorrowAssets, uint128 totalBorrowShares, uint128 lastUpdate, uint128 fee)",
|
|
114
|
-
"function idToMarketParams(bytes32 id) view returns (tuple(address loanToken, address collateralToken, address oracle, address irm, uint256 lltv))"
|
|
115
|
-
];
|
|
116
|
-
var ERC20_ABI = [
|
|
117
|
-
"function balanceOf(address account) view returns (uint256)",
|
|
118
|
-
"function allowance(address owner, address spender) view returns (uint256)",
|
|
119
|
-
"function approve(address spender, uint256 amount) returns (bool)",
|
|
120
|
-
"function transfer(address to, uint256 amount) returns (bool)",
|
|
121
|
-
"function transferFrom(address from, address to, uint256 amount) returns (bool)",
|
|
122
|
-
"function decimals() view returns (uint8)",
|
|
123
|
-
"function symbol() view returns (string)",
|
|
124
|
-
"function name() view returns (string)"
|
|
125
|
-
];
|
|
126
|
-
|
|
127
|
-
// src/utils/config.ts
|
|
128
|
-
var CONTRACT_ADDRESSES = {
|
|
129
|
-
[1 /* Ethereum */]: {
|
|
130
|
-
accountFactory: "0x0000000000000000000000000000000000000000",
|
|
131
|
-
validationRegistry: "0x0000000000000000000000000000000000000000",
|
|
132
|
-
agentReputation: "0x0000000000000000000000000000000000000000",
|
|
133
|
-
usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
134
|
-
identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
|
|
135
|
-
morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb"
|
|
136
|
-
},
|
|
137
|
-
[8453 /* Base */]: {
|
|
138
|
-
accountFactory: "0xeB72f248Ad9F4bf4024e8D9da75cf7AAD37B58f5",
|
|
139
|
-
validationRegistry: "0x8842f2383A86134Dd80c3Ecf6Bbae2e38396A5ec",
|
|
140
|
-
agentReputation: "0xF1bed094D4E33E47CC8C72E086FFFde09e2211b4",
|
|
141
|
-
usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
142
|
-
identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
|
|
143
|
-
morphoBlue: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb"
|
|
144
|
-
},
|
|
145
|
-
[84532 /* BaseSepolia */]: {
|
|
146
|
-
accountFactory: "0x0000000000000000000000000000000000000000",
|
|
147
|
-
validationRegistry: "0x0000000000000000000000000000000000000000",
|
|
148
|
-
agentReputation: "0x0000000000000000000000000000000000000000",
|
|
149
|
-
usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
150
|
-
identityRegistry: "0x8004A818BFB912233c491871b3d84c89A494BD9e",
|
|
151
|
-
morphoBlue: "0x0000000000000000000000000000000000000000"
|
|
152
|
-
},
|
|
153
|
-
[11155111 /* Sepolia */]: {
|
|
154
|
-
accountFactory: "0x0000000000000000000000000000000000000000",
|
|
155
|
-
validationRegistry: "0x0000000000000000000000000000000000000000",
|
|
156
|
-
agentReputation: "0x0000000000000000000000000000000000000000",
|
|
157
|
-
usdc: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
|
|
158
|
-
identityRegistry: "0x8004A818BFB912233c491871b3d84c89A494BD9e",
|
|
159
|
-
morphoBlue: "0x0000000000000000000000000000000000000000"
|
|
160
|
-
},
|
|
161
|
-
[31337 /* Hardhat */]: {
|
|
162
|
-
accountFactory: "0x0000000000000000000000000000000000000000",
|
|
163
|
-
validationRegistry: "0x0000000000000000000000000000000000000000",
|
|
164
|
-
agentReputation: "0x0000000000000000000000000000000000000000",
|
|
165
|
-
usdc: "0x56d4d6aEe0278c5Df2FA23Ecb32eC146C9446FDf",
|
|
166
|
-
identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
|
|
167
|
-
morphoBlue: "0x0000000000000000000000000000000000000000"
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
var RPC_URLS = {
|
|
171
|
-
[1 /* Ethereum */]: "https://ethereum-rpc.publicnode.com",
|
|
172
|
-
[8453 /* Base */]: "https://base-rpc.publicnode.com",
|
|
173
|
-
[84532 /* BaseSepolia */]: "https://sepolia.base.org",
|
|
174
|
-
[11155111 /* Sepolia */]: "https://rpc.sepolia.org",
|
|
175
|
-
[31337 /* Hardhat */]: "http://127.0.0.1:8545"
|
|
176
|
-
};
|
|
177
|
-
var SCORING_ENDPOINTS = {
|
|
178
|
-
[1 /* Ethereum */]: "https://scoring.agether.ai/v1",
|
|
179
|
-
[8453 /* Base */]: "http://95.179.189.214:3001",
|
|
180
|
-
[84532 /* BaseSepolia */]: "http://95.179.189.214:3001",
|
|
181
|
-
[11155111 /* Sepolia */]: "https://scoring-testnet.agether.ai/v1",
|
|
182
|
-
[31337 /* Hardhat */]: "http://127.0.0.1:3001"
|
|
183
|
-
};
|
|
184
|
-
function getDefaultConfig(chainId) {
|
|
185
|
-
return {
|
|
186
|
-
chainId,
|
|
187
|
-
rpcUrl: RPC_URLS[chainId],
|
|
188
|
-
contracts: CONTRACT_ADDRESSES[chainId],
|
|
189
|
-
scoringEndpoint: SCORING_ENDPOINTS[chainId]
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
function createConfig(chainId, options) {
|
|
193
|
-
const defaultConfig = getDefaultConfig(chainId);
|
|
194
|
-
return {
|
|
195
|
-
...defaultConfig,
|
|
196
|
-
...options,
|
|
197
|
-
contracts: {
|
|
198
|
-
...defaultConfig.contracts,
|
|
199
|
-
...options?.contracts
|
|
200
|
-
}
|
|
201
|
-
};
|
|
202
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
ACCOUNT_FACTORY_ABI,
|
|
3
|
+
AGENT_ACCOUNT_ABI,
|
|
4
|
+
AGENT_REPUTATION_ABI,
|
|
5
|
+
AgentNotApprovedError,
|
|
6
|
+
AgetherError,
|
|
7
|
+
ChainId,
|
|
8
|
+
ERC20_ABI,
|
|
9
|
+
IDENTITY_REGISTRY_ABI,
|
|
10
|
+
InsufficientBalanceError,
|
|
11
|
+
MORPHO_BLUE_ABI,
|
|
12
|
+
MorphoClient,
|
|
13
|
+
ScoringRejectedError,
|
|
14
|
+
VALIDATION_REGISTRY_ABI,
|
|
15
|
+
createConfig,
|
|
16
|
+
getDefaultConfig
|
|
17
|
+
} from "./chunk-GAFDBPDW.mjs";
|
|
18
|
+
import {
|
|
19
|
+
X402Client
|
|
20
|
+
} from "./chunk-PTXYOTCG.mjs";
|
|
203
21
|
|
|
204
22
|
// src/clients/AgetherClient.ts
|
|
23
|
+
import { ethers, Contract } from "ethers";
|
|
205
24
|
var AgetherClient = class _AgetherClient {
|
|
206
25
|
constructor(options) {
|
|
207
26
|
this.config = options.config;
|
|
@@ -379,889 +198,12 @@ var AgetherClient = class _AgetherClient {
|
|
|
379
198
|
}
|
|
380
199
|
};
|
|
381
200
|
|
|
382
|
-
// src/clients/MorphoClient.ts
|
|
383
|
-
import { ethers as ethers2, Contract as Contract2 } from "ethers";
|
|
384
|
-
import axios from "axios";
|
|
385
|
-
var BASE_COLLATERALS = {
|
|
386
|
-
WETH: { address: "0x4200000000000000000000000000000000000006", symbol: "WETH", decimals: 18 },
|
|
387
|
-
wstETH: { address: "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452", symbol: "wstETH", decimals: 18 },
|
|
388
|
-
cbETH: { address: "0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22", symbol: "cbETH", decimals: 18 }
|
|
389
|
-
};
|
|
390
|
-
var MORPHO_API_URL = "https://api.morpho.org/graphql";
|
|
391
|
-
var morphoIface = new ethers2.Interface(MORPHO_BLUE_ABI);
|
|
392
|
-
var erc20Iface = new ethers2.Interface(ERC20_ABI);
|
|
393
|
-
var MorphoClient = class {
|
|
394
|
-
constructor(config) {
|
|
395
|
-
this._marketCache = /* @__PURE__ */ new Map();
|
|
396
|
-
this._discoveredAt = 0;
|
|
397
|
-
const chainId = config.chainId ?? 8453 /* Base */;
|
|
398
|
-
const defaultCfg = getDefaultConfig(chainId);
|
|
399
|
-
this.config = defaultCfg;
|
|
400
|
-
this.agentId = config.agentId;
|
|
401
|
-
this.provider = new ethers2.JsonRpcProvider(config.rpcUrl || defaultCfg.rpcUrl);
|
|
402
|
-
this.wallet = new ethers2.Wallet(config.privateKey, this.provider);
|
|
403
|
-
const addrs = { ...defaultCfg.contracts, ...config.contracts };
|
|
404
|
-
this.accountFactory = new Contract2(addrs.accountFactory, ACCOUNT_FACTORY_ABI, this.wallet);
|
|
405
|
-
this.morphoBlue = new Contract2(addrs.morphoBlue, MORPHO_BLUE_ABI, this.provider);
|
|
406
|
-
this.agentReputation = new Contract2(addrs.agentReputation, AGENT_REPUTATION_ABI, this.provider);
|
|
407
|
-
this.identityRegistry = new Contract2(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this.provider);
|
|
408
|
-
}
|
|
409
|
-
// ════════════════════════════════════════════════════════
|
|
410
|
-
// Account Management
|
|
411
|
-
// ════════════════════════════════════════════════════════
|
|
412
|
-
/** Resolve the AgentAccount address (cached). */
|
|
413
|
-
async getAccountAddress() {
|
|
414
|
-
if (this._accountAddress) return this._accountAddress;
|
|
415
|
-
if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
|
|
416
|
-
const addr = await this.accountFactory.getAccount(BigInt(this.agentId));
|
|
417
|
-
if (addr === ethers2.ZeroAddress) {
|
|
418
|
-
throw new AgetherError("No AgentAccount found. Call register() first.", "NO_ACCOUNT");
|
|
419
|
-
}
|
|
420
|
-
this._accountAddress = addr;
|
|
421
|
-
return addr;
|
|
422
|
-
}
|
|
423
|
-
getAgentId() {
|
|
424
|
-
if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
|
|
425
|
-
return this.agentId;
|
|
426
|
-
}
|
|
427
|
-
getWalletAddress() {
|
|
428
|
-
return this.wallet.address;
|
|
429
|
-
}
|
|
430
|
-
/**
|
|
431
|
-
* Register: create ERC-8004 identity + AgentAccount in one flow.
|
|
432
|
-
* If already registered, returns existing state.
|
|
433
|
-
*/
|
|
434
|
-
async register(_name) {
|
|
435
|
-
const eoaAddr = this.wallet.address;
|
|
436
|
-
if (this.agentId) {
|
|
437
|
-
const exists = await this.accountFactory.accountExists(BigInt(this.agentId));
|
|
438
|
-
if (exists) {
|
|
439
|
-
const acct = await this.accountFactory.getAccount(BigInt(this.agentId));
|
|
440
|
-
this._accountAddress = acct;
|
|
441
|
-
return { agentId: this.agentId, address: eoaAddr, agentAccount: acct, alreadyRegistered: true };
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
const balance = await this.identityRegistry.balanceOf(eoaAddr);
|
|
445
|
-
let agentId;
|
|
446
|
-
if (balance > 0n && this.agentId) {
|
|
447
|
-
agentId = BigInt(this.agentId);
|
|
448
|
-
} else if (balance > 0n) {
|
|
449
|
-
throw new AgetherError(
|
|
450
|
-
"Wallet already has an ERC-8004 identity but agentId is unknown. Pass agentId in config.",
|
|
451
|
-
"AGENT_ID_UNKNOWN"
|
|
452
|
-
);
|
|
453
|
-
} else {
|
|
454
|
-
const regTx = await this.identityRegistry.register();
|
|
455
|
-
const regReceipt = await regTx.wait();
|
|
456
|
-
agentId = 0n;
|
|
457
|
-
for (const log of regReceipt.logs) {
|
|
458
|
-
try {
|
|
459
|
-
const parsed = this.identityRegistry.interface.parseLog({ topics: log.topics, data: log.data });
|
|
460
|
-
if (parsed?.name === "Transfer") {
|
|
461
|
-
agentId = parsed.args[2];
|
|
462
|
-
break;
|
|
463
|
-
}
|
|
464
|
-
} catch {
|
|
465
|
-
continue;
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
if (agentId === 0n) throw new AgetherError("Failed to parse agentId from registration", "PARSE_ERROR");
|
|
469
|
-
}
|
|
470
|
-
this.agentId = agentId.toString();
|
|
471
|
-
const acctExists = await this.accountFactory.accountExists(agentId);
|
|
472
|
-
let txHash;
|
|
473
|
-
if (!acctExists) {
|
|
474
|
-
const tx = await this.accountFactory.createAccount(agentId);
|
|
475
|
-
const receipt = await tx.wait();
|
|
476
|
-
txHash = receipt.hash;
|
|
477
|
-
}
|
|
478
|
-
const acctAddr = await this.accountFactory.getAccount(agentId);
|
|
479
|
-
this._accountAddress = acctAddr;
|
|
480
|
-
return {
|
|
481
|
-
agentId: this.agentId,
|
|
482
|
-
address: eoaAddr,
|
|
483
|
-
agentAccount: acctAddr,
|
|
484
|
-
alreadyRegistered: acctExists,
|
|
485
|
-
tx: txHash
|
|
486
|
-
};
|
|
487
|
-
}
|
|
488
|
-
/** Get ETH / USDC balances for EOA and AgentAccount. */
|
|
489
|
-
async getBalances() {
|
|
490
|
-
const eoaAddr = this.wallet.address;
|
|
491
|
-
const usdc = new Contract2(this.config.contracts.usdc, ERC20_ABI, this.provider);
|
|
492
|
-
const ethBal = await this.provider.getBalance(eoaAddr);
|
|
493
|
-
const usdcBal = await usdc.balanceOf(eoaAddr);
|
|
494
|
-
const result = {
|
|
495
|
-
agentId: this.agentId || "?",
|
|
496
|
-
address: eoaAddr,
|
|
497
|
-
eth: ethers2.formatEther(ethBal),
|
|
498
|
-
usdc: ethers2.formatUnits(usdcBal, 6)
|
|
499
|
-
};
|
|
500
|
-
try {
|
|
501
|
-
const acctAddr = await this.getAccountAddress();
|
|
502
|
-
const acctEth = await this.provider.getBalance(acctAddr);
|
|
503
|
-
const acctUsdc = await usdc.balanceOf(acctAddr);
|
|
504
|
-
result.agentAccount = {
|
|
505
|
-
address: acctAddr,
|
|
506
|
-
eth: ethers2.formatEther(acctEth),
|
|
507
|
-
usdc: ethers2.formatUnits(acctUsdc, 6)
|
|
508
|
-
};
|
|
509
|
-
} catch {
|
|
510
|
-
}
|
|
511
|
-
return result;
|
|
512
|
-
}
|
|
513
|
-
/** Transfer USDC from EOA to AgentAccount. */
|
|
514
|
-
async fundAccount(usdcAmount) {
|
|
515
|
-
const acctAddr = await this.getAccountAddress();
|
|
516
|
-
const usdc = new Contract2(this.config.contracts.usdc, ERC20_ABI, this.wallet);
|
|
517
|
-
const amount = ethers2.parseUnits(usdcAmount, 6);
|
|
518
|
-
const tx = await usdc.transfer(acctAddr, amount);
|
|
519
|
-
const receipt = await tx.wait();
|
|
520
|
-
return { tx: receipt.hash, amount: usdcAmount, agentAccount: acctAddr };
|
|
521
|
-
}
|
|
522
|
-
// ════════════════════════════════════════════════════════
|
|
523
|
-
// Market Discovery (Morpho GraphQL API)
|
|
524
|
-
// ════════════════════════════════════════════════════════
|
|
525
|
-
/**
|
|
526
|
-
* Fetch USDC borrow markets on Base from Morpho API.
|
|
527
|
-
* Caches results for 5 minutes.
|
|
528
|
-
*/
|
|
529
|
-
async getMarkets(forceRefresh = false) {
|
|
530
|
-
if (!forceRefresh && this._discoveredMarkets && Date.now() - this._discoveredAt < 3e5) {
|
|
531
|
-
return this._discoveredMarkets;
|
|
532
|
-
}
|
|
533
|
-
const chainId = this.config.chainId;
|
|
534
|
-
const usdcAddr = this.config.contracts.usdc.toLowerCase();
|
|
535
|
-
const query = `{
|
|
536
|
-
markets(
|
|
537
|
-
first: 50
|
|
538
|
-
orderBy: SupplyAssetsUsd
|
|
539
|
-
orderDirection: Desc
|
|
540
|
-
where: { chainId_in: [${chainId}], loanAssetAddress_in: ["${usdcAddr}"] }
|
|
541
|
-
) {
|
|
542
|
-
items {
|
|
543
|
-
uniqueKey
|
|
544
|
-
lltv
|
|
545
|
-
oracleAddress
|
|
546
|
-
irmAddress
|
|
547
|
-
loanAsset { address symbol decimals }
|
|
548
|
-
collateralAsset { address symbol decimals }
|
|
549
|
-
state {
|
|
550
|
-
borrowAssets
|
|
551
|
-
supplyAssets
|
|
552
|
-
utilization
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
}`;
|
|
557
|
-
try {
|
|
558
|
-
const resp = await axios.post(MORPHO_API_URL, { query }, { timeout: 1e4 });
|
|
559
|
-
const items = resp.data?.data?.markets?.items ?? [];
|
|
560
|
-
this._discoveredMarkets = items.map((m) => ({
|
|
561
|
-
uniqueKey: m.uniqueKey,
|
|
562
|
-
loanAsset: m.loanAsset,
|
|
563
|
-
collateralAsset: m.collateralAsset ?? { address: ethers2.ZeroAddress, symbol: "N/A", decimals: 0 },
|
|
564
|
-
oracle: m.oracleAddress,
|
|
565
|
-
irm: m.irmAddress,
|
|
566
|
-
lltv: BigInt(m.lltv),
|
|
567
|
-
totalSupplyAssets: BigInt(m.state?.supplyAssets ?? "0"),
|
|
568
|
-
totalBorrowAssets: BigInt(m.state?.borrowAssets ?? "0"),
|
|
569
|
-
utilization: m.state?.utilization ? Number(m.state.utilization) : 0
|
|
570
|
-
}));
|
|
571
|
-
this._discoveredAt = Date.now();
|
|
572
|
-
for (const mi of this._discoveredMarkets) {
|
|
573
|
-
if (mi.collateralAsset.address !== ethers2.ZeroAddress) {
|
|
574
|
-
this._marketCache.set(mi.collateralAsset.address.toLowerCase(), {
|
|
575
|
-
loanToken: mi.loanAsset.address,
|
|
576
|
-
collateralToken: mi.collateralAsset.address,
|
|
577
|
-
oracle: mi.oracle,
|
|
578
|
-
irm: mi.irm,
|
|
579
|
-
lltv: mi.lltv
|
|
580
|
-
});
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
return this._discoveredMarkets;
|
|
584
|
-
} catch {
|
|
585
|
-
return this._discoveredMarkets ?? [];
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
/**
|
|
589
|
-
* Get MarketParams for a collateral token.
|
|
590
|
-
* Tries cache → API → on-chain idToMarketParams.
|
|
591
|
-
*/
|
|
592
|
-
async findMarketForCollateral(collateralSymbolOrAddress) {
|
|
593
|
-
const colInfo = BASE_COLLATERALS[collateralSymbolOrAddress];
|
|
594
|
-
const colAddr = (colInfo?.address ?? collateralSymbolOrAddress).toLowerCase();
|
|
595
|
-
const cached = this._marketCache.get(colAddr);
|
|
596
|
-
if (cached) return cached;
|
|
597
|
-
await this.getMarkets();
|
|
598
|
-
const fromApi = this._marketCache.get(colAddr);
|
|
599
|
-
if (fromApi) return fromApi;
|
|
600
|
-
throw new AgetherError(
|
|
601
|
-
`No Morpho market found for collateral ${collateralSymbolOrAddress}`,
|
|
602
|
-
"MARKET_NOT_FOUND"
|
|
603
|
-
);
|
|
604
|
-
}
|
|
605
|
-
/** Read MarketParams on-chain by market ID (bytes32). */
|
|
606
|
-
async getMarketParams(marketId) {
|
|
607
|
-
const result = await this.morphoBlue.idToMarketParams(marketId);
|
|
608
|
-
return {
|
|
609
|
-
loanToken: result.loanToken,
|
|
610
|
-
collateralToken: result.collateralToken,
|
|
611
|
-
oracle: result.oracle,
|
|
612
|
-
irm: result.irm,
|
|
613
|
-
lltv: result.lltv
|
|
614
|
-
};
|
|
615
|
-
}
|
|
616
|
-
// ════════════════════════════════════════════════════════
|
|
617
|
-
// Position Reads
|
|
618
|
-
// ════════════════════════════════════════════════════════
|
|
619
|
-
/** Read on-chain position for a specific market. */
|
|
620
|
-
async getPosition(marketId) {
|
|
621
|
-
const acctAddr = await this.getAccountAddress();
|
|
622
|
-
const pos = await this.morphoBlue.position(marketId, acctAddr);
|
|
623
|
-
return {
|
|
624
|
-
supplyShares: pos.supplyShares,
|
|
625
|
-
borrowShares: pos.borrowShares,
|
|
626
|
-
collateral: pos.collateral
|
|
627
|
-
};
|
|
628
|
-
}
|
|
629
|
-
/**
|
|
630
|
-
* Full status: positions across all discovered markets.
|
|
631
|
-
*/
|
|
632
|
-
async getStatus() {
|
|
633
|
-
const acctAddr = await this.getAccountAddress();
|
|
634
|
-
const markets = await this.getMarkets();
|
|
635
|
-
const positions = [];
|
|
636
|
-
let totalDebt = 0n;
|
|
637
|
-
for (const m of markets) {
|
|
638
|
-
if (!m.collateralAsset || m.collateralAsset.address === ethers2.ZeroAddress) continue;
|
|
639
|
-
try {
|
|
640
|
-
const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
|
|
641
|
-
if (pos.collateral === 0n && pos.borrowShares === 0n && pos.supplyShares === 0n) continue;
|
|
642
|
-
let debt = 0n;
|
|
643
|
-
if (pos.borrowShares > 0n) {
|
|
644
|
-
try {
|
|
645
|
-
const mkt = await this.morphoBlue.market(m.uniqueKey);
|
|
646
|
-
const totalBorrowShares = BigInt(mkt.totalBorrowShares);
|
|
647
|
-
const totalBorrowAssets = BigInt(mkt.totalBorrowAssets);
|
|
648
|
-
debt = totalBorrowShares > 0n ? BigInt(pos.borrowShares) * totalBorrowAssets / totalBorrowShares : 0n;
|
|
649
|
-
totalDebt += debt;
|
|
650
|
-
} catch {
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
positions.push({
|
|
654
|
-
marketId: m.uniqueKey,
|
|
655
|
-
collateralToken: m.collateralAsset.symbol,
|
|
656
|
-
collateral: ethers2.formatUnits(pos.collateral, m.collateralAsset.decimals),
|
|
657
|
-
borrowShares: pos.borrowShares.toString(),
|
|
658
|
-
supplyShares: pos.supplyShares.toString(),
|
|
659
|
-
debt: ethers2.formatUnits(debt, 6)
|
|
660
|
-
});
|
|
661
|
-
} catch {
|
|
662
|
-
continue;
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
return {
|
|
666
|
-
agentId: this.agentId || "?",
|
|
667
|
-
agentAccount: acctAddr,
|
|
668
|
-
totalDebt: ethers2.formatUnits(totalDebt, 6),
|
|
669
|
-
positions
|
|
670
|
-
};
|
|
671
|
-
}
|
|
672
|
-
// ════════════════════════════════════════════════════════
|
|
673
|
-
// Lending Operations (all via AgentAccount.executeBatch)
|
|
674
|
-
// ════════════════════════════════════════════════════════
|
|
675
|
-
/**
|
|
676
|
-
* Deposit collateral into Morpho Blue.
|
|
677
|
-
*
|
|
678
|
-
* Flow:
|
|
679
|
-
* 1. EOA transfers collateral to AgentAccount
|
|
680
|
-
* 2. AgentAccount.executeBatch:
|
|
681
|
-
* [collateral.approve(MorphoBlue), Morpho.supplyCollateral(params)]
|
|
682
|
-
*/
|
|
683
|
-
async supplyCollateral(tokenSymbol, amount, marketParams) {
|
|
684
|
-
const acctAddr = await this.getAccountAddress();
|
|
685
|
-
const colInfo = BASE_COLLATERALS[tokenSymbol];
|
|
686
|
-
if (!colInfo) throw new AgetherError(`Unknown collateral: ${tokenSymbol}`, "UNKNOWN_COLLATERAL");
|
|
687
|
-
const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
|
|
688
|
-
const weiAmount = ethers2.parseUnits(amount, colInfo.decimals);
|
|
689
|
-
const morphoAddr = this.config.contracts.morphoBlue;
|
|
690
|
-
const colToken = new Contract2(colInfo.address, ERC20_ABI, this.wallet);
|
|
691
|
-
const transferTx = await colToken.transfer(acctAddr, weiAmount);
|
|
692
|
-
await transferTx.wait();
|
|
693
|
-
const targets = [colInfo.address, morphoAddr];
|
|
694
|
-
const values = [0n, 0n];
|
|
695
|
-
const datas = [
|
|
696
|
-
erc20Iface.encodeFunctionData("approve", [morphoAddr, weiAmount]),
|
|
697
|
-
morphoIface.encodeFunctionData("supplyCollateral", [
|
|
698
|
-
this._toTuple(params),
|
|
699
|
-
weiAmount,
|
|
700
|
-
acctAddr,
|
|
701
|
-
"0x"
|
|
702
|
-
])
|
|
703
|
-
];
|
|
704
|
-
const receipt = await this.batch(targets, values, datas);
|
|
705
|
-
return {
|
|
706
|
-
tx: receipt.hash,
|
|
707
|
-
collateralToken: tokenSymbol,
|
|
708
|
-
amount,
|
|
709
|
-
agentAccount: acctAddr
|
|
710
|
-
};
|
|
711
|
-
}
|
|
712
|
-
/**
|
|
713
|
-
* Borrow USDC against existing collateral.
|
|
714
|
-
*
|
|
715
|
-
* AgentAccount.execute: Morpho.borrow(params, amount, 0, account, account)
|
|
716
|
-
*
|
|
717
|
-
* @param usdcAmount - USDC amount (e.g. '100')
|
|
718
|
-
* @param tokenSymbol - collateral symbol to identify which market (default: first with collateral)
|
|
719
|
-
*/
|
|
720
|
-
async borrow(usdcAmount, tokenSymbol, marketParams) {
|
|
721
|
-
const acctAddr = await this.getAccountAddress();
|
|
722
|
-
const amount = ethers2.parseUnits(usdcAmount, 6);
|
|
723
|
-
const morphoAddr = this.config.contracts.morphoBlue;
|
|
724
|
-
let params;
|
|
725
|
-
let usedToken = tokenSymbol || "WETH";
|
|
726
|
-
if (marketParams) {
|
|
727
|
-
params = marketParams;
|
|
728
|
-
} else if (tokenSymbol) {
|
|
729
|
-
params = await this.findMarketForCollateral(tokenSymbol);
|
|
730
|
-
} else {
|
|
731
|
-
const { params: p, symbol } = await this._findActiveMarket();
|
|
732
|
-
params = p;
|
|
733
|
-
usedToken = symbol;
|
|
734
|
-
}
|
|
735
|
-
const data = morphoIface.encodeFunctionData("borrow", [
|
|
736
|
-
this._toTuple(params),
|
|
737
|
-
amount,
|
|
738
|
-
0n,
|
|
739
|
-
acctAddr,
|
|
740
|
-
acctAddr
|
|
741
|
-
]);
|
|
742
|
-
const receipt = await this.exec(morphoAddr, data);
|
|
743
|
-
return {
|
|
744
|
-
tx: receipt.hash,
|
|
745
|
-
amount: usdcAmount,
|
|
746
|
-
collateralToken: usedToken,
|
|
747
|
-
agentAccount: acctAddr
|
|
748
|
-
};
|
|
749
|
-
}
|
|
750
|
-
/**
|
|
751
|
-
* Deposit collateral AND borrow USDC in one batched transaction.
|
|
752
|
-
*
|
|
753
|
-
* AgentAccount.executeBatch:
|
|
754
|
-
* [collateral.approve, Morpho.supplyCollateral, Morpho.borrow]
|
|
755
|
-
*
|
|
756
|
-
* The collateral must be transferred to AgentAccount first.
|
|
757
|
-
*/
|
|
758
|
-
async depositAndBorrow(tokenSymbol, collateralAmount, borrowUsdcAmount, marketParams) {
|
|
759
|
-
const acctAddr = await this.getAccountAddress();
|
|
760
|
-
const colInfo = BASE_COLLATERALS[tokenSymbol];
|
|
761
|
-
if (!colInfo) throw new AgetherError(`Unknown collateral: ${tokenSymbol}`, "UNKNOWN_COLLATERAL");
|
|
762
|
-
const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
|
|
763
|
-
const colWei = ethers2.parseUnits(collateralAmount, colInfo.decimals);
|
|
764
|
-
const borrowWei = ethers2.parseUnits(borrowUsdcAmount, 6);
|
|
765
|
-
const morphoAddr = this.config.contracts.morphoBlue;
|
|
766
|
-
const colToken = new Contract2(colInfo.address, ERC20_ABI, this.wallet);
|
|
767
|
-
const transferTx = await colToken.transfer(acctAddr, colWei);
|
|
768
|
-
await transferTx.wait();
|
|
769
|
-
const targets = [colInfo.address, morphoAddr, morphoAddr];
|
|
770
|
-
const values = [0n, 0n, 0n];
|
|
771
|
-
const datas = [
|
|
772
|
-
erc20Iface.encodeFunctionData("approve", [morphoAddr, colWei]),
|
|
773
|
-
morphoIface.encodeFunctionData("supplyCollateral", [
|
|
774
|
-
this._toTuple(params),
|
|
775
|
-
colWei,
|
|
776
|
-
acctAddr,
|
|
777
|
-
"0x"
|
|
778
|
-
]),
|
|
779
|
-
morphoIface.encodeFunctionData("borrow", [
|
|
780
|
-
this._toTuple(params),
|
|
781
|
-
borrowWei,
|
|
782
|
-
0n,
|
|
783
|
-
acctAddr,
|
|
784
|
-
acctAddr
|
|
785
|
-
])
|
|
786
|
-
];
|
|
787
|
-
const receipt = await this.batch(targets, values, datas);
|
|
788
|
-
return {
|
|
789
|
-
tx: receipt.hash,
|
|
790
|
-
collateralToken: tokenSymbol,
|
|
791
|
-
collateralAmount,
|
|
792
|
-
borrowAmount: borrowUsdcAmount,
|
|
793
|
-
agentAccount: acctAddr
|
|
794
|
-
};
|
|
795
|
-
}
|
|
796
|
-
/**
|
|
797
|
-
* Repay borrowed USDC from AgentAccount.
|
|
798
|
-
*
|
|
799
|
-
* AgentAccount.executeBatch:
|
|
800
|
-
* [USDC.approve(MorphoBlue), Morpho.repay(params)]
|
|
801
|
-
*/
|
|
802
|
-
async repay(usdcAmount, tokenSymbol, marketParams) {
|
|
803
|
-
const acctAddr = await this.getAccountAddress();
|
|
804
|
-
const amount = ethers2.parseUnits(usdcAmount, 6);
|
|
805
|
-
const morphoAddr = this.config.contracts.morphoBlue;
|
|
806
|
-
const usdcAddr = this.config.contracts.usdc;
|
|
807
|
-
let params;
|
|
808
|
-
if (marketParams) {
|
|
809
|
-
params = marketParams;
|
|
810
|
-
} else if (tokenSymbol) {
|
|
811
|
-
params = await this.findMarketForCollateral(tokenSymbol);
|
|
812
|
-
} else {
|
|
813
|
-
const { params: p } = await this._findActiveMarket();
|
|
814
|
-
params = p;
|
|
815
|
-
}
|
|
816
|
-
const targets = [usdcAddr, morphoAddr];
|
|
817
|
-
const values = [0n, 0n];
|
|
818
|
-
const datas = [
|
|
819
|
-
erc20Iface.encodeFunctionData("approve", [morphoAddr, amount]),
|
|
820
|
-
morphoIface.encodeFunctionData("repay", [
|
|
821
|
-
this._toTuple(params),
|
|
822
|
-
amount,
|
|
823
|
-
0n,
|
|
824
|
-
acctAddr,
|
|
825
|
-
"0x"
|
|
826
|
-
])
|
|
827
|
-
];
|
|
828
|
-
const receipt = await this.batch(targets, values, datas);
|
|
829
|
-
let remainingDebt = "0";
|
|
830
|
-
try {
|
|
831
|
-
const status = await this.getStatus();
|
|
832
|
-
remainingDebt = status.totalDebt;
|
|
833
|
-
} catch {
|
|
834
|
-
}
|
|
835
|
-
return { tx: receipt.hash, amount: usdcAmount, remainingDebt };
|
|
836
|
-
}
|
|
837
|
-
/**
|
|
838
|
-
* Withdraw collateral from Morpho Blue.
|
|
839
|
-
*
|
|
840
|
-
* AgentAccount.execute: Morpho.withdrawCollateral(params, amount, account, receiver)
|
|
841
|
-
*
|
|
842
|
-
* @param receiver - defaults to EOA wallet
|
|
843
|
-
*/
|
|
844
|
-
async withdrawCollateral(tokenSymbol, amount, marketParams, receiver) {
|
|
845
|
-
const acctAddr = await this.getAccountAddress();
|
|
846
|
-
const colInfo = BASE_COLLATERALS[tokenSymbol];
|
|
847
|
-
if (!colInfo) throw new AgetherError(`Unknown collateral: ${tokenSymbol}`, "UNKNOWN_COLLATERAL");
|
|
848
|
-
const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
|
|
849
|
-
const morphoAddr = this.config.contracts.morphoBlue;
|
|
850
|
-
const dest = receiver || this.wallet.address;
|
|
851
|
-
let weiAmount;
|
|
852
|
-
if (amount === "all") {
|
|
853
|
-
const markets = await this.getMarkets();
|
|
854
|
-
const market = markets.find(
|
|
855
|
-
(m) => m.collateralAsset.address.toLowerCase() === colInfo.address.toLowerCase()
|
|
856
|
-
);
|
|
857
|
-
if (!market) throw new AgetherError("Market not found", "MARKET_NOT_FOUND");
|
|
858
|
-
const pos = await this.morphoBlue.position(market.uniqueKey, acctAddr);
|
|
859
|
-
weiAmount = pos.collateral;
|
|
860
|
-
if (weiAmount === 0n) throw new AgetherError("No collateral to withdraw", "NO_COLLATERAL");
|
|
861
|
-
} else {
|
|
862
|
-
weiAmount = ethers2.parseUnits(amount, colInfo.decimals);
|
|
863
|
-
}
|
|
864
|
-
const data = morphoIface.encodeFunctionData("withdrawCollateral", [
|
|
865
|
-
this._toTuple(params),
|
|
866
|
-
weiAmount,
|
|
867
|
-
acctAddr,
|
|
868
|
-
dest
|
|
869
|
-
]);
|
|
870
|
-
const receipt = await this.exec(morphoAddr, data);
|
|
871
|
-
let remainingCollateral = "0";
|
|
872
|
-
try {
|
|
873
|
-
const markets = await this.getMarkets();
|
|
874
|
-
const market = markets.find(
|
|
875
|
-
(m) => m.collateralAsset.address.toLowerCase() === colInfo.address.toLowerCase()
|
|
876
|
-
);
|
|
877
|
-
if (market) {
|
|
878
|
-
const pos = await this.morphoBlue.position(market.uniqueKey, acctAddr);
|
|
879
|
-
remainingCollateral = ethers2.formatUnits(pos.collateral, colInfo.decimals);
|
|
880
|
-
}
|
|
881
|
-
} catch {
|
|
882
|
-
}
|
|
883
|
-
return {
|
|
884
|
-
tx: receipt.hash,
|
|
885
|
-
token: tokenSymbol,
|
|
886
|
-
amount: amount === "all" ? ethers2.formatUnits(weiAmount, colInfo.decimals) : amount,
|
|
887
|
-
remainingCollateral,
|
|
888
|
-
destination: dest
|
|
889
|
-
};
|
|
890
|
-
}
|
|
891
|
-
/**
|
|
892
|
-
* Sponsor: transfer collateral to another agent's AgentAccount.
|
|
893
|
-
* (The agent must then supplyCollateral themselves via their own account.)
|
|
894
|
-
*/
|
|
895
|
-
async sponsor(target, tokenSymbol, amount) {
|
|
896
|
-
const colInfo = BASE_COLLATERALS[tokenSymbol];
|
|
897
|
-
if (!colInfo) throw new AgetherError(`Unknown collateral: ${tokenSymbol}`, "UNKNOWN_COLLATERAL");
|
|
898
|
-
let targetAddr;
|
|
899
|
-
if (target.address) {
|
|
900
|
-
targetAddr = target.address;
|
|
901
|
-
} else if (target.agentId) {
|
|
902
|
-
targetAddr = await this.accountFactory.getAccount(BigInt(target.agentId));
|
|
903
|
-
if (targetAddr === ethers2.ZeroAddress) throw new AgetherError("Target agent has no account", "NO_ACCOUNT");
|
|
904
|
-
} else {
|
|
905
|
-
throw new AgetherError("Provide agentId or address", "INVALID_TARGET");
|
|
906
|
-
}
|
|
907
|
-
const weiAmount = ethers2.parseUnits(amount, colInfo.decimals);
|
|
908
|
-
const colToken = new Contract2(colInfo.address, ERC20_ABI, this.wallet);
|
|
909
|
-
const tx = await colToken.transfer(targetAddr, weiAmount);
|
|
910
|
-
const receipt = await tx.wait();
|
|
911
|
-
return { tx: receipt.hash, targetAccount: targetAddr, targetAgentId: target.agentId };
|
|
912
|
-
}
|
|
913
|
-
// ════════════════════════════════════════════════════════
|
|
914
|
-
// Reputation (AgentReputation contract)
|
|
915
|
-
// ════════════════════════════════════════════════════════
|
|
916
|
-
async getCreditScore() {
|
|
917
|
-
if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
|
|
918
|
-
return this.agentReputation.getCreditScore(BigInt(this.agentId));
|
|
919
|
-
}
|
|
920
|
-
async getAttestation() {
|
|
921
|
-
if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
|
|
922
|
-
const att = await this.agentReputation.getAttestation(BigInt(this.agentId));
|
|
923
|
-
return { score: att.score, timestamp: att.timestamp, signer: att.signer };
|
|
924
|
-
}
|
|
925
|
-
async isEligible(minScore = 500n) {
|
|
926
|
-
if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
|
|
927
|
-
const [eligible, currentScore] = await this.agentReputation.isEligible(BigInt(this.agentId), minScore);
|
|
928
|
-
return { eligible, currentScore };
|
|
929
|
-
}
|
|
930
|
-
async isScoreFresh() {
|
|
931
|
-
if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
|
|
932
|
-
const [fresh, age] = await this.agentReputation.isScoreFresh(BigInt(this.agentId));
|
|
933
|
-
return { fresh, age };
|
|
934
|
-
}
|
|
935
|
-
// ════════════════════════════════════════════════════════
|
|
936
|
-
// Internal Helpers
|
|
937
|
-
// ════════════════════════════════════════════════════════
|
|
938
|
-
/**
|
|
939
|
-
* Execute a single call via AgentAccount.execute.
|
|
940
|
-
*/
|
|
941
|
-
async exec(target, data, value = 0n) {
|
|
942
|
-
const acctAddr = await this.getAccountAddress();
|
|
943
|
-
const account = new Contract2(acctAddr, AGENT_ACCOUNT_ABI, this.wallet);
|
|
944
|
-
let gasLimit;
|
|
945
|
-
try {
|
|
946
|
-
const estimate = await account.execute.estimateGas(target, value, data);
|
|
947
|
-
gasLimit = estimate * 130n / 100n;
|
|
948
|
-
} catch {
|
|
949
|
-
gasLimit = 500000n;
|
|
950
|
-
}
|
|
951
|
-
const tx = await account.execute(target, value, data, { gasLimit });
|
|
952
|
-
return tx.wait();
|
|
953
|
-
}
|
|
954
|
-
/**
|
|
955
|
-
* Execute multiple calls via AgentAccount.executeBatch.
|
|
956
|
-
*/
|
|
957
|
-
async batch(targets, values, datas) {
|
|
958
|
-
const acctAddr = await this.getAccountAddress();
|
|
959
|
-
const account = new Contract2(acctAddr, AGENT_ACCOUNT_ABI, this.wallet);
|
|
960
|
-
let gasLimit;
|
|
961
|
-
try {
|
|
962
|
-
const estimate = await account.executeBatch.estimateGas(targets, values, datas);
|
|
963
|
-
gasLimit = estimate * 130n / 100n;
|
|
964
|
-
} catch {
|
|
965
|
-
gasLimit = 800000n;
|
|
966
|
-
}
|
|
967
|
-
const tx = await account.executeBatch(targets, values, datas, { gasLimit });
|
|
968
|
-
return tx.wait();
|
|
969
|
-
}
|
|
970
|
-
/** Convert MorphoMarketParams to Solidity tuple. */
|
|
971
|
-
_toTuple(p) {
|
|
972
|
-
return [p.loanToken, p.collateralToken, p.oracle, p.irm, p.lltv];
|
|
973
|
-
}
|
|
974
|
-
/** Find the first market where the agent has collateral deposited. */
|
|
975
|
-
async _findActiveMarket() {
|
|
976
|
-
const acctAddr = await this.getAccountAddress();
|
|
977
|
-
const markets = await this.getMarkets();
|
|
978
|
-
for (const m of markets) {
|
|
979
|
-
if (!m.collateralAsset || m.collateralAsset.address === ethers2.ZeroAddress) continue;
|
|
980
|
-
try {
|
|
981
|
-
const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
|
|
982
|
-
if (pos.collateral > 0n) {
|
|
983
|
-
return {
|
|
984
|
-
params: {
|
|
985
|
-
loanToken: m.loanAsset.address,
|
|
986
|
-
collateralToken: m.collateralAsset.address,
|
|
987
|
-
oracle: m.oracle,
|
|
988
|
-
irm: m.irm,
|
|
989
|
-
lltv: m.lltv
|
|
990
|
-
},
|
|
991
|
-
symbol: m.collateralAsset.symbol
|
|
992
|
-
};
|
|
993
|
-
}
|
|
994
|
-
} catch {
|
|
995
|
-
continue;
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
const params = await this.findMarketForCollateral("WETH");
|
|
999
|
-
return { params, symbol: "WETH" };
|
|
1000
|
-
}
|
|
1001
|
-
};
|
|
1002
|
-
|
|
1003
|
-
// src/clients/ScoringClient.ts
|
|
1004
|
-
import axios2 from "axios";
|
|
1005
|
-
|
|
1006
|
-
// src/clients/X402Client.ts
|
|
1007
|
-
import { ethers as ethers3 } from "ethers";
|
|
1008
|
-
var USDC_DOMAINS = {
|
|
1009
|
-
"eip155:1": { name: "USD Coin", version: "2", address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" },
|
|
1010
|
-
"eip155:8453": { name: "USD Coin", version: "2", address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" },
|
|
1011
|
-
"eip155:84532": { name: "USD Coin", version: "2", address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e" },
|
|
1012
|
-
"eip155:42161": { name: "USD Coin", version: "2", address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831" },
|
|
1013
|
-
"eip155:10": { name: "USD Coin", version: "2", address: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85" }
|
|
1014
|
-
};
|
|
1015
|
-
function chainIdFromNetwork(network) {
|
|
1016
|
-
const m = network.match(/^eip155:(\d+)$/);
|
|
1017
|
-
return m ? Number(m[1]) : 1;
|
|
1018
|
-
}
|
|
1019
|
-
var X402Client = class {
|
|
1020
|
-
constructor(config) {
|
|
1021
|
-
this.config = config;
|
|
1022
|
-
const provider = new ethers3.JsonRpcProvider(config.rpcUrl);
|
|
1023
|
-
this.wallet = new ethers3.Wallet(config.privateKey, provider);
|
|
1024
|
-
}
|
|
1025
|
-
async get(url, opts) {
|
|
1026
|
-
return this.request(url, { ...opts, method: "GET" });
|
|
1027
|
-
}
|
|
1028
|
-
async post(url, body, opts) {
|
|
1029
|
-
return this.request(url, {
|
|
1030
|
-
...opts,
|
|
1031
|
-
method: "POST",
|
|
1032
|
-
body: body ? JSON.stringify(body) : void 0,
|
|
1033
|
-
headers: { "Content-Type": "application/json", ...opts?.headers }
|
|
1034
|
-
});
|
|
1035
|
-
}
|
|
1036
|
-
getAddress() {
|
|
1037
|
-
return this.wallet.address;
|
|
1038
|
-
}
|
|
1039
|
-
// ──────────── Core request / 402-retry loop ────────────
|
|
1040
|
-
async request(url, options) {
|
|
1041
|
-
try {
|
|
1042
|
-
console.log(" [1/4] Calling resource server\u2026");
|
|
1043
|
-
const response = await fetch(url, {
|
|
1044
|
-
...options,
|
|
1045
|
-
headers: {
|
|
1046
|
-
...options?.headers,
|
|
1047
|
-
"X-Agent-Id": this.config.agentId || ""
|
|
1048
|
-
}
|
|
1049
|
-
});
|
|
1050
|
-
if (response.ok) {
|
|
1051
|
-
const data = await response.json();
|
|
1052
|
-
return { success: true, data };
|
|
1053
|
-
}
|
|
1054
|
-
if (response.status !== 402) {
|
|
1055
|
-
return { success: false, error: `HTTP ${response.status}: ${await response.text()}` };
|
|
1056
|
-
}
|
|
1057
|
-
console.log(" [2/4] 402 received \u2014 parsing payment requirements\u2026");
|
|
1058
|
-
const parsed = await this.parsePaymentRequired(response);
|
|
1059
|
-
if (!parsed) {
|
|
1060
|
-
return { success: false, error: "Could not parse payment requirements from 402 response" };
|
|
1061
|
-
}
|
|
1062
|
-
const { requirements, resource } = parsed;
|
|
1063
|
-
console.log(` scheme : ${requirements.scheme}`);
|
|
1064
|
-
console.log(` network : ${requirements.network}`);
|
|
1065
|
-
console.log(` amount : ${requirements.amount} (atomic)`);
|
|
1066
|
-
console.log(` asset : ${requirements.asset}`);
|
|
1067
|
-
console.log(` payTo : ${requirements.payTo}`);
|
|
1068
|
-
console.log(" [3/4] Signing EIP-3009 transferWithAuthorization\u2026");
|
|
1069
|
-
const paymentPayload = await this.buildPaymentPayload(requirements, resource, url);
|
|
1070
|
-
const paymentB64 = Buffer.from(JSON.stringify(paymentPayload)).toString("base64");
|
|
1071
|
-
await this.riskCheck(paymentPayload, requirements);
|
|
1072
|
-
console.log(" [4/4] Retrying with PAYMENT-SIGNATURE header\u2026");
|
|
1073
|
-
const paidResponse = await fetch(url, {
|
|
1074
|
-
...options,
|
|
1075
|
-
headers: {
|
|
1076
|
-
...options?.headers,
|
|
1077
|
-
"X-Agent-Id": this.config.agentId || "",
|
|
1078
|
-
// v2 header
|
|
1079
|
-
"PAYMENT-SIGNATURE": paymentB64,
|
|
1080
|
-
// v1 compat header (some servers still use this)
|
|
1081
|
-
"X-PAYMENT": paymentB64
|
|
1082
|
-
}
|
|
1083
|
-
});
|
|
1084
|
-
if (paidResponse.ok) {
|
|
1085
|
-
const data = await paidResponse.json();
|
|
1086
|
-
const settlementHeader = paidResponse.headers.get("PAYMENT-RESPONSE") || paidResponse.headers.get("X-PAYMENT-RESPONSE");
|
|
1087
|
-
let txHash;
|
|
1088
|
-
if (settlementHeader) {
|
|
1089
|
-
try {
|
|
1090
|
-
const settlement = JSON.parse(Buffer.from(settlementHeader, "base64").toString("utf-8"));
|
|
1091
|
-
txHash = settlement.transaction;
|
|
1092
|
-
} catch {
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
return {
|
|
1096
|
-
success: true,
|
|
1097
|
-
data,
|
|
1098
|
-
paymentInfo: {
|
|
1099
|
-
amount: requirements.amount,
|
|
1100
|
-
asset: requirements.extra?.name || "USDC",
|
|
1101
|
-
network: requirements.network,
|
|
1102
|
-
txHash
|
|
1103
|
-
}
|
|
1104
|
-
};
|
|
1105
|
-
}
|
|
1106
|
-
const errBody = await paidResponse.text();
|
|
1107
|
-
return { success: false, error: `Payment rejected (HTTP ${paidResponse.status}): ${errBody}` };
|
|
1108
|
-
} catch (error) {
|
|
1109
|
-
return { success: false, error: `Request failed: ${error instanceof Error ? error.message : String(error)}` };
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
// ──────────── Parse 402 response ────────────
|
|
1113
|
-
async parsePaymentRequired(response) {
|
|
1114
|
-
const prHeader = response.headers.get("PAYMENT-REQUIRED") || response.headers.get("x-payment-required");
|
|
1115
|
-
if (prHeader) {
|
|
1116
|
-
try {
|
|
1117
|
-
const decoded = JSON.parse(Buffer.from(prHeader, "base64").toString("utf-8"));
|
|
1118
|
-
if (decoded.accepts?.length) {
|
|
1119
|
-
return { requirements: decoded.accepts[0], resource: decoded.resource };
|
|
1120
|
-
}
|
|
1121
|
-
} catch {
|
|
1122
|
-
}
|
|
1123
|
-
}
|
|
1124
|
-
try {
|
|
1125
|
-
const body = await response.json();
|
|
1126
|
-
if (body.accepts && Array.isArray(body.accepts) && body.accepts.length > 0) {
|
|
1127
|
-
return { requirements: body.accepts[0], resource: body.resource };
|
|
1128
|
-
}
|
|
1129
|
-
if (body.paymentRequirements) {
|
|
1130
|
-
const pr = Array.isArray(body.paymentRequirements) ? body.paymentRequirements[0] : body.paymentRequirements;
|
|
1131
|
-
return { requirements: pr, resource: body.resource };
|
|
1132
|
-
}
|
|
1133
|
-
if (body.scheme && body.network) {
|
|
1134
|
-
return { requirements: body, resource: body.resource };
|
|
1135
|
-
}
|
|
1136
|
-
} catch {
|
|
1137
|
-
}
|
|
1138
|
-
const wwwAuth = response.headers.get("WWW-Authenticate");
|
|
1139
|
-
if (wwwAuth) {
|
|
1140
|
-
const m = wwwAuth.match(/x402[^"]*"([^"]+)"/);
|
|
1141
|
-
if (m) {
|
|
1142
|
-
try {
|
|
1143
|
-
const decoded = JSON.parse(Buffer.from(m[1], "base64").toString("utf-8"));
|
|
1144
|
-
const reqs = Array.isArray(decoded) ? decoded[0] : decoded;
|
|
1145
|
-
return { requirements: reqs };
|
|
1146
|
-
} catch {
|
|
1147
|
-
}
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
return null;
|
|
1151
|
-
}
|
|
1152
|
-
// ──────────── Build x402 v2 PaymentPayload with EIP-3009 ────────────
|
|
1153
|
-
//
|
|
1154
|
-
// If an AgentAccount is configured, we use it as the `from` address
|
|
1155
|
-
// (smart wallet pays directly). The AgentAccount implements EIP-1271
|
|
1156
|
-
// so USDC's transferWithAuthorization will call isValidSignature()
|
|
1157
|
-
// to verify the owner's ECDSA signature. The facilitator detects
|
|
1158
|
-
// the >65-byte or smart-wallet case and uses the bytes overload.
|
|
1159
|
-
async buildPaymentPayload(reqs, resource, url) {
|
|
1160
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
1161
|
-
const validAfter = String(now - 60);
|
|
1162
|
-
const validBefore = String(now + (reqs.maxTimeoutSeconds || 300));
|
|
1163
|
-
const nonce = ethers3.hexlify(ethers3.randomBytes(32));
|
|
1164
|
-
const chainId = chainIdFromNetwork(reqs.network);
|
|
1165
|
-
const usdcDomain = USDC_DOMAINS[reqs.network] || USDC_DOMAINS["eip155:1"];
|
|
1166
|
-
const payerAddress = this.config.accountAddress || this.wallet.address;
|
|
1167
|
-
const isSmartWallet = !!this.config.accountAddress;
|
|
1168
|
-
const domain = {
|
|
1169
|
-
name: usdcDomain.name,
|
|
1170
|
-
version: usdcDomain.version,
|
|
1171
|
-
chainId,
|
|
1172
|
-
verifyingContract: reqs.asset || usdcDomain.address
|
|
1173
|
-
};
|
|
1174
|
-
const types = {
|
|
1175
|
-
TransferWithAuthorization: [
|
|
1176
|
-
{ name: "from", type: "address" },
|
|
1177
|
-
{ name: "to", type: "address" },
|
|
1178
|
-
{ name: "value", type: "uint256" },
|
|
1179
|
-
{ name: "validAfter", type: "uint256" },
|
|
1180
|
-
{ name: "validBefore", type: "uint256" },
|
|
1181
|
-
{ name: "nonce", type: "bytes32" }
|
|
1182
|
-
]
|
|
1183
|
-
};
|
|
1184
|
-
const value = {
|
|
1185
|
-
from: payerAddress,
|
|
1186
|
-
// AgentAccount or EOA
|
|
1187
|
-
to: reqs.payTo,
|
|
1188
|
-
value: reqs.amount,
|
|
1189
|
-
validAfter,
|
|
1190
|
-
validBefore,
|
|
1191
|
-
nonce
|
|
1192
|
-
};
|
|
1193
|
-
let signature = await this.wallet.signTypedData(domain, types, value);
|
|
1194
|
-
if (isSmartWallet) {
|
|
1195
|
-
signature = signature + "00";
|
|
1196
|
-
}
|
|
1197
|
-
if (isSmartWallet) {
|
|
1198
|
-
console.log(` \u2713 Signed for AgentAccount ${payerAddress.slice(0, 10)}\u2026 (EIP-1271, chain=${chainId})`);
|
|
1199
|
-
} else {
|
|
1200
|
-
console.log(` \u2713 Signed (from=${payerAddress.slice(0, 10)}\u2026, chain=${chainId})`);
|
|
1201
|
-
}
|
|
1202
|
-
return {
|
|
1203
|
-
x402Version: 2,
|
|
1204
|
-
resource: resource || { url, description: "", mimeType: "application/json" },
|
|
1205
|
-
accepted: {
|
|
1206
|
-
scheme: reqs.scheme,
|
|
1207
|
-
network: reqs.network,
|
|
1208
|
-
amount: reqs.amount,
|
|
1209
|
-
asset: reqs.asset,
|
|
1210
|
-
payTo: reqs.payTo,
|
|
1211
|
-
maxTimeoutSeconds: reqs.maxTimeoutSeconds,
|
|
1212
|
-
extra: reqs.extra || {}
|
|
1213
|
-
},
|
|
1214
|
-
payload: {
|
|
1215
|
-
signature,
|
|
1216
|
-
authorization: {
|
|
1217
|
-
from: payerAddress,
|
|
1218
|
-
// AgentAccount address — facilitator checks balance here
|
|
1219
|
-
to: reqs.payTo,
|
|
1220
|
-
value: reqs.amount,
|
|
1221
|
-
validAfter,
|
|
1222
|
-
validBefore,
|
|
1223
|
-
nonce
|
|
1224
|
-
}
|
|
1225
|
-
}
|
|
1226
|
-
};
|
|
1227
|
-
}
|
|
1228
|
-
// ──────────── Risk check via our backend ────────────
|
|
1229
|
-
async riskCheck(paymentPayload, reqs) {
|
|
1230
|
-
try {
|
|
1231
|
-
const verifyUrl = `${this.config.backendUrl}/x402/verify`;
|
|
1232
|
-
const resp = await fetch(verifyUrl, {
|
|
1233
|
-
method: "POST",
|
|
1234
|
-
headers: {
|
|
1235
|
-
"Content-Type": "application/json",
|
|
1236
|
-
"X-Agent-Id": this.config.agentId || "",
|
|
1237
|
-
...this.config.accountAddress ? { "X-Agent-Account": this.config.accountAddress } : {}
|
|
1238
|
-
},
|
|
1239
|
-
body: JSON.stringify({
|
|
1240
|
-
x402Version: 2,
|
|
1241
|
-
paymentPayload,
|
|
1242
|
-
paymentRequirements: reqs
|
|
1243
|
-
}),
|
|
1244
|
-
signal: AbortSignal.timeout(5e3)
|
|
1245
|
-
});
|
|
1246
|
-
if (resp.ok) {
|
|
1247
|
-
const result = await resp.json();
|
|
1248
|
-
const decision = resp.headers.get("X-Risk-Decision") || (result.isValid ? "allow" : "unknown");
|
|
1249
|
-
const score = resp.headers.get("X-Risk-Score") || "?";
|
|
1250
|
-
console.log(` \u2713 Risk check: ${decision} (score=${score})`);
|
|
1251
|
-
} else {
|
|
1252
|
-
console.log(` \u26A0 Risk check failed (HTTP ${resp.status}) \u2014 continuing anyway`);
|
|
1253
|
-
}
|
|
1254
|
-
} catch {
|
|
1255
|
-
console.log(" \u26A0 Risk check unavailable \u2014 continuing");
|
|
1256
|
-
}
|
|
1257
|
-
}
|
|
1258
|
-
};
|
|
1259
|
-
|
|
1260
201
|
// src/clients/ScoringClient.ts
|
|
202
|
+
import axios from "axios";
|
|
1261
203
|
var ScoringClient = class {
|
|
1262
204
|
constructor(config) {
|
|
1263
205
|
this.endpoint = config.endpoint;
|
|
1264
|
-
this.client =
|
|
206
|
+
this.client = axios.create({
|
|
1265
207
|
baseURL: config.endpoint,
|
|
1266
208
|
headers: { "Content-Type": "application/json" },
|
|
1267
209
|
timeout: 3e4
|
|
@@ -1348,7 +290,7 @@ var ScoringClient = class {
|
|
|
1348
290
|
};
|
|
1349
291
|
|
|
1350
292
|
// src/clients/AgentIdentityClient.ts
|
|
1351
|
-
import { ethers as
|
|
293
|
+
import { ethers as ethers2 } from "ethers";
|
|
1352
294
|
var ERC8004_IDENTITY_ABI = [
|
|
1353
295
|
// Registration
|
|
1354
296
|
"function register() returns (uint256)",
|
|
@@ -1390,8 +332,8 @@ var AgentIdentityClient = class {
|
|
|
1390
332
|
this.signer = options.signer;
|
|
1391
333
|
const identityAddr = options.config.contracts?.identityRegistry || ERC8004_SEPOLIA.identityRegistry;
|
|
1392
334
|
const reputationAddr = options.config.contracts?.reputationRegistry || ERC8004_SEPOLIA.reputationRegistry;
|
|
1393
|
-
this.identityRegistry = new
|
|
1394
|
-
this.reputationRegistry = new
|
|
335
|
+
this.identityRegistry = new ethers2.Contract(identityAddr, ERC8004_IDENTITY_ABI, this.signer);
|
|
336
|
+
this.reputationRegistry = new ethers2.Contract(reputationAddr, ERC8004_REPUTATION_ABI, this.signer);
|
|
1395
337
|
}
|
|
1396
338
|
// ============ Identity Functions ============
|
|
1397
339
|
/**
|
|
@@ -1458,7 +400,7 @@ var AgentIdentityClient = class {
|
|
|
1458
400
|
async registerWithMetadata(agentURI, metadata) {
|
|
1459
401
|
const metadataEntries = metadata.map((m) => ({
|
|
1460
402
|
key: m.key,
|
|
1461
|
-
value:
|
|
403
|
+
value: ethers2.toUtf8Bytes(m.value)
|
|
1462
404
|
}));
|
|
1463
405
|
const tx = await this.identityRegistry["register(string,tuple(string,bytes)[])"](
|
|
1464
406
|
agentURI,
|
|
@@ -1495,7 +437,7 @@ var AgentIdentityClient = class {
|
|
|
1495
437
|
const tx = await this.identityRegistry.setMetadata(
|
|
1496
438
|
agentId,
|
|
1497
439
|
key,
|
|
1498
|
-
|
|
440
|
+
ethers2.toUtf8Bytes(value)
|
|
1499
441
|
);
|
|
1500
442
|
const receipt = await tx.wait();
|
|
1501
443
|
return receipt.hash;
|
|
@@ -1505,7 +447,7 @@ var AgentIdentityClient = class {
|
|
|
1505
447
|
*/
|
|
1506
448
|
async getMetadata(agentId, key) {
|
|
1507
449
|
const value = await this.identityRegistry.getMetadata(agentId, key);
|
|
1508
|
-
return
|
|
450
|
+
return ethers2.toUtf8String(value);
|
|
1509
451
|
}
|
|
1510
452
|
/**
|
|
1511
453
|
* Transfer agent to new owner
|
|
@@ -1539,8 +481,8 @@ var AgentIdentityClient = class {
|
|
|
1539
481
|
* Give feedback to an agent
|
|
1540
482
|
*/
|
|
1541
483
|
async giveFeedback(input) {
|
|
1542
|
-
const feedbackHash =
|
|
1543
|
-
|
|
484
|
+
const feedbackHash = ethers2.keccak256(
|
|
485
|
+
ethers2.AbiCoder.defaultAbiCoder().encode(
|
|
1544
486
|
["uint256", "int128", "uint256"],
|
|
1545
487
|
[input.agentId, input.value, Date.now()]
|
|
1546
488
|
)
|