@exagent/sdk 0.1.21 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +14 -0
- package/dist/index.d.ts +440 -2082
- package/dist/index.js +67 -2147
- package/package.json +7 -20
- package/src/client.ts +79 -0
- package/src/index.ts +48 -0
- package/src/types.ts +468 -0
- package/tsconfig.json +8 -0
- package/dist/index.d.mts +0 -2131
- package/dist/index.mjs +0 -2136
package/dist/index.js
CHANGED
|
@@ -1,2168 +1,88 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/index.ts
|
|
21
|
-
var index_exports = {};
|
|
22
|
-
__export(index_exports, {
|
|
23
|
-
CHAIN_CONFIG: () => CHAIN_CONFIG,
|
|
24
|
-
CONTRACT_ADDRESSES: () => CONTRACT_ADDRESSES,
|
|
25
|
-
DEFAULT_RPC_URL: () => DEFAULT_RPC_URL,
|
|
26
|
-
DEX_ADDRESSES: () => DEX_ADDRESSES,
|
|
27
|
-
EXAGENT_API_CONFIG: () => EXAGENT_API_CONFIG,
|
|
28
|
-
EXAGENT_REGISTRY_ABI: () => EXAGENT_REGISTRY_ABI,
|
|
29
|
-
EXAGENT_ROUTER_ABI: () => EXAGENT_ROUTER_ABI,
|
|
30
|
-
EXAGENT_VAULT_FACTORY_ABI: () => EXAGENT_VAULT_FACTORY_ABI,
|
|
31
|
-
ExagentClient: () => ExagentClient,
|
|
32
|
-
ExagentRegistry: () => ExagentRegistry,
|
|
33
|
-
ExagentVault: () => ExagentVault,
|
|
34
|
-
ExagentVaultFactory: () => ExagentVaultFactory,
|
|
35
|
-
SDK_VERSION: () => SDK_VERSION,
|
|
36
|
-
ZERO_X_CONFIG: () => ZERO_X_CONFIG,
|
|
37
|
-
buildGlobalAgentId: () => buildGlobalAgentId,
|
|
38
|
-
getRpcUrl: () => getRpcUrl,
|
|
39
|
-
parseGlobalAgentId: () => parseGlobalAgentId
|
|
40
|
-
});
|
|
41
|
-
module.exports = __toCommonJS(index_exports);
|
|
42
|
-
|
|
43
|
-
// src/client.ts
|
|
44
|
-
var import_viem2 = require("viem");
|
|
45
|
-
var import_accounts = require("viem/accounts");
|
|
46
|
-
|
|
47
|
-
// src/contracts/registry.ts
|
|
48
|
-
var import_viem = require("viem");
|
|
49
|
-
var EXAGENT_REGISTRY_ABI = [
|
|
50
|
-
{
|
|
51
|
-
type: "function",
|
|
52
|
-
name: "registerAgent",
|
|
53
|
-
inputs: [
|
|
54
|
-
{ name: "name", type: "string" },
|
|
55
|
-
{ name: "metadataURI", type: "string" },
|
|
56
|
-
{ name: "riskUniverse", type: "uint8" },
|
|
57
|
-
{ name: "maxPositionSizeBps", type: "uint256" },
|
|
58
|
-
{ name: "maxDailyLossBps", type: "uint256" }
|
|
59
|
-
],
|
|
60
|
-
outputs: [{ name: "agentId", type: "uint256" }],
|
|
61
|
-
stateMutability: "nonpayable"
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
type: "function",
|
|
65
|
-
name: "isNameAvailable",
|
|
66
|
-
inputs: [{ name: "name", type: "string" }],
|
|
67
|
-
outputs: [{ name: "available", type: "bool" }],
|
|
68
|
-
stateMutability: "view"
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
type: "function",
|
|
72
|
-
name: "getAgentByName",
|
|
73
|
-
inputs: [{ name: "name", type: "string" }],
|
|
74
|
-
outputs: [{ name: "agentId", type: "uint256" }],
|
|
75
|
-
stateMutability: "view"
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
type: "function",
|
|
79
|
-
name: "linkWallet",
|
|
80
|
-
inputs: [
|
|
81
|
-
{ name: "agentId", type: "uint256" },
|
|
82
|
-
{ name: "wallet", type: "address" },
|
|
83
|
-
{ name: "signature", type: "bytes" }
|
|
84
|
-
],
|
|
85
|
-
outputs: [],
|
|
86
|
-
stateMutability: "nonpayable"
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
type: "function",
|
|
90
|
-
name: "linkOwnWallet",
|
|
91
|
-
inputs: [{ name: "agentId", type: "uint256" }],
|
|
92
|
-
outputs: [],
|
|
93
|
-
stateMutability: "nonpayable"
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
type: "function",
|
|
97
|
-
name: "unlinkWallet",
|
|
98
|
-
inputs: [
|
|
99
|
-
{ name: "agentId", type: "uint256" },
|
|
100
|
-
{ name: "wallet", type: "address" }
|
|
101
|
-
],
|
|
102
|
-
outputs: [],
|
|
103
|
-
stateMutability: "nonpayable"
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
type: "function",
|
|
107
|
-
name: "updateMetadata",
|
|
108
|
-
inputs: [
|
|
109
|
-
{ name: "agentId", type: "uint256" },
|
|
110
|
-
{ name: "newURI", type: "string" }
|
|
111
|
-
],
|
|
112
|
-
outputs: [],
|
|
113
|
-
stateMutability: "nonpayable"
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
type: "function",
|
|
117
|
-
name: "agents",
|
|
118
|
-
inputs: [{ name: "agentId", type: "uint256" }],
|
|
119
|
-
outputs: [
|
|
120
|
-
{ name: "owner", type: "address" },
|
|
121
|
-
{ name: "name", type: "string" },
|
|
122
|
-
{ name: "metadataURI", type: "string" },
|
|
123
|
-
{ name: "registrationTime", type: "uint256" },
|
|
124
|
-
{ name: "verified", type: "bool" },
|
|
125
|
-
{ name: "linkedWalletCount", type: "uint256" }
|
|
126
|
-
],
|
|
127
|
-
stateMutability: "view"
|
|
128
|
-
},
|
|
129
|
-
{
|
|
130
|
-
type: "function",
|
|
131
|
-
name: "getLinkedWallets",
|
|
132
|
-
inputs: [{ name: "agentId", type: "uint256" }],
|
|
133
|
-
outputs: [{ name: "", type: "address[]" }],
|
|
134
|
-
stateMutability: "view"
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
type: "function",
|
|
138
|
-
name: "getAgentForWallet",
|
|
139
|
-
inputs: [{ name: "wallet", type: "address" }],
|
|
140
|
-
outputs: [{ name: "", type: "uint256" }],
|
|
141
|
-
stateMutability: "view"
|
|
142
|
-
},
|
|
143
|
-
{
|
|
144
|
-
type: "function",
|
|
145
|
-
name: "walletToAgent",
|
|
146
|
-
inputs: [{ name: "wallet", type: "address" }],
|
|
147
|
-
outputs: [{ name: "", type: "uint256" }],
|
|
148
|
-
stateMutability: "view"
|
|
149
|
-
},
|
|
150
|
-
{
|
|
151
|
-
type: "function",
|
|
152
|
-
name: "nonces",
|
|
153
|
-
inputs: [{ name: "wallet", type: "address" }],
|
|
154
|
-
outputs: [{ name: "", type: "uint256" }],
|
|
155
|
-
stateMutability: "view"
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
type: "function",
|
|
159
|
-
name: "ownerOf",
|
|
160
|
-
inputs: [{ name: "tokenId", type: "uint256" }],
|
|
161
|
-
outputs: [{ name: "", type: "address" }],
|
|
162
|
-
stateMutability: "view"
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
type: "function",
|
|
166
|
-
name: "balanceOf",
|
|
167
|
-
inputs: [{ name: "owner", type: "address" }],
|
|
168
|
-
outputs: [{ name: "", type: "uint256" }],
|
|
169
|
-
stateMutability: "view"
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
type: "event",
|
|
173
|
-
name: "AgentRegistered",
|
|
174
|
-
inputs: [
|
|
175
|
-
{ name: "agentId", type: "uint256", indexed: true },
|
|
176
|
-
{ name: "owner", type: "address", indexed: true },
|
|
177
|
-
{ name: "name", type: "string", indexed: false },
|
|
178
|
-
{ name: "metadataURI", type: "string", indexed: false }
|
|
179
|
-
]
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
type: "event",
|
|
183
|
-
name: "WalletLinked",
|
|
184
|
-
inputs: [
|
|
185
|
-
{ name: "agentId", type: "uint256", indexed: true },
|
|
186
|
-
{ name: "wallet", type: "address", indexed: true }
|
|
187
|
-
]
|
|
188
|
-
},
|
|
189
|
-
{
|
|
190
|
-
type: "event",
|
|
191
|
-
name: "WalletUnlinked",
|
|
192
|
-
inputs: [
|
|
193
|
-
{ name: "agentId", type: "uint256", indexed: true },
|
|
194
|
-
{ name: "wallet", type: "address", indexed: true }
|
|
195
|
-
]
|
|
196
|
-
},
|
|
197
|
-
// V4: One agent per wallet
|
|
198
|
-
{
|
|
199
|
-
type: "function",
|
|
200
|
-
name: "ownerToAgentId",
|
|
201
|
-
inputs: [{ name: "owner", type: "address" }],
|
|
202
|
-
outputs: [{ name: "", type: "uint256" }],
|
|
203
|
-
stateMutability: "view"
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
type: "function",
|
|
207
|
-
name: "getAgentByOwner",
|
|
208
|
-
inputs: [{ name: "wallet", type: "address" }],
|
|
209
|
-
outputs: [{ name: "agentId", type: "uint256" }],
|
|
210
|
-
stateMutability: "view"
|
|
211
|
-
},
|
|
212
|
-
{
|
|
213
|
-
type: "function",
|
|
214
|
-
name: "canWalletRegister",
|
|
215
|
-
inputs: [{ name: "wallet", type: "address" }],
|
|
216
|
-
outputs: [
|
|
217
|
-
{ name: "canRegister", type: "bool" },
|
|
218
|
-
{ name: "existingAgentId", type: "uint256" }
|
|
219
|
-
],
|
|
220
|
-
stateMutability: "view"
|
|
221
|
-
},
|
|
222
|
-
// Config Epochs
|
|
223
|
-
{
|
|
224
|
-
type: "function",
|
|
225
|
-
name: "setConfig",
|
|
226
|
-
inputs: [
|
|
227
|
-
{ name: "agentId", type: "uint256" },
|
|
228
|
-
{ name: "configHash", type: "bytes32" }
|
|
229
|
-
],
|
|
230
|
-
outputs: [],
|
|
231
|
-
stateMutability: "nonpayable"
|
|
232
|
-
},
|
|
233
|
-
{
|
|
234
|
-
type: "function",
|
|
235
|
-
name: "getConfigHash",
|
|
236
|
-
inputs: [{ name: "agentId", type: "uint256" }],
|
|
237
|
-
outputs: [{ name: "", type: "bytes32" }],
|
|
238
|
-
stateMutability: "view"
|
|
239
|
-
},
|
|
240
|
-
// Mainnet: Agent retirement
|
|
241
|
-
{
|
|
242
|
-
type: "function",
|
|
243
|
-
name: "retireAgent",
|
|
244
|
-
inputs: [{ name: "agentId", type: "uint256" }],
|
|
245
|
-
outputs: [],
|
|
246
|
-
stateMutability: "nonpayable"
|
|
247
|
-
},
|
|
248
|
-
{
|
|
249
|
-
type: "function",
|
|
250
|
-
name: "retired",
|
|
251
|
-
inputs: [{ name: "agentId", type: "uint256" }],
|
|
252
|
-
outputs: [{ type: "bool" }],
|
|
253
|
-
stateMutability: "view"
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
type: "function",
|
|
257
|
-
name: "isRetired",
|
|
258
|
-
inputs: [{ name: "agentId", type: "uint256" }],
|
|
259
|
-
outputs: [{ type: "bool" }],
|
|
260
|
-
stateMutability: "view"
|
|
261
|
-
},
|
|
262
|
-
// Mainnet: Risk universe token whitelists
|
|
263
|
-
{
|
|
264
|
-
type: "function",
|
|
265
|
-
name: "isTradeAllowed",
|
|
266
|
-
inputs: [
|
|
267
|
-
{ name: "agentId", type: "uint256" },
|
|
268
|
-
{ name: "token", type: "address" },
|
|
269
|
-
{ name: "aggregator", type: "address" }
|
|
270
|
-
],
|
|
271
|
-
outputs: [{ type: "bool" }],
|
|
272
|
-
stateMutability: "view"
|
|
273
|
-
},
|
|
274
|
-
{
|
|
275
|
-
type: "function",
|
|
276
|
-
name: "getRiskUniverse",
|
|
277
|
-
inputs: [{ name: "agentId", type: "uint256" }],
|
|
278
|
-
outputs: [{ type: "uint8" }],
|
|
279
|
-
stateMutability: "view"
|
|
280
|
-
},
|
|
281
|
-
{
|
|
282
|
-
type: "function",
|
|
283
|
-
name: "tradeCount",
|
|
284
|
-
inputs: [{ name: "agentId", type: "uint256" }],
|
|
285
|
-
outputs: [{ type: "uint256" }],
|
|
286
|
-
stateMutability: "view"
|
|
287
|
-
},
|
|
288
|
-
// Events
|
|
289
|
-
{
|
|
290
|
-
type: "event",
|
|
291
|
-
name: "AgentRetired",
|
|
292
|
-
inputs: [
|
|
293
|
-
{ name: "agentId", type: "uint256", indexed: true }
|
|
294
|
-
]
|
|
295
|
-
},
|
|
296
|
-
{
|
|
297
|
-
type: "event",
|
|
298
|
-
name: "ConfigUpdated",
|
|
299
|
-
inputs: [
|
|
300
|
-
{ name: "agentId", type: "uint256", indexed: true },
|
|
301
|
-
{ name: "oldConfigHash", type: "bytes32", indexed: false },
|
|
302
|
-
{ name: "newConfigHash", type: "bytes32", indexed: false },
|
|
303
|
-
{ name: "epochId", type: "uint256", indexed: false },
|
|
304
|
-
{ name: "blockNumber", type: "uint256", indexed: false }
|
|
305
|
-
]
|
|
306
|
-
},
|
|
307
|
-
// Custom errors — must match ExagentRegistry.sol for viem to decode reverts
|
|
308
|
-
{ type: "error", name: "AgentNotOwner", inputs: [] },
|
|
309
|
-
{ type: "error", name: "WalletAlreadyLinked", inputs: [] },
|
|
310
|
-
{ type: "error", name: "WalletNotLinked", inputs: [] },
|
|
311
|
-
{ type: "error", name: "InvalidSignature", inputs: [] },
|
|
312
|
-
{ type: "error", name: "TransferDisabled", inputs: [] },
|
|
313
|
-
{ type: "error", name: "InvalidMetadataURI", inputs: [] },
|
|
314
|
-
{ type: "error", name: "AgentDoesNotExist", inputs: [] },
|
|
315
|
-
{ type: "error", name: "NameAlreadyTaken", inputs: [] },
|
|
316
|
-
{ type: "error", name: "InvalidName", inputs: [] },
|
|
317
|
-
{ type: "error", name: "OwnerAlreadyHasAgent", inputs: [{ name: "existingAgentId", type: "uint256" }] },
|
|
318
|
-
{ type: "error", name: "InvalidRiskUniverse", inputs: [] },
|
|
319
|
-
{ type: "error", name: "InvalidTradingConfig", inputs: [] },
|
|
320
|
-
{ type: "error", name: "NotAuthorizedCaller", inputs: [] },
|
|
321
|
-
{ type: "error", name: "MetadataValueTooLarge", inputs: [] },
|
|
322
|
-
{ type: "error", name: "AgentIsRetired", inputs: [] },
|
|
323
|
-
{ type: "error", name: "InvalidRiskUniverseForWhitelist", inputs: [] }
|
|
324
|
-
];
|
|
325
|
-
var ExagentRegistry = class {
|
|
326
|
-
address;
|
|
327
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
328
|
-
publicClient;
|
|
329
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
330
|
-
walletClient;
|
|
331
|
-
chain;
|
|
332
|
-
account;
|
|
333
|
-
constructor(address, publicClient, walletClient, chain, account) {
|
|
334
|
-
this.address = address;
|
|
335
|
-
this.publicClient = publicClient;
|
|
336
|
-
this.walletClient = walletClient;
|
|
337
|
-
this.chain = chain;
|
|
338
|
-
this.account = account;
|
|
339
|
-
}
|
|
340
|
-
/**
|
|
341
|
-
* Register a new agent
|
|
342
|
-
* @param name Unique agent name (3-32 chars, alphanumeric + spaces/hyphens/underscores)
|
|
343
|
-
* @param metadataURI IPFS URI for agent metadata
|
|
344
|
-
* @param riskUniverse Risk tier: 0=Core, 1=Established, 2=Derivatives, 3=Emerging, 4=Frontier
|
|
345
|
-
* @param maxPositionSizeBps Maximum position size in basis points (1-10000)
|
|
346
|
-
* @param maxDailyLossBps Maximum daily loss in basis points (1-10000)
|
|
347
|
-
* @returns Transaction hash
|
|
348
|
-
*/
|
|
349
|
-
async register(name, metadataURI, riskUniverse = 1, maxPositionSizeBps = 1000n, maxDailyLossBps = 500n) {
|
|
350
|
-
if (!this.walletClient || !this.account) throw new Error("Wallet client and account required for write operations");
|
|
351
|
-
const hash = await this.walletClient.writeContract({
|
|
352
|
-
account: this.account,
|
|
353
|
-
chain: this.chain,
|
|
354
|
-
address: this.address,
|
|
355
|
-
abi: EXAGENT_REGISTRY_ABI,
|
|
356
|
-
functionName: "registerAgent",
|
|
357
|
-
args: [name, metadataURI, riskUniverse, maxPositionSizeBps, maxDailyLossBps]
|
|
358
|
-
});
|
|
359
|
-
return hash;
|
|
360
|
-
}
|
|
361
|
-
/**
|
|
362
|
-
* Check if a name is available for registration
|
|
363
|
-
* @param name The name to check
|
|
364
|
-
* @returns True if the name can be used
|
|
365
|
-
*/
|
|
366
|
-
async isNameAvailable(name) {
|
|
367
|
-
const available = await this.publicClient.readContract({
|
|
368
|
-
address: this.address,
|
|
369
|
-
abi: EXAGENT_REGISTRY_ABI,
|
|
370
|
-
functionName: "isNameAvailable",
|
|
371
|
-
args: [name]
|
|
372
|
-
});
|
|
373
|
-
return available;
|
|
374
|
-
}
|
|
375
|
-
/**
|
|
376
|
-
* Get the agent ID that owns a specific name
|
|
377
|
-
* @param name The name to look up
|
|
378
|
-
* @returns Agent ID (0 if not taken)
|
|
379
|
-
*/
|
|
380
|
-
async getAgentByName(name) {
|
|
381
|
-
const agentId = await this.publicClient.readContract({
|
|
382
|
-
address: this.address,
|
|
383
|
-
abi: EXAGENT_REGISTRY_ABI,
|
|
384
|
-
functionName: "getAgentByName",
|
|
385
|
-
args: [name]
|
|
386
|
-
});
|
|
387
|
-
return agentId;
|
|
388
|
-
}
|
|
389
|
-
/**
|
|
390
|
-
* Link the wallet used by the agent to their agent ID
|
|
391
|
-
* @param agentId The agent's ID
|
|
392
|
-
* @returns Transaction hash
|
|
393
|
-
*/
|
|
394
|
-
async linkOwnWallet(agentId) {
|
|
395
|
-
if (!this.walletClient || !this.account) throw new Error("Wallet client and account required for write operations");
|
|
396
|
-
const hash = await this.walletClient.writeContract({
|
|
397
|
-
account: this.account,
|
|
398
|
-
chain: this.chain,
|
|
399
|
-
address: this.address,
|
|
400
|
-
abi: EXAGENT_REGISTRY_ABI,
|
|
401
|
-
functionName: "linkOwnWallet",
|
|
402
|
-
args: [agentId]
|
|
403
|
-
});
|
|
404
|
-
return hash;
|
|
405
|
-
}
|
|
406
|
-
/**
|
|
407
|
-
* Link an external wallet with signature proof
|
|
408
|
-
* @param agentId The agent's ID
|
|
409
|
-
* @param wallet The wallet to link
|
|
410
|
-
* @param signature Signature from the wallet proving ownership
|
|
411
|
-
* @returns Transaction hash
|
|
412
|
-
*/
|
|
413
|
-
async linkWallet(agentId, wallet, signature) {
|
|
414
|
-
if (!this.walletClient || !this.account) throw new Error("Wallet client and account required for write operations");
|
|
415
|
-
const hash = await this.walletClient.writeContract({
|
|
416
|
-
account: this.account,
|
|
417
|
-
chain: this.chain,
|
|
418
|
-
address: this.address,
|
|
419
|
-
abi: EXAGENT_REGISTRY_ABI,
|
|
420
|
-
functionName: "linkWallet",
|
|
421
|
-
args: [agentId, wallet, signature]
|
|
422
|
-
});
|
|
423
|
-
return hash;
|
|
424
|
-
}
|
|
425
|
-
/**
|
|
426
|
-
* Unlink a wallet from an agent
|
|
427
|
-
* @param agentId The agent's ID
|
|
428
|
-
* @param wallet The wallet to unlink
|
|
429
|
-
* @returns Transaction hash
|
|
430
|
-
*/
|
|
431
|
-
async unlinkWallet(agentId, wallet) {
|
|
432
|
-
if (!this.walletClient || !this.account) throw new Error("Wallet client and account required for write operations");
|
|
433
|
-
const hash = await this.walletClient.writeContract({
|
|
434
|
-
account: this.account,
|
|
435
|
-
chain: this.chain,
|
|
436
|
-
address: this.address,
|
|
437
|
-
abi: EXAGENT_REGISTRY_ABI,
|
|
438
|
-
functionName: "unlinkWallet",
|
|
439
|
-
args: [agentId, wallet]
|
|
440
|
-
});
|
|
441
|
-
return hash;
|
|
442
|
-
}
|
|
443
|
-
/**
|
|
444
|
-
* Update agent metadata
|
|
445
|
-
* @param agentId The agent's ID
|
|
446
|
-
* @param newURI New IPFS URI for metadata
|
|
447
|
-
* @returns Transaction hash
|
|
448
|
-
*/
|
|
449
|
-
async updateMetadata(agentId, newURI) {
|
|
450
|
-
if (!this.walletClient || !this.account) throw new Error("Wallet client and account required for write operations");
|
|
451
|
-
const hash = await this.walletClient.writeContract({
|
|
452
|
-
account: this.account,
|
|
453
|
-
chain: this.chain,
|
|
454
|
-
address: this.address,
|
|
455
|
-
abi: EXAGENT_REGISTRY_ABI,
|
|
456
|
-
functionName: "updateMetadata",
|
|
457
|
-
args: [agentId, newURI]
|
|
458
|
-
});
|
|
459
|
-
return hash;
|
|
460
|
-
}
|
|
461
|
-
/**
|
|
462
|
-
* Get agent profile by ID
|
|
463
|
-
* @param agentId The agent's ID
|
|
464
|
-
* @returns Agent profile data
|
|
465
|
-
*/
|
|
466
|
-
async getAgent(agentId) {
|
|
467
|
-
const result = await this.publicClient.readContract({
|
|
468
|
-
address: this.address,
|
|
469
|
-
abi: EXAGENT_REGISTRY_ABI,
|
|
470
|
-
functionName: "agents",
|
|
471
|
-
args: [agentId]
|
|
472
|
-
});
|
|
473
|
-
return {
|
|
474
|
-
agentId,
|
|
475
|
-
owner: result[0],
|
|
476
|
-
name: result[1],
|
|
477
|
-
metadataURI: result[2],
|
|
478
|
-
registrationTime: result[3],
|
|
479
|
-
verified: result[4],
|
|
480
|
-
linkedWalletCount: result[5]
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
|
-
/**
|
|
484
|
-
* Get all linked wallets for an agent
|
|
485
|
-
* @param agentId The agent's ID
|
|
486
|
-
* @returns Array of linked wallet addresses
|
|
487
|
-
*/
|
|
488
|
-
async getLinkedWallets(agentId) {
|
|
489
|
-
const wallets = await this.publicClient.readContract({
|
|
490
|
-
address: this.address,
|
|
491
|
-
abi: EXAGENT_REGISTRY_ABI,
|
|
492
|
-
functionName: "getLinkedWallets",
|
|
493
|
-
args: [agentId]
|
|
494
|
-
});
|
|
495
|
-
return wallets;
|
|
496
|
-
}
|
|
497
|
-
/**
|
|
498
|
-
* Get agent ID for a wallet (for trade attribution)
|
|
499
|
-
* @param wallet The wallet address
|
|
500
|
-
* @returns Agent ID (0 if not linked)
|
|
501
|
-
*/
|
|
502
|
-
async getAgentForWallet(wallet) {
|
|
503
|
-
const agentId = await this.publicClient.readContract({
|
|
504
|
-
address: this.address,
|
|
505
|
-
abi: EXAGENT_REGISTRY_ABI,
|
|
506
|
-
functionName: "walletToAgent",
|
|
507
|
-
args: [wallet]
|
|
508
|
-
});
|
|
509
|
-
return agentId;
|
|
510
|
-
}
|
|
511
|
-
/**
|
|
512
|
-
* Check if a wallet is linked to a specific agent
|
|
513
|
-
* @param agentId The agent's ID
|
|
514
|
-
* @param wallet The wallet address to check
|
|
515
|
-
* @returns True if the wallet is linked to the agent
|
|
516
|
-
*/
|
|
517
|
-
async isLinkedWallet(agentId, wallet) {
|
|
518
|
-
const linkedWallets = await this.getLinkedWallets(agentId);
|
|
519
|
-
return linkedWallets.some((w) => w.toLowerCase() === wallet.toLowerCase());
|
|
520
|
-
}
|
|
521
|
-
/**
|
|
522
|
-
* Get the nonce for wallet linking signature
|
|
523
|
-
* @param wallet The wallet address
|
|
524
|
-
* @returns Current nonce
|
|
525
|
-
*/
|
|
526
|
-
async getNonce(wallet) {
|
|
527
|
-
const nonce = await this.publicClient.readContract({
|
|
528
|
-
address: this.address,
|
|
529
|
-
abi: EXAGENT_REGISTRY_ABI,
|
|
530
|
-
functionName: "nonces",
|
|
531
|
-
args: [wallet]
|
|
532
|
-
});
|
|
533
|
-
return nonce;
|
|
534
|
-
}
|
|
535
|
-
/**
|
|
536
|
-
* Generate the message hash for wallet linking.
|
|
537
|
-
* Matches the contract's keccak256(abi.encodePacked(...)) exactly.
|
|
538
|
-
* Sign the returned hash with signMessage({ raw: hash }) to produce a valid signature.
|
|
539
|
-
* @param wallet The wallet to link
|
|
540
|
-
* @param agentId The agent ID to link to
|
|
541
|
-
* @param nonce The current nonce for the wallet
|
|
542
|
-
* @returns keccak256 hash of the packed message (32 bytes)
|
|
543
|
-
*/
|
|
544
|
-
static generateLinkMessage(wallet, agentId, nonce) {
|
|
545
|
-
return (0, import_viem.keccak256)((0, import_viem.encodePacked)(
|
|
546
|
-
["string", "address", "string", "uint256", "string", "uint256"],
|
|
547
|
-
["Link wallet ", wallet, " to Exagent ", agentId, " nonce ", nonce]
|
|
548
|
-
));
|
|
549
|
-
}
|
|
550
|
-
// ============ V4: One Agent Per Wallet ============
|
|
551
|
-
/**
|
|
552
|
-
* Get the agent owned by a wallet (not linked, owned)
|
|
553
|
-
* @param wallet The wallet to look up
|
|
554
|
-
* @returns Agent ID (0 if wallet doesn't own an agent)
|
|
555
|
-
*/
|
|
556
|
-
async getAgentByOwner(wallet) {
|
|
557
|
-
const agentId = await this.publicClient.readContract({
|
|
558
|
-
address: this.address,
|
|
559
|
-
abi: EXAGENT_REGISTRY_ABI,
|
|
560
|
-
functionName: "getAgentByOwner",
|
|
561
|
-
args: [wallet]
|
|
562
|
-
});
|
|
563
|
-
return agentId;
|
|
564
|
-
}
|
|
565
|
-
/**
|
|
566
|
-
* Check if a wallet can register a new agent
|
|
567
|
-
* @param wallet The wallet to check
|
|
568
|
-
* @returns Object with canRegister boolean and existingAgentId (0 if none)
|
|
569
|
-
*/
|
|
570
|
-
async canWalletRegister(wallet) {
|
|
571
|
-
const result = await this.publicClient.readContract({
|
|
572
|
-
address: this.address,
|
|
573
|
-
abi: EXAGENT_REGISTRY_ABI,
|
|
574
|
-
functionName: "canWalletRegister",
|
|
575
|
-
args: [wallet]
|
|
576
|
-
});
|
|
577
|
-
const [canRegister, existingAgentId] = result;
|
|
578
|
-
return { canRegister, existingAgentId };
|
|
579
|
-
}
|
|
580
|
-
// ============ Config Epochs ============
|
|
581
|
-
/**
|
|
582
|
-
* Update the agent's LLM config hash on-chain
|
|
583
|
-
* @param agentId The agent's ID
|
|
584
|
-
* @param configHash The keccak256 hash of (provider, model)
|
|
585
|
-
* @returns Transaction hash
|
|
586
|
-
*/
|
|
587
|
-
async updateConfig(agentId, configHash) {
|
|
588
|
-
if (!this.walletClient || !this.account) throw new Error("Wallet client and account required for write operations");
|
|
589
|
-
const hash = await this.walletClient.writeContract({
|
|
590
|
-
account: this.account,
|
|
591
|
-
chain: this.chain,
|
|
592
|
-
address: this.address,
|
|
593
|
-
abi: EXAGENT_REGISTRY_ABI,
|
|
594
|
-
functionName: "setConfig",
|
|
595
|
-
args: [agentId, configHash]
|
|
596
|
-
});
|
|
597
|
-
return hash;
|
|
598
|
-
}
|
|
599
|
-
/**
|
|
600
|
-
* Get the current config hash for an agent
|
|
601
|
-
* @param agentId The agent's ID
|
|
602
|
-
* @returns Config hash (bytes32(0) if never set)
|
|
603
|
-
*/
|
|
604
|
-
async getConfigHash(agentId) {
|
|
605
|
-
const configHash = await this.publicClient.readContract({
|
|
606
|
-
address: this.address,
|
|
607
|
-
abi: EXAGENT_REGISTRY_ABI,
|
|
608
|
-
functionName: "getConfigHash",
|
|
609
|
-
args: [agentId]
|
|
610
|
-
});
|
|
611
|
-
return configHash;
|
|
612
|
-
}
|
|
613
|
-
/**
|
|
614
|
-
* Calculate the config hash for a provider and model
|
|
615
|
-
* @param provider The LLM provider name (e.g., "openai", "anthropic")
|
|
616
|
-
* @param model The model name (e.g., "gpt-4", "claude-opus-4.5")
|
|
617
|
-
* @returns keccak256 hash of the config
|
|
618
|
-
*/
|
|
619
|
-
static calculateConfigHash(provider, model) {
|
|
620
|
-
return (0, import_viem.keccak256)((0, import_viem.encodePacked)(["string", "string"], [provider, model]));
|
|
621
|
-
}
|
|
622
|
-
// ============ Agent Retirement ============
|
|
623
|
-
/**
|
|
624
|
-
* Retire an agent — marks it as retired, unlinks all wallets, allows new agent registration
|
|
625
|
-
* @param agentId The agent's ID
|
|
626
|
-
* @returns Transaction hash
|
|
627
|
-
*/
|
|
628
|
-
async retireAgent(agentId) {
|
|
629
|
-
if (!this.walletClient || !this.account) throw new Error("Wallet client and account required for write operations");
|
|
630
|
-
const hash = await this.walletClient.writeContract({
|
|
631
|
-
account: this.account,
|
|
632
|
-
chain: this.chain,
|
|
633
|
-
address: this.address,
|
|
634
|
-
abi: EXAGENT_REGISTRY_ABI,
|
|
635
|
-
functionName: "retireAgent",
|
|
636
|
-
args: [agentId]
|
|
637
|
-
});
|
|
638
|
-
return hash;
|
|
639
|
-
}
|
|
640
|
-
/**
|
|
641
|
-
* Check if an agent is retired
|
|
642
|
-
* @param agentId The agent's ID
|
|
643
|
-
* @returns True if agent is retired
|
|
644
|
-
*/
|
|
645
|
-
async isRetired(agentId) {
|
|
646
|
-
const result = await this.publicClient.readContract({
|
|
647
|
-
address: this.address,
|
|
648
|
-
abi: EXAGENT_REGISTRY_ABI,
|
|
649
|
-
functionName: "isRetired",
|
|
650
|
-
args: [agentId]
|
|
651
|
-
});
|
|
652
|
-
return result;
|
|
653
|
-
}
|
|
654
|
-
// ============ Risk Universe Token Eligibility ============
|
|
655
|
-
/**
|
|
656
|
-
* Check if a token trade is allowed for an agent's risk universe
|
|
657
|
-
* @param agentId The agent's ID
|
|
658
|
-
* @param token The token address to check
|
|
659
|
-
* @param aggregator The aggregator being used (for trusted aggregator bypass)
|
|
660
|
-
* @returns True if the trade is allowed
|
|
661
|
-
*/
|
|
662
|
-
async isTradeAllowed(agentId, token, aggregator) {
|
|
663
|
-
const result = await this.publicClient.readContract({
|
|
664
|
-
address: this.address,
|
|
665
|
-
abi: EXAGENT_REGISTRY_ABI,
|
|
666
|
-
functionName: "isTradeAllowed",
|
|
667
|
-
args: [agentId, token, aggregator]
|
|
668
|
-
});
|
|
669
|
-
return result;
|
|
670
|
-
}
|
|
671
|
-
/**
|
|
672
|
-
* Get the risk universe for an agent
|
|
673
|
-
* @param agentId The agent's ID
|
|
674
|
-
* @returns Risk universe (0=Core, 1=Established, 2=Derivatives, 3=Emerging, 4=Frontier)
|
|
675
|
-
*/
|
|
676
|
-
async getRiskUniverse(agentId) {
|
|
677
|
-
const result = await this.publicClient.readContract({
|
|
678
|
-
address: this.address,
|
|
679
|
-
abi: EXAGENT_REGISTRY_ABI,
|
|
680
|
-
functionName: "getRiskUniverse",
|
|
681
|
-
args: [agentId]
|
|
682
|
-
});
|
|
683
|
-
return Number(result);
|
|
684
|
-
}
|
|
685
|
-
/**
|
|
686
|
-
* Get trade count for an agent
|
|
687
|
-
* @param agentId The agent's ID
|
|
688
|
-
* @returns Number of recorded trades
|
|
689
|
-
*/
|
|
690
|
-
async getTradeCount(agentId) {
|
|
691
|
-
const result = await this.publicClient.readContract({
|
|
692
|
-
address: this.address,
|
|
693
|
-
abi: EXAGENT_REGISTRY_ABI,
|
|
694
|
-
functionName: "tradeCount",
|
|
695
|
-
args: [agentId]
|
|
696
|
-
});
|
|
697
|
-
return result;
|
|
698
|
-
}
|
|
699
|
-
};
|
|
700
|
-
|
|
701
|
-
// src/contracts/router.ts
|
|
702
|
-
var EXAGENT_ROUTER_ABI = [
|
|
703
|
-
// Custom errors — must match ExagentRouterV2.sol for viem to decode reverts
|
|
704
|
-
{ type: "error", name: "InvalidAgentId", inputs: [] },
|
|
705
|
-
{ type: "error", name: "SwapFailed", inputs: [] },
|
|
706
|
-
{ type: "error", name: "InsufficientOutput", inputs: [] },
|
|
707
|
-
{ type: "error", name: "ZeroAddress", inputs: [] },
|
|
708
|
-
{ type: "error", name: "ZeroAmount", inputs: [] },
|
|
709
|
-
{ type: "error", name: "AggregatorNotWhitelisted", inputs: [] },
|
|
710
|
-
{ type: "error", name: "ETHTransferFailed", inputs: [] },
|
|
711
|
-
{ type: "error", name: "FeeBpsTooHigh", inputs: [] },
|
|
712
|
-
{ type: "error", name: "NotAuthorizedForAgent", inputs: [{ name: "agentId", type: "uint256" }, { name: "caller", type: "address" }] },
|
|
713
|
-
{ type: "error", name: "ConfigMismatch", inputs: [{ name: "provided", type: "bytes32" }, { name: "onChain", type: "bytes32" }] },
|
|
714
|
-
{ type: "error", name: "MsgValueMismatch", inputs: [] },
|
|
715
|
-
{ type: "error", name: "FeeCollectorNotSet", inputs: [] },
|
|
716
|
-
{ type: "error", name: "TokenNotAllowedForAgent", inputs: [{ name: "agentId", type: "uint256" }, { name: "token", type: "address" }] },
|
|
717
|
-
{ type: "error", name: "NotAuthorized", inputs: [] },
|
|
718
|
-
{ type: "error", name: "RiskUniverseTooLow", inputs: [{ name: "agentId", type: "uint256" }, { name: "riskUniverse", type: "uint256" }] },
|
|
719
|
-
{ type: "error", name: "FillAlreadyProcessed", inputs: [{ name: "fillId", type: "bytes32" }] }
|
|
720
|
-
];
|
|
721
|
-
|
|
722
|
-
// src/contracts/vault.ts
|
|
723
|
-
var EXAGENT_VAULT_ABI = [
|
|
724
|
-
// ERC-4626 Standard
|
|
725
|
-
{ type: "function", name: "asset", inputs: [], outputs: [{ type: "address" }], stateMutability: "view" },
|
|
726
|
-
{ type: "function", name: "totalAssets", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
727
|
-
{ type: "function", name: "convertToShares", inputs: [{ name: "assets", type: "uint256" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
728
|
-
{ type: "function", name: "convertToAssets", inputs: [{ name: "shares", type: "uint256" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
729
|
-
{ type: "function", name: "maxDeposit", inputs: [{ name: "receiver", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
730
|
-
{ type: "function", name: "maxMint", inputs: [{ name: "receiver", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
731
|
-
{ type: "function", name: "maxWithdraw", inputs: [{ name: "owner", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
732
|
-
{ type: "function", name: "maxRedeem", inputs: [{ name: "owner", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
733
|
-
{ type: "function", name: "previewDeposit", inputs: [{ name: "assets", type: "uint256" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
734
|
-
{ type: "function", name: "previewMint", inputs: [{ name: "shares", type: "uint256" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
735
|
-
{ type: "function", name: "previewWithdraw", inputs: [{ name: "assets", type: "uint256" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
736
|
-
{ type: "function", name: "previewRedeem", inputs: [{ name: "shares", type: "uint256" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
737
|
-
{ type: "function", name: "deposit", inputs: [{ name: "assets", type: "uint256" }, { name: "receiver", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "nonpayable" },
|
|
738
|
-
{ type: "function", name: "mint", inputs: [{ name: "shares", type: "uint256" }, { name: "receiver", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "nonpayable" },
|
|
739
|
-
{ type: "function", name: "withdraw", inputs: [{ name: "assets", type: "uint256" }, { name: "receiver", type: "address" }, { name: "owner", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "nonpayable" },
|
|
740
|
-
{ type: "function", name: "redeem", inputs: [{ name: "shares", type: "uint256" }, { name: "receiver", type: "address" }, { name: "owner", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "nonpayable" },
|
|
741
|
-
// ERC-20
|
|
742
|
-
{ type: "function", name: "name", inputs: [], outputs: [{ type: "string" }], stateMutability: "view" },
|
|
743
|
-
{ type: "function", name: "symbol", inputs: [], outputs: [{ type: "string" }], stateMutability: "view" },
|
|
744
|
-
{ type: "function", name: "decimals", inputs: [], outputs: [{ type: "uint8" }], stateMutability: "view" },
|
|
745
|
-
{ type: "function", name: "totalSupply", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
746
|
-
{ type: "function", name: "balanceOf", inputs: [{ name: "account", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
747
|
-
{ type: "function", name: "allowance", inputs: [{ name: "owner", type: "address" }, { name: "spender", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
748
|
-
{ type: "function", name: "approve", inputs: [{ name: "spender", type: "address" }, { name: "amount", type: "uint256" }], outputs: [{ type: "bool" }], stateMutability: "nonpayable" },
|
|
749
|
-
// Custom Exagent Vault
|
|
750
|
-
{ type: "function", name: "agentId", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
751
|
-
{ type: "function", name: "sharePrice", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
752
|
-
{ type: "function", name: "effectiveShares", inputs: [{ name: "user", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
753
|
-
{ type: "function", name: "userHighWaterMark", inputs: [{ name: "user", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
754
|
-
{ type: "function", name: "performanceFeeBps", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
755
|
-
{ type: "function", name: "managementFeeBps", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
756
|
-
{ type: "function", name: "feeRecipient", inputs: [], outputs: [{ type: "address" }], stateMutability: "view" },
|
|
757
|
-
{ type: "function", name: "highWaterMark", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
758
|
-
{ type: "function", name: "depositsPaused", inputs: [], outputs: [{ type: "bool" }], stateMutability: "view" },
|
|
759
|
-
{ type: "function", name: "withdrawalsPaused", inputs: [], outputs: [{ type: "bool" }], stateMutability: "view" },
|
|
760
|
-
{ type: "function", name: "circuitBreakerActive", inputs: [], outputs: [{ type: "bool" }], stateMutability: "view" },
|
|
761
|
-
{ type: "function", name: "pendingWithdrawals", inputs: [{ name: "user", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
762
|
-
{ type: "function", name: "getPendingWithdrawals", inputs: [{ name: "owner", type: "address" }], outputs: [{ name: "requestIds", type: "uint256[]" }], stateMutability: "view" },
|
|
763
|
-
{ type: "function", name: "getClaimableAmount", inputs: [{ name: "requestId", type: "uint256" }], outputs: [{ name: "assets", type: "uint256" }], stateMutability: "view" },
|
|
764
|
-
{ type: "function", name: "getRateLimitStatus", inputs: [], outputs: [{ name: "remaining", type: "uint256" }, { name: "periodEnds", type: "uint256" }], stateMutability: "view" },
|
|
765
|
-
{ type: "function", name: "getWithdrawalQueueLength", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
766
|
-
// Withdrawal Queue
|
|
767
|
-
{ type: "function", name: "requestWithdrawal", inputs: [{ name: "shares", type: "uint256" }, { name: "receiver", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "nonpayable" },
|
|
768
|
-
{ type: "function", name: "claimWithdrawal", inputs: [{ name: "requestId", type: "uint256" }], outputs: [{ type: "uint256" }], stateMutability: "nonpayable" },
|
|
769
|
-
{ type: "function", name: "cancelWithdrawal", inputs: [{ name: "requestId", type: "uint256" }], outputs: [], stateMutability: "nonpayable" },
|
|
770
|
-
{
|
|
771
|
-
type: "function",
|
|
772
|
-
name: "getPendingWithdrawal",
|
|
773
|
-
inputs: [{ name: "requestId", type: "uint256" }],
|
|
774
|
-
outputs: [
|
|
775
|
-
{ name: "owner", type: "address" },
|
|
776
|
-
{ name: "receiver", type: "address" },
|
|
777
|
-
{ name: "shares", type: "uint256" },
|
|
778
|
-
{ name: "requestTime", type: "uint256" },
|
|
779
|
-
{ name: "processed", type: "bool" },
|
|
780
|
-
{ name: "claimableAt", type: "uint256" }
|
|
781
|
-
],
|
|
782
|
-
stateMutability: "view"
|
|
783
|
-
},
|
|
784
|
-
// V2: Safe "withdraw all"
|
|
785
|
-
{ type: "function", name: "redeemMax", inputs: [{ name: "receiver", type: "address" }, { name: "owner", type: "address" }], outputs: [{ name: "assets", type: "uint256" }], stateMutability: "nonpayable" },
|
|
786
|
-
{ type: "function", name: "withdrawMax", inputs: [{ name: "receiver", type: "address" }, { name: "owner", type: "address" }], outputs: [{ name: "assets", type: "uint256" }], stateMutability: "nonpayable" },
|
|
787
|
-
// V2: Emergency exit with penalty
|
|
788
|
-
{ type: "function", name: "emergencyWithdraw", inputs: [], outputs: [{ name: "assets", type: "uint256" }], stateMutability: "nonpayable" },
|
|
789
|
-
// Events
|
|
790
|
-
{ type: "event", name: "Deposit", inputs: [{ name: "sender", type: "address", indexed: true }, { name: "owner", type: "address", indexed: true }, { name: "assets", type: "uint256" }, { name: "shares", type: "uint256" }] },
|
|
791
|
-
{ type: "event", name: "Withdraw", inputs: [{ name: "sender", type: "address", indexed: true }, { name: "receiver", type: "address", indexed: true }, { name: "owner", type: "address", indexed: true }, { name: "assets", type: "uint256" }, { name: "shares", type: "uint256" }] },
|
|
792
|
-
{ type: "event", name: "PerformanceFeeCharged", inputs: [{ name: "user", type: "address", indexed: true }, { name: "feeShares", type: "uint256" }, { name: "profit", type: "uint256" }] },
|
|
793
|
-
{ type: "event", name: "WithdrawalRequested", inputs: [{ name: "requestId", type: "uint256", indexed: true }, { name: "owner", type: "address", indexed: true }, { name: "shares", type: "uint256" }, { name: "timestamp", type: "uint256" }] },
|
|
794
|
-
{ type: "event", name: "WithdrawalClaimed", inputs: [{ name: "requestId", type: "uint256", indexed: true }, { name: "receiver", type: "address", indexed: true }, { name: "assets", type: "uint256" }] },
|
|
795
|
-
{ type: "event", name: "WithdrawalCancelled", inputs: [{ name: "requestId", type: "uint256", indexed: true }] },
|
|
796
|
-
{ type: "event", name: "EmergencyWithdrawal", inputs: [{ name: "user", type: "address", indexed: true }, { name: "shares", type: "uint256" }, { name: "assets", type: "uint256" }] }
|
|
797
|
-
];
|
|
798
|
-
var ERC20_APPROVE_ABI = [
|
|
799
|
-
{ type: "function", name: "approve", inputs: [{ name: "spender", type: "address" }, { name: "amount", type: "uint256" }], outputs: [{ type: "bool" }], stateMutability: "nonpayable" }
|
|
800
|
-
];
|
|
801
|
-
var ExagentVault = class {
|
|
802
|
-
address;
|
|
803
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
804
|
-
publicClient;
|
|
805
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
806
|
-
walletClient;
|
|
807
|
-
chain;
|
|
808
|
-
account;
|
|
809
|
-
constructor(vaultAddress, publicClient, walletClient, chain, account) {
|
|
810
|
-
this.address = vaultAddress;
|
|
811
|
-
this.publicClient = publicClient;
|
|
812
|
-
this.walletClient = walletClient;
|
|
813
|
-
if (!chain) {
|
|
814
|
-
throw new Error("Chain parameter is required");
|
|
815
|
-
}
|
|
816
|
-
this.chain = chain;
|
|
817
|
-
this.account = account;
|
|
818
|
-
}
|
|
819
|
-
// ============ Read Functions ============
|
|
820
|
-
/**
|
|
821
|
-
* Get comprehensive vault info
|
|
822
|
-
*/
|
|
823
|
-
async getVaultInfo() {
|
|
824
|
-
const [
|
|
825
|
-
name,
|
|
826
|
-
symbol,
|
|
827
|
-
asset,
|
|
828
|
-
agentId,
|
|
829
|
-
totalAssets,
|
|
830
|
-
totalSupply,
|
|
831
|
-
sharePrice,
|
|
832
|
-
highWaterMark,
|
|
833
|
-
performanceFeeBps,
|
|
834
|
-
managementFeeBps,
|
|
835
|
-
feeRecipient,
|
|
836
|
-
depositsPaused,
|
|
837
|
-
withdrawalsPaused,
|
|
838
|
-
circuitBreakerActive
|
|
839
|
-
] = await Promise.all([
|
|
840
|
-
this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "name" }),
|
|
841
|
-
this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "symbol" }),
|
|
842
|
-
this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "asset" }),
|
|
843
|
-
this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "agentId" }),
|
|
844
|
-
this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "totalAssets" }),
|
|
845
|
-
this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "totalSupply" }),
|
|
846
|
-
this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "sharePrice" }),
|
|
847
|
-
this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "highWaterMark" }),
|
|
848
|
-
this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "performanceFeeBps" }),
|
|
849
|
-
this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "managementFeeBps" }),
|
|
850
|
-
this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "feeRecipient" }),
|
|
851
|
-
this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "depositsPaused" }),
|
|
852
|
-
this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "withdrawalsPaused" }),
|
|
853
|
-
this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "circuitBreakerActive" })
|
|
854
|
-
]);
|
|
855
|
-
return {
|
|
856
|
-
address: this.address,
|
|
857
|
-
name,
|
|
858
|
-
symbol,
|
|
859
|
-
asset,
|
|
860
|
-
agentId,
|
|
861
|
-
totalAssets,
|
|
862
|
-
totalSupply,
|
|
863
|
-
sharePrice,
|
|
864
|
-
highWaterMark,
|
|
865
|
-
performanceFeeBps,
|
|
866
|
-
managementFeeBps,
|
|
867
|
-
feeRecipient,
|
|
868
|
-
depositsPaused,
|
|
869
|
-
withdrawalsPaused,
|
|
870
|
-
circuitBreakerActive
|
|
871
|
-
};
|
|
872
|
-
}
|
|
873
|
-
/**
|
|
874
|
-
* Get user's position in the vault
|
|
875
|
-
*/
|
|
876
|
-
async getPosition(user) {
|
|
877
|
-
const [
|
|
878
|
-
shares,
|
|
879
|
-
effectiveShares,
|
|
880
|
-
pendingWithdrawals,
|
|
881
|
-
userHighWaterMark
|
|
882
|
-
] = await Promise.all([
|
|
883
|
-
this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "balanceOf", args: [user] }),
|
|
884
|
-
this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "effectiveShares", args: [user] }),
|
|
885
|
-
this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "pendingWithdrawals", args: [user] }),
|
|
886
|
-
this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "userHighWaterMark", args: [user] })
|
|
887
|
-
]);
|
|
888
|
-
const assetsValue = await this.publicClient.readContract({
|
|
889
|
-
address: this.address,
|
|
890
|
-
abi: EXAGENT_VAULT_ABI,
|
|
891
|
-
functionName: "convertToAssets",
|
|
892
|
-
args: [effectiveShares]
|
|
893
|
-
});
|
|
894
|
-
return {
|
|
895
|
-
shares,
|
|
896
|
-
effectiveShares,
|
|
897
|
-
pendingWithdrawals,
|
|
898
|
-
assetsValue,
|
|
899
|
-
userHighWaterMark
|
|
900
|
-
};
|
|
901
|
-
}
|
|
902
|
-
/**
|
|
903
|
-
* Get current share price (assets per share, scaled to 1e18)
|
|
904
|
-
*/
|
|
905
|
-
async getSharePrice() {
|
|
906
|
-
return this.publicClient.readContract({
|
|
907
|
-
address: this.address,
|
|
908
|
-
abi: EXAGENT_VAULT_ABI,
|
|
909
|
-
functionName: "sharePrice"
|
|
910
|
-
});
|
|
911
|
-
}
|
|
912
|
-
/**
|
|
913
|
-
* Preview deposit - get shares for given assets
|
|
914
|
-
*/
|
|
915
|
-
async previewDeposit(assets) {
|
|
916
|
-
return this.publicClient.readContract({
|
|
917
|
-
address: this.address,
|
|
918
|
-
abi: EXAGENT_VAULT_ABI,
|
|
919
|
-
functionName: "previewDeposit",
|
|
920
|
-
args: [assets]
|
|
921
|
-
});
|
|
922
|
-
}
|
|
923
|
-
/**
|
|
924
|
-
* Preview withdrawal - get assets for given shares
|
|
925
|
-
*/
|
|
926
|
-
async previewRedeem(shares) {
|
|
927
|
-
return this.publicClient.readContract({
|
|
928
|
-
address: this.address,
|
|
929
|
-
abi: EXAGENT_VAULT_ABI,
|
|
930
|
-
functionName: "previewRedeem",
|
|
931
|
-
args: [shares]
|
|
932
|
-
});
|
|
933
|
-
}
|
|
934
|
-
/**
|
|
935
|
-
* Get max deposit amount
|
|
936
|
-
*/
|
|
937
|
-
async maxDeposit(receiver) {
|
|
938
|
-
return this.publicClient.readContract({
|
|
939
|
-
address: this.address,
|
|
940
|
-
abi: EXAGENT_VAULT_ABI,
|
|
941
|
-
functionName: "maxDeposit",
|
|
942
|
-
args: [receiver]
|
|
943
|
-
});
|
|
944
|
-
}
|
|
945
|
-
/**
|
|
946
|
-
* Get max withdrawal amount
|
|
947
|
-
*/
|
|
948
|
-
async maxWithdraw(owner) {
|
|
949
|
-
return this.publicClient.readContract({
|
|
950
|
-
address: this.address,
|
|
951
|
-
abi: EXAGENT_VAULT_ABI,
|
|
952
|
-
functionName: "maxWithdraw",
|
|
953
|
-
args: [owner]
|
|
954
|
-
});
|
|
955
|
-
}
|
|
956
|
-
/**
|
|
957
|
-
* Get rate limit status
|
|
958
|
-
*/
|
|
959
|
-
async getRateLimitStatus() {
|
|
960
|
-
const result = await this.publicClient.readContract({
|
|
961
|
-
address: this.address,
|
|
962
|
-
abi: EXAGENT_VAULT_ABI,
|
|
963
|
-
functionName: "getRateLimitStatus"
|
|
964
|
-
});
|
|
965
|
-
return { remaining: result[0], periodEnds: result[1] };
|
|
966
|
-
}
|
|
967
|
-
/**
|
|
968
|
-
* Get pending withdrawal request
|
|
969
|
-
*/
|
|
970
|
-
async getPendingWithdrawal(requestId) {
|
|
971
|
-
const result = await this.publicClient.readContract({
|
|
972
|
-
address: this.address,
|
|
973
|
-
abi: EXAGENT_VAULT_ABI,
|
|
974
|
-
functionName: "getPendingWithdrawal",
|
|
975
|
-
args: [requestId]
|
|
976
|
-
});
|
|
977
|
-
return {
|
|
978
|
-
requestId,
|
|
979
|
-
owner: result[0],
|
|
980
|
-
receiver: result[1],
|
|
981
|
-
shares: result[2],
|
|
982
|
-
requestTime: result[3],
|
|
983
|
-
processed: result[4],
|
|
984
|
-
claimableAt: result[5]
|
|
985
|
-
};
|
|
986
|
-
}
|
|
987
|
-
// ============ Write Functions ============
|
|
988
|
-
/**
|
|
989
|
-
* Deposit assets into the vault
|
|
990
|
-
* @param assets Amount of underlying asset to deposit
|
|
991
|
-
* @param receiver Address to receive vault shares
|
|
992
|
-
* @returns Transaction hash
|
|
993
|
-
*/
|
|
994
|
-
async deposit(assets, receiver) {
|
|
995
|
-
if (!this.walletClient || !this.account) {
|
|
996
|
-
throw new Error("Wallet client required for write operations");
|
|
997
|
-
}
|
|
998
|
-
const to = receiver ?? this.account.address;
|
|
999
|
-
const hash = await this.walletClient.writeContract({
|
|
1000
|
-
address: this.address,
|
|
1001
|
-
abi: EXAGENT_VAULT_ABI,
|
|
1002
|
-
functionName: "deposit",
|
|
1003
|
-
args: [assets, to],
|
|
1004
|
-
account: this.account,
|
|
1005
|
-
chain: this.chain
|
|
1006
|
-
});
|
|
1007
|
-
return hash;
|
|
1008
|
-
}
|
|
1009
|
-
/**
|
|
1010
|
-
* Withdraw assets from the vault
|
|
1011
|
-
* @param assets Amount of underlying asset to withdraw
|
|
1012
|
-
* @param receiver Address to receive assets
|
|
1013
|
-
* @param owner Address whose shares to burn (defaults to caller)
|
|
1014
|
-
* @returns Transaction hash
|
|
1015
|
-
*/
|
|
1016
|
-
async withdraw(assets, receiver, owner) {
|
|
1017
|
-
if (!this.walletClient || !this.account) {
|
|
1018
|
-
throw new Error("Wallet client required for write operations");
|
|
1019
|
-
}
|
|
1020
|
-
const to = receiver ?? this.account.address;
|
|
1021
|
-
const from = owner ?? this.account.address;
|
|
1022
|
-
const hash = await this.walletClient.writeContract({
|
|
1023
|
-
address: this.address,
|
|
1024
|
-
abi: EXAGENT_VAULT_ABI,
|
|
1025
|
-
functionName: "withdraw",
|
|
1026
|
-
args: [assets, to, from],
|
|
1027
|
-
account: this.account,
|
|
1028
|
-
chain: this.chain
|
|
1029
|
-
});
|
|
1030
|
-
return hash;
|
|
1031
|
-
}
|
|
1032
|
-
/**
|
|
1033
|
-
* Redeem shares for assets
|
|
1034
|
-
* @param shares Amount of shares to redeem
|
|
1035
|
-
* @param receiver Address to receive assets
|
|
1036
|
-
* @param owner Address whose shares to burn (defaults to caller)
|
|
1037
|
-
* @returns Transaction hash
|
|
1038
|
-
*/
|
|
1039
|
-
async redeem(shares, receiver, owner) {
|
|
1040
|
-
if (!this.walletClient || !this.account) {
|
|
1041
|
-
throw new Error("Wallet client required for write operations");
|
|
1042
|
-
}
|
|
1043
|
-
const to = receiver ?? this.account.address;
|
|
1044
|
-
const from = owner ?? this.account.address;
|
|
1045
|
-
const hash = await this.walletClient.writeContract({
|
|
1046
|
-
address: this.address,
|
|
1047
|
-
abi: EXAGENT_VAULT_ABI,
|
|
1048
|
-
functionName: "redeem",
|
|
1049
|
-
args: [shares, to, from],
|
|
1050
|
-
account: this.account,
|
|
1051
|
-
chain: this.chain
|
|
1052
|
-
});
|
|
1053
|
-
return hash;
|
|
1054
|
-
}
|
|
1055
|
-
/**
|
|
1056
|
-
* Redeem all shares safely — charges performance fee first, then redeems remaining balance.
|
|
1057
|
-
* Use this instead of redeem(fullBalance) to avoid ERC4626ExceededMaxRedeem revert.
|
|
1058
|
-
* @param receiver Address to receive assets
|
|
1059
|
-
* @param owner Address whose shares to burn (defaults to caller)
|
|
1060
|
-
* @returns Transaction hash
|
|
1061
|
-
*/
|
|
1062
|
-
async redeemMax(receiver, owner) {
|
|
1063
|
-
if (!this.walletClient || !this.account) {
|
|
1064
|
-
throw new Error("Wallet client required for write operations");
|
|
1065
|
-
}
|
|
1066
|
-
const to = receiver ?? this.account.address;
|
|
1067
|
-
const from = owner ?? this.account.address;
|
|
1068
|
-
const hash = await this.walletClient.writeContract({
|
|
1069
|
-
address: this.address,
|
|
1070
|
-
abi: EXAGENT_VAULT_ABI,
|
|
1071
|
-
functionName: "redeemMax",
|
|
1072
|
-
args: [to, from],
|
|
1073
|
-
account: this.account,
|
|
1074
|
-
chain: this.chain
|
|
1075
|
-
});
|
|
1076
|
-
return hash;
|
|
1077
|
-
}
|
|
1078
|
-
/**
|
|
1079
|
-
* Withdraw all assets safely — charges performance fee first, then withdraws remaining balance.
|
|
1080
|
-
* @param receiver Address to receive assets
|
|
1081
|
-
* @param owner Address whose shares to burn (defaults to caller)
|
|
1082
|
-
* @returns Transaction hash
|
|
1083
|
-
*/
|
|
1084
|
-
async withdrawMax(receiver, owner) {
|
|
1085
|
-
if (!this.walletClient || !this.account) {
|
|
1086
|
-
throw new Error("Wallet client required for write operations");
|
|
1087
|
-
}
|
|
1088
|
-
const to = receiver ?? this.account.address;
|
|
1089
|
-
const from = owner ?? this.account.address;
|
|
1090
|
-
const hash = await this.walletClient.writeContract({
|
|
1091
|
-
address: this.address,
|
|
1092
|
-
abi: EXAGENT_VAULT_ABI,
|
|
1093
|
-
functionName: "withdrawMax",
|
|
1094
|
-
args: [to, from],
|
|
1095
|
-
account: this.account,
|
|
1096
|
-
chain: this.chain
|
|
1097
|
-
});
|
|
1098
|
-
return hash;
|
|
1099
|
-
}
|
|
1100
|
-
/**
|
|
1101
|
-
* Request a queued withdrawal (for large amounts)
|
|
1102
|
-
* @param shares Amount of shares to withdraw
|
|
1103
|
-
* @param receiver Address to receive assets
|
|
1104
|
-
* @returns Transaction hash
|
|
1105
|
-
*/
|
|
1106
|
-
async requestWithdrawal(shares, receiver) {
|
|
1107
|
-
if (!this.walletClient || !this.account) {
|
|
1108
|
-
throw new Error("Wallet client required for write operations");
|
|
1109
|
-
}
|
|
1110
|
-
const to = receiver ?? this.account.address;
|
|
1111
|
-
const hash = await this.walletClient.writeContract({
|
|
1112
|
-
address: this.address,
|
|
1113
|
-
abi: EXAGENT_VAULT_ABI,
|
|
1114
|
-
functionName: "requestWithdrawal",
|
|
1115
|
-
args: [shares, to],
|
|
1116
|
-
account: this.account,
|
|
1117
|
-
chain: this.chain
|
|
1118
|
-
});
|
|
1119
|
-
return hash;
|
|
1120
|
-
}
|
|
1121
|
-
/**
|
|
1122
|
-
* Claim a pending withdrawal request
|
|
1123
|
-
* @param requestId The withdrawal request ID
|
|
1124
|
-
* @returns Transaction hash
|
|
1125
|
-
*/
|
|
1126
|
-
async claimWithdrawal(requestId) {
|
|
1127
|
-
if (!this.walletClient || !this.account) {
|
|
1128
|
-
throw new Error("Wallet client required for write operations");
|
|
1129
|
-
}
|
|
1130
|
-
const hash = await this.walletClient.writeContract({
|
|
1131
|
-
address: this.address,
|
|
1132
|
-
abi: EXAGENT_VAULT_ABI,
|
|
1133
|
-
functionName: "claimWithdrawal",
|
|
1134
|
-
args: [requestId],
|
|
1135
|
-
account: this.account,
|
|
1136
|
-
chain: this.chain
|
|
1137
|
-
});
|
|
1138
|
-
return hash;
|
|
1139
|
-
}
|
|
1140
|
-
/**
|
|
1141
|
-
* Cancel a pending withdrawal request
|
|
1142
|
-
* @param requestId The withdrawal request ID
|
|
1143
|
-
* @returns Transaction hash
|
|
1144
|
-
*/
|
|
1145
|
-
async cancelWithdrawal(requestId) {
|
|
1146
|
-
if (!this.walletClient || !this.account) {
|
|
1147
|
-
throw new Error("Wallet client required for write operations");
|
|
1148
|
-
}
|
|
1149
|
-
const hash = await this.walletClient.writeContract({
|
|
1150
|
-
address: this.address,
|
|
1151
|
-
abi: EXAGENT_VAULT_ABI,
|
|
1152
|
-
functionName: "cancelWithdrawal",
|
|
1153
|
-
args: [requestId],
|
|
1154
|
-
account: this.account,
|
|
1155
|
-
chain: this.chain
|
|
1156
|
-
});
|
|
1157
|
-
return hash;
|
|
1158
|
-
}
|
|
1159
|
-
/**
|
|
1160
|
-
* Emergency withdrawal with penalty (50% if vault < 7 days old, 20% otherwise).
|
|
1161
|
-
* Penalty stays in the vault for remaining backers.
|
|
1162
|
-
* @returns Transaction hash
|
|
1163
|
-
*/
|
|
1164
|
-
async emergencyWithdraw() {
|
|
1165
|
-
if (!this.walletClient || !this.account) {
|
|
1166
|
-
throw new Error("Wallet client required for write operations");
|
|
1167
|
-
}
|
|
1168
|
-
const hash = await this.walletClient.writeContract({
|
|
1169
|
-
address: this.address,
|
|
1170
|
-
abi: EXAGENT_VAULT_ABI,
|
|
1171
|
-
functionName: "emergencyWithdraw",
|
|
1172
|
-
args: [],
|
|
1173
|
-
account: this.account,
|
|
1174
|
-
chain: this.chain
|
|
1175
|
-
});
|
|
1176
|
-
return hash;
|
|
1177
|
-
}
|
|
1178
|
-
/**
|
|
1179
|
-
* Approve vault to spend underlying asset
|
|
1180
|
-
* @param assetAddress The asset token address
|
|
1181
|
-
* @param amount Amount to approve
|
|
1182
|
-
* @returns Transaction hash
|
|
1183
|
-
*/
|
|
1184
|
-
async approveAsset(assetAddress, amount) {
|
|
1185
|
-
if (!this.walletClient || !this.account) {
|
|
1186
|
-
throw new Error("Wallet client required for write operations");
|
|
1187
|
-
}
|
|
1188
|
-
const hash = await this.walletClient.writeContract({
|
|
1189
|
-
address: assetAddress,
|
|
1190
|
-
abi: ERC20_APPROVE_ABI,
|
|
1191
|
-
functionName: "approve",
|
|
1192
|
-
args: [this.address, amount],
|
|
1193
|
-
account: this.account,
|
|
1194
|
-
chain: this.chain
|
|
1195
|
-
});
|
|
1196
|
-
return hash;
|
|
1197
|
-
}
|
|
1198
|
-
};
|
|
1199
|
-
|
|
1200
|
-
// src/constants.ts
|
|
1201
|
-
var import_chains = require("viem/chains");
|
|
1202
|
-
var SDK_VERSION = "0.1.21";
|
|
1203
|
-
var DEFAULT_RPC_URL = "https://mainnet.base.org";
|
|
1204
|
-
function getRpcUrl() {
|
|
1205
|
-
if (typeof process !== "undefined" && process.env) {
|
|
1206
|
-
return process.env.BASE_RPC_URL || process.env.EXAGENT_RPC_URL || DEFAULT_RPC_URL;
|
|
1207
|
-
}
|
|
1208
|
-
return DEFAULT_RPC_URL;
|
|
1209
|
-
}
|
|
1210
|
-
var CHAIN_CONFIG = {
|
|
1211
|
-
mainnet: import_chains.base
|
|
1212
|
-
};
|
|
1213
|
-
var CONTRACT_ADDRESSES = {
|
|
1214
|
-
mainnet: {
|
|
1215
|
-
agentRegistry: "0x2261706C751F8ac5cdDb481B7b56EA2137d4A723",
|
|
1216
|
-
router: "0xBfE186E2Bba9B730c8732917AE36E7AC143420d3",
|
|
1217
|
-
vaultFactory: "0x3312f7C0059C03b47Df63DA4f73B79A63a874ef5",
|
|
1218
|
-
feeCollector: "0x00Ab9847049b5496619dFDd1A7bd36FA49eB7195",
|
|
1219
|
-
serviceEscrow: "0x63A4d1dA774422EFC2cc57d71F948231BD812516"
|
|
1220
|
-
}
|
|
1221
|
-
};
|
|
1222
|
-
var DEX_ADDRESSES = {
|
|
1223
|
-
// Aerodrome
|
|
1224
|
-
aerodromeRouter: "0xcF77a3Ba9A5CA399B7c97c74d54e5b1Beb874E43",
|
|
1225
|
-
aerodromeSlipstream: "0xBE6D8f0d05cC4be24d5167a3eF062215bE6D18a5",
|
|
1226
|
-
// Uniswap
|
|
1227
|
-
uniswapUniversalRouter: "0x198EF79F1F515F02dFE9e3115eD9fC07183f02fC",
|
|
1228
|
-
uniswapV4Router: "0x6ff5693b99212da76ad316178a184ab56d299b43",
|
|
1229
|
-
// Common tokens
|
|
1230
|
-
WETH: "0x4200000000000000000000000000000000000006",
|
|
1231
|
-
USDC: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"
|
|
1232
|
-
};
|
|
1233
|
-
var ZERO_X_CONFIG = {
|
|
1234
|
-
baseUrl: "https://api.0x.org",
|
|
1235
|
-
chainId: 8453
|
|
1236
|
-
// Base
|
|
1237
|
-
};
|
|
1238
|
-
var EXAGENT_API_CONFIG = {
|
|
1239
|
-
mainnet: "https://exagent-api.onrender.com"
|
|
1240
|
-
};
|
|
1241
|
-
var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
1242
|
-
function validateContractAddresses(network) {
|
|
1243
|
-
const addresses = CONTRACT_ADDRESSES[network];
|
|
1244
|
-
const missing = Object.entries(addresses).filter(([, addr]) => addr === ZERO_ADDRESS).map(([name]) => name);
|
|
1245
|
-
if (missing.length > 0) {
|
|
1246
|
-
throw new Error(
|
|
1247
|
-
`Contract addresses not deployed on ${network}. Missing: ${missing.join(", ")}. Update @exagent/sdk to the latest version.`
|
|
1248
|
-
);
|
|
1249
|
-
}
|
|
1250
|
-
}
|
|
1251
|
-
|
|
1252
|
-
// src/types.ts
|
|
1253
|
-
function buildGlobalAgentId(chainId, registryAddress, agentId) {
|
|
1254
|
-
return `eip155:${chainId}:${registryAddress}:${Number(agentId)}`;
|
|
1255
|
-
}
|
|
1256
|
-
function parseGlobalAgentId(globalId) {
|
|
1257
|
-
const parts = globalId.split(":");
|
|
1258
|
-
if (parts.length !== 4 || parts[0] !== "eip155") {
|
|
1259
|
-
throw new Error(`Invalid ERC-8004 global agent ID: ${globalId}`);
|
|
1260
|
-
}
|
|
1261
|
-
const chainId = parseInt(parts[1], 10);
|
|
1262
|
-
const registryAddress = parts[2];
|
|
1263
|
-
const agentId = parseInt(parts[3], 10);
|
|
1264
|
-
if (isNaN(chainId) || isNaN(agentId)) {
|
|
1265
|
-
throw new Error(`Invalid ERC-8004 global agent ID: ${globalId}`);
|
|
1266
|
-
}
|
|
1267
|
-
return { chainId, registryAddress, agentId };
|
|
1268
|
-
}
|
|
1269
|
-
|
|
1270
1
|
// src/client.ts
|
|
1271
2
|
var ExagentClient = class {
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
account;
|
|
1275
|
-
network;
|
|
1276
|
-
apiKey;
|
|
1277
|
-
// Contract interfaces
|
|
1278
|
-
registry;
|
|
1279
|
-
// Cached agent ID
|
|
1280
|
-
_agentId;
|
|
3
|
+
baseUrl;
|
|
4
|
+
token;
|
|
1281
5
|
constructor(config) {
|
|
1282
|
-
this.
|
|
1283
|
-
this.
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
const
|
|
1287
|
-
const
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
6
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
7
|
+
this.token = config.token;
|
|
8
|
+
}
|
|
9
|
+
async request(path, options = {}) {
|
|
10
|
+
const url = `${this.baseUrl}${path}`;
|
|
11
|
+
const res = await fetch(url, {
|
|
12
|
+
...options,
|
|
13
|
+
headers: {
|
|
14
|
+
"Content-Type": "application/json",
|
|
15
|
+
Authorization: `Bearer ${this.token}`,
|
|
16
|
+
...options.headers
|
|
17
|
+
}
|
|
1291
18
|
});
|
|
1292
|
-
if (
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
} else if (config.privateKey) {
|
|
1296
|
-
this.account = (0, import_accounts.privateKeyToAccount)(config.privateKey);
|
|
1297
|
-
this.walletClient = (0, import_viem2.createWalletClient)({
|
|
1298
|
-
account: this.account,
|
|
1299
|
-
chain,
|
|
1300
|
-
transport
|
|
1301
|
-
});
|
|
1302
|
-
} else {
|
|
1303
|
-
throw new Error("Either privateKey or walletClient must be provided");
|
|
19
|
+
if (!res.ok) {
|
|
20
|
+
const body = await res.text();
|
|
21
|
+
throw new Error(`API error ${res.status}: ${body}`);
|
|
1304
22
|
}
|
|
1305
|
-
|
|
1306
|
-
this.registry = new ExagentRegistry(
|
|
1307
|
-
addresses.agentRegistry,
|
|
1308
|
-
this.publicClient,
|
|
1309
|
-
this.walletClient,
|
|
1310
|
-
chain,
|
|
1311
|
-
this.account
|
|
1312
|
-
);
|
|
23
|
+
return res.json();
|
|
1313
24
|
}
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
return {
|
|
1317
|
-
...contentType && { "Content-Type": contentType },
|
|
1318
|
-
"X-Exagent-SDK-Version": SDK_VERSION,
|
|
1319
|
-
...this.apiKey && { "X-API-Key": this.apiKey }
|
|
1320
|
-
};
|
|
1321
|
-
}
|
|
1322
|
-
// ============ Agent Registration ============
|
|
1323
|
-
/**
|
|
1324
|
-
* Register as a new agent on Exagent.
|
|
1325
|
-
*
|
|
1326
|
-
* RECOMMENDED: Register your agent at https://exagent.io instead of using this method.
|
|
1327
|
-
* The website handles the full registration flow including risk universe selection,
|
|
1328
|
-
* position size limits, daily loss limits, and metadata upload — all in one step.
|
|
1329
|
-
* After registering on the website, use your agent ID in agent-config.json.
|
|
1330
|
-
*
|
|
1331
|
-
* This SDK method is available for programmatic registration but uses default
|
|
1332
|
-
* risk parameters (universe=1, maxPositionSize=10%, maxDailyLoss=5%).
|
|
1333
|
-
*
|
|
1334
|
-
* @param metadata Agent metadata (will be uploaded to IPFS)
|
|
1335
|
-
* @returns The assigned agent ID
|
|
1336
|
-
* @throws Error if wallet already owns an agent (one agent per wallet rule)
|
|
1337
|
-
*/
|
|
1338
|
-
async register(metadata) {
|
|
1339
|
-
const { canRegister, existingAgentId } = await this.registry.canWalletRegister(this.account.address);
|
|
1340
|
-
if (!canRegister) {
|
|
1341
|
-
throw new Error(
|
|
1342
|
-
`This wallet already owns agent #${existingAgentId}. Each wallet can only own one agent. Use a different wallet to create a new agent.`
|
|
1343
|
-
);
|
|
1344
|
-
}
|
|
1345
|
-
const nameAvailable = await this.registry.isNameAvailable(metadata.name);
|
|
1346
|
-
if (!nameAvailable) {
|
|
1347
|
-
throw new Error(`Agent name "${metadata.name}" is already taken`);
|
|
1348
|
-
}
|
|
1349
|
-
const metadataURI = await this.uploadMetadata(metadata);
|
|
1350
|
-
const hash = await this.registry.register(metadata.name, metadataURI);
|
|
1351
|
-
const receipt = await this.publicClient.waitForTransactionReceipt({ hash });
|
|
1352
|
-
const agentId = this.parseAgentIdFromReceipt(receipt);
|
|
1353
|
-
this._agentId = agentId;
|
|
1354
|
-
const linkHash = await this.registry.linkOwnWallet(agentId);
|
|
1355
|
-
await this.publicClient.waitForTransactionReceipt({ hash: linkHash });
|
|
1356
|
-
return agentId;
|
|
25
|
+
async getMe() {
|
|
26
|
+
return this.request("/v1/auth/me");
|
|
1357
27
|
}
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
* @param name The name to check
|
|
1361
|
-
* @returns True if the name is available
|
|
1362
|
-
*/
|
|
1363
|
-
async isNameAvailable(name) {
|
|
1364
|
-
return this.registry.isNameAvailable(name);
|
|
1365
|
-
}
|
|
1366
|
-
/**
|
|
1367
|
-
* Get agent by name (returns 0 if not found)
|
|
1368
|
-
* @param name The agent name to look up
|
|
1369
|
-
* @returns Agent ID or 0 if not found
|
|
1370
|
-
*/
|
|
1371
|
-
async getAgentByName(name) {
|
|
1372
|
-
return this.registry.getAgentByName(name);
|
|
1373
|
-
}
|
|
1374
|
-
/**
|
|
1375
|
-
* Get the current agent's ID (if registered).
|
|
1376
|
-
*
|
|
1377
|
-
* Resolution order:
|
|
1378
|
-
* 1. Cached value (from prior register() or getAgentId() call)
|
|
1379
|
-
* 2. walletToAgent mapping (linked wallets)
|
|
1380
|
-
* 3. Owner lookup (unlinked owner wallet)
|
|
1381
|
-
*
|
|
1382
|
-
* If the agent was just registered, public RPCs may return stale data (0).
|
|
1383
|
-
* Use `retries` to wait for the on-chain state to propagate.
|
|
1384
|
-
*
|
|
1385
|
-
* @param retries Number of retries with 2s delay for stale RPC reads (default: 0)
|
|
1386
|
-
*/
|
|
1387
|
-
async getAgentId(retries = 0) {
|
|
1388
|
-
if (this._agentId) return this._agentId;
|
|
1389
|
-
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
1390
|
-
if (attempt > 0) {
|
|
1391
|
-
await new Promise((r) => setTimeout(r, 2e3));
|
|
1392
|
-
}
|
|
1393
|
-
const agentId = await this.registry.getAgentForWallet(this.account.address);
|
|
1394
|
-
if (agentId > 0n) {
|
|
1395
|
-
this._agentId = agentId;
|
|
1396
|
-
return agentId;
|
|
1397
|
-
}
|
|
1398
|
-
const ownedAgentId = await this.registry.getAgentByOwner(this.account.address);
|
|
1399
|
-
if (ownedAgentId > 0n) {
|
|
1400
|
-
this._agentId = ownedAgentId;
|
|
1401
|
-
return ownedAgentId;
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
|
-
return void 0;
|
|
28
|
+
async listAgents() {
|
|
29
|
+
return this.request("/v1/agents");
|
|
1405
30
|
}
|
|
1406
|
-
/**
|
|
1407
|
-
* Get agent profile
|
|
1408
|
-
* @param agentId Optional agent ID (defaults to current agent)
|
|
1409
|
-
*/
|
|
1410
31
|
async getAgent(agentId) {
|
|
1411
|
-
|
|
1412
|
-
if (!id) throw new Error("Agent not registered");
|
|
1413
|
-
return this.registry.getAgent(id);
|
|
32
|
+
return this.request(`/v1/agents/${agentId}`);
|
|
1414
33
|
}
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
* Link an additional wallet to this agent
|
|
1418
|
-
* @param wallet Wallet address to link
|
|
1419
|
-
* @param signMessage Function to sign the message hash with the wallet (use signMessage({ raw: hash }))
|
|
1420
|
-
*/
|
|
1421
|
-
async linkWallet(wallet, signMessage) {
|
|
1422
|
-
const agentId = await this.getAgentId();
|
|
1423
|
-
if (!agentId) throw new Error("Agent not registered");
|
|
1424
|
-
const nonce = await this.registry.getNonce(wallet);
|
|
1425
|
-
const messageHash = ExagentRegistry.generateLinkMessage(wallet, agentId, nonce);
|
|
1426
|
-
const signature = await signMessage({ raw: messageHash });
|
|
1427
|
-
return this.registry.linkWallet(agentId, wallet, signature);
|
|
1428
|
-
}
|
|
1429
|
-
/**
|
|
1430
|
-
* Get all wallets linked to this agent
|
|
1431
|
-
*/
|
|
1432
|
-
async getLinkedWallets() {
|
|
1433
|
-
const agentId = await this.getAgentId();
|
|
1434
|
-
if (!agentId) throw new Error("Agent not registered");
|
|
1435
|
-
return this.registry.getLinkedWallets(agentId);
|
|
1436
|
-
}
|
|
1437
|
-
// ============ Trading ============
|
|
1438
|
-
/**
|
|
1439
|
-
* Execute a trade through ExagentRouter
|
|
1440
|
-
*
|
|
1441
|
-
* All trades MUST go through the ExagentRouter. This ensures:
|
|
1442
|
-
* - Trade attribution for leaderboard ranking
|
|
1443
|
-
* - Protocol fee collection (0.2%)
|
|
1444
|
-
* - On-chain performance tracking
|
|
1445
|
-
* - Token whitelist enforcement per risk universe
|
|
1446
|
-
*
|
|
1447
|
-
* There is no way to trade outside the router. This is by design.
|
|
1448
|
-
*
|
|
1449
|
-
* @param intent Trade parameters
|
|
1450
|
-
* @returns Trade result with transaction hash
|
|
1451
|
-
*
|
|
1452
|
-
* @example
|
|
1453
|
-
* ```typescript
|
|
1454
|
-
* const result = await exagent.trade({
|
|
1455
|
-
* tokenIn: WETH,
|
|
1456
|
-
* tokenOut: USDC,
|
|
1457
|
-
* amountIn: parseEther('1'),
|
|
1458
|
-
* maxSlippageBps: 50,
|
|
1459
|
-
* });
|
|
1460
|
-
* console.log('Trade submitted:', result.hash);
|
|
1461
|
-
* ```
|
|
1462
|
-
*/
|
|
1463
|
-
async trade(intent) {
|
|
1464
|
-
const agentId = await this.getAgentId();
|
|
1465
|
-
if (!agentId) throw new Error("Agent not registered");
|
|
1466
|
-
const routerTrade = await this.buildRouterTrade(intent, agentId);
|
|
1467
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1468
|
-
for (const approval of routerTrade.approvals) {
|
|
1469
|
-
const key = `${approval.token.toLowerCase()}:${approval.spender.toLowerCase()}`;
|
|
1470
|
-
if (seen.has(key)) continue;
|
|
1471
|
-
seen.add(key);
|
|
1472
|
-
if (!approval.amount) {
|
|
1473
|
-
console.warn(`Skipping approval with missing amount for token ${approval.token} \u2014 0x did not return expected allowance`);
|
|
1474
|
-
continue;
|
|
1475
|
-
}
|
|
1476
|
-
const amount = BigInt(approval.amount);
|
|
1477
|
-
const existing = await this.getAllowance(
|
|
1478
|
-
approval.token,
|
|
1479
|
-
approval.spender
|
|
1480
|
-
);
|
|
1481
|
-
if (existing >= amount) continue;
|
|
1482
|
-
await this.approveToken(
|
|
1483
|
-
approval.token,
|
|
1484
|
-
approval.spender,
|
|
1485
|
-
import_viem2.maxUint256
|
|
1486
|
-
);
|
|
1487
|
-
}
|
|
1488
|
-
const txParams = {
|
|
1489
|
-
account: this.account,
|
|
1490
|
-
chain: CHAIN_CONFIG[this.network],
|
|
1491
|
-
to: routerTrade.transaction.to,
|
|
1492
|
-
data: routerTrade.transaction.data,
|
|
1493
|
-
value: BigInt(routerTrade.transaction.value)
|
|
1494
|
-
};
|
|
1495
|
-
const isETHInput = this.isETHAddress(intent.tokenIn);
|
|
1496
|
-
try {
|
|
1497
|
-
const estimated = await this.publicClient.estimateGas({
|
|
1498
|
-
account: this.account,
|
|
1499
|
-
to: routerTrade.transaction.to,
|
|
1500
|
-
data: routerTrade.transaction.data,
|
|
1501
|
-
value: BigInt(routerTrade.transaction.value)
|
|
1502
|
-
});
|
|
1503
|
-
txParams.gas = estimated * 150n / 100n;
|
|
1504
|
-
} catch (err) {
|
|
1505
|
-
const errorData = err?.data;
|
|
1506
|
-
if (isETHInput) {
|
|
1507
|
-
if (errorData && errorData.length > 2) {
|
|
1508
|
-
console.error(`Gas estimation revert data: ${errorData}`);
|
|
1509
|
-
try {
|
|
1510
|
-
const decoded = (0, import_viem2.decodeErrorResult)({
|
|
1511
|
-
abi: [...EXAGENT_ROUTER_ABI, ...EXAGENT_REGISTRY_ABI],
|
|
1512
|
-
data: errorData
|
|
1513
|
-
});
|
|
1514
|
-
throw new Error(`Trade will revert: ${decoded.errorName}${decoded.args ? ` (${decoded.args.join(", ")})` : ""}`);
|
|
1515
|
-
} catch (decodeErr) {
|
|
1516
|
-
if (decodeErr instanceof Error && decodeErr.message.startsWith("Trade will revert:")) throw decodeErr;
|
|
1517
|
-
throw new Error(`Trade will revert: unknown error selector ${errorData.slice(0, 10)} (raw: ${errorData.slice(0, 66)})`);
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
|
-
throw new Error(`Trade will revert: gas estimation failed. ${err?.message || "Unknown reason"}`);
|
|
1521
|
-
}
|
|
1522
|
-
if (routerTrade.gasEstimate) {
|
|
1523
|
-
const apiGas = BigInt(routerTrade.gasEstimate);
|
|
1524
|
-
txParams.gas = apiGas * 200n / 100n;
|
|
1525
|
-
console.warn(
|
|
1526
|
-
`[SDK] Local gas estimation failed for sell, using API estimate with 100% buffer: ${txParams.gas}. This is expected for some DEX routes. Warning: ${routerTrade.simulationWarning || "none"}`
|
|
1527
|
-
);
|
|
1528
|
-
} else {
|
|
1529
|
-
txParams.gas = 800000n;
|
|
1530
|
-
console.warn(
|
|
1531
|
-
`[SDK] Local gas estimation failed for sell and no API estimate available. Using safe default: 800000. This may result in wasted gas if the transaction reverts.`
|
|
1532
|
-
);
|
|
1533
|
-
}
|
|
1534
|
-
}
|
|
1535
|
-
const hash = await this.walletClient.sendTransaction(txParams);
|
|
1536
|
-
if (routerTrade.route && routerTrade.route.length > 0) {
|
|
1537
|
-
const dexSource = [...new Set(routerTrade.route.map((r) => r.dex))].join(", ");
|
|
1538
|
-
const routeApiUrl = EXAGENT_API_CONFIG[this.network];
|
|
1539
|
-
fetch(`${routeApiUrl}/v1/router/trade-route`, {
|
|
1540
|
-
method: "POST",
|
|
1541
|
-
headers: this.apiHeaders("application/json"),
|
|
1542
|
-
body: JSON.stringify({
|
|
1543
|
-
txHash: hash,
|
|
1544
|
-
agentId: Number(agentId),
|
|
1545
|
-
dexSource,
|
|
1546
|
-
route: routerTrade.route
|
|
1547
|
-
})
|
|
1548
|
-
}).catch(() => {
|
|
1549
|
-
});
|
|
1550
|
-
}
|
|
1551
|
-
return {
|
|
1552
|
-
hash,
|
|
1553
|
-
agentId,
|
|
1554
|
-
tokenIn: routerTrade.tokenIn,
|
|
1555
|
-
tokenOut: routerTrade.tokenOut,
|
|
1556
|
-
amountIn: routerTrade.amountIn,
|
|
1557
|
-
expectedAmountOut: routerTrade.amountOut
|
|
1558
|
-
};
|
|
1559
|
-
}
|
|
1560
|
-
/**
|
|
1561
|
-
* Build a router trade transaction without executing
|
|
1562
|
-
* Useful for simulation or multi-step workflows
|
|
1563
|
-
*/
|
|
1564
|
-
async buildRouterTrade(intent, agentId) {
|
|
1565
|
-
const id = agentId ?? await this.getAgentId();
|
|
1566
|
-
if (!id) throw new Error("Agent not registered");
|
|
1567
|
-
const apiUrl = EXAGENT_API_CONFIG[this.network];
|
|
1568
|
-
let configHash = intent.configHash;
|
|
1569
|
-
if (!configHash) {
|
|
1570
|
-
const onChainHash = await this.registry.getConfigHash(id);
|
|
1571
|
-
if (onChainHash && onChainHash !== "0x0000000000000000000000000000000000000000000000000000000000000000") {
|
|
1572
|
-
configHash = onChainHash;
|
|
1573
|
-
}
|
|
1574
|
-
}
|
|
1575
|
-
const response = await fetch(`${apiUrl}/v1/router/trade`, {
|
|
34
|
+
async createAgent(data) {
|
|
35
|
+
return this.request("/v1/agents", {
|
|
1576
36
|
method: "POST",
|
|
1577
|
-
|
|
1578
|
-
body: JSON.stringify({
|
|
1579
|
-
agentId: id.toString(),
|
|
1580
|
-
tokenIn: intent.tokenIn,
|
|
1581
|
-
tokenOut: intent.tokenOut,
|
|
1582
|
-
amountIn: intent.amountIn.toString(),
|
|
1583
|
-
slippageBps: intent.maxSlippageBps ?? 50,
|
|
1584
|
-
taker: this.account.address,
|
|
1585
|
-
...configHash && { configHash }
|
|
1586
|
-
})
|
|
1587
|
-
});
|
|
1588
|
-
if (!response.ok) {
|
|
1589
|
-
const error = await response.json().catch(() => ({ error: response.statusText }));
|
|
1590
|
-
throw new Error(`Failed to build trade: ${error.error || error.message}`);
|
|
1591
|
-
}
|
|
1592
|
-
return response.json();
|
|
1593
|
-
}
|
|
1594
|
-
/**
|
|
1595
|
-
* Check if an address is the ETH sentinel or WETH
|
|
1596
|
-
*/
|
|
1597
|
-
isETHAddress(addr) {
|
|
1598
|
-
const lower = addr.toLowerCase();
|
|
1599
|
-
return lower === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" || lower === "0x0000000000000000000000000000000000000000" || lower === "0x4200000000000000000000000000000000000006";
|
|
1600
|
-
}
|
|
1601
|
-
/**
|
|
1602
|
-
* Read current ERC-20 allowance for a (token, spender) pair
|
|
1603
|
-
*/
|
|
1604
|
-
async getAllowance(token, spender) {
|
|
1605
|
-
try {
|
|
1606
|
-
const data = await this.publicClient.call({
|
|
1607
|
-
to: token,
|
|
1608
|
-
data: `0xdd62ed3e${this.account.address.slice(2).padStart(64, "0")}${spender.slice(2).padStart(64, "0")}`
|
|
1609
|
-
});
|
|
1610
|
-
if (!data.data || data.data === "0x") return 0n;
|
|
1611
|
-
return BigInt(data.data);
|
|
1612
|
-
} catch {
|
|
1613
|
-
return 0n;
|
|
1614
|
-
}
|
|
1615
|
-
}
|
|
1616
|
-
/**
|
|
1617
|
-
* Approve token spending for router.
|
|
1618
|
-
* Verifies the approval receipt succeeded — previous version silently continued
|
|
1619
|
-
* on reverted approvals, causing downstream "transfer amount exceeds allowance" errors.
|
|
1620
|
-
*/
|
|
1621
|
-
async approveToken(token, spender, amount) {
|
|
1622
|
-
const approveData = this.encodeApprove(spender, amount);
|
|
1623
|
-
const hash = await this.walletClient.sendTransaction({
|
|
1624
|
-
account: this.account,
|
|
1625
|
-
chain: CHAIN_CONFIG[this.network],
|
|
1626
|
-
to: token,
|
|
1627
|
-
data: approveData
|
|
37
|
+
body: JSON.stringify(data)
|
|
1628
38
|
});
|
|
1629
|
-
const receipt = await this.publicClient.waitForTransactionReceipt({ hash });
|
|
1630
|
-
if (receipt.status === "reverted") {
|
|
1631
|
-
throw new Error(
|
|
1632
|
-
`Token approval reverted: approve(${spender}, ${amount}) on ${token}. The token may have non-standard approval behavior.`
|
|
1633
|
-
);
|
|
1634
|
-
}
|
|
1635
|
-
return hash;
|
|
1636
|
-
}
|
|
1637
|
-
/**
|
|
1638
|
-
* Encode ERC20 approve calldata
|
|
1639
|
-
*/
|
|
1640
|
-
encodeApprove(spender, amount) {
|
|
1641
|
-
const selector = "0x095ea7b3";
|
|
1642
|
-
const paddedSpender = spender.slice(2).padStart(64, "0");
|
|
1643
|
-
const paddedAmount = amount.toString(16).padStart(64, "0");
|
|
1644
|
-
return `${selector}${paddedSpender}${paddedAmount}`;
|
|
1645
39
|
}
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
* Request a service from another agent
|
|
1649
|
-
*/
|
|
1650
|
-
async requestService(request) {
|
|
1651
|
-
const agentId = await this.getAgentId();
|
|
1652
|
-
if (!agentId) throw new Error("Agent not registered");
|
|
1653
|
-
const apiUrl = EXAGENT_API_CONFIG[this.network];
|
|
1654
|
-
const response = await fetch(`${apiUrl}/v1/services/request`, {
|
|
40
|
+
async reportTradeSignal(agentId, signal) {
|
|
41
|
+
await this.request(`/v1/agents/${agentId}/signals`, {
|
|
1655
42
|
method: "POST",
|
|
1656
|
-
|
|
1657
|
-
body: JSON.stringify({
|
|
1658
|
-
requesterId: agentId.toString(),
|
|
1659
|
-
...request
|
|
1660
|
-
})
|
|
43
|
+
body: JSON.stringify(signal)
|
|
1661
44
|
});
|
|
1662
|
-
if (!response.ok) {
|
|
1663
|
-
throw new Error(`Failed to request service: ${response.statusText}`);
|
|
1664
|
-
}
|
|
1665
|
-
return response.json();
|
|
1666
45
|
}
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
async listServices(serviceType) {
|
|
1671
|
-
const apiUrl = EXAGENT_API_CONFIG[this.network];
|
|
1672
|
-
const params = new URLSearchParams();
|
|
1673
|
-
if (serviceType) params.set("type", serviceType);
|
|
1674
|
-
const response = await fetch(`${apiUrl}/v1/services?${params}`, {
|
|
1675
|
-
headers: this.apiHeaders()
|
|
1676
|
-
});
|
|
1677
|
-
return response.json();
|
|
1678
|
-
}
|
|
1679
|
-
// ============ Leaderboards ============
|
|
1680
|
-
/**
|
|
1681
|
-
* Get agent leaderboard
|
|
1682
|
-
*/
|
|
1683
|
-
async getLeaderboard(options) {
|
|
1684
|
-
const apiUrl = EXAGENT_API_CONFIG[this.network];
|
|
1685
|
-
const params = new URLSearchParams();
|
|
1686
|
-
if (options?.category) params.set("category", options.category);
|
|
1687
|
-
if (options?.limit) params.set("limit", options.limit.toString());
|
|
1688
|
-
if (options?.offset) params.set("offset", options.offset.toString());
|
|
1689
|
-
const response = await fetch(`${apiUrl}/v1/rankings/leaderboard?${params}`, {
|
|
1690
|
-
headers: this.apiHeaders()
|
|
1691
|
-
});
|
|
1692
|
-
const data = await response.json();
|
|
1693
|
-
return data.agents ?? [];
|
|
46
|
+
getWebSocketUrl() {
|
|
47
|
+
const wsBase = this.baseUrl.replace(/^http:/, "ws:").replace(/^https:/, "wss:");
|
|
48
|
+
return `${wsBase}/ws/agent`;
|
|
1694
49
|
}
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
* @param vaultAddress The vault contract address
|
|
1699
|
-
* @returns ExagentVault instance
|
|
1700
|
-
*/
|
|
1701
|
-
getVault(vaultAddress) {
|
|
1702
|
-
return new ExagentVault(
|
|
1703
|
-
vaultAddress,
|
|
1704
|
-
this.publicClient,
|
|
1705
|
-
this.walletClient,
|
|
1706
|
-
CHAIN_CONFIG[this.network],
|
|
1707
|
-
this.account
|
|
1708
|
-
);
|
|
1709
|
-
}
|
|
1710
|
-
/**
|
|
1711
|
-
* List all vaults for a given agent
|
|
1712
|
-
* @param agentId Agent ID to get vaults for
|
|
1713
|
-
* @returns Array of vault summaries
|
|
1714
|
-
*/
|
|
1715
|
-
async getAgentVaults(agentId) {
|
|
1716
|
-
const id = agentId ?? await this.getAgentId();
|
|
1717
|
-
if (!id) throw new Error("Agent not registered");
|
|
1718
|
-
const apiUrl = EXAGENT_API_CONFIG[this.network];
|
|
1719
|
-
const response = await fetch(`${apiUrl}/v1/vaults?agentId=${id}`, {
|
|
1720
|
-
headers: this.apiHeaders()
|
|
1721
|
-
});
|
|
1722
|
-
if (!response.ok) {
|
|
1723
|
-
throw new Error(`Failed to get vaults: ${response.statusText}`);
|
|
1724
|
-
}
|
|
1725
|
-
return response.json();
|
|
1726
|
-
}
|
|
1727
|
-
/**
|
|
1728
|
-
* List all vaults the user has positions in
|
|
1729
|
-
* @param userAddress User address (defaults to connected wallet)
|
|
1730
|
-
* @returns Array of vault summaries with user position info
|
|
1731
|
-
*/
|
|
1732
|
-
async getUserVaults(userAddress) {
|
|
1733
|
-
const user = userAddress ?? this.account.address;
|
|
1734
|
-
const apiUrl = EXAGENT_API_CONFIG[this.network];
|
|
1735
|
-
const response = await fetch(`${apiUrl}/v1/vaults?depositor=${user}`, {
|
|
1736
|
-
headers: this.apiHeaders()
|
|
1737
|
-
});
|
|
1738
|
-
if (!response.ok) {
|
|
1739
|
-
throw new Error(`Failed to get user vaults: ${response.statusText}`);
|
|
1740
|
-
}
|
|
1741
|
-
return response.json();
|
|
1742
|
-
}
|
|
1743
|
-
/**
|
|
1744
|
-
* List top performing vaults
|
|
1745
|
-
* @param options Filter options
|
|
1746
|
-
* @returns Array of vault summaries sorted by performance
|
|
1747
|
-
*/
|
|
1748
|
-
async getTopVaults(options) {
|
|
1749
|
-
const apiUrl = EXAGENT_API_CONFIG[this.network];
|
|
1750
|
-
const params = new URLSearchParams();
|
|
1751
|
-
if (options?.asset) params.set("asset", options.asset);
|
|
1752
|
-
if (options?.minTvl) params.set("minTvl", options.minTvl.toString());
|
|
1753
|
-
if (options?.period) params.set("period", options.period);
|
|
1754
|
-
if (options?.limit) params.set("limit", options.limit.toString());
|
|
1755
|
-
const response = await fetch(`${apiUrl}/v1/vaults/top?${params}`, {
|
|
1756
|
-
headers: this.apiHeaders()
|
|
1757
|
-
});
|
|
1758
|
-
if (!response.ok) {
|
|
1759
|
-
throw new Error(`Failed to get top vaults: ${response.statusText}`);
|
|
1760
|
-
}
|
|
1761
|
-
return response.json();
|
|
1762
|
-
}
|
|
1763
|
-
/**
|
|
1764
|
-
* Deposit into a vault
|
|
1765
|
-
* @param vaultAddress Vault contract address
|
|
1766
|
-
* @param amount Amount of underlying asset to deposit
|
|
1767
|
-
* @returns Transaction hash
|
|
1768
|
-
*/
|
|
1769
|
-
async depositToVault(vaultAddress, amount) {
|
|
1770
|
-
const vault = this.getVault(vaultAddress);
|
|
1771
|
-
const info = await vault.getVaultInfo();
|
|
1772
|
-
await vault.approveAsset(info.asset, amount);
|
|
1773
|
-
return vault.deposit(amount);
|
|
1774
|
-
}
|
|
1775
|
-
/**
|
|
1776
|
-
* Withdraw from a vault
|
|
1777
|
-
* @param vaultAddress Vault contract address
|
|
1778
|
-
* @param assets Amount of underlying asset to withdraw
|
|
1779
|
-
* @returns Transaction hash
|
|
1780
|
-
*/
|
|
1781
|
-
async withdrawFromVault(vaultAddress, assets) {
|
|
1782
|
-
const vault = this.getVault(vaultAddress);
|
|
1783
|
-
return vault.withdraw(assets);
|
|
1784
|
-
}
|
|
1785
|
-
/**
|
|
1786
|
-
* Redeem shares from a vault
|
|
1787
|
-
* @param vaultAddress Vault contract address
|
|
1788
|
-
* @param shares Amount of shares to redeem
|
|
1789
|
-
* @returns Transaction hash
|
|
1790
|
-
*/
|
|
1791
|
-
async redeemFromVault(vaultAddress, shares) {
|
|
1792
|
-
const vault = this.getVault(vaultAddress);
|
|
1793
|
-
return vault.redeem(shares);
|
|
1794
|
-
}
|
|
1795
|
-
// ============ ERC-8004 Global Agent Identity ============
|
|
1796
|
-
/**
|
|
1797
|
-
* Get the ERC-8004 global agent identifier for the current agent
|
|
1798
|
-
*
|
|
1799
|
-
* Format: eip155:{chainId}:{registryAddress}:{agentId}
|
|
1800
|
-
*
|
|
1801
|
-
* This creates a universally unique identifier that can be used for
|
|
1802
|
-
* cross-protocol agent discovery and interoperability.
|
|
1803
|
-
*
|
|
1804
|
-
* @returns The global agent ID string
|
|
1805
|
-
* @throws Error if agent is not registered
|
|
1806
|
-
*
|
|
1807
|
-
* @example
|
|
1808
|
-
* ```typescript
|
|
1809
|
-
* const globalId = await exagent.getGlobalAgentId();
|
|
1810
|
-
* // => "eip155:8453:0xABC...DEF:42"
|
|
1811
|
-
* ```
|
|
1812
|
-
*/
|
|
1813
|
-
async getGlobalAgentId() {
|
|
1814
|
-
const agentId = await this.getAgentId();
|
|
1815
|
-
if (!agentId) throw new Error("Agent not registered");
|
|
1816
|
-
const chain = CHAIN_CONFIG[this.network];
|
|
1817
|
-
const addresses = CONTRACT_ADDRESSES[this.network];
|
|
1818
|
-
return buildGlobalAgentId(
|
|
1819
|
-
chain.id,
|
|
1820
|
-
addresses.agentRegistry,
|
|
1821
|
-
agentId
|
|
1822
|
-
);
|
|
1823
|
-
}
|
|
1824
|
-
/**
|
|
1825
|
-
* Build a global agent ID for any agent (static utility)
|
|
1826
|
-
*
|
|
1827
|
-
* @param chainId - EVM chain ID
|
|
1828
|
-
* @param registryAddress - ExagentRegistry contract address
|
|
1829
|
-
* @param agentId - On-chain agent ID
|
|
1830
|
-
* @returns ERC-8004 global agent identifier
|
|
1831
|
-
*/
|
|
1832
|
-
static buildGlobalAgentId(chainId, registryAddress, agentId) {
|
|
1833
|
-
return buildGlobalAgentId(chainId, registryAddress, agentId);
|
|
1834
|
-
}
|
|
1835
|
-
// ============ Helpers ============
|
|
1836
|
-
/**
|
|
1837
|
-
* Get the agent's wallet address
|
|
1838
|
-
*/
|
|
1839
|
-
get address() {
|
|
1840
|
-
return this.account.address;
|
|
1841
|
-
}
|
|
1842
|
-
/**
|
|
1843
|
-
* Sign a message with the wallet's private key (EIP-191 personal sign)
|
|
1844
|
-
* @param message The message to sign — string for UTF-8, or { raw: Hex } for raw bytes
|
|
1845
|
-
* @returns The signature
|
|
1846
|
-
*/
|
|
1847
|
-
async signMessage(message) {
|
|
1848
|
-
return this.walletClient.signMessage({ account: this.account, message });
|
|
1849
|
-
}
|
|
1850
|
-
async uploadMetadata(metadata) {
|
|
1851
|
-
const apiUrl = EXAGENT_API_CONFIG[this.network];
|
|
1852
|
-
const response = await fetch(`${apiUrl}/v1/metadata/upload`, {
|
|
1853
|
-
method: "POST",
|
|
1854
|
-
headers: this.apiHeaders("application/json"),
|
|
1855
|
-
body: JSON.stringify(metadata)
|
|
1856
|
-
});
|
|
1857
|
-
if (!response.ok) {
|
|
1858
|
-
throw new Error(`Failed to upload metadata: ${response.statusText}`);
|
|
1859
|
-
}
|
|
1860
|
-
const result = await response.json();
|
|
1861
|
-
return result.uri;
|
|
1862
|
-
}
|
|
1863
|
-
parseAgentIdFromReceipt(receipt) {
|
|
1864
|
-
const registryAddress = this.registry.address.toLowerCase();
|
|
1865
|
-
const AGENT_REGISTERED_TOPIC = (0, import_viem2.keccak256)(
|
|
1866
|
-
(0, import_viem2.toHex)("AgentRegistered(uint256,address,string,string)")
|
|
1867
|
-
);
|
|
1868
|
-
const TRANSFER_TOPIC = (0, import_viem2.keccak256)(
|
|
1869
|
-
(0, import_viem2.toHex)("Transfer(address,address,uint256)")
|
|
1870
|
-
);
|
|
1871
|
-
const ZERO_ADDRESS2 = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
1872
|
-
for (const log of receipt.logs) {
|
|
1873
|
-
if (log.address.toLowerCase() !== registryAddress) continue;
|
|
1874
|
-
if (log.topics[0] === AGENT_REGISTERED_TOPIC && log.topics[1]) {
|
|
1875
|
-
return BigInt(log.topics[1]);
|
|
1876
|
-
}
|
|
1877
|
-
}
|
|
1878
|
-
for (const log of receipt.logs) {
|
|
1879
|
-
if (log.address.toLowerCase() !== registryAddress) continue;
|
|
1880
|
-
if (log.topics[0] === TRANSFER_TOPIC && log.topics[1] === ZERO_ADDRESS2 && log.topics[3]) {
|
|
1881
|
-
return BigInt(log.topics[3]);
|
|
1882
|
-
}
|
|
1883
|
-
}
|
|
1884
|
-
throw new Error(
|
|
1885
|
-
"Could not extract agent ID from transaction receipt.\nNeither AgentRegistered nor ERC721 Transfer event found in logs.\nCheck the transaction on BaseScan to verify registration succeeded."
|
|
1886
|
-
);
|
|
50
|
+
getDashboardWebSocketUrl() {
|
|
51
|
+
const wsBase = this.baseUrl.replace(/^http:/, "ws:").replace(/^https:/, "wss:");
|
|
52
|
+
return `${wsBase}/ws/dashboard`;
|
|
1887
53
|
}
|
|
1888
54
|
};
|
|
1889
55
|
|
|
1890
|
-
// src/
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
// deployed ExagentVaultFactoryV2 contract. SDK methods that called these
|
|
1907
|
-
// now use inline validation (allowedAssets, vaults, MIN_SEED_AMOUNT) instead.
|
|
1908
|
-
// Write functions
|
|
1909
|
-
{
|
|
1910
|
-
type: "function",
|
|
1911
|
-
name: "createVault",
|
|
1912
|
-
inputs: [
|
|
1913
|
-
{ name: "agentId", type: "uint256" },
|
|
1914
|
-
{ name: "asset", type: "address" },
|
|
1915
|
-
{ name: "seedAmount", type: "uint256" },
|
|
1916
|
-
{ name: "name", type: "string" },
|
|
1917
|
-
{ name: "symbol", type: "string" },
|
|
1918
|
-
{ name: "feeRecipient", type: "address" }
|
|
1919
|
-
],
|
|
1920
|
-
outputs: [{ type: "address" }],
|
|
1921
|
-
stateMutability: "nonpayable"
|
|
1922
|
-
},
|
|
1923
|
-
// Events
|
|
1924
|
-
{
|
|
1925
|
-
type: "event",
|
|
1926
|
-
name: "VaultCreated",
|
|
1927
|
-
inputs: [
|
|
1928
|
-
{ name: "vault", type: "address", indexed: true },
|
|
1929
|
-
{ name: "agentId", type: "uint256", indexed: true },
|
|
1930
|
-
{ name: "asset", type: "address", indexed: true },
|
|
1931
|
-
{ name: "creator", type: "address", indexed: false },
|
|
1932
|
-
{ name: "name", type: "string", indexed: false },
|
|
1933
|
-
{ name: "symbol", type: "string", indexed: false }
|
|
1934
|
-
]
|
|
1935
|
-
},
|
|
1936
|
-
{
|
|
1937
|
-
type: "event",
|
|
1938
|
-
name: "AllowedAssetUpdated",
|
|
1939
|
-
inputs: [
|
|
1940
|
-
{ name: "asset", type: "address", indexed: true },
|
|
1941
|
-
{ name: "allowed", type: "bool", indexed: false }
|
|
1942
|
-
]
|
|
1943
|
-
}
|
|
1944
|
-
];
|
|
1945
|
-
var ExagentVaultFactory = class {
|
|
1946
|
-
address;
|
|
1947
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1948
|
-
publicClient;
|
|
1949
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1950
|
-
walletClient;
|
|
1951
|
-
chain;
|
|
1952
|
-
account;
|
|
1953
|
-
constructor(factoryAddress, publicClient, walletClient, chain, account) {
|
|
1954
|
-
this.address = factoryAddress;
|
|
1955
|
-
this.publicClient = publicClient;
|
|
1956
|
-
this.walletClient = walletClient;
|
|
1957
|
-
if (!chain) {
|
|
1958
|
-
throw new Error("Chain parameter is required");
|
|
1959
|
-
}
|
|
1960
|
-
this.chain = chain;
|
|
1961
|
-
this.account = account;
|
|
1962
|
-
}
|
|
1963
|
-
// ============ Read Functions ============
|
|
1964
|
-
/**
|
|
1965
|
-
* Get vault creation requirements (mainnet: seed-based, no burn fee)
|
|
1966
|
-
*/
|
|
1967
|
-
async getRequirements() {
|
|
1968
|
-
const [minSeedAmount, unverifiedCapMultiplier, verifiedCapMultiplier] = await Promise.all([
|
|
1969
|
-
this.publicClient.readContract({
|
|
1970
|
-
address: this.address,
|
|
1971
|
-
abi: EXAGENT_VAULT_FACTORY_ABI,
|
|
1972
|
-
functionName: "MIN_SEED_AMOUNT"
|
|
1973
|
-
}),
|
|
1974
|
-
this.publicClient.readContract({
|
|
1975
|
-
address: this.address,
|
|
1976
|
-
abi: EXAGENT_VAULT_FACTORY_ABI,
|
|
1977
|
-
functionName: "UNVERIFIED_CAP_MULTIPLIER"
|
|
1978
|
-
}),
|
|
1979
|
-
this.publicClient.readContract({
|
|
1980
|
-
address: this.address,
|
|
1981
|
-
abi: EXAGENT_VAULT_FACTORY_ABI,
|
|
1982
|
-
functionName: "VERIFIED_CAP_MULTIPLIER"
|
|
1983
|
-
})
|
|
1984
|
-
]);
|
|
1985
|
-
return {
|
|
1986
|
-
minSeedAmount,
|
|
1987
|
-
unverifiedCapMultiplier,
|
|
1988
|
-
verifiedCapMultiplier
|
|
1989
|
-
};
|
|
1990
|
-
}
|
|
1991
|
-
/**
|
|
1992
|
-
* Check if an address can create a vault.
|
|
1993
|
-
* Performs inline validation since the on-chain contract does not expose
|
|
1994
|
-
* a canCreateVault() view function.
|
|
1995
|
-
* @param creator Address to check
|
|
1996
|
-
*/
|
|
1997
|
-
async canCreateVault(creator) {
|
|
1998
|
-
try {
|
|
1999
|
-
const isUsdcAllowed = await this.isAssetAllowed("0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913");
|
|
2000
|
-
if (!isUsdcAllowed) {
|
|
2001
|
-
return { canCreate: false, reason: "USDC is not an allowed asset" };
|
|
2002
|
-
}
|
|
2003
|
-
} catch {
|
|
2004
|
-
}
|
|
2005
|
-
return { canCreate: true, reason: "" };
|
|
2006
|
-
}
|
|
2007
|
-
/**
|
|
2008
|
-
* Check if an asset is whitelisted for vault creation
|
|
2009
|
-
* @param asset Asset address to check
|
|
2010
|
-
*/
|
|
2011
|
-
async isAssetAllowed(asset) {
|
|
2012
|
-
return this.publicClient.readContract({
|
|
2013
|
-
address: this.address,
|
|
2014
|
-
abi: EXAGENT_VAULT_FACTORY_ABI,
|
|
2015
|
-
functionName: "allowedAssets",
|
|
2016
|
-
args: [asset]
|
|
2017
|
-
});
|
|
2018
|
-
}
|
|
2019
|
-
/**
|
|
2020
|
-
* Get existing vault for an agent and asset
|
|
2021
|
-
* @param agentId Agent ID
|
|
2022
|
-
* @param asset Asset address
|
|
2023
|
-
* @returns Vault address or zero address if none exists
|
|
2024
|
-
*/
|
|
2025
|
-
async getVault(agentId, asset) {
|
|
2026
|
-
return this.publicClient.readContract({
|
|
2027
|
-
address: this.address,
|
|
2028
|
-
abi: EXAGENT_VAULT_FACTORY_ABI,
|
|
2029
|
-
functionName: "vaults",
|
|
2030
|
-
args: [agentId, asset]
|
|
2031
|
-
});
|
|
2032
|
-
}
|
|
2033
|
-
/**
|
|
2034
|
-
* Get count of vaults for an agent
|
|
2035
|
-
* @param agentId Agent ID
|
|
2036
|
-
*/
|
|
2037
|
-
async getAgentVaultCount(agentId) {
|
|
2038
|
-
return this.publicClient.readContract({
|
|
2039
|
-
address: this.address,
|
|
2040
|
-
abi: EXAGENT_VAULT_FACTORY_ABI,
|
|
2041
|
-
functionName: "agentVaultCount",
|
|
2042
|
-
args: [agentId]
|
|
2043
|
-
});
|
|
2044
|
-
}
|
|
2045
|
-
/**
|
|
2046
|
-
* Check if agent already has a vault for an asset
|
|
2047
|
-
* @param agentId Agent ID
|
|
2048
|
-
* @param asset Asset address
|
|
2049
|
-
*/
|
|
2050
|
-
async hasVault(agentId, asset) {
|
|
2051
|
-
const vault = await this.getVault(agentId, asset);
|
|
2052
|
-
return vault !== "0x0000000000000000000000000000000000000000";
|
|
2053
|
-
}
|
|
2054
|
-
// ============ Write Functions ============
|
|
2055
|
-
/**
|
|
2056
|
-
* Create a new vault for an agent (mainnet: requires seed amount)
|
|
2057
|
-
* @param options Vault creation options including seedAmount
|
|
2058
|
-
* @returns Transaction hash
|
|
2059
|
-
*/
|
|
2060
|
-
async createVault(options) {
|
|
2061
|
-
if (!this.walletClient || !this.account) {
|
|
2062
|
-
throw new Error("Wallet client required for vault creation");
|
|
2063
|
-
}
|
|
2064
|
-
const feeRecipient = options.feeRecipient ?? this.account.address;
|
|
2065
|
-
const hash = await this.walletClient.writeContract({
|
|
2066
|
-
address: this.address,
|
|
2067
|
-
abi: EXAGENT_VAULT_FACTORY_ABI,
|
|
2068
|
-
functionName: "createVault",
|
|
2069
|
-
args: [options.agentId, options.asset, options.seedAmount, options.name, options.symbol, feeRecipient],
|
|
2070
|
-
account: this.account,
|
|
2071
|
-
chain: this.chain
|
|
2072
|
-
});
|
|
2073
|
-
return hash;
|
|
2074
|
-
}
|
|
2075
|
-
// ============ Convenience Methods ============
|
|
2076
|
-
/**
|
|
2077
|
-
* Check all requirements and create a vault if possible
|
|
2078
|
-
* Returns detailed status about each requirement
|
|
2079
|
-
*/
|
|
2080
|
-
async checkAndCreateVault(agentId, asset, seedAmount, name, symbol, feeRecipient) {
|
|
2081
|
-
const [canCreateResult, assetAllowed, hasExisting] = await Promise.all([
|
|
2082
|
-
this.canCreateVault(this.account?.address ?? "0x0000000000000000000000000000000000000000"),
|
|
2083
|
-
this.isAssetAllowed(asset),
|
|
2084
|
-
this.hasVault(agentId, asset)
|
|
2085
|
-
]);
|
|
2086
|
-
const checks = {
|
|
2087
|
-
canCreate: canCreateResult.canCreate,
|
|
2088
|
-
canCreateReason: canCreateResult.reason,
|
|
2089
|
-
assetAllowed,
|
|
2090
|
-
hasExistingVault: hasExisting
|
|
2091
|
-
};
|
|
2092
|
-
if (!canCreateResult.canCreate) {
|
|
2093
|
-
return {
|
|
2094
|
-
success: false,
|
|
2095
|
-
error: `Cannot create vault: ${canCreateResult.reason}`,
|
|
2096
|
-
checks
|
|
2097
|
-
};
|
|
2098
|
-
}
|
|
2099
|
-
if (!assetAllowed) {
|
|
2100
|
-
return {
|
|
2101
|
-
success: false,
|
|
2102
|
-
error: `Asset ${asset} is not whitelisted for vault creation`,
|
|
2103
|
-
checks
|
|
2104
|
-
};
|
|
2105
|
-
}
|
|
2106
|
-
if (hasExisting) {
|
|
2107
|
-
const existingVault = await this.getVault(agentId, asset);
|
|
2108
|
-
return {
|
|
2109
|
-
success: false,
|
|
2110
|
-
error: `Vault already exists for this agent and asset`,
|
|
2111
|
-
vaultAddress: existingVault,
|
|
2112
|
-
checks
|
|
2113
|
-
};
|
|
2114
|
-
}
|
|
2115
|
-
try {
|
|
2116
|
-
const txHash = await this.createVault({
|
|
2117
|
-
agentId,
|
|
2118
|
-
asset,
|
|
2119
|
-
seedAmount,
|
|
2120
|
-
name,
|
|
2121
|
-
symbol,
|
|
2122
|
-
feeRecipient
|
|
2123
|
-
});
|
|
2124
|
-
const receipt = await this.publicClient.waitForTransactionReceipt({ hash: txHash });
|
|
2125
|
-
if (receipt.status !== "success") {
|
|
2126
|
-
return {
|
|
2127
|
-
success: false,
|
|
2128
|
-
error: "Transaction failed",
|
|
2129
|
-
txHash,
|
|
2130
|
-
checks
|
|
2131
|
-
};
|
|
2132
|
-
}
|
|
2133
|
-
const vaultAddress = await this.getVault(agentId, asset);
|
|
2134
|
-
return {
|
|
2135
|
-
success: true,
|
|
2136
|
-
vaultAddress,
|
|
2137
|
-
txHash,
|
|
2138
|
-
checks
|
|
2139
|
-
};
|
|
2140
|
-
} catch (error) {
|
|
2141
|
-
return {
|
|
2142
|
-
success: false,
|
|
2143
|
-
error: error instanceof Error ? error.message : "Unknown error creating vault",
|
|
2144
|
-
checks
|
|
2145
|
-
};
|
|
2146
|
-
}
|
|
2147
|
-
}
|
|
2148
|
-
};
|
|
2149
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
2150
|
-
0 && (module.exports = {
|
|
2151
|
-
CHAIN_CONFIG,
|
|
2152
|
-
CONTRACT_ADDRESSES,
|
|
2153
|
-
DEFAULT_RPC_URL,
|
|
2154
|
-
DEX_ADDRESSES,
|
|
2155
|
-
EXAGENT_API_CONFIG,
|
|
2156
|
-
EXAGENT_REGISTRY_ABI,
|
|
2157
|
-
EXAGENT_ROUTER_ABI,
|
|
2158
|
-
EXAGENT_VAULT_FACTORY_ABI,
|
|
2159
|
-
ExagentClient,
|
|
2160
|
-
ExagentRegistry,
|
|
2161
|
-
ExagentVault,
|
|
2162
|
-
ExagentVaultFactory,
|
|
2163
|
-
SDK_VERSION,
|
|
2164
|
-
ZERO_X_CONFIG,
|
|
2165
|
-
buildGlobalAgentId,
|
|
2166
|
-
getRpcUrl,
|
|
2167
|
-
parseGlobalAgentId
|
|
56
|
+
// src/types.ts
|
|
57
|
+
import { z } from "zod";
|
|
58
|
+
var tradeSignalSchema = z.object({
|
|
59
|
+
venue: z.string(),
|
|
60
|
+
chain: z.string().optional(),
|
|
61
|
+
symbol: z.string(),
|
|
62
|
+
side: z.enum(["long", "short", "buy", "sell"]),
|
|
63
|
+
size: z.number().positive(),
|
|
64
|
+
price: z.number().positive(),
|
|
65
|
+
fee: z.number().min(0),
|
|
66
|
+
venueFillId: z.string(),
|
|
67
|
+
venueTimestamp: z.string(),
|
|
68
|
+
leverage: z.number().optional(),
|
|
69
|
+
orderType: z.string().optional(),
|
|
70
|
+
confidence: z.number().min(0).max(1).optional(),
|
|
71
|
+
reasoning: z.string().optional()
|
|
2168
72
|
});
|
|
73
|
+
var tradingConfigSchema = z.object({
|
|
74
|
+
mode: z.enum(["live", "paper"]).default("paper"),
|
|
75
|
+
timeHorizon: z.enum(["intraday", "swing", "position"]).default("swing"),
|
|
76
|
+
maxPositionSizeBps: z.number().min(100).max(1e4).default(2e3),
|
|
77
|
+
maxDailyLossBps: z.number().min(0).max(1e4).default(500),
|
|
78
|
+
maxConcurrentPositions: z.number().min(1).max(100).default(5),
|
|
79
|
+
tradingIntervalMs: z.number().min(1e3).default(6e4),
|
|
80
|
+
maxSlippageBps: z.number().min(10).max(1e3).default(100),
|
|
81
|
+
minTradeValueUSD: z.number().min(0).default(10),
|
|
82
|
+
initialCapitalUSD: z.number().optional()
|
|
83
|
+
});
|
|
84
|
+
export {
|
|
85
|
+
ExagentClient,
|
|
86
|
+
tradeSignalSchema,
|
|
87
|
+
tradingConfigSchema
|
|
88
|
+
};
|