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