@agirails/sdk 2.5.3 → 2.5.4

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.
Files changed (166) hide show
  1. package/dist/ACTPClient.d.ts +18 -0
  2. package/dist/ACTPClient.d.ts.map +1 -1
  3. package/dist/ACTPClient.js +67 -22
  4. package/dist/ACTPClient.js.map +1 -1
  5. package/dist/adapters/BasicAdapter.d.ts +12 -0
  6. package/dist/adapters/BasicAdapter.d.ts.map +1 -1
  7. package/dist/adapters/BasicAdapter.js +30 -4
  8. package/dist/adapters/BasicAdapter.js.map +1 -1
  9. package/dist/adapters/StandardAdapter.d.ts +20 -3
  10. package/dist/adapters/StandardAdapter.d.ts.map +1 -1
  11. package/dist/adapters/StandardAdapter.js +45 -11
  12. package/dist/adapters/StandardAdapter.js.map +1 -1
  13. package/dist/cli/commands/publish.js +16 -4
  14. package/dist/cli/commands/publish.js.map +1 -1
  15. package/dist/cli/commands/register.js +16 -4
  16. package/dist/cli/commands/register.js.map +1 -1
  17. package/dist/cli/commands/tx.js +31 -3
  18. package/dist/cli/commands/tx.js.map +1 -1
  19. package/dist/config/networks.d.ts +2 -2
  20. package/dist/config/networks.d.ts.map +1 -1
  21. package/dist/config/networks.js +27 -22
  22. package/dist/config/networks.js.map +1 -1
  23. package/dist/level0/request.d.ts.map +1 -1
  24. package/dist/level0/request.js +2 -1
  25. package/dist/level0/request.js.map +1 -1
  26. package/dist/runtime/BlockchainRuntime.d.ts.map +1 -1
  27. package/dist/runtime/BlockchainRuntime.js +11 -5
  28. package/dist/runtime/BlockchainRuntime.js.map +1 -1
  29. package/dist/utils/IPFSClient.d.ts +3 -1
  30. package/dist/utils/IPFSClient.d.ts.map +1 -1
  31. package/dist/utils/IPFSClient.js +27 -7
  32. package/dist/utils/IPFSClient.js.map +1 -1
  33. package/dist/wallet/AutoWalletProvider.d.ts.map +1 -1
  34. package/dist/wallet/AutoWalletProvider.js +52 -18
  35. package/dist/wallet/AutoWalletProvider.js.map +1 -1
  36. package/dist/wallet/SmartWalletRouter.d.ts +116 -0
  37. package/dist/wallet/SmartWalletRouter.d.ts.map +1 -0
  38. package/dist/wallet/SmartWalletRouter.js +212 -0
  39. package/dist/wallet/SmartWalletRouter.js.map +1 -0
  40. package/dist/wallet/aa/DualNonceManager.d.ts +19 -0
  41. package/dist/wallet/aa/DualNonceManager.d.ts.map +1 -1
  42. package/dist/wallet/aa/DualNonceManager.js +100 -5
  43. package/dist/wallet/aa/DualNonceManager.js.map +1 -1
  44. package/package.json +3 -6
  45. package/src/ACTPClient.ts +0 -1579
  46. package/src/abi/ACTPKernel.json +0 -1356
  47. package/src/abi/AgentRegistry.json +0 -915
  48. package/src/abi/ERC20.json +0 -40
  49. package/src/abi/EscrowVault.json +0 -134
  50. package/src/abi/IdentityRegistry.json +0 -316
  51. package/src/adapters/AdapterRegistry.ts +0 -173
  52. package/src/adapters/AdapterRouter.ts +0 -416
  53. package/src/adapters/BaseAdapter.ts +0 -498
  54. package/src/adapters/BasicAdapter.ts +0 -514
  55. package/src/adapters/IAdapter.ts +0 -292
  56. package/src/adapters/StandardAdapter.ts +0 -555
  57. package/src/adapters/X402Adapter.ts +0 -731
  58. package/src/adapters/index.ts +0 -60
  59. package/src/builders/DeliveryProofBuilder.ts +0 -327
  60. package/src/builders/QuoteBuilder.ts +0 -483
  61. package/src/builders/index.ts +0 -17
  62. package/src/cli/commands/balance.ts +0 -110
  63. package/src/cli/commands/batch.ts +0 -487
  64. package/src/cli/commands/config.ts +0 -231
  65. package/src/cli/commands/deploy-check.ts +0 -364
  66. package/src/cli/commands/deploy-env.ts +0 -120
  67. package/src/cli/commands/diff.ts +0 -141
  68. package/src/cli/commands/init.ts +0 -469
  69. package/src/cli/commands/mint.ts +0 -116
  70. package/src/cli/commands/pay.ts +0 -113
  71. package/src/cli/commands/publish.ts +0 -475
  72. package/src/cli/commands/pull.ts +0 -124
  73. package/src/cli/commands/register.ts +0 -247
  74. package/src/cli/commands/simulate.ts +0 -345
  75. package/src/cli/commands/time.ts +0 -302
  76. package/src/cli/commands/tx.ts +0 -448
  77. package/src/cli/commands/watch.ts +0 -211
  78. package/src/cli/index.ts +0 -134
  79. package/src/cli/utils/client.ts +0 -252
  80. package/src/cli/utils/config.ts +0 -389
  81. package/src/cli/utils/output.ts +0 -465
  82. package/src/cli/utils/wallet.ts +0 -109
  83. package/src/config/agirailsmd.ts +0 -262
  84. package/src/config/networks.ts +0 -275
  85. package/src/config/pendingPublish.ts +0 -237
  86. package/src/config/publishPipeline.ts +0 -359
  87. package/src/config/syncOperations.ts +0 -279
  88. package/src/erc8004/ERC8004Bridge.ts +0 -462
  89. package/src/erc8004/ReputationReporter.ts +0 -468
  90. package/src/erc8004/index.ts +0 -61
  91. package/src/errors/index.ts +0 -427
  92. package/src/index.ts +0 -364
  93. package/src/level0/Provider.ts +0 -117
  94. package/src/level0/ServiceDirectory.ts +0 -131
  95. package/src/level0/index.ts +0 -10
  96. package/src/level0/provide.ts +0 -132
  97. package/src/level0/request.ts +0 -432
  98. package/src/level1/Agent.ts +0 -1426
  99. package/src/level1/index.ts +0 -10
  100. package/src/level1/pricing/PriceCalculator.ts +0 -255
  101. package/src/level1/pricing/PricingStrategy.ts +0 -198
  102. package/src/level1/types/Job.ts +0 -179
  103. package/src/level1/types/Options.ts +0 -291
  104. package/src/level1/types/index.ts +0 -8
  105. package/src/protocol/ACTPKernel.ts +0 -808
  106. package/src/protocol/AgentRegistry.ts +0 -559
  107. package/src/protocol/DIDManager.ts +0 -629
  108. package/src/protocol/DIDResolver.ts +0 -554
  109. package/src/protocol/EASHelper.ts +0 -378
  110. package/src/protocol/EscrowVault.ts +0 -255
  111. package/src/protocol/EventMonitor.ts +0 -204
  112. package/src/protocol/MessageSigner.ts +0 -510
  113. package/src/protocol/ProofGenerator.ts +0 -339
  114. package/src/protocol/QuoteBuilder.ts +0 -15
  115. package/src/registry/AgentRegistryClient.ts +0 -202
  116. package/src/runtime/BlockchainRuntime.ts +0 -1015
  117. package/src/runtime/IACTPRuntime.ts +0 -306
  118. package/src/runtime/MockRuntime.ts +0 -1298
  119. package/src/runtime/MockStateManager.ts +0 -577
  120. package/src/runtime/index.ts +0 -25
  121. package/src/runtime/types/MockState.ts +0 -237
  122. package/src/storage/ArchiveBundleBuilder.ts +0 -561
  123. package/src/storage/ArweaveClient.ts +0 -946
  124. package/src/storage/FilebaseClient.ts +0 -790
  125. package/src/storage/index.ts +0 -96
  126. package/src/storage/types.ts +0 -348
  127. package/src/types/adapter.ts +0 -310
  128. package/src/types/agent.ts +0 -79
  129. package/src/types/did.ts +0 -223
  130. package/src/types/eip712.ts +0 -175
  131. package/src/types/erc8004.ts +0 -293
  132. package/src/types/escrow.ts +0 -27
  133. package/src/types/index.ts +0 -17
  134. package/src/types/message.ts +0 -145
  135. package/src/types/state.ts +0 -87
  136. package/src/types/transaction.ts +0 -69
  137. package/src/types/x402.ts +0 -251
  138. package/src/utils/ErrorRecoveryGuide.ts +0 -676
  139. package/src/utils/Helpers.ts +0 -688
  140. package/src/utils/IPFSClient.ts +0 -368
  141. package/src/utils/Logger.ts +0 -484
  142. package/src/utils/NonceManager.ts +0 -591
  143. package/src/utils/RateLimiter.ts +0 -534
  144. package/src/utils/ReceivedNonceTracker.ts +0 -567
  145. package/src/utils/SDKLifecycle.ts +0 -416
  146. package/src/utils/SecureNonce.ts +0 -78
  147. package/src/utils/Semaphore.ts +0 -276
  148. package/src/utils/UsedAttestationTracker.ts +0 -385
  149. package/src/utils/canonicalJson.ts +0 -38
  150. package/src/utils/circuitBreaker.ts +0 -324
  151. package/src/utils/computeTypeHash.ts +0 -48
  152. package/src/utils/fsSafe.ts +0 -80
  153. package/src/utils/index.ts +0 -80
  154. package/src/utils/retry.ts +0 -364
  155. package/src/utils/security.ts +0 -418
  156. package/src/utils/validation.ts +0 -540
  157. package/src/wallet/AutoWalletProvider.ts +0 -299
  158. package/src/wallet/EOAWalletProvider.ts +0 -69
  159. package/src/wallet/IWalletProvider.ts +0 -135
  160. package/src/wallet/aa/BundlerClient.ts +0 -274
  161. package/src/wallet/aa/DualNonceManager.ts +0 -173
  162. package/src/wallet/aa/PaymasterClient.ts +0 -174
  163. package/src/wallet/aa/TransactionBatcher.ts +0 -353
  164. package/src/wallet/aa/UserOpBuilder.ts +0 -246
  165. package/src/wallet/aa/constants.ts +0 -60
  166. package/src/wallet/keystore.ts +0 -240
@@ -1,567 +0,0 @@
1
- /**
2
- * ReceivedNonceTracker - Replay Attack Prevention for Message Receivers
3
- *
4
- * This utility tracks nonces of received messages to prevent replay attacks.
5
- * It works in conjunction with NonceManager (for senders) but serves the receiver side.
6
- *
7
- * Reference: V4 Security Vulnerability (EIP-712 Replay Attack)
8
- *
9
- * Usage Pattern:
10
- * - Sender: Uses NonceManager to generate monotonically increasing nonces
11
- * - Receiver: Uses ReceivedNonceTracker to validate and track received nonces
12
- *
13
- * Security Properties:
14
- * 1. Nonces must be monotonically increasing per sender + message type
15
- * 2. Duplicate nonces are rejected (replay attack prevention)
16
- * 3. Nonces that are lower than the highest seen are rejected (old replay prevention)
17
- *
18
- * ⚠️ WARNING: In-memory tracking only. For production:
19
- * - Use persistent storage (Redis, PostgreSQL, etc.)
20
- * - Implement nonce recovery from transaction history
21
- * - Consider nonce expiry for long-running processes
22
- */
23
-
24
- /**
25
- * Nonce validation result
26
- */
27
- export interface NonceValidationResult {
28
- valid: boolean;
29
- reason?: string;
30
- expectedMinimum?: string; // bytes32 format
31
- receivedNonce?: string; // bytes32 format
32
- }
33
-
34
- /**
35
- * Interface for tracking received nonces
36
- */
37
- export interface IReceivedNonceTracker {
38
- /**
39
- * Validate and record a received nonce
40
- * @param sender - Sender DID (e.g., "did:ethr:0x...")
41
- * @param messageType - Message type (e.g., "agirails.delivery.v1")
42
- * @param nonce - Nonce value (bytes32 format: "0x...")
43
- * @returns Validation result
44
- */
45
- validateAndRecord(sender: string, messageType: string, nonce: string): NonceValidationResult;
46
-
47
- /**
48
- * Check if a nonce has been used (without recording)
49
- * @param sender - Sender DID
50
- * @param messageType - Message type
51
- * @param nonce - Nonce value (bytes32 format)
52
- * @returns true if nonce was already used
53
- */
54
- hasBeenUsed(sender: string, messageType: string, nonce: string): boolean;
55
-
56
- /**
57
- * Get highest nonce seen for sender + message type
58
- * @param sender - Sender DID
59
- * @param messageType - Message type
60
- * @returns Highest nonce (bytes32 format) or null if none seen
61
- */
62
- getHighestNonce(sender: string, messageType: string): string | null;
63
-
64
- /**
65
- * Reset tracking for a specific sender + message type
66
- * @param sender - Sender DID
67
- * @param messageType - Message type
68
- */
69
- reset(sender: string, messageType: string): void;
70
-
71
- /**
72
- * Clear all tracked nonces
73
- */
74
- clearAll(): void;
75
- }
76
-
77
- /**
78
- * In-Memory Received Nonce Tracker
79
- *
80
- * Strategy: Track highest nonce seen per sender + message type
81
- * - Accept nonces that are strictly greater than the highest seen
82
- * - Reject nonces that are <= highest seen (replay attack)
83
- *
84
- * Trade-off:
85
- * - Memory efficient (one value per sender + type)
86
- * - Requires ordered nonce sequences
87
- * - Cannot skip nonces (nonce gaps are rejected)
88
- */
89
- export class InMemoryReceivedNonceTracker implements IReceivedNonceTracker {
90
- // Map: sender -> messageType -> highest nonce (as BigInt for comparison)
91
- private highestNonces: Map<string, Map<string, bigint>> = new Map();
92
-
93
- /**
94
- * Validate and record a received nonce
95
- */
96
- validateAndRecord(sender: string, messageType: string, nonce: string): NonceValidationResult {
97
- // Validate nonce format (must be bytes32: 0x + 64 hex chars)
98
- if (!/^0x[a-fA-F0-9]{64}$/.test(nonce)) {
99
- return {
100
- valid: false,
101
- reason: 'Invalid nonce format (must be bytes32)',
102
- receivedNonce: nonce
103
- };
104
- }
105
-
106
- // Convert nonce to BigInt for comparison
107
- const nonceValue = BigInt(nonce);
108
-
109
- // Get sender's nonce map
110
- let senderNonces = this.highestNonces.get(sender);
111
- if (!senderNonces) {
112
- senderNonces = new Map<string, bigint>();
113
- this.highestNonces.set(sender, senderNonces);
114
- }
115
-
116
- // Get highest nonce for this message type
117
- const highestNonce = senderNonces.get(messageType);
118
-
119
- if (highestNonce === undefined) {
120
- // First message from this sender for this type
121
- senderNonces.set(messageType, nonceValue);
122
- return { valid: true };
123
- }
124
-
125
- // Nonce must be strictly greater than highest seen
126
- if (nonceValue <= highestNonce) {
127
- const expectedMinimum = '0x' + (highestNonce + BigInt(1)).toString(16).padStart(64, '0');
128
- return {
129
- valid: false,
130
- reason: `Nonce replay detected: nonce must be > ${this.bigintToBytes32(highestNonce)}`,
131
- expectedMinimum,
132
- receivedNonce: nonce
133
- };
134
- }
135
-
136
- // Valid nonce - record it
137
- senderNonces.set(messageType, nonceValue);
138
- return { valid: true };
139
- }
140
-
141
- /**
142
- * Check if a nonce has been used (non-mutating)
143
- */
144
- hasBeenUsed(sender: string, messageType: string, nonce: string): boolean {
145
- const nonceValue = BigInt(nonce);
146
- const senderNonces = this.highestNonces.get(sender);
147
-
148
- if (!senderNonces) {
149
- return false; // No nonces seen from this sender
150
- }
151
-
152
- const highestNonce = senderNonces.get(messageType);
153
- if (highestNonce === undefined) {
154
- return false; // No nonces seen for this message type
155
- }
156
-
157
- // If the provided nonce is <= highest seen, it's been "used"
158
- return nonceValue <= highestNonce;
159
- }
160
-
161
- /**
162
- * Get highest nonce seen
163
- */
164
- getHighestNonce(sender: string, messageType: string): string | null {
165
- const senderNonces = this.highestNonces.get(sender);
166
- if (!senderNonces) {
167
- return null;
168
- }
169
-
170
- const highestNonce = senderNonces.get(messageType);
171
- if (highestNonce === undefined) {
172
- return null;
173
- }
174
-
175
- return this.bigintToBytes32(highestNonce);
176
- }
177
-
178
- /**
179
- * Reset tracking for sender + message type
180
- */
181
- reset(sender: string, messageType: string): void {
182
- const senderNonces = this.highestNonces.get(sender);
183
- if (senderNonces) {
184
- senderNonces.delete(messageType);
185
- // Clean up sender map if empty
186
- if (senderNonces.size === 0) {
187
- this.highestNonces.delete(sender);
188
- }
189
- }
190
- }
191
-
192
- /**
193
- * Clear all tracked nonces
194
- */
195
- clearAll(): void {
196
- this.highestNonces.clear();
197
- }
198
-
199
- /**
200
- * Convert BigInt to bytes32 hex string
201
- */
202
- private bigintToBytes32(value: bigint): string {
203
- return '0x' + value.toString(16).padStart(64, '0');
204
- }
205
-
206
- /**
207
- * Get all nonces (for debugging/persistence)
208
- */
209
- getAllNonces(): Record<string, Record<string, string>> {
210
- const result: Record<string, Record<string, string>> = {};
211
-
212
- this.highestNonces.forEach((senderNonces, sender) => {
213
- result[sender] = {};
214
- senderNonces.forEach((nonce, messageType) => {
215
- result[sender][messageType] = this.bigintToBytes32(nonce);
216
- });
217
- });
218
-
219
- return result;
220
- }
221
- }
222
-
223
- /**
224
- * Set-Based Received Nonce Tracker
225
- *
226
- * Strategy: Track exact set of used nonces per sender + message type
227
- * - Accept nonces that haven't been seen before
228
- * - Reject duplicate nonces (replay attack)
229
- * - Allows non-sequential nonces (nonce gaps are OK)
230
- *
231
- * SECURITY FIX (NEW-H-2): Max size enforcement to prevent memory exhaustion
232
- * SECURITY FIX (HIGH-2): Global total entries limit to prevent DoS via many sender combinations
233
- * SECURITY FIX (H-2): Rate limiting per sender to prevent flood attacks
234
- *
235
- * Trade-off:
236
- * - Higher memory usage (stores every nonce)
237
- * - More flexible (allows out-of-order delivery)
238
- * - Requires periodic cleanup to prevent unbounded growth
239
- */
240
- export class SetBasedReceivedNonceTracker implements IReceivedNonceTracker {
241
- // Map: sender -> messageType -> Set of used nonces
242
- private usedNonces: Map<string, Map<string, Set<string>>> = new Map();
243
-
244
- // SECURITY FIX (NEW-H-2): Maximum entries per sender+messageType
245
- private readonly maxSizePerType: number;
246
-
247
- // SECURITY FIX (HIGH-2): Global limit across ALL sender+messageType combinations
248
- private readonly maxTotalEntries: number;
249
- private totalEntries: number = 0;
250
-
251
- // SECURITY FIX (H-2): Rate limiting per sender
252
- // Map: sender -> { count: number, windowStart: number }
253
- private rateLimitState: Map<string, { count: number; windowStart: number }> = new Map();
254
- private readonly maxNoncesPerMinute: number;
255
- private readonly rateLimitWindowMs: number = 60000; // 1 minute window
256
-
257
- /**
258
- * Create set-based tracker with optional max size
259
- * @param maxSizePerType - Maximum nonces per sender+messageType (default: 10,000)
260
- * @param maxTotalEntries - Maximum total nonces across all combinations (default: 100,000)
261
- * @param maxNoncesPerMinute - Maximum nonces per sender per minute (default: 100)
262
- */
263
- constructor(
264
- maxSizePerType: number = 10000,
265
- maxTotalEntries: number = 100000,
266
- maxNoncesPerMinute: number = 100
267
- ) {
268
- if (maxSizePerType <= 0) {
269
- throw new Error('maxSizePerType must be positive');
270
- }
271
- if (maxTotalEntries <= 0) {
272
- throw new Error('maxTotalEntries must be positive');
273
- }
274
- if (maxNoncesPerMinute <= 0) {
275
- throw new Error('maxNoncesPerMinute must be positive');
276
- }
277
- this.maxSizePerType = maxSizePerType;
278
- this.maxTotalEntries = maxTotalEntries;
279
- this.maxNoncesPerMinute = maxNoncesPerMinute;
280
- }
281
-
282
- /**
283
- * SECURITY FIX (H-2): Check rate limit for sender
284
- * @param sender - Sender DID
285
- * @returns true if rate limit exceeded
286
- */
287
- private checkRateLimit(sender: string): boolean {
288
- const now = Date.now();
289
- const state = this.rateLimitState.get(sender);
290
-
291
- if (!state) {
292
- // First nonce from this sender
293
- this.rateLimitState.set(sender, { count: 1, windowStart: now });
294
- return false; // Not rate limited
295
- }
296
-
297
- // Check if window expired (reset counter)
298
- if (now - state.windowStart >= this.rateLimitWindowMs) {
299
- state.count = 1;
300
- state.windowStart = now;
301
- return false; // Not rate limited
302
- }
303
-
304
- // Increment counter
305
- state.count++;
306
-
307
- // Check if rate limit exceeded
308
- return state.count > this.maxNoncesPerMinute;
309
- }
310
-
311
- /**
312
- * SECURITY FIX (H-2): Periodic cleanup of rate limit state
313
- * Removes expired rate limit entries (older than 5 minutes)
314
- */
315
- private cleanupRateLimitState(): void {
316
- const now = Date.now();
317
- const expiryThreshold = 5 * 60 * 1000; // 5 minutes
318
-
319
- for (const [sender, state] of this.rateLimitState.entries()) {
320
- if (now - state.windowStart > expiryThreshold) {
321
- this.rateLimitState.delete(sender);
322
- }
323
- }
324
- }
325
-
326
- /**
327
- * Validate and record a received nonce
328
- *
329
- * SECURITY FIX (NEW-H-2): Automatic cleanup when max size reached
330
- * SECURITY FIX (HIGH-2): Global limit check to prevent DoS
331
- * SECURITY FIX (H-2): Rate limiting per sender (max 100 nonces/minute)
332
- */
333
- validateAndRecord(sender: string, messageType: string, nonce: string): NonceValidationResult {
334
- // Validate nonce format
335
- if (!/^0x[a-fA-F0-9]{64}$/.test(nonce)) {
336
- return {
337
- valid: false,
338
- reason: 'Invalid nonce format (must be bytes32)',
339
- receivedNonce: nonce
340
- };
341
- }
342
-
343
- // SECURITY FIX (H-2): Rate limit check (BEFORE global limit to avoid unnecessary work)
344
- if (this.checkRateLimit(sender)) {
345
- return {
346
- valid: false,
347
- reason: `Rate limit exceeded for sender ${sender}: ` +
348
- `Maximum ${this.maxNoncesPerMinute} nonces per minute allowed. ` +
349
- `This may indicate a flood attack or misconfigured client. ` +
350
- `Wait 1 minute before retrying.`,
351
- receivedNonce: nonce
352
- };
353
- }
354
-
355
- // SECURITY FIX (H-2): Periodic cleanup every 100 validations (amortized cost)
356
- if (this.totalEntries % 100 === 0) {
357
- this.cleanupRateLimitState();
358
- }
359
-
360
- // SECURITY FIX (HIGH-2): Check global limit BEFORE adding
361
- if (this.totalEntries >= this.maxTotalEntries) {
362
- return {
363
- valid: false,
364
- reason: `Global nonce tracker limit reached (${this.maxTotalEntries} entries). ` +
365
- `This may indicate a DoS attack or need for cleanup. ` +
366
- `Current usage: ${this.totalEntries} entries across ${this.getCombinationCount()} sender+type combinations.`,
367
- receivedNonce: nonce
368
- };
369
- }
370
-
371
- // Get sender's nonce map
372
- let senderNonces = this.usedNonces.get(sender);
373
- if (!senderNonces) {
374
- senderNonces = new Map<string, Set<string>>();
375
- this.usedNonces.set(sender, senderNonces);
376
- }
377
-
378
- // Get set of used nonces for this message type
379
- let usedSet = senderNonces.get(messageType);
380
- if (!usedSet) {
381
- usedSet = new Set<string>();
382
- senderNonces.set(messageType, usedSet);
383
- }
384
-
385
- // Check if nonce was already used
386
- if (usedSet.has(nonce)) {
387
- return {
388
- valid: false,
389
- reason: 'Nonce replay detected: this nonce has already been used',
390
- receivedNonce: nonce
391
- };
392
- }
393
-
394
- // SECURITY FIX (NEW-H-2): Auto-cleanup if max size per type reached
395
- if (usedSet.size >= this.maxSizePerType) {
396
- // Keep only last 80% of entries (sorted by nonce value)
397
- const keepCount = Math.floor(this.maxSizePerType * 0.8);
398
- const sortedNonces = Array.from(usedSet).sort((a, b) => {
399
- const aVal = BigInt(a);
400
- const bVal = BigInt(b);
401
- return aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
402
- });
403
- const removedCount = usedSet.size - keepCount;
404
- usedSet = new Set(sortedNonces.slice(-keepCount));
405
- senderNonces.set(messageType, usedSet);
406
- // SECURITY FIX (HIGH-2): Update global counter
407
- this.totalEntries -= removedCount;
408
- }
409
-
410
- // Valid nonce - record it
411
- usedSet.add(nonce);
412
- // SECURITY FIX (HIGH-2): Update global counter
413
- this.totalEntries++;
414
- return { valid: true };
415
- }
416
-
417
- /**
418
- * Get number of sender+messageType combinations (for monitoring)
419
- * SECURITY FIX (HIGH-2): Monitoring method
420
- */
421
- private getCombinationCount(): number {
422
- let count = 0;
423
- this.usedNonces.forEach(senderMap => {
424
- count += senderMap.size;
425
- });
426
- return count;
427
- }
428
-
429
- /**
430
- * Get memory usage statistics
431
- * SECURITY FIX (HIGH-2): Monitoring method for DoS detection
432
- */
433
- getMemoryUsage(): { totalEntries: number; combinations: number; maxTotalEntries: number } {
434
- return {
435
- totalEntries: this.totalEntries,
436
- combinations: this.getCombinationCount(),
437
- maxTotalEntries: this.maxTotalEntries
438
- };
439
- }
440
-
441
- /**
442
- * Check if a nonce has been used
443
- */
444
- hasBeenUsed(sender: string, messageType: string, nonce: string): boolean {
445
- const senderNonces = this.usedNonces.get(sender);
446
- if (!senderNonces) {
447
- return false;
448
- }
449
-
450
- const usedSet = senderNonces.get(messageType);
451
- if (!usedSet) {
452
- return false;
453
- }
454
-
455
- return usedSet.has(nonce);
456
- }
457
-
458
- /**
459
- * Get highest nonce seen (for this strategy, compute from set)
460
- */
461
- getHighestNonce(sender: string, messageType: string): string | null {
462
- const senderNonces = this.usedNonces.get(sender);
463
- if (!senderNonces) {
464
- return null;
465
- }
466
-
467
- const usedSet = senderNonces.get(messageType);
468
- if (!usedSet || usedSet.size === 0) {
469
- return null;
470
- }
471
-
472
- // Find maximum nonce in set
473
- let maxNonce = BigInt(0);
474
- usedSet.forEach(nonce => {
475
- const value = BigInt(nonce);
476
- if (value > maxNonce) {
477
- maxNonce = value;
478
- }
479
- });
480
-
481
- return '0x' + maxNonce.toString(16).padStart(64, '0');
482
- }
483
-
484
- /**
485
- * Reset tracking for sender + message type
486
- */
487
- reset(sender: string, messageType: string): void {
488
- const senderNonces = this.usedNonces.get(sender);
489
- if (senderNonces) {
490
- const usedSet = senderNonces.get(messageType);
491
- if (usedSet) {
492
- // SECURITY FIX (HIGH-2): Update global counter
493
- this.totalEntries -= usedSet.size;
494
- }
495
- senderNonces.delete(messageType);
496
- if (senderNonces.size === 0) {
497
- this.usedNonces.delete(sender);
498
- }
499
- }
500
- }
501
-
502
- /**
503
- * Clear all tracked nonces
504
- */
505
- clearAll(): void {
506
- this.usedNonces.clear();
507
- // SECURITY FIX (HIGH-2): Reset global counter
508
- this.totalEntries = 0;
509
- }
510
-
511
- /**
512
- * Get nonce count for sender + message type (for monitoring)
513
- */
514
- getNonceCount(sender: string, messageType: string): number {
515
- const senderNonces = this.usedNonces.get(sender);
516
- if (!senderNonces) {
517
- return 0;
518
- }
519
-
520
- const usedSet = senderNonces.get(messageType);
521
- return usedSet ? usedSet.size : 0;
522
- }
523
-
524
- /**
525
- * Cleanup old nonces (keep only last N)
526
- * This prevents unbounded memory growth
527
- */
528
- cleanup(sender: string, messageType: string, keepLast: number = 1000): void {
529
- const senderNonces = this.usedNonces.get(sender);
530
- if (!senderNonces) {
531
- return;
532
- }
533
-
534
- const usedSet = senderNonces.get(messageType);
535
- if (!usedSet || usedSet.size <= keepLast) {
536
- return;
537
- }
538
-
539
- // Convert to array and sort by nonce value
540
- const sortedNonces = Array.from(usedSet).sort((a, b) => {
541
- const aVal = BigInt(a);
542
- const bVal = BigInt(b);
543
- return aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
544
- });
545
-
546
- // Keep only the last N nonces
547
- const removedCount = usedSet.size - keepLast;
548
- const toKeep = new Set(sortedNonces.slice(-keepLast));
549
- senderNonces.set(messageType, toKeep);
550
- // SECURITY FIX (HIGH-2): Update global counter
551
- this.totalEntries -= removedCount;
552
- }
553
- }
554
-
555
- /**
556
- * Factory function to create a nonce tracker
557
- * @param strategy - 'memory-efficient' (highest nonce) or 'set-based' (all nonces)
558
- * @returns IReceivedNonceTracker instance
559
- */
560
- export function createReceivedNonceTracker(
561
- strategy: 'memory-efficient' | 'set-based' = 'memory-efficient'
562
- ): IReceivedNonceTracker {
563
- if (strategy === 'set-based') {
564
- return new SetBasedReceivedNonceTracker();
565
- }
566
- return new InMemoryReceivedNonceTracker();
567
- }