irsb-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/src/client.ts ADDED
@@ -0,0 +1,392 @@
1
+ import { ethers, Signer, Provider, Contract, TransactionResponse } from 'ethers';
2
+ import {
3
+ ChainConfig,
4
+ CHAIN_CONFIGS,
5
+ SolverInfo,
6
+ SolverStatus,
7
+ IntentReceipt,
8
+ ReceiptStatus,
9
+ Challenge,
10
+ DisputeReason,
11
+ PostReceiptParams,
12
+ CONSTANTS,
13
+ } from './types';
14
+ import {
15
+ SOLVER_REGISTRY_ABI,
16
+ INTENT_RECEIPT_HUB_ABI,
17
+ DISPUTE_MODULE_ABI,
18
+ } from './contracts/abis';
19
+
20
+ export interface IRSBClientConfig {
21
+ /** Chain name ('sepolia') or custom config */
22
+ chain: string | ChainConfig;
23
+ /** Ethers signer for write operations */
24
+ signer?: Signer;
25
+ /** Ethers provider for read operations (optional if signer provided) */
26
+ provider?: Provider;
27
+ }
28
+
29
+ /**
30
+ * IRSB Protocol SDK Client
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * import { IRSBClient } from '@irsb/sdk';
35
+ * import { ethers } from 'ethers';
36
+ *
37
+ * const provider = new ethers.JsonRpcProvider('https://rpc.sepolia.org');
38
+ * const signer = new ethers.Wallet(PRIVATE_KEY, provider);
39
+ *
40
+ * const client = new IRSBClient({
41
+ * chain: 'sepolia',
42
+ * signer,
43
+ * });
44
+ *
45
+ * // Register as solver
46
+ * await client.register({ value: ethers.parseEther('0.1') });
47
+ *
48
+ * // Post a receipt
49
+ * await client.postReceipt({
50
+ * intentHash: '0x...',
51
+ * constraintsHash: '0x...',
52
+ * outcomeHash: '0x...',
53
+ * evidenceHash: '0x...',
54
+ * deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
55
+ * solverSig: '0x...',
56
+ * });
57
+ * ```
58
+ */
59
+ export class IRSBClient {
60
+ readonly config: ChainConfig;
61
+ readonly provider: Provider;
62
+ readonly signer?: Signer;
63
+
64
+ private solverRegistry: Contract;
65
+ private intentReceiptHub: Contract;
66
+ private disputeModule: Contract;
67
+
68
+ constructor(options: IRSBClientConfig) {
69
+ // Resolve chain config
70
+ if (typeof options.chain === 'string') {
71
+ const config = CHAIN_CONFIGS[options.chain];
72
+ if (!config) {
73
+ throw new Error(`Unknown chain: ${options.chain}. Available: ${Object.keys(CHAIN_CONFIGS).join(', ')}`);
74
+ }
75
+ this.config = config;
76
+ } else {
77
+ this.config = options.chain;
78
+ }
79
+
80
+ // Set up provider
81
+ if (options.signer) {
82
+ this.signer = options.signer;
83
+ this.provider = options.signer.provider!;
84
+ } else if (options.provider) {
85
+ this.provider = options.provider;
86
+ } else {
87
+ this.provider = new ethers.JsonRpcProvider(this.config.rpcUrl);
88
+ }
89
+
90
+ // Initialize contracts
91
+ const signerOrProvider = this.signer || this.provider;
92
+ this.solverRegistry = new Contract(
93
+ this.config.solverRegistry,
94
+ SOLVER_REGISTRY_ABI,
95
+ signerOrProvider
96
+ );
97
+ this.intentReceiptHub = new Contract(
98
+ this.config.intentReceiptHub,
99
+ INTENT_RECEIPT_HUB_ABI,
100
+ signerOrProvider
101
+ );
102
+ this.disputeModule = new Contract(
103
+ this.config.disputeModule,
104
+ DISPUTE_MODULE_ABI,
105
+ signerOrProvider
106
+ );
107
+ }
108
+
109
+ // ============ Solver Registry - Read ============
110
+
111
+ /**
112
+ * Get solver information
113
+ */
114
+ async getSolver(address: string): Promise<SolverInfo> {
115
+ const data = await this.solverRegistry.solvers(address);
116
+ return {
117
+ bondAmount: data.bondAmount,
118
+ lockedAmount: data.lockedAmount,
119
+ reputation: data.reputation,
120
+ registrationTime: data.registrationTime,
121
+ lastActiveTime: data.lastActiveTime,
122
+ totalIntents: data.totalIntents,
123
+ successfulIntents: data.successfulIntents,
124
+ jailCount: Number(data.jailCount),
125
+ status: Number(data.status) as SolverStatus,
126
+ pendingWithdrawal: data.pendingWithdrawal,
127
+ withdrawalRequestTime: data.withdrawalRequestTime,
128
+ };
129
+ }
130
+
131
+ /**
132
+ * Check if address is an active solver
133
+ */
134
+ async isActiveSolver(address: string): Promise<boolean> {
135
+ return this.solverRegistry.isActiveSolver(address);
136
+ }
137
+
138
+ /**
139
+ * Get solver's total bond amount
140
+ */
141
+ async getSolverBond(address: string): Promise<bigint> {
142
+ return this.solverRegistry.getSolverBond(address);
143
+ }
144
+
145
+ /**
146
+ * Get solver's available (unlocked) bond
147
+ */
148
+ async getAvailableBond(address: string): Promise<bigint> {
149
+ return this.solverRegistry.getAvailableBond(address);
150
+ }
151
+
152
+ /**
153
+ * Get minimum bond required for registration
154
+ */
155
+ async getMinimumBond(): Promise<bigint> {
156
+ return this.solverRegistry.MINIMUM_BOND();
157
+ }
158
+
159
+ // ============ Solver Registry - Write ============
160
+
161
+ /**
162
+ * Register as a solver with initial bond
163
+ * @param options.value - ETH to deposit as bond (must be >= MINIMUM_BOND)
164
+ */
165
+ async register(options: { value: bigint }): Promise<TransactionResponse> {
166
+ this.requireSigner();
167
+ return this.solverRegistry.register({ value: options.value });
168
+ }
169
+
170
+ /**
171
+ * Deposit additional bond
172
+ * @param options.value - ETH to deposit
173
+ */
174
+ async depositBond(options: { value: bigint }): Promise<TransactionResponse> {
175
+ this.requireSigner();
176
+ return this.solverRegistry.depositBond({ value: options.value });
177
+ }
178
+
179
+ /**
180
+ * Request withdrawal of bond (starts cooldown)
181
+ * @param amount - Amount to withdraw
182
+ */
183
+ async requestWithdrawal(amount: bigint): Promise<TransactionResponse> {
184
+ this.requireSigner();
185
+ return this.solverRegistry.requestWithdrawal(amount);
186
+ }
187
+
188
+ /**
189
+ * Cancel pending withdrawal
190
+ */
191
+ async cancelWithdrawal(): Promise<TransactionResponse> {
192
+ this.requireSigner();
193
+ return this.solverRegistry.cancelWithdrawal();
194
+ }
195
+
196
+ /**
197
+ * Execute withdrawal after cooldown
198
+ */
199
+ async executeWithdrawal(): Promise<TransactionResponse> {
200
+ this.requireSigner();
201
+ return this.solverRegistry.executeWithdrawal();
202
+ }
203
+
204
+ /**
205
+ * Unjail solver by paying penalty
206
+ * @param options.value - Unjail penalty amount
207
+ */
208
+ async unjail(options: { value: bigint }): Promise<TransactionResponse> {
209
+ this.requireSigner();
210
+ return this.solverRegistry.unjail({ value: options.value });
211
+ }
212
+
213
+ // ============ Intent Receipt Hub - Read ============
214
+
215
+ /**
216
+ * Get receipt by intent hash
217
+ */
218
+ async getReceipt(intentHash: string): Promise<IntentReceipt | null> {
219
+ try {
220
+ const data = await this.intentReceiptHub.getReceipt(intentHash);
221
+ if (data.solver === ethers.ZeroAddress) return null;
222
+ return {
223
+ solver: data.solver,
224
+ intentHash: data.intentHash,
225
+ constraintsHash: data.constraintsHash,
226
+ outcomeHash: data.outcomeHash,
227
+ evidenceHash: data.evidenceHash,
228
+ postedAt: data.postedAt,
229
+ deadline: data.deadline,
230
+ solverSig: data.solverSig,
231
+ status: Number(data.status) as ReceiptStatus,
232
+ };
233
+ } catch {
234
+ return null;
235
+ }
236
+ }
237
+
238
+ /**
239
+ * Get challenge for an intent
240
+ */
241
+ async getChallenge(intentHash: string): Promise<Challenge | null> {
242
+ try {
243
+ const data = await this.intentReceiptHub.getChallenge(intentHash);
244
+ if (data.challenger === ethers.ZeroAddress) return null;
245
+ return {
246
+ challenger: data.challenger,
247
+ reason: Number(data.reason) as DisputeReason,
248
+ bond: data.bond,
249
+ timestamp: data.timestamp,
250
+ };
251
+ } catch {
252
+ return null;
253
+ }
254
+ }
255
+
256
+ /**
257
+ * Get challenge window duration
258
+ */
259
+ async getChallengeWindow(): Promise<bigint> {
260
+ return this.intentReceiptHub.challengeWindow();
261
+ }
262
+
263
+ // ============ Intent Receipt Hub - Write ============
264
+
265
+ /**
266
+ * Post a receipt for an executed intent
267
+ */
268
+ async postReceipt(params: PostReceiptParams): Promise<TransactionResponse> {
269
+ this.requireSigner();
270
+ return this.intentReceiptHub.postReceipt(
271
+ params.intentHash,
272
+ params.constraintsHash,
273
+ params.outcomeHash,
274
+ params.evidenceHash,
275
+ params.deadline,
276
+ params.solverSig
277
+ );
278
+ }
279
+
280
+ /**
281
+ * Challenge a receipt
282
+ * @param intentHash - Hash of the intent to challenge
283
+ * @param reason - Dispute reason code
284
+ * @param options.value - Challenger bond (must meet minimum)
285
+ */
286
+ async challengeReceipt(
287
+ intentHash: string,
288
+ reason: DisputeReason,
289
+ options: { value: bigint }
290
+ ): Promise<TransactionResponse> {
291
+ this.requireSigner();
292
+ return this.intentReceiptHub.challengeReceipt(intentHash, reason, {
293
+ value: options.value,
294
+ });
295
+ }
296
+
297
+ /**
298
+ * Finalize a receipt after challenge window
299
+ */
300
+ async finalizeReceipt(intentHash: string): Promise<TransactionResponse> {
301
+ this.requireSigner();
302
+ return this.intentReceiptHub.finalizeReceipt(intentHash);
303
+ }
304
+
305
+ // ============ Dispute Module - Read ============
306
+
307
+ /**
308
+ * Get dispute details
309
+ */
310
+ async getDispute(intentHash: string): Promise<any | null> {
311
+ try {
312
+ const data = await this.disputeModule.getDispute(intentHash);
313
+ if (data.challenger === ethers.ZeroAddress) return null;
314
+ return data;
315
+ } catch {
316
+ return null;
317
+ }
318
+ }
319
+
320
+ // ============ Dispute Module - Write ============
321
+
322
+ /**
323
+ * Submit evidence for a dispute
324
+ */
325
+ async submitEvidence(
326
+ intentHash: string,
327
+ evidenceHash: string
328
+ ): Promise<TransactionResponse> {
329
+ this.requireSigner();
330
+ return this.disputeModule.submitEvidence(intentHash, evidenceHash);
331
+ }
332
+
333
+ /**
334
+ * Escalate dispute to arbitration
335
+ */
336
+ async escalateToArbitration(intentHash: string): Promise<TransactionResponse> {
337
+ this.requireSigner();
338
+ return this.disputeModule.escalateToArbitration(intentHash);
339
+ }
340
+
341
+ // ============ Utilities ============
342
+
343
+ /**
344
+ * Create a signed receipt for posting
345
+ */
346
+ async signReceipt(params: {
347
+ intentHash: string;
348
+ constraintsHash: string;
349
+ outcomeHash: string;
350
+ evidenceHash: string;
351
+ deadline: bigint;
352
+ }): Promise<string> {
353
+ this.requireSigner();
354
+
355
+ const message = ethers.solidityPackedKeccak256(
356
+ ['bytes32', 'bytes32', 'bytes32', 'bytes32', 'uint64'],
357
+ [
358
+ params.intentHash,
359
+ params.constraintsHash,
360
+ params.outcomeHash,
361
+ params.evidenceHash,
362
+ params.deadline,
363
+ ]
364
+ );
365
+
366
+ return this.signer!.signMessage(ethers.getBytes(message));
367
+ }
368
+
369
+ /**
370
+ * Calculate required challenger bond for a slash amount
371
+ */
372
+ calculateChallengerBond(slashAmount: bigint): bigint {
373
+ return (slashAmount * BigInt(CONSTANTS.CHALLENGER_BOND_BPS)) / BigInt(10000);
374
+ }
375
+
376
+ /**
377
+ * Get contract addresses
378
+ */
379
+ getAddresses() {
380
+ return {
381
+ solverRegistry: this.config.solverRegistry,
382
+ intentReceiptHub: this.config.intentReceiptHub,
383
+ disputeModule: this.config.disputeModule,
384
+ };
385
+ }
386
+
387
+ private requireSigner(): void {
388
+ if (!this.signer) {
389
+ throw new Error('Signer required for write operations');
390
+ }
391
+ }
392
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Contract ABIs for IRSB Protocol
3
+ * Simplified to essential functions for SDK usage
4
+ */
5
+
6
+ export const SOLVER_REGISTRY_ABI = [
7
+ // Read functions
8
+ 'function MINIMUM_BOND() view returns (uint256)',
9
+ 'function WITHDRAWAL_COOLDOWN() view returns (uint64)',
10
+ 'function MAX_JAILS() view returns (uint8)',
11
+ 'function solvers(address) view returns (uint256 bondAmount, uint256 lockedAmount, uint256 reputation, uint64 registrationTime, uint64 lastActiveTime, uint64 totalIntents, uint64 successfulIntents, uint8 jailCount, uint8 status, uint256 pendingWithdrawal, uint64 withdrawalRequestTime)',
12
+ 'function isActiveSolver(address solver) view returns (bool)',
13
+ 'function getSolverBond(address solver) view returns (uint256)',
14
+ 'function getAvailableBond(address solver) view returns (uint256)',
15
+ 'function owner() view returns (address)',
16
+
17
+ // Write functions
18
+ 'function register() payable',
19
+ 'function depositBond() payable',
20
+ 'function requestWithdrawal(uint256 amount)',
21
+ 'function cancelWithdrawal()',
22
+ 'function executeWithdrawal()',
23
+ 'function unjail() payable',
24
+
25
+ // Events
26
+ 'event SolverRegistered(address indexed solver, uint256 bondAmount)',
27
+ 'event BondDeposited(address indexed solver, uint256 amount, uint256 newTotal)',
28
+ 'event WithdrawalRequested(address indexed solver, uint256 amount)',
29
+ 'event WithdrawalExecuted(address indexed solver, uint256 amount)',
30
+ 'event WithdrawalCancelled(address indexed solver)',
31
+ 'event SolverSlashed(address indexed solver, uint256 amount, bytes32 reason)',
32
+ 'event SolverJailed(address indexed solver, uint8 jailCount)',
33
+ 'event SolverUnjailed(address indexed solver)',
34
+ 'event SolverBanned(address indexed solver)',
35
+ ] as const;
36
+
37
+ export const INTENT_RECEIPT_HUB_ABI = [
38
+ // Read functions
39
+ 'function challengeWindow() view returns (uint64)',
40
+ 'function challengerBondBps() view returns (uint16)',
41
+ 'function receipts(bytes32) view returns (address solver, bytes32 intentHash, bytes32 constraintsHash, bytes32 outcomeHash, bytes32 evidenceHash, uint64 postedAt, uint64 deadline, bytes solverSig, uint8 status)',
42
+ 'function challenges(bytes32) view returns (address challenger, uint8 reason, uint256 bond, uint64 timestamp)',
43
+ 'function getReceipt(bytes32 intentHash) view returns (tuple(address solver, bytes32 intentHash, bytes32 constraintsHash, bytes32 outcomeHash, bytes32 evidenceHash, uint64 postedAt, uint64 deadline, bytes solverSig, uint8 status))',
44
+ 'function getChallenge(bytes32 intentHash) view returns (tuple(address challenger, uint8 reason, uint256 bond, uint64 timestamp))',
45
+ 'function solverRegistry() view returns (address)',
46
+
47
+ // Write functions
48
+ 'function postReceipt(bytes32 intentHash, bytes32 constraintsHash, bytes32 outcomeHash, bytes32 evidenceHash, uint64 deadline, bytes solverSig)',
49
+ 'function challengeReceipt(bytes32 intentHash, uint8 reason) payable',
50
+ 'function finalizeReceipt(bytes32 intentHash)',
51
+ 'function resolveDeterministic(bytes32 intentHash, bytes settlementProof)',
52
+
53
+ // Events
54
+ 'event ReceiptPosted(bytes32 indexed intentHash, address indexed solver, uint64 deadline)',
55
+ 'event ReceiptChallenged(bytes32 indexed intentHash, address indexed challenger, uint8 reason, uint256 bond)',
56
+ 'event ReceiptFinalized(bytes32 indexed intentHash)',
57
+ 'event ReceiptSlashed(bytes32 indexed intentHash, address indexed solver, uint256 slashAmount)',
58
+ 'event ChallengeResolved(bytes32 indexed intentHash, bool solverWins)',
59
+ ] as const;
60
+
61
+ export const DISPUTE_MODULE_ABI = [
62
+ // Read functions
63
+ 'function evidenceWindow() view returns (uint64)',
64
+ 'function arbitrationTimeout() view returns (uint64)',
65
+ 'function arbitrator() view returns (address)',
66
+ 'function disputes(bytes32) view returns (bytes32 intentHash, address challenger, address solver, uint8 reason, bytes32 solverEvidence, bytes32 challengerEvidence, uint64 createdAt, uint64 evidenceDeadline, uint8 status, uint8 resolution)',
67
+ 'function getDispute(bytes32 intentHash) view returns (tuple(bytes32 intentHash, address challenger, address solver, uint8 reason, bytes32 solverEvidence, bytes32 challengerEvidence, uint64 createdAt, uint64 evidenceDeadline, uint8 status, uint8 resolution))',
68
+
69
+ // Write functions
70
+ 'function submitEvidence(bytes32 intentHash, bytes32 evidenceHash)',
71
+ 'function escalateToArbitration(bytes32 intentHash)',
72
+ 'function resolveArbitration(bytes32 intentHash, uint8 resolution, uint16 solverShareBps)',
73
+ 'function resolveByTimeout(bytes32 intentHash)',
74
+
75
+ // Events
76
+ 'event DisputeCreated(bytes32 indexed intentHash, address indexed challenger, address indexed solver, uint8 reason)',
77
+ 'event EvidenceSubmitted(bytes32 indexed intentHash, address indexed submitter, bytes32 evidenceHash)',
78
+ 'event DisputeEscalated(bytes32 indexed intentHash)',
79
+ 'event DisputeResolved(bytes32 indexed intentHash, uint8 resolution)',
80
+ ] as const;
package/src/index.ts ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * IRSB Protocol SDK
3
+ *
4
+ * SDK for interacting with the IRSB (Intent Receipts & Solver Bonds) Protocol.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+
9
+ // Main client
10
+ export { IRSBClient, type IRSBClientConfig } from './client';
11
+
12
+ // Types
13
+ export {
14
+ // Enums
15
+ SolverStatus,
16
+ ReceiptStatus,
17
+ DisputeReason,
18
+ DisputeStatus,
19
+ DisputeResolution,
20
+ // Structs
21
+ type SolverInfo,
22
+ type IntentReceipt,
23
+ type Challenge,
24
+ type Dispute,
25
+ // Input types
26
+ type PostReceiptParams,
27
+ type ChallengeParams,
28
+ // Config
29
+ type ChainConfig,
30
+ CHAIN_CONFIGS,
31
+ CONSTANTS,
32
+ } from './types';
33
+
34
+ // ABIs (for advanced usage)
35
+ export {
36
+ SOLVER_REGISTRY_ABI,
37
+ INTENT_RECEIPT_HUB_ABI,
38
+ DISPUTE_MODULE_ABI,
39
+ } from './contracts/abis';
package/src/types.ts ADDED
@@ -0,0 +1,145 @@
1
+ /**
2
+ * IRSB Protocol Types
3
+ * Matches Solidity contracts in src/libraries/Types.sol
4
+ */
5
+
6
+ // ============ Enums ============
7
+
8
+ export enum SolverStatus {
9
+ Inactive = 0,
10
+ Active = 1,
11
+ Jailed = 2,
12
+ Banned = 3,
13
+ }
14
+
15
+ export enum ReceiptStatus {
16
+ None = 0,
17
+ Posted = 1,
18
+ Challenged = 2,
19
+ Finalized = 3,
20
+ Slashed = 4,
21
+ }
22
+
23
+ export enum DisputeReason {
24
+ None = 0x00,
25
+ Timeout = 0x01,
26
+ MinOutViolation = 0x02,
27
+ WrongToken = 0x03,
28
+ WrongChain = 0x04,
29
+ WrongRecipient = 0x05,
30
+ ReceiptForgery = 0x06,
31
+ InvalidSignature = 0x07,
32
+ }
33
+
34
+ export enum DisputeStatus {
35
+ None = 0,
36
+ Open = 1,
37
+ EvidenceSubmitted = 2,
38
+ Escalated = 3,
39
+ Resolved = 4,
40
+ }
41
+
42
+ export enum DisputeResolution {
43
+ None = 0,
44
+ SolverWins = 1,
45
+ ChallengerWins = 2,
46
+ Split = 3,
47
+ Timeout = 4,
48
+ }
49
+
50
+ // ============ Structs ============
51
+
52
+ export interface SolverInfo {
53
+ bondAmount: bigint;
54
+ lockedAmount: bigint;
55
+ reputation: bigint;
56
+ registrationTime: bigint;
57
+ lastActiveTime: bigint;
58
+ totalIntents: bigint;
59
+ successfulIntents: bigint;
60
+ jailCount: number;
61
+ status: SolverStatus;
62
+ pendingWithdrawal: bigint;
63
+ withdrawalRequestTime: bigint;
64
+ }
65
+
66
+ export interface IntentReceipt {
67
+ solver: string;
68
+ intentHash: string;
69
+ constraintsHash: string;
70
+ outcomeHash: string;
71
+ evidenceHash: string;
72
+ postedAt: bigint;
73
+ deadline: bigint;
74
+ solverSig: string;
75
+ status: ReceiptStatus;
76
+ }
77
+
78
+ export interface Challenge {
79
+ challenger: string;
80
+ reason: DisputeReason;
81
+ bond: bigint;
82
+ timestamp: bigint;
83
+ }
84
+
85
+ export interface Dispute {
86
+ intentHash: string;
87
+ challenger: string;
88
+ solver: string;
89
+ reason: DisputeReason;
90
+ solverEvidence: string;
91
+ challengerEvidence: string;
92
+ createdAt: bigint;
93
+ evidenceDeadline: bigint;
94
+ status: DisputeStatus;
95
+ resolution: DisputeResolution;
96
+ }
97
+
98
+ // ============ Input Types ============
99
+
100
+ export interface PostReceiptParams {
101
+ intentHash: string;
102
+ constraintsHash: string;
103
+ outcomeHash: string;
104
+ evidenceHash: string;
105
+ deadline: bigint;
106
+ solverSig: string;
107
+ }
108
+
109
+ export interface ChallengeParams {
110
+ intentHash: string;
111
+ reason: DisputeReason;
112
+ }
113
+
114
+ // ============ Config ============
115
+
116
+ export interface ChainConfig {
117
+ chainId: number;
118
+ rpcUrl: string;
119
+ solverRegistry: string;
120
+ intentReceiptHub: string;
121
+ disputeModule: string;
122
+ }
123
+
124
+ export const CHAIN_CONFIGS: Record<string, ChainConfig> = {
125
+ sepolia: {
126
+ chainId: 11155111,
127
+ rpcUrl: 'https://rpc.sepolia.org',
128
+ solverRegistry: '0xB6ab964832808E49635fF82D1996D6a888ecB745',
129
+ intentReceiptHub: '0xD66A1e880AA3939CA066a9EA1dD37ad3d01D977c',
130
+ disputeModule: '0x144DfEcB57B08471e2A75E78fc0d2A74A89DB79D',
131
+ },
132
+ // mainnet: { ... } // Add after mainnet deployment
133
+ };
134
+
135
+ // ============ Constants ============
136
+
137
+ export const CONSTANTS = {
138
+ MINIMUM_BOND: BigInt('100000000000000000'), // 0.1 ETH
139
+ WITHDRAWAL_COOLDOWN: BigInt(7 * 24 * 60 * 60), // 7 days
140
+ MAX_JAILS: 3,
141
+ CHALLENGE_WINDOW: BigInt(60 * 60), // 1 hour
142
+ CHALLENGER_BOND_BPS: 1000, // 10%
143
+ EVIDENCE_WINDOW: BigInt(24 * 60 * 60), // 24 hours
144
+ ARBITRATION_TIMEOUT: BigInt(7 * 24 * 60 * 60), // 7 days
145
+ } as const;