@exagent/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,2738 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/client.ts
9
+ import {
10
+ createPublicClient,
11
+ createWalletClient,
12
+ http
13
+ } from "viem";
14
+ import { privateKeyToAccount } from "viem/accounts";
15
+
16
+ // src/contracts/registry.ts
17
+ var EXAGENT_REGISTRY_ABI = [
18
+ {
19
+ type: "function",
20
+ name: "registerAgent",
21
+ inputs: [
22
+ { name: "name", type: "string" },
23
+ { name: "metadataURI", type: "string" }
24
+ ],
25
+ outputs: [{ name: "agentId", type: "uint256" }],
26
+ stateMutability: "nonpayable"
27
+ },
28
+ {
29
+ type: "function",
30
+ name: "isNameAvailable",
31
+ inputs: [{ name: "name", type: "string" }],
32
+ outputs: [{ name: "available", type: "bool" }],
33
+ stateMutability: "view"
34
+ },
35
+ {
36
+ type: "function",
37
+ name: "getAgentByName",
38
+ inputs: [{ name: "name", type: "string" }],
39
+ outputs: [{ name: "agentId", type: "uint256" }],
40
+ stateMutability: "view"
41
+ },
42
+ {
43
+ type: "function",
44
+ name: "linkWallet",
45
+ inputs: [
46
+ { name: "agentId", type: "uint256" },
47
+ { name: "wallet", type: "address" },
48
+ { name: "signature", type: "bytes" }
49
+ ],
50
+ outputs: [],
51
+ stateMutability: "nonpayable"
52
+ },
53
+ {
54
+ type: "function",
55
+ name: "linkOwnWallet",
56
+ inputs: [{ name: "agentId", type: "uint256" }],
57
+ outputs: [],
58
+ stateMutability: "nonpayable"
59
+ },
60
+ {
61
+ type: "function",
62
+ name: "unlinkWallet",
63
+ inputs: [
64
+ { name: "agentId", type: "uint256" },
65
+ { name: "wallet", type: "address" }
66
+ ],
67
+ outputs: [],
68
+ stateMutability: "nonpayable"
69
+ },
70
+ {
71
+ type: "function",
72
+ name: "updateMetadata",
73
+ inputs: [
74
+ { name: "agentId", type: "uint256" },
75
+ { name: "newURI", type: "string" }
76
+ ],
77
+ outputs: [],
78
+ stateMutability: "nonpayable"
79
+ },
80
+ {
81
+ type: "function",
82
+ name: "agents",
83
+ inputs: [{ name: "agentId", type: "uint256" }],
84
+ outputs: [
85
+ { name: "owner", type: "address" },
86
+ { name: "name", type: "string" },
87
+ { name: "metadataURI", type: "string" },
88
+ { name: "registrationTime", type: "uint256" },
89
+ { name: "verified", type: "bool" },
90
+ { name: "linkedWalletCount", type: "uint256" }
91
+ ],
92
+ stateMutability: "view"
93
+ },
94
+ {
95
+ type: "function",
96
+ name: "getLinkedWallets",
97
+ inputs: [{ name: "agentId", type: "uint256" }],
98
+ outputs: [{ name: "", type: "address[]" }],
99
+ stateMutability: "view"
100
+ },
101
+ {
102
+ type: "function",
103
+ name: "getAgentForWallet",
104
+ inputs: [{ name: "wallet", type: "address" }],
105
+ outputs: [{ name: "", type: "uint256" }],
106
+ stateMutability: "view"
107
+ },
108
+ {
109
+ type: "function",
110
+ name: "walletToAgent",
111
+ inputs: [{ name: "wallet", type: "address" }],
112
+ outputs: [{ name: "", type: "uint256" }],
113
+ stateMutability: "view"
114
+ },
115
+ {
116
+ type: "function",
117
+ name: "nonces",
118
+ inputs: [{ name: "wallet", type: "address" }],
119
+ outputs: [{ name: "", type: "uint256" }],
120
+ stateMutability: "view"
121
+ },
122
+ {
123
+ type: "function",
124
+ name: "nextAgentId",
125
+ inputs: [],
126
+ outputs: [{ name: "", type: "uint256" }],
127
+ stateMutability: "view"
128
+ },
129
+ {
130
+ type: "function",
131
+ name: "ownerOf",
132
+ inputs: [{ name: "tokenId", type: "uint256" }],
133
+ outputs: [{ name: "", type: "address" }],
134
+ stateMutability: "view"
135
+ },
136
+ {
137
+ type: "function",
138
+ name: "balanceOf",
139
+ inputs: [{ name: "owner", type: "address" }],
140
+ outputs: [{ name: "", type: "uint256" }],
141
+ stateMutability: "view"
142
+ },
143
+ {
144
+ type: "event",
145
+ name: "AgentRegistered",
146
+ inputs: [
147
+ { name: "agentId", type: "uint256", indexed: true },
148
+ { name: "owner", type: "address", indexed: true },
149
+ { name: "name", type: "string", indexed: false },
150
+ { name: "metadataURI", type: "string", indexed: false }
151
+ ]
152
+ },
153
+ {
154
+ type: "event",
155
+ name: "WalletLinked",
156
+ inputs: [
157
+ { name: "agentId", type: "uint256", indexed: true },
158
+ { name: "wallet", type: "address", indexed: true }
159
+ ]
160
+ },
161
+ {
162
+ type: "event",
163
+ name: "WalletUnlinked",
164
+ inputs: [
165
+ { name: "agentId", type: "uint256", indexed: true },
166
+ { name: "wallet", type: "address", indexed: true }
167
+ ]
168
+ },
169
+ // V4: One agent per wallet
170
+ {
171
+ type: "function",
172
+ name: "ownerToAgentId",
173
+ inputs: [{ name: "owner", type: "address" }],
174
+ outputs: [{ name: "", type: "uint256" }],
175
+ stateMutability: "view"
176
+ },
177
+ {
178
+ type: "function",
179
+ name: "getAgentByOwner",
180
+ inputs: [{ name: "wallet", type: "address" }],
181
+ outputs: [{ name: "agentId", type: "uint256" }],
182
+ stateMutability: "view"
183
+ },
184
+ {
185
+ type: "function",
186
+ name: "canWalletRegister",
187
+ inputs: [{ name: "wallet", type: "address" }],
188
+ outputs: [
189
+ { name: "canRegister", type: "bool" },
190
+ { name: "existingAgentId", type: "uint256" }
191
+ ],
192
+ stateMutability: "view"
193
+ },
194
+ {
195
+ type: "function",
196
+ name: "version",
197
+ inputs: [],
198
+ outputs: [{ name: "", type: "string" }],
199
+ stateMutability: "pure"
200
+ },
201
+ // Config Epochs
202
+ {
203
+ type: "function",
204
+ name: "updateConfig",
205
+ inputs: [
206
+ { name: "agentId", type: "uint256" },
207
+ { name: "newConfigHash", type: "bytes32" }
208
+ ],
209
+ outputs: [],
210
+ stateMutability: "nonpayable"
211
+ },
212
+ {
213
+ type: "function",
214
+ name: "getConfigHash",
215
+ inputs: [{ name: "agentId", type: "uint256" }],
216
+ outputs: [{ name: "", type: "bytes32" }],
217
+ stateMutability: "view"
218
+ },
219
+ {
220
+ type: "function",
221
+ name: "getCurrentEpoch",
222
+ inputs: [{ name: "agentId", type: "uint256" }],
223
+ outputs: [{ name: "", type: "uint256" }],
224
+ stateMutability: "view"
225
+ },
226
+ {
227
+ type: "function",
228
+ name: "getAgentConfig",
229
+ inputs: [{ name: "agentId", type: "uint256" }],
230
+ outputs: [
231
+ {
232
+ name: "",
233
+ type: "tuple",
234
+ components: [
235
+ { name: "configHash", type: "bytes32" },
236
+ { name: "epochId", type: "uint256" },
237
+ { name: "epochStartBlock", type: "uint256" }
238
+ ]
239
+ }
240
+ ],
241
+ stateMutability: "view"
242
+ },
243
+ {
244
+ type: "function",
245
+ name: "getEpochConfigHash",
246
+ inputs: [
247
+ { name: "agentId", type: "uint256" },
248
+ { name: "epochId", type: "uint256" }
249
+ ],
250
+ outputs: [{ name: "", type: "bytes32" }],
251
+ stateMutability: "view"
252
+ },
253
+ {
254
+ type: "event",
255
+ name: "ConfigUpdated",
256
+ inputs: [
257
+ { name: "agentId", type: "uint256", indexed: true },
258
+ { name: "oldConfigHash", type: "bytes32", indexed: false },
259
+ { name: "newConfigHash", type: "bytes32", indexed: false },
260
+ { name: "epochId", type: "uint256", indexed: false },
261
+ { name: "blockNumber", type: "uint256", indexed: false }
262
+ ]
263
+ }
264
+ ];
265
+ var ExagentRegistry = class {
266
+ address;
267
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
268
+ publicClient;
269
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
270
+ walletClient;
271
+ chain;
272
+ account;
273
+ constructor(address, publicClient, walletClient, chain, account) {
274
+ this.address = address;
275
+ this.publicClient = publicClient;
276
+ this.walletClient = walletClient;
277
+ this.chain = chain;
278
+ this.account = account;
279
+ }
280
+ /**
281
+ * Register a new agent
282
+ * @param name Unique agent name (3-32 chars, alphanumeric + spaces/hyphens/underscores)
283
+ * @param metadataURI IPFS URI for agent metadata
284
+ * @returns Transaction hash
285
+ */
286
+ async register(name, metadataURI) {
287
+ if (!this.walletClient || !this.account) throw new Error("Wallet client and account required for write operations");
288
+ const hash = await this.walletClient.writeContract({
289
+ account: this.account,
290
+ chain: this.chain,
291
+ address: this.address,
292
+ abi: EXAGENT_REGISTRY_ABI,
293
+ functionName: "registerAgent",
294
+ args: [name, metadataURI]
295
+ });
296
+ return hash;
297
+ }
298
+ /**
299
+ * Check if a name is available for registration
300
+ * @param name The name to check
301
+ * @returns True if the name can be used
302
+ */
303
+ async isNameAvailable(name) {
304
+ const available = await this.publicClient.readContract({
305
+ address: this.address,
306
+ abi: EXAGENT_REGISTRY_ABI,
307
+ functionName: "isNameAvailable",
308
+ args: [name]
309
+ });
310
+ return available;
311
+ }
312
+ /**
313
+ * Get the agent ID that owns a specific name
314
+ * @param name The name to look up
315
+ * @returns Agent ID (0 if not taken)
316
+ */
317
+ async getAgentByName(name) {
318
+ const agentId = await this.publicClient.readContract({
319
+ address: this.address,
320
+ abi: EXAGENT_REGISTRY_ABI,
321
+ functionName: "getAgentByName",
322
+ args: [name]
323
+ });
324
+ return agentId;
325
+ }
326
+ /**
327
+ * Link the wallet used by the agent to their agent ID
328
+ * @param agentId The agent's ID
329
+ * @returns Transaction hash
330
+ */
331
+ async linkOwnWallet(agentId) {
332
+ if (!this.walletClient || !this.account) throw new Error("Wallet client and account required for write operations");
333
+ const hash = await this.walletClient.writeContract({
334
+ account: this.account,
335
+ chain: this.chain,
336
+ address: this.address,
337
+ abi: EXAGENT_REGISTRY_ABI,
338
+ functionName: "linkOwnWallet",
339
+ args: [agentId]
340
+ });
341
+ return hash;
342
+ }
343
+ /**
344
+ * Link an external wallet with signature proof
345
+ * @param agentId The agent's ID
346
+ * @param wallet The wallet to link
347
+ * @param signature Signature from the wallet proving ownership
348
+ * @returns Transaction hash
349
+ */
350
+ async linkWallet(agentId, wallet, signature) {
351
+ if (!this.walletClient || !this.account) throw new Error("Wallet client and account required for write operations");
352
+ const hash = await this.walletClient.writeContract({
353
+ account: this.account,
354
+ chain: this.chain,
355
+ address: this.address,
356
+ abi: EXAGENT_REGISTRY_ABI,
357
+ functionName: "linkWallet",
358
+ args: [agentId, wallet, signature]
359
+ });
360
+ return hash;
361
+ }
362
+ /**
363
+ * Unlink a wallet from an agent
364
+ * @param agentId The agent's ID
365
+ * @param wallet The wallet to unlink
366
+ * @returns Transaction hash
367
+ */
368
+ async unlinkWallet(agentId, wallet) {
369
+ if (!this.walletClient || !this.account) throw new Error("Wallet client and account required for write operations");
370
+ const hash = await this.walletClient.writeContract({
371
+ account: this.account,
372
+ chain: this.chain,
373
+ address: this.address,
374
+ abi: EXAGENT_REGISTRY_ABI,
375
+ functionName: "unlinkWallet",
376
+ args: [agentId, wallet]
377
+ });
378
+ return hash;
379
+ }
380
+ /**
381
+ * Update agent metadata
382
+ * @param agentId The agent's ID
383
+ * @param newURI New IPFS URI for metadata
384
+ * @returns Transaction hash
385
+ */
386
+ async updateMetadata(agentId, newURI) {
387
+ if (!this.walletClient || !this.account) throw new Error("Wallet client and account required for write operations");
388
+ const hash = await this.walletClient.writeContract({
389
+ account: this.account,
390
+ chain: this.chain,
391
+ address: this.address,
392
+ abi: EXAGENT_REGISTRY_ABI,
393
+ functionName: "updateMetadata",
394
+ args: [agentId, newURI]
395
+ });
396
+ return hash;
397
+ }
398
+ /**
399
+ * Get agent profile by ID
400
+ * @param agentId The agent's ID
401
+ * @returns Agent profile data
402
+ */
403
+ async getAgent(agentId) {
404
+ const result = await this.publicClient.readContract({
405
+ address: this.address,
406
+ abi: EXAGENT_REGISTRY_ABI,
407
+ functionName: "agents",
408
+ args: [agentId]
409
+ });
410
+ return {
411
+ agentId,
412
+ owner: result[0],
413
+ name: result[1],
414
+ metadataURI: result[2],
415
+ registrationTime: result[3],
416
+ verified: result[4],
417
+ linkedWalletCount: result[5]
418
+ };
419
+ }
420
+ /**
421
+ * Get all linked wallets for an agent
422
+ * @param agentId The agent's ID
423
+ * @returns Array of linked wallet addresses
424
+ */
425
+ async getLinkedWallets(agentId) {
426
+ const wallets = await this.publicClient.readContract({
427
+ address: this.address,
428
+ abi: EXAGENT_REGISTRY_ABI,
429
+ functionName: "getLinkedWallets",
430
+ args: [agentId]
431
+ });
432
+ return wallets;
433
+ }
434
+ /**
435
+ * Get agent ID for a wallet (for trade attribution)
436
+ * @param wallet The wallet address
437
+ * @returns Agent ID (0 if not linked)
438
+ */
439
+ async getAgentForWallet(wallet) {
440
+ const agentId = await this.publicClient.readContract({
441
+ address: this.address,
442
+ abi: EXAGENT_REGISTRY_ABI,
443
+ functionName: "walletToAgent",
444
+ args: [wallet]
445
+ });
446
+ return agentId;
447
+ }
448
+ /**
449
+ * Check if a wallet is linked to a specific agent
450
+ * @param agentId The agent's ID
451
+ * @param wallet The wallet address to check
452
+ * @returns True if the wallet is linked to the agent
453
+ */
454
+ async isLinkedWallet(agentId, wallet) {
455
+ const linkedWallets = await this.getLinkedWallets(agentId);
456
+ return linkedWallets.some((w) => w.toLowerCase() === wallet.toLowerCase());
457
+ }
458
+ /**
459
+ * Get the nonce for wallet linking signature
460
+ * @param wallet The wallet address
461
+ * @returns Current nonce
462
+ */
463
+ async getNonce(wallet) {
464
+ const nonce = await this.publicClient.readContract({
465
+ address: this.address,
466
+ abi: EXAGENT_REGISTRY_ABI,
467
+ functionName: "nonces",
468
+ args: [wallet]
469
+ });
470
+ return nonce;
471
+ }
472
+ /**
473
+ * Get the next agent ID that will be assigned
474
+ * @returns Next agent ID
475
+ */
476
+ async getNextAgentId() {
477
+ const nextId = await this.publicClient.readContract({
478
+ address: this.address,
479
+ abi: EXAGENT_REGISTRY_ABI,
480
+ functionName: "nextAgentId"
481
+ });
482
+ return nextId;
483
+ }
484
+ /**
485
+ * Generate the message to sign for wallet linking
486
+ * @param wallet The wallet to link
487
+ * @param agentId The agent ID to link to
488
+ * @param nonce The current nonce for the wallet
489
+ * @returns Message to sign
490
+ */
491
+ static generateLinkMessage(wallet, agentId, nonce) {
492
+ return `Link wallet ${wallet} to Exagent ${agentId} nonce ${nonce}`;
493
+ }
494
+ // ============ V4: One Agent Per Wallet ============
495
+ /**
496
+ * Get the agent owned by a wallet (not linked, owned)
497
+ * @param wallet The wallet to look up
498
+ * @returns Agent ID (0 if wallet doesn't own an agent)
499
+ */
500
+ async getAgentByOwner(wallet) {
501
+ const agentId = await this.publicClient.readContract({
502
+ address: this.address,
503
+ abi: EXAGENT_REGISTRY_ABI,
504
+ functionName: "getAgentByOwner",
505
+ args: [wallet]
506
+ });
507
+ return agentId;
508
+ }
509
+ /**
510
+ * Check if a wallet can register a new agent
511
+ * @param wallet The wallet to check
512
+ * @returns Object with canRegister boolean and existingAgentId (0 if none)
513
+ */
514
+ async canWalletRegister(wallet) {
515
+ const result = await this.publicClient.readContract({
516
+ address: this.address,
517
+ abi: EXAGENT_REGISTRY_ABI,
518
+ functionName: "canWalletRegister",
519
+ args: [wallet]
520
+ });
521
+ const [canRegister, existingAgentId] = result;
522
+ return { canRegister, existingAgentId };
523
+ }
524
+ /**
525
+ * Get the registry contract version
526
+ * @returns Version string (e.g., "4.0.0")
527
+ */
528
+ async getVersion() {
529
+ const version = await this.publicClient.readContract({
530
+ address: this.address,
531
+ abi: EXAGENT_REGISTRY_ABI,
532
+ functionName: "version"
533
+ });
534
+ return version;
535
+ }
536
+ // ============ Config Epochs ============
537
+ /**
538
+ * Update the agent's LLM config hash on-chain
539
+ * @param agentId The agent's ID
540
+ * @param configHash The keccak256 hash of (provider, model)
541
+ * @returns Transaction hash
542
+ */
543
+ async updateConfig(agentId, configHash) {
544
+ if (!this.walletClient || !this.account) throw new Error("Wallet client and account required for write operations");
545
+ const hash = await this.walletClient.writeContract({
546
+ account: this.account,
547
+ chain: this.chain,
548
+ address: this.address,
549
+ abi: EXAGENT_REGISTRY_ABI,
550
+ functionName: "updateConfig",
551
+ args: [agentId, configHash]
552
+ });
553
+ return hash;
554
+ }
555
+ /**
556
+ * Get the current config hash for an agent
557
+ * @param agentId The agent's ID
558
+ * @returns Config hash (bytes32(0) if never set)
559
+ */
560
+ async getConfigHash(agentId) {
561
+ const configHash = await this.publicClient.readContract({
562
+ address: this.address,
563
+ abi: EXAGENT_REGISTRY_ABI,
564
+ functionName: "getConfigHash",
565
+ args: [agentId]
566
+ });
567
+ return configHash;
568
+ }
569
+ /**
570
+ * Get the current epoch ID for an agent
571
+ * @param agentId The agent's ID
572
+ * @returns Current epoch (0 if never configured)
573
+ */
574
+ async getCurrentEpoch(agentId) {
575
+ const epochId = await this.publicClient.readContract({
576
+ address: this.address,
577
+ abi: EXAGENT_REGISTRY_ABI,
578
+ functionName: "getCurrentEpoch",
579
+ args: [agentId]
580
+ });
581
+ return epochId;
582
+ }
583
+ /**
584
+ * Get full config info for an agent
585
+ * @param agentId The agent's ID
586
+ * @returns AgentConfig struct (configHash, epochId, epochStartBlock)
587
+ */
588
+ async getAgentConfig(agentId) {
589
+ const config = await this.publicClient.readContract({
590
+ address: this.address,
591
+ abi: EXAGENT_REGISTRY_ABI,
592
+ functionName: "getAgentConfig",
593
+ args: [agentId]
594
+ });
595
+ const result = config;
596
+ return {
597
+ configHash: result.configHash,
598
+ epochId: result.epochId,
599
+ epochStartBlock: result.epochStartBlock
600
+ };
601
+ }
602
+ /**
603
+ * Get the config hash for a specific epoch
604
+ * @param agentId The agent's ID
605
+ * @param epochId The epoch to look up
606
+ * @returns Config hash for that epoch
607
+ */
608
+ async getEpochConfigHash(agentId, epochId) {
609
+ const configHash = await this.publicClient.readContract({
610
+ address: this.address,
611
+ abi: EXAGENT_REGISTRY_ABI,
612
+ functionName: "getEpochConfigHash",
613
+ args: [agentId, epochId]
614
+ });
615
+ return configHash;
616
+ }
617
+ /**
618
+ * Calculate the config hash for a provider and model
619
+ * @param provider The LLM provider name (e.g., "openai", "anthropic")
620
+ * @param model The model name (e.g., "gpt-4", "claude-opus-4.5")
621
+ * @returns keccak256 hash of the config
622
+ */
623
+ static calculateConfigHash(provider, model) {
624
+ const { keccak256, encodePacked } = __require("viem");
625
+ return keccak256(encodePacked(["string", "string"], [provider, model]));
626
+ }
627
+ };
628
+
629
+ // src/contracts/vault.ts
630
+ var EXAGENT_VAULT_ABI = [
631
+ // ERC-4626 Standard
632
+ { type: "function", name: "asset", inputs: [], outputs: [{ type: "address" }], stateMutability: "view" },
633
+ { type: "function", name: "totalAssets", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
634
+ { type: "function", name: "convertToShares", inputs: [{ name: "assets", type: "uint256" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
635
+ { type: "function", name: "convertToAssets", inputs: [{ name: "shares", type: "uint256" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
636
+ { type: "function", name: "maxDeposit", inputs: [{ name: "receiver", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
637
+ { type: "function", name: "maxMint", inputs: [{ name: "receiver", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
638
+ { type: "function", name: "maxWithdraw", inputs: [{ name: "owner", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
639
+ { type: "function", name: "maxRedeem", inputs: [{ name: "owner", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
640
+ { type: "function", name: "previewDeposit", inputs: [{ name: "assets", type: "uint256" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
641
+ { type: "function", name: "previewMint", inputs: [{ name: "shares", type: "uint256" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
642
+ { type: "function", name: "previewWithdraw", inputs: [{ name: "assets", type: "uint256" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
643
+ { type: "function", name: "previewRedeem", inputs: [{ name: "shares", type: "uint256" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
644
+ { type: "function", name: "deposit", inputs: [{ name: "assets", type: "uint256" }, { name: "receiver", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "nonpayable" },
645
+ { type: "function", name: "mint", inputs: [{ name: "shares", type: "uint256" }, { name: "receiver", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "nonpayable" },
646
+ { type: "function", name: "withdraw", inputs: [{ name: "assets", type: "uint256" }, { name: "receiver", type: "address" }, { name: "owner", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "nonpayable" },
647
+ { type: "function", name: "redeem", inputs: [{ name: "shares", type: "uint256" }, { name: "receiver", type: "address" }, { name: "owner", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "nonpayable" },
648
+ // ERC-20
649
+ { type: "function", name: "name", inputs: [], outputs: [{ type: "string" }], stateMutability: "view" },
650
+ { type: "function", name: "symbol", inputs: [], outputs: [{ type: "string" }], stateMutability: "view" },
651
+ { type: "function", name: "decimals", inputs: [], outputs: [{ type: "uint8" }], stateMutability: "view" },
652
+ { type: "function", name: "totalSupply", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
653
+ { type: "function", name: "balanceOf", inputs: [{ name: "account", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
654
+ { type: "function", name: "allowance", inputs: [{ name: "owner", type: "address" }, { name: "spender", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
655
+ { type: "function", name: "approve", inputs: [{ name: "spender", type: "address" }, { name: "amount", type: "uint256" }], outputs: [{ type: "bool" }], stateMutability: "nonpayable" },
656
+ // Custom Exagent Vault
657
+ { type: "function", name: "agentId", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
658
+ { type: "function", name: "sharePrice", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
659
+ { type: "function", name: "effectiveShares", inputs: [{ name: "user", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
660
+ { type: "function", name: "userHighWaterMark", inputs: [{ name: "user", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
661
+ { type: "function", name: "performanceFeeBps", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
662
+ { type: "function", name: "managementFeeBps", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
663
+ { type: "function", name: "feeRecipient", inputs: [], outputs: [{ type: "address" }], stateMutability: "view" },
664
+ { type: "function", name: "highWaterMark", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
665
+ { type: "function", name: "depositsPaused", inputs: [], outputs: [{ type: "bool" }], stateMutability: "view" },
666
+ { type: "function", name: "withdrawalsPaused", inputs: [], outputs: [{ type: "bool" }], stateMutability: "view" },
667
+ { type: "function", name: "circuitBreakerActive", inputs: [], outputs: [{ type: "bool" }], stateMutability: "view" },
668
+ { type: "function", name: "pendingWithdrawals", inputs: [{ name: "user", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
669
+ { type: "function", name: "canWithdraw", inputs: [{ name: "user", type: "address" }], outputs: [{ type: "bool" }, { type: "uint256" }], stateMutability: "view" },
670
+ { type: "function", name: "getRateLimitStatus", inputs: [], outputs: [{ name: "remaining", type: "uint256" }, { name: "periodEnds", type: "uint256" }], stateMutability: "view" },
671
+ { type: "function", name: "getWithdrawalQueueLength", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
672
+ // Withdrawal Queue
673
+ { type: "function", name: "requestWithdrawal", inputs: [{ name: "shares", type: "uint256" }, { name: "receiver", type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "nonpayable" },
674
+ { type: "function", name: "claimWithdrawal", inputs: [{ name: "requestId", type: "uint256" }], outputs: [{ type: "uint256" }], stateMutability: "nonpayable" },
675
+ { type: "function", name: "cancelWithdrawal", inputs: [{ name: "requestId", type: "uint256" }], outputs: [], stateMutability: "nonpayable" },
676
+ {
677
+ type: "function",
678
+ name: "getPendingWithdrawal",
679
+ inputs: [{ name: "requestId", type: "uint256" }],
680
+ outputs: [
681
+ { name: "owner", type: "address" },
682
+ { name: "receiver", type: "address" },
683
+ { name: "shares", type: "uint256" },
684
+ { name: "requestTime", type: "uint256" },
685
+ { name: "processed", type: "bool" },
686
+ { name: "claimableAt", type: "uint256" }
687
+ ],
688
+ stateMutability: "view"
689
+ },
690
+ // Emergency
691
+ { type: "function", name: "emergencyWithdraw", inputs: [], outputs: [], stateMutability: "nonpayable" },
692
+ // Events
693
+ { 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" }] },
694
+ { 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" }] },
695
+ { type: "event", name: "PerformanceFeeCharged", inputs: [{ name: "user", type: "address", indexed: true }, { name: "feeShares", type: "uint256" }, { name: "profit", type: "uint256" }] },
696
+ { 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" }] },
697
+ { type: "event", name: "WithdrawalClaimed", inputs: [{ name: "requestId", type: "uint256", indexed: true }, { name: "receiver", type: "address", indexed: true }, { name: "assets", type: "uint256" }] },
698
+ { type: "event", name: "WithdrawalCancelled", inputs: [{ name: "requestId", type: "uint256", indexed: true }] },
699
+ { type: "event", name: "EmergencyWithdrawal", inputs: [{ name: "user", type: "address", indexed: true }, { name: "shares", type: "uint256" }, { name: "assets", type: "uint256" }] }
700
+ ];
701
+ var ERC20_APPROVE_ABI = [
702
+ { type: "function", name: "approve", inputs: [{ name: "spender", type: "address" }, { name: "amount", type: "uint256" }], outputs: [{ type: "bool" }], stateMutability: "nonpayable" }
703
+ ];
704
+ var ExagentVault = class {
705
+ address;
706
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
707
+ publicClient;
708
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
709
+ walletClient;
710
+ chain;
711
+ account;
712
+ constructor(vaultAddress, publicClient, walletClient, chain, account) {
713
+ this.address = vaultAddress;
714
+ this.publicClient = publicClient;
715
+ this.walletClient = walletClient;
716
+ this.chain = chain;
717
+ this.account = account;
718
+ }
719
+ // ============ Read Functions ============
720
+ /**
721
+ * Get comprehensive vault info
722
+ */
723
+ async getVaultInfo() {
724
+ const [
725
+ name,
726
+ symbol,
727
+ asset,
728
+ agentId,
729
+ totalAssets,
730
+ totalSupply,
731
+ sharePrice,
732
+ highWaterMark,
733
+ performanceFeeBps,
734
+ managementFeeBps,
735
+ feeRecipient,
736
+ depositsPaused,
737
+ withdrawalsPaused,
738
+ circuitBreakerActive
739
+ ] = await Promise.all([
740
+ this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "name" }),
741
+ this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "symbol" }),
742
+ this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "asset" }),
743
+ this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "agentId" }),
744
+ this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "totalAssets" }),
745
+ this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "totalSupply" }),
746
+ this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "sharePrice" }),
747
+ this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "highWaterMark" }),
748
+ this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "performanceFeeBps" }),
749
+ this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "managementFeeBps" }),
750
+ this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "feeRecipient" }),
751
+ this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "depositsPaused" }),
752
+ this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "withdrawalsPaused" }),
753
+ this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "circuitBreakerActive" })
754
+ ]);
755
+ return {
756
+ address: this.address,
757
+ name,
758
+ symbol,
759
+ asset,
760
+ agentId,
761
+ totalAssets,
762
+ totalSupply,
763
+ sharePrice,
764
+ highWaterMark,
765
+ performanceFeeBps,
766
+ managementFeeBps,
767
+ feeRecipient,
768
+ depositsPaused,
769
+ withdrawalsPaused,
770
+ circuitBreakerActive
771
+ };
772
+ }
773
+ /**
774
+ * Get user's position in the vault
775
+ */
776
+ async getPosition(user) {
777
+ const [
778
+ shares,
779
+ effectiveShares,
780
+ pendingWithdrawals,
781
+ userHighWaterMark,
782
+ canWithdrawResult
783
+ ] = await Promise.all([
784
+ this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "balanceOf", args: [user] }),
785
+ this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "effectiveShares", args: [user] }),
786
+ this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "pendingWithdrawals", args: [user] }),
787
+ this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "userHighWaterMark", args: [user] }),
788
+ this.publicClient.readContract({ address: this.address, abi: EXAGENT_VAULT_ABI, functionName: "canWithdraw", args: [user] })
789
+ ]);
790
+ const assetsValue = await this.publicClient.readContract({
791
+ address: this.address,
792
+ abi: EXAGENT_VAULT_ABI,
793
+ functionName: "convertToAssets",
794
+ args: [effectiveShares]
795
+ });
796
+ return {
797
+ shares,
798
+ effectiveShares,
799
+ pendingWithdrawals,
800
+ assetsValue,
801
+ userHighWaterMark,
802
+ canWithdraw: canWithdrawResult[0],
803
+ cooldownRemaining: canWithdrawResult[1]
804
+ };
805
+ }
806
+ /**
807
+ * Get current share price (assets per share, scaled to 1e18)
808
+ */
809
+ async getSharePrice() {
810
+ return this.publicClient.readContract({
811
+ address: this.address,
812
+ abi: EXAGENT_VAULT_ABI,
813
+ functionName: "sharePrice"
814
+ });
815
+ }
816
+ /**
817
+ * Preview deposit - get shares for given assets
818
+ */
819
+ async previewDeposit(assets) {
820
+ return this.publicClient.readContract({
821
+ address: this.address,
822
+ abi: EXAGENT_VAULT_ABI,
823
+ functionName: "previewDeposit",
824
+ args: [assets]
825
+ });
826
+ }
827
+ /**
828
+ * Preview withdrawal - get assets for given shares
829
+ */
830
+ async previewRedeem(shares) {
831
+ return this.publicClient.readContract({
832
+ address: this.address,
833
+ abi: EXAGENT_VAULT_ABI,
834
+ functionName: "previewRedeem",
835
+ args: [shares]
836
+ });
837
+ }
838
+ /**
839
+ * Get max deposit amount
840
+ */
841
+ async maxDeposit(receiver) {
842
+ return this.publicClient.readContract({
843
+ address: this.address,
844
+ abi: EXAGENT_VAULT_ABI,
845
+ functionName: "maxDeposit",
846
+ args: [receiver]
847
+ });
848
+ }
849
+ /**
850
+ * Get max withdrawal amount
851
+ */
852
+ async maxWithdraw(owner) {
853
+ return this.publicClient.readContract({
854
+ address: this.address,
855
+ abi: EXAGENT_VAULT_ABI,
856
+ functionName: "maxWithdraw",
857
+ args: [owner]
858
+ });
859
+ }
860
+ /**
861
+ * Get rate limit status
862
+ */
863
+ async getRateLimitStatus() {
864
+ const result = await this.publicClient.readContract({
865
+ address: this.address,
866
+ abi: EXAGENT_VAULT_ABI,
867
+ functionName: "getRateLimitStatus"
868
+ });
869
+ return { remaining: result[0], periodEnds: result[1] };
870
+ }
871
+ /**
872
+ * Get pending withdrawal request
873
+ */
874
+ async getPendingWithdrawal(requestId) {
875
+ const result = await this.publicClient.readContract({
876
+ address: this.address,
877
+ abi: EXAGENT_VAULT_ABI,
878
+ functionName: "getPendingWithdrawal",
879
+ args: [requestId]
880
+ });
881
+ return {
882
+ requestId,
883
+ owner: result[0],
884
+ receiver: result[1],
885
+ shares: result[2],
886
+ requestTime: result[3],
887
+ processed: result[4],
888
+ claimableAt: result[5]
889
+ };
890
+ }
891
+ // ============ Write Functions ============
892
+ /**
893
+ * Deposit assets into the vault
894
+ * @param assets Amount of underlying asset to deposit
895
+ * @param receiver Address to receive vault shares
896
+ * @returns Transaction hash
897
+ */
898
+ async deposit(assets, receiver) {
899
+ if (!this.walletClient || !this.account) {
900
+ throw new Error("Wallet client required for write operations");
901
+ }
902
+ const to = receiver ?? this.account.address;
903
+ const hash = await this.walletClient.writeContract({
904
+ address: this.address,
905
+ abi: EXAGENT_VAULT_ABI,
906
+ functionName: "deposit",
907
+ args: [assets, to],
908
+ account: this.account,
909
+ chain: this.chain
910
+ });
911
+ return hash;
912
+ }
913
+ /**
914
+ * Withdraw assets from the vault
915
+ * @param assets Amount of underlying asset to withdraw
916
+ * @param receiver Address to receive assets
917
+ * @param owner Address whose shares to burn (defaults to caller)
918
+ * @returns Transaction hash
919
+ */
920
+ async withdraw(assets, receiver, owner) {
921
+ if (!this.walletClient || !this.account) {
922
+ throw new Error("Wallet client required for write operations");
923
+ }
924
+ const to = receiver ?? this.account.address;
925
+ const from = owner ?? this.account.address;
926
+ const hash = await this.walletClient.writeContract({
927
+ address: this.address,
928
+ abi: EXAGENT_VAULT_ABI,
929
+ functionName: "withdraw",
930
+ args: [assets, to, from],
931
+ account: this.account,
932
+ chain: this.chain
933
+ });
934
+ return hash;
935
+ }
936
+ /**
937
+ * Redeem shares for assets
938
+ * @param shares Amount of shares to redeem
939
+ * @param receiver Address to receive assets
940
+ * @param owner Address whose shares to burn (defaults to caller)
941
+ * @returns Transaction hash
942
+ */
943
+ async redeem(shares, receiver, owner) {
944
+ if (!this.walletClient || !this.account) {
945
+ throw new Error("Wallet client required for write operations");
946
+ }
947
+ const to = receiver ?? this.account.address;
948
+ const from = owner ?? this.account.address;
949
+ const hash = await this.walletClient.writeContract({
950
+ address: this.address,
951
+ abi: EXAGENT_VAULT_ABI,
952
+ functionName: "redeem",
953
+ args: [shares, to, from],
954
+ account: this.account,
955
+ chain: this.chain
956
+ });
957
+ return hash;
958
+ }
959
+ /**
960
+ * Request a queued withdrawal (for large amounts)
961
+ * @param shares Amount of shares to withdraw
962
+ * @param receiver Address to receive assets
963
+ * @returns Transaction hash
964
+ */
965
+ async requestWithdrawal(shares, receiver) {
966
+ if (!this.walletClient || !this.account) {
967
+ throw new Error("Wallet client required for write operations");
968
+ }
969
+ const to = receiver ?? this.account.address;
970
+ const hash = await this.walletClient.writeContract({
971
+ address: this.address,
972
+ abi: EXAGENT_VAULT_ABI,
973
+ functionName: "requestWithdrawal",
974
+ args: [shares, to],
975
+ account: this.account,
976
+ chain: this.chain
977
+ });
978
+ return hash;
979
+ }
980
+ /**
981
+ * Claim a pending withdrawal request
982
+ * @param requestId The withdrawal request ID
983
+ * @returns Transaction hash
984
+ */
985
+ async claimWithdrawal(requestId) {
986
+ if (!this.walletClient || !this.account) {
987
+ throw new Error("Wallet client required for write operations");
988
+ }
989
+ const hash = await this.walletClient.writeContract({
990
+ address: this.address,
991
+ abi: EXAGENT_VAULT_ABI,
992
+ functionName: "claimWithdrawal",
993
+ args: [requestId],
994
+ account: this.account,
995
+ chain: this.chain
996
+ });
997
+ return hash;
998
+ }
999
+ /**
1000
+ * Cancel a pending withdrawal request
1001
+ * @param requestId The withdrawal request ID
1002
+ * @returns Transaction hash
1003
+ */
1004
+ async cancelWithdrawal(requestId) {
1005
+ if (!this.walletClient || !this.account) {
1006
+ throw new Error("Wallet client required for write operations");
1007
+ }
1008
+ const hash = await this.walletClient.writeContract({
1009
+ address: this.address,
1010
+ abi: EXAGENT_VAULT_ABI,
1011
+ functionName: "cancelWithdrawal",
1012
+ args: [requestId],
1013
+ account: this.account,
1014
+ chain: this.chain
1015
+ });
1016
+ return hash;
1017
+ }
1018
+ /**
1019
+ * Emergency withdrawal (bypasses cooldown, forfeits pending rewards)
1020
+ * @returns Transaction hash
1021
+ */
1022
+ async emergencyWithdraw() {
1023
+ if (!this.walletClient || !this.account) {
1024
+ throw new Error("Wallet client required for write operations");
1025
+ }
1026
+ const hash = await this.walletClient.writeContract({
1027
+ address: this.address,
1028
+ abi: EXAGENT_VAULT_ABI,
1029
+ functionName: "emergencyWithdraw",
1030
+ args: [],
1031
+ account: this.account,
1032
+ chain: this.chain
1033
+ });
1034
+ return hash;
1035
+ }
1036
+ /**
1037
+ * Approve vault to spend underlying asset
1038
+ * @param assetAddress The asset token address
1039
+ * @param amount Amount to approve
1040
+ * @returns Transaction hash
1041
+ */
1042
+ async approveAsset(assetAddress, amount) {
1043
+ if (!this.walletClient || !this.account) {
1044
+ throw new Error("Wallet client required for write operations");
1045
+ }
1046
+ const hash = await this.walletClient.writeContract({
1047
+ address: assetAddress,
1048
+ abi: ERC20_APPROVE_ABI,
1049
+ functionName: "approve",
1050
+ args: [this.address, amount],
1051
+ account: this.account,
1052
+ chain: this.chain
1053
+ });
1054
+ return hash;
1055
+ }
1056
+ };
1057
+
1058
+ // src/contracts/staking.ts
1059
+ var EXAGENT_STAKING_ABI = [
1060
+ // ============ State Variables ============
1061
+ { type: "function", name: "exaToken", inputs: [], outputs: [{ type: "address" }], stateMutability: "view" },
1062
+ { type: "function", name: "totalStaked", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
1063
+ { type: "function", name: "totalVeEXA", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
1064
+ { type: "function", name: "registry", inputs: [], outputs: [{ type: "address" }], stateMutability: "view" },
1065
+ // ============ Constants ============
1066
+ { type: "function", name: "MIN_LOCK_DURATION", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
1067
+ { type: "function", name: "MAX_LOCK_DURATION", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
1068
+ { type: "function", name: "PRECISION", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
1069
+ // ============ Staking Functions ============
1070
+ {
1071
+ type: "function",
1072
+ name: "stake",
1073
+ inputs: [
1074
+ { name: "amount", type: "uint256" },
1075
+ { name: "lockDuration", type: "uint256" }
1076
+ ],
1077
+ outputs: [],
1078
+ stateMutability: "nonpayable"
1079
+ },
1080
+ { type: "function", name: "unstake", inputs: [], outputs: [], stateMutability: "nonpayable" },
1081
+ {
1082
+ type: "function",
1083
+ name: "extendLock",
1084
+ inputs: [{ name: "newLockDuration", type: "uint256" }],
1085
+ outputs: [],
1086
+ stateMutability: "nonpayable"
1087
+ },
1088
+ // ============ Reward Functions ============
1089
+ { type: "function", name: "claimRewards", inputs: [], outputs: [], stateMutability: "nonpayable" },
1090
+ { type: "function", name: "claimRewardsMulti", inputs: [], outputs: [], stateMutability: "nonpayable" },
1091
+ {
1092
+ type: "function",
1093
+ name: "claimRewardsToken",
1094
+ inputs: [{ name: "token", type: "address" }],
1095
+ outputs: [],
1096
+ stateMutability: "nonpayable"
1097
+ },
1098
+ // ============ Delegation Functions ============
1099
+ {
1100
+ type: "function",
1101
+ name: "delegate",
1102
+ inputs: [{ name: "agentId", type: "uint256" }],
1103
+ outputs: [],
1104
+ stateMutability: "nonpayable"
1105
+ },
1106
+ { type: "function", name: "undelegate", inputs: [], outputs: [], stateMutability: "nonpayable" },
1107
+ {
1108
+ type: "function",
1109
+ name: "redelegate",
1110
+ inputs: [{ name: "newAgentId", type: "uint256" }],
1111
+ outputs: [],
1112
+ stateMutability: "nonpayable"
1113
+ },
1114
+ // ============ View Functions ============
1115
+ {
1116
+ type: "function",
1117
+ name: "stakes",
1118
+ inputs: [{ name: "user", type: "address" }],
1119
+ outputs: [
1120
+ { name: "amount", type: "uint256" },
1121
+ { name: "unlockTime", type: "uint256" },
1122
+ { name: "lockDuration", type: "uint256" },
1123
+ { name: "vEXABalance", type: "uint256" }
1124
+ ],
1125
+ stateMutability: "view"
1126
+ },
1127
+ {
1128
+ type: "function",
1129
+ name: "getVeEXABalance",
1130
+ inputs: [{ name: "user", type: "address" }],
1131
+ outputs: [{ type: "uint256" }],
1132
+ stateMutability: "view"
1133
+ },
1134
+ {
1135
+ type: "function",
1136
+ name: "calculateVeEXA",
1137
+ inputs: [
1138
+ { name: "amount", type: "uint256" },
1139
+ { name: "lockDuration", type: "uint256" }
1140
+ ],
1141
+ outputs: [{ type: "uint256" }],
1142
+ stateMutability: "pure"
1143
+ },
1144
+ {
1145
+ type: "function",
1146
+ name: "pendingRewards",
1147
+ inputs: [{ name: "user", type: "address" }],
1148
+ outputs: [{ type: "uint256" }],
1149
+ stateMutability: "view"
1150
+ },
1151
+ {
1152
+ type: "function",
1153
+ name: "pendingRewardsForToken",
1154
+ inputs: [
1155
+ { name: "user", type: "address" },
1156
+ { name: "token", type: "address" }
1157
+ ],
1158
+ outputs: [{ type: "uint256" }],
1159
+ stateMutability: "view"
1160
+ },
1161
+ {
1162
+ type: "function",
1163
+ name: "getDelegatedAgent",
1164
+ inputs: [{ name: "user", type: "address" }],
1165
+ outputs: [{ type: "uint256" }],
1166
+ stateMutability: "view"
1167
+ },
1168
+ {
1169
+ type: "function",
1170
+ name: "getAgentDelegation",
1171
+ inputs: [{ name: "agentId", type: "uint256" }],
1172
+ outputs: [
1173
+ { name: "vexa", type: "uint256" },
1174
+ { name: "count", type: "uint256" }
1175
+ ],
1176
+ stateMutability: "view"
1177
+ },
1178
+ {
1179
+ type: "function",
1180
+ name: "getDiscountTier",
1181
+ inputs: [{ name: "user", type: "address" }],
1182
+ outputs: [{ name: "discountBps", type: "uint256" }],
1183
+ stateMutability: "view"
1184
+ },
1185
+ {
1186
+ type: "function",
1187
+ name: "getRewardTokens",
1188
+ inputs: [],
1189
+ outputs: [{ type: "address[]" }],
1190
+ stateMutability: "view"
1191
+ },
1192
+ {
1193
+ type: "function",
1194
+ name: "delegatedTo",
1195
+ inputs: [{ name: "user", type: "address" }],
1196
+ outputs: [{ type: "uint256" }],
1197
+ stateMutability: "view"
1198
+ },
1199
+ {
1200
+ type: "function",
1201
+ name: "userDelegatedVeEXA",
1202
+ inputs: [{ name: "user", type: "address" }],
1203
+ outputs: [{ type: "uint256" }],
1204
+ stateMutability: "view"
1205
+ },
1206
+ {
1207
+ type: "function",
1208
+ name: "agentDelegatedVeEXA",
1209
+ inputs: [{ name: "agentId", type: "uint256" }],
1210
+ outputs: [{ type: "uint256" }],
1211
+ stateMutability: "view"
1212
+ },
1213
+ {
1214
+ type: "function",
1215
+ name: "agentDelegatorCount",
1216
+ inputs: [{ name: "agentId", type: "uint256" }],
1217
+ outputs: [{ type: "uint256" }],
1218
+ stateMutability: "view"
1219
+ },
1220
+ {
1221
+ type: "function",
1222
+ name: "isRewardToken",
1223
+ inputs: [{ name: "token", type: "address" }],
1224
+ outputs: [{ type: "bool" }],
1225
+ stateMutability: "view"
1226
+ },
1227
+ // ============ Events ============
1228
+ {
1229
+ type: "event",
1230
+ name: "Staked",
1231
+ inputs: [
1232
+ { name: "user", type: "address", indexed: true },
1233
+ { name: "amount", type: "uint256", indexed: false },
1234
+ { name: "lockDuration", type: "uint256", indexed: false },
1235
+ { name: "unlockTime", type: "uint256", indexed: false },
1236
+ { name: "vEXABalance", type: "uint256", indexed: false }
1237
+ ]
1238
+ },
1239
+ {
1240
+ type: "event",
1241
+ name: "Unstaked",
1242
+ inputs: [
1243
+ { name: "user", type: "address", indexed: true },
1244
+ { name: "amount", type: "uint256", indexed: false }
1245
+ ]
1246
+ },
1247
+ {
1248
+ type: "event",
1249
+ name: "LockExtended",
1250
+ inputs: [
1251
+ { name: "user", type: "address", indexed: true },
1252
+ { name: "newUnlockTime", type: "uint256", indexed: false },
1253
+ { name: "newVeEXABalance", type: "uint256", indexed: false }
1254
+ ]
1255
+ },
1256
+ {
1257
+ type: "event",
1258
+ name: "RewardsClaimed",
1259
+ inputs: [
1260
+ { name: "user", type: "address", indexed: true },
1261
+ { name: "amount", type: "uint256", indexed: false }
1262
+ ]
1263
+ },
1264
+ {
1265
+ type: "event",
1266
+ name: "Delegated",
1267
+ inputs: [
1268
+ { name: "delegator", type: "address", indexed: true },
1269
+ { name: "agentId", type: "uint256", indexed: true },
1270
+ { name: "veEXAAmount", type: "uint256", indexed: false }
1271
+ ]
1272
+ },
1273
+ {
1274
+ type: "event",
1275
+ name: "Undelegated",
1276
+ inputs: [
1277
+ { name: "delegator", type: "address", indexed: true },
1278
+ { name: "agentId", type: "uint256", indexed: true },
1279
+ { name: "veEXAAmount", type: "uint256", indexed: false }
1280
+ ]
1281
+ },
1282
+ {
1283
+ type: "event",
1284
+ name: "MultiTokenRewardsClaimed",
1285
+ inputs: [
1286
+ { name: "user", type: "address", indexed: true },
1287
+ { name: "token", type: "address", indexed: true },
1288
+ { name: "amount", type: "uint256", indexed: false }
1289
+ ]
1290
+ }
1291
+ ];
1292
+ var ERC20_APPROVE_ABI2 = [
1293
+ {
1294
+ type: "function",
1295
+ name: "approve",
1296
+ inputs: [
1297
+ { name: "spender", type: "address" },
1298
+ { name: "amount", type: "uint256" }
1299
+ ],
1300
+ outputs: [{ type: "bool" }],
1301
+ stateMutability: "nonpayable"
1302
+ }
1303
+ ];
1304
+ var DISCOUNT_TIERS = {
1305
+ none: 0,
1306
+ bronze: 1e3,
1307
+ // 10% discount at 10,000 vEXA
1308
+ silver: 2500,
1309
+ // 25% discount at 50,000 vEXA
1310
+ gold: 5e3
1311
+ // 50% discount at 100,000 vEXA
1312
+ };
1313
+ var ExagentStaking = class {
1314
+ address;
1315
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1316
+ publicClient;
1317
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1318
+ walletClient;
1319
+ chain;
1320
+ account;
1321
+ constructor(stakingAddress, publicClient, walletClient, chain, account) {
1322
+ this.address = stakingAddress;
1323
+ this.publicClient = publicClient;
1324
+ this.walletClient = walletClient;
1325
+ this.chain = chain;
1326
+ this.account = account;
1327
+ }
1328
+ // ============ Staking Write Functions ============
1329
+ /**
1330
+ * Stake EXA tokens to receive vEXA voting power
1331
+ * @param amount Amount of EXA to stake (in wei)
1332
+ * @param lockDuration Lock duration in seconds (30 days to 2 years)
1333
+ * @returns Transaction hash
1334
+ *
1335
+ * @example
1336
+ * ```typescript
1337
+ * // Stake 1000 EXA for 6 months
1338
+ * const tx = await staking.stake(
1339
+ * parseEther('1000'),
1340
+ * BigInt(180 * 24 * 60 * 60) // 180 days in seconds
1341
+ * );
1342
+ * ```
1343
+ */
1344
+ async stake(amount, lockDuration) {
1345
+ if (!this.walletClient || !this.account) {
1346
+ throw new Error("Wallet client required for write operations");
1347
+ }
1348
+ const hash = await this.walletClient.writeContract({
1349
+ address: this.address,
1350
+ abi: EXAGENT_STAKING_ABI,
1351
+ functionName: "stake",
1352
+ args: [amount, lockDuration],
1353
+ account: this.account,
1354
+ chain: this.chain
1355
+ });
1356
+ return hash;
1357
+ }
1358
+ /**
1359
+ * Unstake EXA tokens after lock expires
1360
+ * @returns Transaction hash
1361
+ * @throws Error if lock has not expired
1362
+ */
1363
+ async unstake() {
1364
+ if (!this.walletClient || !this.account) {
1365
+ throw new Error("Wallet client required for write operations");
1366
+ }
1367
+ const hash = await this.walletClient.writeContract({
1368
+ address: this.address,
1369
+ abi: EXAGENT_STAKING_ABI,
1370
+ functionName: "unstake",
1371
+ args: [],
1372
+ account: this.account,
1373
+ chain: this.chain
1374
+ });
1375
+ return hash;
1376
+ }
1377
+ /**
1378
+ * Extend lock duration for additional voting power
1379
+ * @param newLockDuration New lock duration in seconds (must be longer than remaining)
1380
+ * @returns Transaction hash
1381
+ */
1382
+ async extendLock(newLockDuration) {
1383
+ if (!this.walletClient || !this.account) {
1384
+ throw new Error("Wallet client required for write operations");
1385
+ }
1386
+ const hash = await this.walletClient.writeContract({
1387
+ address: this.address,
1388
+ abi: EXAGENT_STAKING_ABI,
1389
+ functionName: "extendLock",
1390
+ args: [newLockDuration],
1391
+ account: this.account,
1392
+ chain: this.chain
1393
+ });
1394
+ return hash;
1395
+ }
1396
+ // ============ Reward Write Functions ============
1397
+ /**
1398
+ * Claim accumulated EXA rewards
1399
+ * @returns Transaction hash
1400
+ */
1401
+ async claimRewards() {
1402
+ if (!this.walletClient || !this.account) {
1403
+ throw new Error("Wallet client required for write operations");
1404
+ }
1405
+ const hash = await this.walletClient.writeContract({
1406
+ address: this.address,
1407
+ abi: EXAGENT_STAKING_ABI,
1408
+ functionName: "claimRewards",
1409
+ args: [],
1410
+ account: this.account,
1411
+ chain: this.chain
1412
+ });
1413
+ return hash;
1414
+ }
1415
+ /**
1416
+ * Claim all pending multi-token rewards (ETH, USDC, etc.)
1417
+ * @returns Transaction hash
1418
+ */
1419
+ async claimRewardsMulti() {
1420
+ if (!this.walletClient || !this.account) {
1421
+ throw new Error("Wallet client required for write operations");
1422
+ }
1423
+ const hash = await this.walletClient.writeContract({
1424
+ address: this.address,
1425
+ abi: EXAGENT_STAKING_ABI,
1426
+ functionName: "claimRewardsMulti",
1427
+ args: [],
1428
+ account: this.account,
1429
+ chain: this.chain
1430
+ });
1431
+ return hash;
1432
+ }
1433
+ /**
1434
+ * Claim pending rewards for a specific token
1435
+ * @param token The reward token address to claim
1436
+ * @returns Transaction hash
1437
+ */
1438
+ async claimRewardsToken(token) {
1439
+ if (!this.walletClient || !this.account) {
1440
+ throw new Error("Wallet client required for write operations");
1441
+ }
1442
+ const hash = await this.walletClient.writeContract({
1443
+ address: this.address,
1444
+ abi: EXAGENT_STAKING_ABI,
1445
+ functionName: "claimRewardsToken",
1446
+ args: [token],
1447
+ account: this.account,
1448
+ chain: this.chain
1449
+ });
1450
+ return hash;
1451
+ }
1452
+ // ============ Delegation Write Functions ============
1453
+ /**
1454
+ * Delegate vEXA voting power to an agent ("Agent Wars")
1455
+ * @param agentId The agent ID to delegate to
1456
+ * @returns Transaction hash
1457
+ */
1458
+ async delegate(agentId) {
1459
+ if (!this.walletClient || !this.account) {
1460
+ throw new Error("Wallet client required for write operations");
1461
+ }
1462
+ const hash = await this.walletClient.writeContract({
1463
+ address: this.address,
1464
+ abi: EXAGENT_STAKING_ABI,
1465
+ functionName: "delegate",
1466
+ args: [agentId],
1467
+ account: this.account,
1468
+ chain: this.chain
1469
+ });
1470
+ return hash;
1471
+ }
1472
+ /**
1473
+ * Remove delegation from current agent
1474
+ * @returns Transaction hash
1475
+ */
1476
+ async undelegate() {
1477
+ if (!this.walletClient || !this.account) {
1478
+ throw new Error("Wallet client required for write operations");
1479
+ }
1480
+ const hash = await this.walletClient.writeContract({
1481
+ address: this.address,
1482
+ abi: EXAGENT_STAKING_ABI,
1483
+ functionName: "undelegate",
1484
+ args: [],
1485
+ account: this.account,
1486
+ chain: this.chain
1487
+ });
1488
+ return hash;
1489
+ }
1490
+ /**
1491
+ * Re-delegate to a different agent (undelegate + delegate in one tx)
1492
+ * @param newAgentId The new agent ID to delegate to
1493
+ * @returns Transaction hash
1494
+ */
1495
+ async redelegate(newAgentId) {
1496
+ if (!this.walletClient || !this.account) {
1497
+ throw new Error("Wallet client required for write operations");
1498
+ }
1499
+ const hash = await this.walletClient.writeContract({
1500
+ address: this.address,
1501
+ abi: EXAGENT_STAKING_ABI,
1502
+ functionName: "redelegate",
1503
+ args: [newAgentId],
1504
+ account: this.account,
1505
+ chain: this.chain
1506
+ });
1507
+ return hash;
1508
+ }
1509
+ // ============ Read Functions ============
1510
+ /**
1511
+ * Get comprehensive staking info for a user
1512
+ * @param userAddress Address to check (defaults to connected wallet)
1513
+ * @returns Staking info with amount, unlock time, and vEXA balance
1514
+ */
1515
+ async getStakeInfo(userAddress) {
1516
+ const user = userAddress ?? this.account?.address;
1517
+ if (!user) {
1518
+ throw new Error("User address required");
1519
+ }
1520
+ const [stakeResult, currentVeEXA] = await Promise.all([
1521
+ this.publicClient.readContract({
1522
+ address: this.address,
1523
+ abi: EXAGENT_STAKING_ABI,
1524
+ functionName: "stakes",
1525
+ args: [user]
1526
+ }),
1527
+ this.publicClient.readContract({
1528
+ address: this.address,
1529
+ abi: EXAGENT_STAKING_ABI,
1530
+ functionName: "getVeEXABalance",
1531
+ args: [user]
1532
+ })
1533
+ ]);
1534
+ const stake = stakeResult;
1535
+ const now = BigInt(Math.floor(Date.now() / 1e3));
1536
+ const isUnlocked = stake[1] <= now;
1537
+ const remainingLockTime = isUnlocked ? 0n : stake[1] - now;
1538
+ return {
1539
+ amount: stake[0],
1540
+ unlockTime: stake[1],
1541
+ lockDuration: stake[2],
1542
+ vEXABalance: stake[3],
1543
+ currentVeEXA,
1544
+ isUnlocked,
1545
+ remainingLockTime
1546
+ };
1547
+ }
1548
+ /**
1549
+ * Get current vEXA balance (with time decay applied)
1550
+ * @param userAddress Address to check (defaults to connected wallet)
1551
+ * @returns Current vEXA balance
1552
+ */
1553
+ async getVeEXABalance(userAddress) {
1554
+ const user = userAddress ?? this.account?.address;
1555
+ if (!user) {
1556
+ throw new Error("User address required");
1557
+ }
1558
+ return this.publicClient.readContract({
1559
+ address: this.address,
1560
+ abi: EXAGENT_STAKING_ABI,
1561
+ functionName: "getVeEXABalance",
1562
+ args: [user]
1563
+ });
1564
+ }
1565
+ /**
1566
+ * Get the agent ID a user is delegating to
1567
+ * @param userAddress Address to check (defaults to connected wallet)
1568
+ * @returns Agent ID (0 if not delegating)
1569
+ */
1570
+ async getDelegatedAgent(userAddress) {
1571
+ const user = userAddress ?? this.account?.address;
1572
+ if (!user) {
1573
+ throw new Error("User address required");
1574
+ }
1575
+ return this.publicClient.readContract({
1576
+ address: this.address,
1577
+ abi: EXAGENT_STAKING_ABI,
1578
+ functionName: "getDelegatedAgent",
1579
+ args: [user]
1580
+ });
1581
+ }
1582
+ /**
1583
+ * Get delegation stats for an agent
1584
+ * @param agentId The agent ID to check
1585
+ * @returns Delegation info with total vEXA and delegator count
1586
+ */
1587
+ async getAgentDelegation(agentId) {
1588
+ const result = await this.publicClient.readContract({
1589
+ address: this.address,
1590
+ abi: EXAGENT_STAKING_ABI,
1591
+ functionName: "getAgentDelegation",
1592
+ args: [agentId]
1593
+ });
1594
+ return {
1595
+ totalVeEXA: result[0],
1596
+ delegatorCount: result[1]
1597
+ };
1598
+ }
1599
+ /**
1600
+ * Get trading fee discount tier for a user
1601
+ * @param userAddress Address to check (defaults to connected wallet)
1602
+ * @returns Discount tier name and basis points
1603
+ */
1604
+ async getDiscountTier(userAddress) {
1605
+ const user = userAddress ?? this.account?.address;
1606
+ if (!user) {
1607
+ throw new Error("User address required");
1608
+ }
1609
+ const discountBps = await this.publicClient.readContract({
1610
+ address: this.address,
1611
+ abi: EXAGENT_STAKING_ABI,
1612
+ functionName: "getDiscountTier",
1613
+ args: [user]
1614
+ });
1615
+ let tier = "none";
1616
+ if (discountBps >= 5000n) {
1617
+ tier = "gold";
1618
+ } else if (discountBps >= 2500n) {
1619
+ tier = "silver";
1620
+ } else if (discountBps >= 1000n) {
1621
+ tier = "bronze";
1622
+ }
1623
+ return { tier, discountBps };
1624
+ }
1625
+ /**
1626
+ * Get pending EXA rewards for a user
1627
+ * @param userAddress Address to check (defaults to connected wallet)
1628
+ * @returns Pending reward amount in wei
1629
+ */
1630
+ async pendingRewards(userAddress) {
1631
+ const user = userAddress ?? this.account?.address;
1632
+ if (!user) {
1633
+ throw new Error("User address required");
1634
+ }
1635
+ return this.publicClient.readContract({
1636
+ address: this.address,
1637
+ abi: EXAGENT_STAKING_ABI,
1638
+ functionName: "pendingRewards",
1639
+ args: [user]
1640
+ });
1641
+ }
1642
+ /**
1643
+ * Get pending rewards for a specific token
1644
+ * @param token The reward token address
1645
+ * @param userAddress Address to check (defaults to connected wallet)
1646
+ * @returns Pending reward amount in wei
1647
+ */
1648
+ async pendingRewardsMulti(token, userAddress) {
1649
+ const user = userAddress ?? this.account?.address;
1650
+ if (!user) {
1651
+ throw new Error("User address required");
1652
+ }
1653
+ return this.publicClient.readContract({
1654
+ address: this.address,
1655
+ abi: EXAGENT_STAKING_ABI,
1656
+ functionName: "pendingRewardsForToken",
1657
+ args: [user, token]
1658
+ });
1659
+ }
1660
+ /**
1661
+ * Get list of whitelisted reward tokens
1662
+ * @returns Array of reward token addresses
1663
+ */
1664
+ async getRewardTokens() {
1665
+ return this.publicClient.readContract({
1666
+ address: this.address,
1667
+ abi: EXAGENT_STAKING_ABI,
1668
+ functionName: "getRewardTokens"
1669
+ });
1670
+ }
1671
+ /**
1672
+ * Check if a token is whitelisted for rewards
1673
+ * @param token The token address to check
1674
+ * @returns True if token is whitelisted
1675
+ */
1676
+ async isRewardToken(token) {
1677
+ return this.publicClient.readContract({
1678
+ address: this.address,
1679
+ abi: EXAGENT_STAKING_ABI,
1680
+ functionName: "isRewardToken",
1681
+ args: [token]
1682
+ });
1683
+ }
1684
+ /**
1685
+ * Get total staked EXA across all users
1686
+ * @returns Total staked amount in wei
1687
+ */
1688
+ async getTotalStaked() {
1689
+ return this.publicClient.readContract({
1690
+ address: this.address,
1691
+ abi: EXAGENT_STAKING_ABI,
1692
+ functionName: "totalStaked"
1693
+ });
1694
+ }
1695
+ /**
1696
+ * Get total vEXA supply across all users
1697
+ * @returns Total vEXA supply
1698
+ */
1699
+ async getTotalVeEXA() {
1700
+ return this.publicClient.readContract({
1701
+ address: this.address,
1702
+ abi: EXAGENT_STAKING_ABI,
1703
+ functionName: "totalVeEXA"
1704
+ });
1705
+ }
1706
+ /**
1707
+ * Calculate vEXA balance for a given stake (preview)
1708
+ * @param amount Amount of EXA to stake
1709
+ * @param lockDuration Lock duration in seconds
1710
+ * @returns Expected vEXA balance
1711
+ */
1712
+ async calculateVeEXA(amount, lockDuration) {
1713
+ return this.publicClient.readContract({
1714
+ address: this.address,
1715
+ abi: EXAGENT_STAKING_ABI,
1716
+ functionName: "calculateVeEXA",
1717
+ args: [amount, lockDuration]
1718
+ });
1719
+ }
1720
+ /**
1721
+ * Get the EXA token address
1722
+ * @returns EXA token contract address
1723
+ */
1724
+ async getExaTokenAddress() {
1725
+ return this.publicClient.readContract({
1726
+ address: this.address,
1727
+ abi: EXAGENT_STAKING_ABI,
1728
+ functionName: "exaToken"
1729
+ });
1730
+ }
1731
+ // ============ Helper Functions ============
1732
+ /**
1733
+ * Approve EXA token spending for staking
1734
+ * @param amount Amount to approve
1735
+ * @returns Transaction hash
1736
+ */
1737
+ async approveExa(amount) {
1738
+ if (!this.walletClient || !this.account) {
1739
+ throw new Error("Wallet client required for write operations");
1740
+ }
1741
+ const exaToken = await this.getExaTokenAddress();
1742
+ const hash = await this.walletClient.writeContract({
1743
+ address: exaToken,
1744
+ abi: ERC20_APPROVE_ABI2,
1745
+ functionName: "approve",
1746
+ args: [this.address, amount],
1747
+ account: this.account,
1748
+ chain: this.chain
1749
+ });
1750
+ return hash;
1751
+ }
1752
+ // ============ Lock Duration Constants ============
1753
+ /** Minimum lock duration: 30 days in seconds */
1754
+ static MIN_LOCK_DURATION = 30n * 24n * 60n * 60n;
1755
+ /** Maximum lock duration: 2 years in seconds */
1756
+ static MAX_LOCK_DURATION = 730n * 24n * 60n * 60n;
1757
+ /** 1 month lock duration in seconds */
1758
+ static LOCK_1_MONTH = 30n * 24n * 60n * 60n;
1759
+ /** 3 months lock duration in seconds */
1760
+ static LOCK_3_MONTHS = 90n * 24n * 60n * 60n;
1761
+ /** 6 months lock duration in seconds */
1762
+ static LOCK_6_MONTHS = 180n * 24n * 60n * 60n;
1763
+ /** 1 year lock duration in seconds */
1764
+ static LOCK_1_YEAR = 365n * 24n * 60n * 60n;
1765
+ /** 2 years lock duration in seconds */
1766
+ static LOCK_2_YEARS = 730n * 24n * 60n * 60n;
1767
+ };
1768
+
1769
+ // src/constants.ts
1770
+ import { base, baseSepolia } from "viem/chains";
1771
+ var CHAIN_CONFIG = {
1772
+ mainnet: base,
1773
+ testnet: baseSepolia
1774
+ };
1775
+ var CONTRACT_ADDRESSES = {
1776
+ mainnet: {
1777
+ agentRegistry: "0x0000000000000000000000000000000000000000",
1778
+ // To be deployed
1779
+ exaToken: "0x0000000000000000000000000000000000000000",
1780
+ staking: "0x0000000000000000000000000000000000000000",
1781
+ router: "0x0000000000000000000000000000000000000000",
1782
+ vaultFactory: "0x0000000000000000000000000000000000000000",
1783
+ feeCollector: "0x0000000000000000000000000000000000000000",
1784
+ buyback: "0x0000000000000000000000000000000000000000",
1785
+ serviceEscrow: "0x0000000000000000000000000000000000000000"
1786
+ },
1787
+ testnet: {
1788
+ agentRegistry: "0xCF48C341e3FebeCA5ECB7eb2535f61A2Ba855d9C",
1789
+ // V4 UUPS proxy, one-agent-per-wallet
1790
+ exaToken: "0x66c39b0ad96B3f5eE198Fef913c6636353a48A87",
1791
+ staking: "0x439441468e1b1b616E9D36b80969C241F261A011",
1792
+ // V2 with delegation
1793
+ router: "0xc0c27eEE047E414CD716D06C2444CF2073113d5C",
1794
+ // V3 with config epochs
1795
+ vaultFactory: "0x5c099daaE33801a907Bb57011c6749655b55dc75",
1796
+ // V2 with requirements
1797
+ feeCollector: "0xcB57b03a50df054b9C738Df1324C17A4fDe4fe46",
1798
+ buyback: "0x35cdEa810A130A846265682e5c71A68A507aB895",
1799
+ serviceEscrow: "0x74a3496b148DEE735ac388299aF9Ac2F7C4EdCBf"
1800
+ }
1801
+ };
1802
+ var DEX_ADDRESSES = {
1803
+ // Aerodrome
1804
+ aerodromeRouter: "0xcF77a3Ba9A5CA399B7c97c74d54e5b1Beb874E43",
1805
+ aerodromeSlipstream: "0xBE6D8f0d05cC4be24d5167a3eF062215bE6D18a5",
1806
+ // Uniswap
1807
+ uniswapUniversalRouter: "0x198EF79F1F515F02dFE9e3115eD9fC07183f02fC",
1808
+ uniswapV4Router: "0x6ff5693b99212da76ad316178a184ab56d299b43",
1809
+ // Common tokens
1810
+ WETH: "0x4200000000000000000000000000000000000006",
1811
+ USDC: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"
1812
+ };
1813
+ var ZERO_X_CONFIG = {
1814
+ baseUrl: "https://api.0x.org",
1815
+ chainId: 8453
1816
+ // Base
1817
+ };
1818
+ var EXAGENT_API_CONFIG = {
1819
+ mainnet: "https://api.exagent.io",
1820
+ testnet: "https://api.testnet.exagent.io"
1821
+ };
1822
+
1823
+ // src/client.ts
1824
+ var ExagentClient = class {
1825
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1826
+ publicClient;
1827
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1828
+ walletClient;
1829
+ account;
1830
+ network;
1831
+ apiKey;
1832
+ // Contract interfaces
1833
+ registry;
1834
+ staking;
1835
+ // Cached agent ID
1836
+ _agentId;
1837
+ constructor(config) {
1838
+ this.network = config.network ?? "testnet";
1839
+ this.apiKey = config.apiKey;
1840
+ const chain = CHAIN_CONFIG[this.network];
1841
+ this.publicClient = createPublicClient({
1842
+ chain,
1843
+ transport: http(config.rpcUrl)
1844
+ });
1845
+ if (config.walletClient) {
1846
+ this.walletClient = config.walletClient;
1847
+ this.account = config.walletClient.account;
1848
+ } else if (config.privateKey) {
1849
+ this.account = privateKeyToAccount(config.privateKey);
1850
+ this.walletClient = createWalletClient({
1851
+ account: this.account,
1852
+ chain,
1853
+ transport: http(config.rpcUrl)
1854
+ });
1855
+ } else {
1856
+ throw new Error("Either privateKey or walletClient must be provided");
1857
+ }
1858
+ const addresses = CONTRACT_ADDRESSES[this.network];
1859
+ this.registry = new ExagentRegistry(
1860
+ addresses.agentRegistry,
1861
+ this.publicClient,
1862
+ this.walletClient,
1863
+ chain,
1864
+ this.account
1865
+ );
1866
+ this.staking = new ExagentStaking(
1867
+ addresses.staking,
1868
+ this.publicClient,
1869
+ this.walletClient,
1870
+ chain,
1871
+ this.account
1872
+ );
1873
+ }
1874
+ // ============ Agent Registration ============
1875
+ /**
1876
+ * Register as a new agent on Exagent
1877
+ * @param metadata Agent metadata (will be uploaded to IPFS)
1878
+ * @returns The assigned agent ID
1879
+ * @throws Error if wallet already owns an agent (one agent per wallet rule)
1880
+ */
1881
+ async register(metadata) {
1882
+ const { canRegister, existingAgentId } = await this.registry.canWalletRegister(this.account.address);
1883
+ if (!canRegister) {
1884
+ throw new Error(
1885
+ `This wallet already owns agent #${existingAgentId}. Each wallet can only own one agent. Use a different wallet to create a new agent.`
1886
+ );
1887
+ }
1888
+ const nameAvailable = await this.registry.isNameAvailable(metadata.name);
1889
+ if (!nameAvailable) {
1890
+ throw new Error(`Agent name "${metadata.name}" is already taken`);
1891
+ }
1892
+ const metadataURI = await this.uploadMetadata(metadata);
1893
+ const hash = await this.registry.register(metadata.name, metadataURI);
1894
+ const receipt = await this.publicClient.waitForTransactionReceipt({ hash });
1895
+ const agentId = this.parseAgentIdFromReceipt(receipt);
1896
+ this._agentId = agentId;
1897
+ await this.registry.linkOwnWallet(agentId);
1898
+ return agentId;
1899
+ }
1900
+ /**
1901
+ * Check if an agent name is available for registration
1902
+ * @param name The name to check
1903
+ * @returns True if the name is available
1904
+ */
1905
+ async isNameAvailable(name) {
1906
+ return this.registry.isNameAvailable(name);
1907
+ }
1908
+ /**
1909
+ * Get agent by name (returns 0 if not found)
1910
+ * @param name The agent name to look up
1911
+ * @returns Agent ID or 0 if not found
1912
+ */
1913
+ async getAgentByName(name) {
1914
+ return this.registry.getAgentByName(name);
1915
+ }
1916
+ /**
1917
+ * Get the current agent's ID (if registered)
1918
+ */
1919
+ async getAgentId() {
1920
+ if (this._agentId) return this._agentId;
1921
+ const agentId = await this.registry.getAgentForWallet(this.account.address);
1922
+ if (agentId > 0n) {
1923
+ this._agentId = agentId;
1924
+ return agentId;
1925
+ }
1926
+ return void 0;
1927
+ }
1928
+ /**
1929
+ * Get agent profile
1930
+ * @param agentId Optional agent ID (defaults to current agent)
1931
+ */
1932
+ async getAgent(agentId) {
1933
+ const id = agentId ?? await this.getAgentId();
1934
+ if (!id) throw new Error("Agent not registered");
1935
+ return this.registry.getAgent(id);
1936
+ }
1937
+ // ============ Wallet Management ============
1938
+ /**
1939
+ * Link an additional wallet to this agent
1940
+ * @param wallet Wallet address to link
1941
+ * @param signMessage Function to sign a message with the wallet
1942
+ */
1943
+ async linkWallet(wallet, signMessage) {
1944
+ const agentId = await this.getAgentId();
1945
+ if (!agentId) throw new Error("Agent not registered");
1946
+ const nonce = await this.registry.getNonce(wallet);
1947
+ const message = ExagentRegistry.generateLinkMessage(wallet, agentId, nonce);
1948
+ const signature = await signMessage(message);
1949
+ return this.registry.linkWallet(agentId, wallet, signature);
1950
+ }
1951
+ /**
1952
+ * Get all wallets linked to this agent
1953
+ */
1954
+ async getLinkedWallets() {
1955
+ const agentId = await this.getAgentId();
1956
+ if (!agentId) throw new Error("Agent not registered");
1957
+ return this.registry.getLinkedWallets(agentId);
1958
+ }
1959
+ // ============ Trading ============
1960
+ /**
1961
+ * Get optimal DEX route for a trade
1962
+ * Uses 0x API for aggregation across Aerodrome, Uniswap, etc.
1963
+ */
1964
+ async getRoute(intent) {
1965
+ const apiUrl = EXAGENT_API_CONFIG[this.network];
1966
+ const response = await fetch(`${apiUrl}/v1/routes/quote`, {
1967
+ method: "POST",
1968
+ headers: {
1969
+ "Content-Type": "application/json",
1970
+ ...this.apiKey && { "X-API-Key": this.apiKey }
1971
+ },
1972
+ body: JSON.stringify({
1973
+ tokenIn: intent.tokenIn,
1974
+ tokenOut: intent.tokenOut,
1975
+ amountIn: intent.amountIn.toString(),
1976
+ slippageBps: intent.maxSlippageBps ?? 50,
1977
+ taker: this.account.address
1978
+ })
1979
+ });
1980
+ if (!response.ok) {
1981
+ const error = await response.json().catch(() => ({ error: response.statusText }));
1982
+ throw new Error(`Failed to get route: ${error.error}`);
1983
+ }
1984
+ return response.json();
1985
+ }
1986
+ /**
1987
+ * Get price quote without transaction data (faster)
1988
+ */
1989
+ async getPrice(tokenIn, tokenOut, amountIn) {
1990
+ const apiUrl = EXAGENT_API_CONFIG[this.network];
1991
+ const response = await fetch(`${apiUrl}/v1/routes/price`, {
1992
+ method: "POST",
1993
+ headers: {
1994
+ "Content-Type": "application/json",
1995
+ ...this.apiKey && { "X-API-Key": this.apiKey }
1996
+ },
1997
+ body: JSON.stringify({
1998
+ tokenIn,
1999
+ tokenOut,
2000
+ amountIn: amountIn.toString()
2001
+ })
2002
+ });
2003
+ if (!response.ok) {
2004
+ const error = await response.json().catch(() => ({ error: response.statusText }));
2005
+ throw new Error(`Failed to get price: ${error.error}`);
2006
+ }
2007
+ return response.json();
2008
+ }
2009
+ /**
2010
+ * Execute a trade using a pre-fetched route
2011
+ * @param route Route quote from getRoute()
2012
+ * @param options Trade execution options
2013
+ * @returns Transaction hash
2014
+ */
2015
+ async executeTrade(route, options) {
2016
+ if (route.validUntil && Date.now() > route.validUntil) {
2017
+ throw new Error("Quote expired, please fetch a new route");
2018
+ }
2019
+ if (route.issues?.allowance) {
2020
+ throw new Error(
2021
+ `Insufficient allowance for ${route.issues.allowance.spender}. Need ${route.issues.allowance.expected}, have ${route.issues.allowance.actual}`
2022
+ );
2023
+ }
2024
+ if (options?.validateSlippage !== false) {
2025
+ const freshPrice = await this.getPrice(
2026
+ route.tokenIn,
2027
+ route.tokenOut,
2028
+ BigInt(route.amountIn)
2029
+ );
2030
+ const quotedOutput = BigInt(route.amountOut);
2031
+ const freshOutput = BigInt(freshPrice.amountOut);
2032
+ if (freshOutput < quotedOutput * 99n / 100n) {
2033
+ console.warn("Price has moved significantly since quote was fetched");
2034
+ }
2035
+ }
2036
+ const hash = await this.walletClient.sendTransaction({
2037
+ account: this.account,
2038
+ chain: CHAIN_CONFIG[this.network],
2039
+ to: route.transaction.to,
2040
+ data: route.transaction.data,
2041
+ value: BigInt(route.transaction.value)
2042
+ });
2043
+ return hash;
2044
+ }
2045
+ /**
2046
+ * Get and execute a trade in one call
2047
+ * Convenience method that fetches route and executes
2048
+ */
2049
+ async swap(intent) {
2050
+ const route = await this.getRoute(intent);
2051
+ const hash = await this.executeTrade(route);
2052
+ return { hash, route };
2053
+ }
2054
+ /**
2055
+ * Broadcast a trade intent to the network
2056
+ * Other agents can see this and potentially provide better execution
2057
+ */
2058
+ async broadcastIntent(intent) {
2059
+ const agentId = await this.getAgentId();
2060
+ if (!agentId) throw new Error("Agent not registered");
2061
+ const apiUrl = EXAGENT_API_CONFIG[this.network];
2062
+ await fetch(`${apiUrl}/v1/intents`, {
2063
+ method: "POST",
2064
+ headers: {
2065
+ "Content-Type": "application/json",
2066
+ ...this.apiKey && { "X-API-Key": this.apiKey }
2067
+ },
2068
+ body: JSON.stringify({
2069
+ agentId: agentId.toString(),
2070
+ intent,
2071
+ signature: await this.signIntent(intent)
2072
+ })
2073
+ });
2074
+ }
2075
+ // ============ Router Trading (Attributed) ============
2076
+ /**
2077
+ * Execute a trade through ExagentRouter for full attribution
2078
+ *
2079
+ * This is the recommended way for agents to trade. All trades routed through
2080
+ * the ExagentRouter emit TradeExecuted events that are captured by the indexer
2081
+ * for accurate performance tracking and rankings.
2082
+ *
2083
+ * @param intent Trade parameters
2084
+ * @returns Trade result with transaction hash
2085
+ *
2086
+ * @example
2087
+ * ```typescript
2088
+ * const result = await exagent.trade({
2089
+ * tokenIn: WETH,
2090
+ * tokenOut: USDC,
2091
+ * amountIn: parseEther('1'),
2092
+ * maxSlippageBps: 50,
2093
+ * });
2094
+ * console.log('Trade submitted:', result.hash);
2095
+ * ```
2096
+ */
2097
+ async trade(intent) {
2098
+ const agentId = await this.getAgentId();
2099
+ if (!agentId) throw new Error("Agent not registered");
2100
+ const routerTrade = await this.buildRouterTrade(intent, agentId);
2101
+ for (const approval of routerTrade.approvals) {
2102
+ await this.approveToken(
2103
+ approval.token,
2104
+ approval.spender,
2105
+ BigInt(approval.amount)
2106
+ );
2107
+ }
2108
+ const hash = await this.walletClient.sendTransaction({
2109
+ account: this.account,
2110
+ chain: CHAIN_CONFIG[this.network],
2111
+ to: routerTrade.transaction.to,
2112
+ data: routerTrade.transaction.data,
2113
+ value: BigInt(routerTrade.transaction.value)
2114
+ });
2115
+ return {
2116
+ hash,
2117
+ agentId,
2118
+ tokenIn: routerTrade.tokenIn,
2119
+ tokenOut: routerTrade.tokenOut,
2120
+ amountIn: routerTrade.amountIn,
2121
+ expectedAmountOut: routerTrade.amountOut
2122
+ };
2123
+ }
2124
+ /**
2125
+ * Build a router trade transaction without executing
2126
+ * Useful for simulation or multi-step workflows
2127
+ */
2128
+ async buildRouterTrade(intent, agentId) {
2129
+ const id = agentId ?? await this.getAgentId();
2130
+ if (!id) throw new Error("Agent not registered");
2131
+ const apiUrl = EXAGENT_API_CONFIG[this.network];
2132
+ const response = await fetch(`${apiUrl}/v1/router/trade`, {
2133
+ method: "POST",
2134
+ headers: {
2135
+ "Content-Type": "application/json",
2136
+ ...this.apiKey && { "X-API-Key": this.apiKey }
2137
+ },
2138
+ body: JSON.stringify({
2139
+ agentId: id.toString(),
2140
+ tokenIn: intent.tokenIn,
2141
+ tokenOut: intent.tokenOut,
2142
+ amountIn: intent.amountIn.toString(),
2143
+ slippageBps: intent.maxSlippageBps ?? 50,
2144
+ taker: this.account.address
2145
+ })
2146
+ });
2147
+ if (!response.ok) {
2148
+ const error = await response.json().catch(() => ({ error: response.statusText }));
2149
+ throw new Error(`Failed to build trade: ${error.error || error.message}`);
2150
+ }
2151
+ return response.json();
2152
+ }
2153
+ /**
2154
+ * Approve token spending for router
2155
+ */
2156
+ async approveToken(token, spender, amount) {
2157
+ const approveData = this.encodeApprove(spender, amount);
2158
+ const hash = await this.walletClient.sendTransaction({
2159
+ account: this.account,
2160
+ chain: CHAIN_CONFIG[this.network],
2161
+ to: token,
2162
+ data: approveData
2163
+ });
2164
+ await this.publicClient.waitForTransactionReceipt({ hash });
2165
+ return hash;
2166
+ }
2167
+ /**
2168
+ * Encode ERC20 approve calldata
2169
+ */
2170
+ encodeApprove(spender, amount) {
2171
+ const selector = "0x095ea7b3";
2172
+ const paddedSpender = spender.slice(2).padStart(64, "0");
2173
+ const paddedAmount = amount.toString(16).padStart(64, "0");
2174
+ return `${selector}${paddedSpender}${paddedAmount}`;
2175
+ }
2176
+ // ============ M2M Services ============
2177
+ /**
2178
+ * Request a service from another agent
2179
+ */
2180
+ async requestService(request) {
2181
+ const agentId = await this.getAgentId();
2182
+ if (!agentId) throw new Error("Agent not registered");
2183
+ const apiUrl = EXAGENT_API_CONFIG[this.network];
2184
+ const response = await fetch(`${apiUrl}/v1/services/request`, {
2185
+ method: "POST",
2186
+ headers: {
2187
+ "Content-Type": "application/json",
2188
+ ...this.apiKey && { "X-API-Key": this.apiKey }
2189
+ },
2190
+ body: JSON.stringify({
2191
+ requesterId: agentId.toString(),
2192
+ ...request
2193
+ })
2194
+ });
2195
+ if (!response.ok) {
2196
+ throw new Error(`Failed to request service: ${response.statusText}`);
2197
+ }
2198
+ return response.json();
2199
+ }
2200
+ /**
2201
+ * List available services
2202
+ */
2203
+ async listServices(serviceType) {
2204
+ const apiUrl = EXAGENT_API_CONFIG[this.network];
2205
+ const params = new URLSearchParams();
2206
+ if (serviceType) params.set("type", serviceType);
2207
+ const response = await fetch(`${apiUrl}/v1/services?${params}`);
2208
+ return response.json();
2209
+ }
2210
+ // ============ Leaderboards ============
2211
+ /**
2212
+ * Get agent leaderboard
2213
+ */
2214
+ async getLeaderboard(options) {
2215
+ const apiUrl = EXAGENT_API_CONFIG[this.network];
2216
+ const params = new URLSearchParams();
2217
+ if (options?.category) params.set("category", options.category);
2218
+ if (options?.limit) params.set("limit", options.limit.toString());
2219
+ if (options?.offset) params.set("offset", options.offset.toString());
2220
+ const response = await fetch(`${apiUrl}/v1/rankings/leaderboard?${params}`);
2221
+ return response.json();
2222
+ }
2223
+ // ============ Vault Functions (Phase 4: Copy Trading) ============
2224
+ /**
2225
+ * Get a vault interface for interacting with an ExagentVault
2226
+ * @param vaultAddress The vault contract address
2227
+ * @returns ExagentVault instance
2228
+ */
2229
+ getVault(vaultAddress) {
2230
+ return new ExagentVault(
2231
+ vaultAddress,
2232
+ this.publicClient,
2233
+ this.walletClient,
2234
+ CHAIN_CONFIG[this.network],
2235
+ this.account
2236
+ );
2237
+ }
2238
+ /**
2239
+ * List all vaults for a given agent
2240
+ * @param agentId Agent ID to get vaults for
2241
+ * @returns Array of vault summaries
2242
+ */
2243
+ async getAgentVaults(agentId) {
2244
+ const id = agentId ?? await this.getAgentId();
2245
+ if (!id) throw new Error("Agent not registered");
2246
+ const apiUrl = EXAGENT_API_CONFIG[this.network];
2247
+ const response = await fetch(`${apiUrl}/v1/vaults?agentId=${id}`, {
2248
+ headers: {
2249
+ ...this.apiKey && { "X-API-Key": this.apiKey }
2250
+ }
2251
+ });
2252
+ if (!response.ok) {
2253
+ throw new Error(`Failed to get vaults: ${response.statusText}`);
2254
+ }
2255
+ return response.json();
2256
+ }
2257
+ /**
2258
+ * List all vaults the user has positions in
2259
+ * @param userAddress User address (defaults to connected wallet)
2260
+ * @returns Array of vault summaries with user position info
2261
+ */
2262
+ async getUserVaults(userAddress) {
2263
+ const user = userAddress ?? this.account.address;
2264
+ const apiUrl = EXAGENT_API_CONFIG[this.network];
2265
+ const response = await fetch(`${apiUrl}/v1/vaults?depositor=${user}`, {
2266
+ headers: {
2267
+ ...this.apiKey && { "X-API-Key": this.apiKey }
2268
+ }
2269
+ });
2270
+ if (!response.ok) {
2271
+ throw new Error(`Failed to get user vaults: ${response.statusText}`);
2272
+ }
2273
+ return response.json();
2274
+ }
2275
+ /**
2276
+ * List top performing vaults
2277
+ * @param options Filter options
2278
+ * @returns Array of vault summaries sorted by performance
2279
+ */
2280
+ async getTopVaults(options) {
2281
+ const apiUrl = EXAGENT_API_CONFIG[this.network];
2282
+ const params = new URLSearchParams();
2283
+ if (options?.asset) params.set("asset", options.asset);
2284
+ if (options?.minTvl) params.set("minTvl", options.minTvl.toString());
2285
+ if (options?.period) params.set("period", options.period);
2286
+ if (options?.limit) params.set("limit", options.limit.toString());
2287
+ const response = await fetch(`${apiUrl}/v1/vaults/top?${params}`, {
2288
+ headers: {
2289
+ ...this.apiKey && { "X-API-Key": this.apiKey }
2290
+ }
2291
+ });
2292
+ if (!response.ok) {
2293
+ throw new Error(`Failed to get top vaults: ${response.statusText}`);
2294
+ }
2295
+ return response.json();
2296
+ }
2297
+ /**
2298
+ * Deposit into a vault
2299
+ * @param vaultAddress Vault contract address
2300
+ * @param amount Amount of underlying asset to deposit
2301
+ * @returns Transaction hash
2302
+ */
2303
+ async depositToVault(vaultAddress, amount) {
2304
+ const vault = this.getVault(vaultAddress);
2305
+ const info = await vault.getVaultInfo();
2306
+ await vault.approveAsset(info.asset, amount);
2307
+ return vault.deposit(amount);
2308
+ }
2309
+ /**
2310
+ * Withdraw from a vault
2311
+ * @param vaultAddress Vault contract address
2312
+ * @param assets Amount of underlying asset to withdraw
2313
+ * @returns Transaction hash
2314
+ */
2315
+ async withdrawFromVault(vaultAddress, assets) {
2316
+ const vault = this.getVault(vaultAddress);
2317
+ return vault.withdraw(assets);
2318
+ }
2319
+ /**
2320
+ * Redeem shares from a vault
2321
+ * @param vaultAddress Vault contract address
2322
+ * @param shares Amount of shares to redeem
2323
+ * @returns Transaction hash
2324
+ */
2325
+ async redeemFromVault(vaultAddress, shares) {
2326
+ const vault = this.getVault(vaultAddress);
2327
+ return vault.redeem(shares);
2328
+ }
2329
+ // ============ Staking Functions ============
2330
+ /**
2331
+ * Stake EXA tokens to receive vEXA voting power
2332
+ * @param amount Amount of EXA to stake (in wei)
2333
+ * @param lockDuration Lock duration in seconds (30 days to 2 years)
2334
+ * @returns Transaction hash
2335
+ *
2336
+ * @example
2337
+ * ```typescript
2338
+ * // Stake 1000 EXA for 6 months
2339
+ * const tx = await exagent.stakeExa(
2340
+ * parseEther('1000'),
2341
+ * ExagentStaking.LOCK_6_MONTHS
2342
+ * );
2343
+ * ```
2344
+ */
2345
+ async stakeExa(amount, lockDuration) {
2346
+ await this.staking.approveExa(amount);
2347
+ return this.staking.stake(amount, lockDuration);
2348
+ }
2349
+ /**
2350
+ * Unstake EXA tokens after lock expires
2351
+ * @returns Transaction hash
2352
+ */
2353
+ async unstakeExa() {
2354
+ return this.staking.unstake();
2355
+ }
2356
+ /**
2357
+ * Get staking info for the connected wallet
2358
+ * @returns Staking info including amount, unlock time, and vEXA balance
2359
+ */
2360
+ async getStakingInfo() {
2361
+ return this.staking.getStakeInfo();
2362
+ }
2363
+ /**
2364
+ * Get current vEXA balance for the connected wallet
2365
+ * @returns Current vEXA balance (with time decay applied)
2366
+ */
2367
+ async getVeEXABalance() {
2368
+ return this.staking.getVeEXABalance();
2369
+ }
2370
+ /**
2371
+ * Delegate vEXA voting power to an agent
2372
+ * @param agentId The agent ID to delegate to
2373
+ * @returns Transaction hash
2374
+ */
2375
+ async delegateToAgent(agentId) {
2376
+ return this.staking.delegate(agentId);
2377
+ }
2378
+ /**
2379
+ * Get delegation stats for an agent
2380
+ * @param agentId The agent ID to check
2381
+ * @returns Delegation info with total vEXA and delegator count
2382
+ */
2383
+ async getAgentDelegation(agentId) {
2384
+ return this.staking.getAgentDelegation(agentId);
2385
+ }
2386
+ /**
2387
+ * Claim all pending staking rewards (EXA + multi-token)
2388
+ * @returns Transaction hashes for EXA and multi-token claims
2389
+ */
2390
+ async claimAllRewards() {
2391
+ const exaRewards = await this.staking.claimRewards();
2392
+ const multiTokenRewards = await this.staking.claimRewardsMulti();
2393
+ return { exaRewards, multiTokenRewards };
2394
+ }
2395
+ // ============ Helpers ============
2396
+ /**
2397
+ * Get the agent's wallet address
2398
+ */
2399
+ get address() {
2400
+ return this.account.address;
2401
+ }
2402
+ async uploadMetadata(metadata) {
2403
+ const apiUrl = EXAGENT_API_CONFIG[this.network];
2404
+ const response = await fetch(`${apiUrl}/v1/metadata/upload`, {
2405
+ method: "POST",
2406
+ headers: {
2407
+ "Content-Type": "application/json",
2408
+ ...this.apiKey && { "X-API-Key": this.apiKey }
2409
+ },
2410
+ body: JSON.stringify(metadata)
2411
+ });
2412
+ if (!response.ok) {
2413
+ throw new Error(`Failed to upload metadata: ${response.statusText}`);
2414
+ }
2415
+ const result = await response.json();
2416
+ return result.uri;
2417
+ }
2418
+ async signIntent(intent) {
2419
+ const message = JSON.stringify(intent);
2420
+ return this.walletClient.signMessage({ account: this.account, message });
2421
+ }
2422
+ parseAgentIdFromReceipt(receipt) {
2423
+ return 1n;
2424
+ }
2425
+ };
2426
+
2427
+ // src/contracts/vault-factory.ts
2428
+ var EXAGENT_VAULT_FACTORY_ABI = [
2429
+ // Read functions
2430
+ { type: "function", name: "owner", inputs: [], outputs: [{ type: "address" }], stateMutability: "view" },
2431
+ { type: "function", name: "registry", inputs: [], outputs: [{ type: "address" }], stateMutability: "view" },
2432
+ { type: "function", name: "router", inputs: [], outputs: [{ type: "address" }], stateMutability: "view" },
2433
+ { type: "function", name: "minimumVeEXARequired", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
2434
+ { type: "function", name: "eXABurnFee", inputs: [], outputs: [{ type: "uint256" }], stateMutability: "view" },
2435
+ { type: "function", name: "allowedAssets", inputs: [{ name: "asset", type: "address" }], outputs: [{ type: "bool" }], stateMutability: "view" },
2436
+ { type: "function", name: "vaults", inputs: [{ name: "agentId", type: "uint256" }, { name: "asset", type: "address" }], outputs: [{ type: "address" }], stateMutability: "view" },
2437
+ { type: "function", name: "agentVaultCount", inputs: [{ name: "agentId", type: "uint256" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
2438
+ {
2439
+ type: "function",
2440
+ name: "canCreateVault",
2441
+ inputs: [{ name: "creator", type: "address" }],
2442
+ outputs: [{ name: "canCreate", type: "bool" }, { name: "reason", type: "string" }],
2443
+ stateMutability: "view"
2444
+ },
2445
+ {
2446
+ type: "function",
2447
+ name: "getVaultCreationRequirements",
2448
+ inputs: [],
2449
+ outputs: [
2450
+ { name: "veXARequired", type: "uint256" },
2451
+ { name: "burnFee", type: "uint256" },
2452
+ { name: "stakingContract", type: "address" },
2453
+ { name: "exaToken", type: "address" }
2454
+ ],
2455
+ stateMutability: "view"
2456
+ },
2457
+ // Write functions
2458
+ {
2459
+ type: "function",
2460
+ name: "createVault",
2461
+ inputs: [
2462
+ { name: "agentId", type: "uint256" },
2463
+ { name: "asset", type: "address" },
2464
+ { name: "name", type: "string" },
2465
+ { name: "symbol", type: "string" },
2466
+ { name: "feeRecipient", type: "address" }
2467
+ ],
2468
+ outputs: [{ type: "address" }],
2469
+ stateMutability: "nonpayable"
2470
+ },
2471
+ // Events
2472
+ {
2473
+ type: "event",
2474
+ name: "VaultCreated",
2475
+ inputs: [
2476
+ { name: "vault", type: "address", indexed: true },
2477
+ { name: "agentId", type: "uint256", indexed: true },
2478
+ { name: "asset", type: "address", indexed: true },
2479
+ { name: "creator", type: "address", indexed: false },
2480
+ { name: "name", type: "string", indexed: false },
2481
+ { name: "symbol", type: "string", indexed: false }
2482
+ ]
2483
+ },
2484
+ {
2485
+ type: "event",
2486
+ name: "AllowedAssetUpdated",
2487
+ inputs: [
2488
+ { name: "asset", type: "address", indexed: true },
2489
+ { name: "allowed", type: "bool", indexed: false }
2490
+ ]
2491
+ }
2492
+ ];
2493
+ var ExagentVaultFactory = class {
2494
+ address;
2495
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2496
+ publicClient;
2497
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2498
+ walletClient;
2499
+ chain;
2500
+ account;
2501
+ constructor(factoryAddress, publicClient, walletClient, chain, account) {
2502
+ this.address = factoryAddress;
2503
+ this.publicClient = publicClient;
2504
+ this.walletClient = walletClient;
2505
+ this.chain = chain;
2506
+ this.account = account;
2507
+ }
2508
+ // ============ Read Functions ============
2509
+ /**
2510
+ * Get vault creation requirements
2511
+ */
2512
+ async getRequirements() {
2513
+ try {
2514
+ const result = await this.publicClient.readContract({
2515
+ address: this.address,
2516
+ abi: EXAGENT_VAULT_FACTORY_ABI,
2517
+ functionName: "getVaultCreationRequirements"
2518
+ });
2519
+ const isBypassed = result[0] === BigInt(0) && result[1] === BigInt(0) && (result[2] === "0x0000000000000000000000000000000000000000" || result[3] === "0x0000000000000000000000000000000000000000");
2520
+ return {
2521
+ veXARequired: result[0],
2522
+ burnFee: result[1],
2523
+ stakingContract: result[2],
2524
+ exaToken: result[3],
2525
+ isBypassed
2526
+ };
2527
+ } catch {
2528
+ const [veXARequired, burnFee] = await Promise.all([
2529
+ this.publicClient.readContract({
2530
+ address: this.address,
2531
+ abi: EXAGENT_VAULT_FACTORY_ABI,
2532
+ functionName: "minimumVeEXARequired"
2533
+ }),
2534
+ this.publicClient.readContract({
2535
+ address: this.address,
2536
+ abi: EXAGENT_VAULT_FACTORY_ABI,
2537
+ functionName: "eXABurnFee"
2538
+ })
2539
+ ]);
2540
+ const isBypassed = veXARequired === BigInt(0) && burnFee === BigInt(0);
2541
+ return {
2542
+ veXARequired,
2543
+ burnFee,
2544
+ stakingContract: "0x0000000000000000000000000000000000000000",
2545
+ exaToken: "0x0000000000000000000000000000000000000000",
2546
+ isBypassed
2547
+ };
2548
+ }
2549
+ }
2550
+ /**
2551
+ * Check if an address can create a vault
2552
+ * @param creator Address to check
2553
+ */
2554
+ async canCreateVault(creator) {
2555
+ const result = await this.publicClient.readContract({
2556
+ address: this.address,
2557
+ abi: EXAGENT_VAULT_FACTORY_ABI,
2558
+ functionName: "canCreateVault",
2559
+ args: [creator]
2560
+ });
2561
+ return {
2562
+ canCreate: result[0],
2563
+ reason: result[1]
2564
+ };
2565
+ }
2566
+ /**
2567
+ * Check if an asset is whitelisted for vault creation
2568
+ * @param asset Asset address to check
2569
+ */
2570
+ async isAssetAllowed(asset) {
2571
+ return this.publicClient.readContract({
2572
+ address: this.address,
2573
+ abi: EXAGENT_VAULT_FACTORY_ABI,
2574
+ functionName: "allowedAssets",
2575
+ args: [asset]
2576
+ });
2577
+ }
2578
+ /**
2579
+ * Get existing vault for an agent and asset
2580
+ * @param agentId Agent ID
2581
+ * @param asset Asset address
2582
+ * @returns Vault address or zero address if none exists
2583
+ */
2584
+ async getVault(agentId, asset) {
2585
+ return this.publicClient.readContract({
2586
+ address: this.address,
2587
+ abi: EXAGENT_VAULT_FACTORY_ABI,
2588
+ functionName: "vaults",
2589
+ args: [agentId, asset]
2590
+ });
2591
+ }
2592
+ /**
2593
+ * Get count of vaults for an agent
2594
+ * @param agentId Agent ID
2595
+ */
2596
+ async getAgentVaultCount(agentId) {
2597
+ return this.publicClient.readContract({
2598
+ address: this.address,
2599
+ abi: EXAGENT_VAULT_FACTORY_ABI,
2600
+ functionName: "agentVaultCount",
2601
+ args: [agentId]
2602
+ });
2603
+ }
2604
+ /**
2605
+ * Check if agent already has a vault for an asset
2606
+ * @param agentId Agent ID
2607
+ * @param asset Asset address
2608
+ */
2609
+ async hasVault(agentId, asset) {
2610
+ const vault = await this.getVault(agentId, asset);
2611
+ return vault !== "0x0000000000000000000000000000000000000000";
2612
+ }
2613
+ // ============ Write Functions ============
2614
+ /**
2615
+ * Create a new vault for an agent
2616
+ * @param options Vault creation options
2617
+ * @returns Transaction hash
2618
+ */
2619
+ async createVault(options) {
2620
+ if (!this.walletClient || !this.account) {
2621
+ throw new Error("Wallet client required for vault creation");
2622
+ }
2623
+ const feeRecipient = options.feeRecipient ?? this.account.address;
2624
+ const hash = await this.walletClient.writeContract({
2625
+ address: this.address,
2626
+ abi: EXAGENT_VAULT_FACTORY_ABI,
2627
+ functionName: "createVault",
2628
+ args: [options.agentId, options.asset, options.name, options.symbol, feeRecipient],
2629
+ account: this.account,
2630
+ chain: this.chain
2631
+ });
2632
+ return hash;
2633
+ }
2634
+ // ============ Convenience Methods ============
2635
+ /**
2636
+ * Check all requirements and create a vault if possible
2637
+ * Returns detailed status about each requirement
2638
+ */
2639
+ async checkAndCreateVault(agentId, asset, name, symbol, feeRecipient) {
2640
+ const [canCreateResult, assetAllowed, hasExisting] = await Promise.all([
2641
+ this.canCreateVault(this.account?.address ?? "0x0000000000000000000000000000000000000000"),
2642
+ this.isAssetAllowed(asset),
2643
+ this.hasVault(agentId, asset)
2644
+ ]);
2645
+ const checks = {
2646
+ canCreate: canCreateResult.canCreate,
2647
+ canCreateReason: canCreateResult.reason,
2648
+ assetAllowed,
2649
+ hasExistingVault: hasExisting
2650
+ };
2651
+ if (!canCreateResult.canCreate) {
2652
+ return {
2653
+ success: false,
2654
+ error: `Cannot create vault: ${canCreateResult.reason}`,
2655
+ checks
2656
+ };
2657
+ }
2658
+ if (!assetAllowed) {
2659
+ return {
2660
+ success: false,
2661
+ error: `Asset ${asset} is not whitelisted for vault creation`,
2662
+ checks
2663
+ };
2664
+ }
2665
+ if (hasExisting) {
2666
+ const existingVault = await this.getVault(agentId, asset);
2667
+ return {
2668
+ success: false,
2669
+ error: `Vault already exists for this agent and asset`,
2670
+ vaultAddress: existingVault,
2671
+ checks
2672
+ };
2673
+ }
2674
+ try {
2675
+ const txHash = await this.createVault({
2676
+ agentId,
2677
+ asset,
2678
+ name,
2679
+ symbol,
2680
+ feeRecipient
2681
+ });
2682
+ const receipt = await this.publicClient.waitForTransactionReceipt({ hash: txHash });
2683
+ if (receipt.status !== "success") {
2684
+ return {
2685
+ success: false,
2686
+ error: "Transaction failed",
2687
+ txHash,
2688
+ checks
2689
+ };
2690
+ }
2691
+ const vaultAddress = await this.getVault(agentId, asset);
2692
+ return {
2693
+ success: true,
2694
+ vaultAddress,
2695
+ txHash,
2696
+ checks
2697
+ };
2698
+ } catch (error) {
2699
+ return {
2700
+ success: false,
2701
+ error: error instanceof Error ? error.message : "Unknown error creating vault",
2702
+ checks
2703
+ };
2704
+ }
2705
+ }
2706
+ };
2707
+
2708
+ // src/index.ts
2709
+ var TESTNET_ADDRESSES = {
2710
+ registry: "0xCF48C341e3FebeCA5ECB7eb2535f61A2Ba855d9C",
2711
+ // V4 UUPS proxy
2712
+ token: "0x66c39b0ad96B3f5eE198Fef913c6636353a48A87",
2713
+ staking: "0x439441468e1b1b616E9D36b80969C241F261A011",
2714
+ router: "0xc0c27eEE047E414CD716D06C2444CF2073113d5C",
2715
+ // V3 with config epochs
2716
+ vaultFactory: "0x5c099daaE33801a907Bb57011c6749655b55dc75",
2717
+ feeCollector: "0xcB57b03a50df054b9C738Df1324C17A4fDe4fe46",
2718
+ buyback: "0x35cdEa810A130A846265682e5c71A68A507aB895",
2719
+ serviceEscrow: "0x74a3496b148DEE735ac388299aF9Ac2F7C4EdCBf",
2720
+ usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
2721
+ // Circle's Base Sepolia USDC (only vault asset)
2722
+ };
2723
+ export {
2724
+ CHAIN_CONFIG,
2725
+ CONTRACT_ADDRESSES,
2726
+ DEX_ADDRESSES,
2727
+ DISCOUNT_TIERS,
2728
+ EXAGENT_API_CONFIG,
2729
+ EXAGENT_STAKING_ABI,
2730
+ EXAGENT_VAULT_FACTORY_ABI,
2731
+ ExagentClient,
2732
+ ExagentRegistry,
2733
+ ExagentStaking,
2734
+ ExagentVault,
2735
+ ExagentVaultFactory,
2736
+ TESTNET_ADDRESSES,
2737
+ ZERO_X_CONFIG
2738
+ };