@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,498 +0,0 @@
1
- /**
2
- * BaseAdapter - Abstract base class for all adapter implementations
3
- *
4
- * Provides shared utility methods for parsing user-friendly inputs into
5
- * protocol-level types. All adapters extend this class to ensure consistent
6
- * behavior across the Three-Level API.
7
- *
8
- * Key Responsibilities:
9
- * - Amount parsing (string → bigint with 6 decimals for USDC)
10
- * - Address validation (0x-prefixed hex)
11
- * - Deadline parsing ("+24h" → Unix timestamp)
12
- * - User-friendly error messages
13
- *
14
- * @module adapters/BaseAdapter
15
- */
16
-
17
- // ============================================================================
18
- // Constants
19
- // ============================================================================
20
-
21
- /**
22
- * Default dispute window in seconds (2 days).
23
- * Used when no dispute window is specified in transaction parameters.
24
- */
25
- export const DEFAULT_DISPUTE_WINDOW_SECONDS = 172800;
26
-
27
- /**
28
- * Minimum dispute window in seconds (1 hour).
29
- * Ensures requesters have reasonable time to dispute.
30
- *
31
- * SECURITY: Prevents providers from setting windows too short
32
- * to avoid dispute detection.
33
- */
34
- export const MIN_DISPUTE_WINDOW_SECONDS = 3600; // 1 hour
35
-
36
- /**
37
- * Maximum dispute window in seconds (30 days).
38
- * Prevents excessively long fund locks.
39
- *
40
- * SECURITY: Prevents DoS via indefinite fund locking.
41
- */
42
- export const MAX_DISPUTE_WINDOW_SECONDS = 30 * 24 * 3600; // 30 days
43
-
44
- /**
45
- * Default deadline offset in seconds (24 hours).
46
- * Used when no deadline is specified in transaction parameters.
47
- */
48
- export const DEFAULT_DEADLINE_SECONDS = 86400;
49
-
50
- /**
51
- * Minimum transaction amount in USDC wei (6 decimals).
52
- * $0.05 minimum per AGIRAILS protocol specification.
53
- */
54
- export const MIN_AMOUNT_WEI = 50_000n; // $0.05 USDC
55
-
56
- /**
57
- * Maximum deadline in hours (10 years).
58
- * Prevents integer overflow in deadline calculations.
59
- */
60
- export const MAX_DEADLINE_HOURS = 87600; // 10 years
61
-
62
- /**
63
- * Maximum deadline in days (10 years).
64
- * Prevents integer overflow in deadline calculations.
65
- */
66
- export const MAX_DEADLINE_DAYS = 3650; // 10 years
67
-
68
- /**
69
- * Custom error for validation failures.
70
- *
71
- * Thrown when user input is invalid (e.g., malformed address, negative amount).
72
- * Provides descriptive error messages for end-user debugging.
73
- *
74
- * @example
75
- * ```typescript
76
- * throw new ValidationError('Invalid amount format: "abc". Expected number like "100" or "100.50"');
77
- * ```
78
- */
79
- export class ValidationError extends Error {
80
- constructor(message: string) {
81
- super(message);
82
- this.name = 'ValidationError';
83
- }
84
- }
85
-
86
- /**
87
- * Abstract base adapter with shared parsing utilities.
88
- *
89
- * Provides common functionality for all adapter implementations:
90
- * - Amount parsing (USDC has 6 decimals)
91
- * - Address validation
92
- * - Deadline parsing (relative time or Unix timestamp)
93
- * - Amount formatting
94
- *
95
- * @abstract
96
- */
97
- export abstract class BaseAdapter {
98
- /**
99
- * Creates a new BaseAdapter instance.
100
- *
101
- * @param requesterAddress - The requester's Ethereum address
102
- */
103
- constructor(protected requesterAddress: string) {}
104
-
105
- /**
106
- * Parse user-friendly amount string to bigint (USDC has 6 decimals).
107
- *
108
- * Accepts multiple input formats:
109
- * - "100" → 100_000_000n (100.00 USDC)
110
- * - "100.50" → 100_500_000n (100.50 USDC)
111
- * - "100 USDC" → 100_000_000n (strips currency suffix)
112
- * - "$100" → 100_000_000n (strips $ prefix)
113
- * - 100 (number) → 100_000_000n
114
- *
115
- * Rejects:
116
- * - "abc" → throws ValidationError
117
- * - "" → throws ValidationError
118
- * - "-100" → throws ValidationError (negative amounts)
119
- * - "100.1234567" → throws ValidationError (too many decimals)
120
- *
121
- * @param amount - Amount as string or number
122
- * @returns Amount as bigint with 6 decimals
123
- * @throws {ValidationError} If amount format is invalid
124
- *
125
- * @example
126
- * ```typescript
127
- * const amount = this.parseAmount("100.50"); // 100_500_000n
128
- * const amount = this.parseAmount("100 USDC"); // 100_000_000n
129
- * ```
130
- */
131
- protected parseAmount(amount: string | number): bigint {
132
- // Issue #3 Fix: Normalize input - handle all Unicode whitespace
133
- // Converts all Unicode whitespace to regular spaces, then strip currency symbols
134
- let normalized = String(amount)
135
- .replace(/[\s\u00A0\u2000-\u200B\uFEFF]/g, ' ') // Replace all Unicode whitespace with regular space
136
- .replace(/^[$]/, '') // Strip leading $
137
- .replace(/\s*(USDC|usdc)$/, '') // Strip trailing USDC
138
- .replace(/,/g, '') // Strip thousands separators
139
- .replace(/\s+/g, '') // Remove ALL whitespace (including normalized Unicode spaces)
140
- .trim(); // Final trim for edge cases
141
-
142
- // Check for negative
143
- if (normalized.startsWith('-')) {
144
- throw new ValidationError('Amount cannot be negative');
145
- }
146
-
147
- // Validate format (integer or decimal with up to 6 decimal places)
148
- if (!/^\d+(\.\d{1,6})?$/.test(normalized)) {
149
- throw new ValidationError(
150
- `Invalid amount format: "${amount}". Expected number like "100" or "100.50"`
151
- );
152
- }
153
-
154
- // Parse to bigint with 6 decimals
155
- try {
156
- const parts = normalized.split('.');
157
- const wholePart = parts[0];
158
- const decimalPart = (parts[1] || '').padEnd(6, '0'); // Pad to 6 decimals
159
-
160
- const wholeAmount = BigInt(wholePart) * 1_000_000n;
161
- const decimalAmount = BigInt(decimalPart);
162
-
163
- const totalAmount = wholeAmount + decimalAmount;
164
-
165
- // M1 Fix: Enforce minimum amount ($0.05 USDC = 50,000 wei)
166
- if (totalAmount < MIN_AMOUNT_WEI) {
167
- throw new ValidationError(
168
- `Amount too small: "${amount}". Minimum transaction is $0.05 USDC`
169
- );
170
- }
171
-
172
- return totalAmount;
173
- } catch (error) {
174
- // Re-throw ValidationError as-is
175
- if (error instanceof ValidationError) {
176
- throw error;
177
- }
178
- throw new ValidationError(
179
- `Failed to parse amount: "${amount}". Please use format like "100" or "100.50"`
180
- );
181
- }
182
- }
183
-
184
- /**
185
- * Validate Ethereum address format.
186
- *
187
- * Checks that address:
188
- * - Is a string
189
- * - Starts with "0x"
190
- * - Is exactly 42 characters (0x + 40 hex chars)
191
- * - Contains only valid hex characters
192
- *
193
- * Note: Does not validate checksum (EIP-55) in mock mode.
194
- *
195
- * @param address - Address to validate
196
- * @param paramName - Parameter name for error message
197
- * @returns Validated address (unchanged)
198
- * @throws {ValidationError} If address format is invalid
199
- *
200
- * @example
201
- * ```typescript
202
- * const provider = this.validateAddress(params.to, 'to');
203
- * ```
204
- */
205
- protected validateAddress(address: string, paramName: string): string {
206
- if (typeof address !== 'string') {
207
- throw new ValidationError(
208
- `Invalid ${paramName} address: expected string, got ${typeof address}`
209
- );
210
- }
211
-
212
- // Check 0x prefix
213
- if (!address.startsWith('0x')) {
214
- throw new ValidationError(
215
- `Invalid ${paramName} address: "${address}". Expected 0x-prefixed hex string.`
216
- );
217
- }
218
-
219
- // Check length (0x + 40 hex chars = 42 total)
220
- if (address.length !== 42) {
221
- throw new ValidationError(
222
- `Invalid ${paramName} address: "${address}". Expected 42 characters (0x + 40 hex).`
223
- );
224
- }
225
-
226
- // Check hex format
227
- if (!/^0x[0-9a-fA-F]{40}$/.test(address)) {
228
- throw new ValidationError(
229
- `Invalid ${paramName} address: "${address}". Contains invalid hex characters.`
230
- );
231
- }
232
-
233
- // Issue #2 Fix: Normalize to lowercase for consistency
234
- // This prevents case-sensitivity issues when comparing addresses
235
- return address.toLowerCase();
236
- }
237
-
238
- /**
239
- * Parse deadline from relative time expression or Unix timestamp.
240
- *
241
- * Accepts multiple formats:
242
- * - undefined → now + 24 hours (default)
243
- * - 1734076400 (number) → passed through as Unix timestamp
244
- * - "+1h" → now + 1 hour
245
- * - "+24h" → now + 24 hours
246
- * - "+7d" → now + 7 days
247
- *
248
- * Rejects:
249
- * - "invalid" → throws ValidationError
250
- * - "-24h" → throws ValidationError (negative time)
251
- *
252
- * @param deadline - Deadline as relative time string, Unix timestamp, or undefined
253
- * @param currentTime - Current time in seconds (defaults to Date.now() / 1000)
254
- * @returns Unix timestamp in seconds
255
- * @throws {ValidationError} If deadline format is invalid
256
- *
257
- * @example
258
- * ```typescript
259
- * const deadline = this.parseDeadline("+24h"); // now + 86400
260
- * const deadline = this.parseDeadline(1734076400); // 1734076400
261
- * const deadline = this.parseDeadline(); // now + 86400 (default)
262
- * ```
263
- */
264
- protected parseDeadline(deadline?: string | number, currentTime?: number): number {
265
- const now = currentTime ?? Math.floor(Date.now() / 1000);
266
-
267
- if (deadline === undefined) {
268
- // Default: 24 hours from now
269
- return now + DEFAULT_DEADLINE_SECONDS;
270
- }
271
-
272
- if (typeof deadline === 'number') {
273
- return deadline;
274
- }
275
-
276
- // Parse relative time
277
- const match = deadline.match(/^\+(\d+)(h|d)$/);
278
- if (!match) {
279
- throw new ValidationError(
280
- `Invalid deadline format: "${deadline}". Expected Unix timestamp or relative time (e.g., "+24h", "+7d")`
281
- );
282
- }
283
-
284
- const [, amountStr, unit] = match;
285
- const amount = parseInt(amountStr, 10);
286
-
287
- // H1 Fix: Add bounds check to prevent integer overflow
288
- if (unit === 'h' && amount > MAX_DEADLINE_HOURS) {
289
- throw new ValidationError(
290
- `Deadline too far in future: "${deadline}". Maximum is 10 years (${MAX_DEADLINE_HOURS}h)`
291
- );
292
- }
293
- if (unit === 'd' && amount > MAX_DEADLINE_DAYS) {
294
- throw new ValidationError(
295
- `Deadline too far in future: "${deadline}". Maximum is 10 years (${MAX_DEADLINE_DAYS}d)`
296
- );
297
- }
298
-
299
- const multiplier = unit === 'h' ? 3600 : 86400;
300
-
301
- return now + amount * multiplier;
302
- }
303
-
304
- /**
305
- * Validate and normalize dispute window.
306
- *
307
- * SECURITY FIX (L-1): Enforces bounds on dispute window:
308
- * - Minimum: 1 hour (prevents skipping disputes)
309
- * - Maximum: 30 days (prevents indefinite fund locking)
310
- *
311
- * @param disputeWindow - Dispute window in seconds (undefined uses default)
312
- * @returns Validated dispute window in seconds
313
- * @throws {ValidationError} If window is outside allowed bounds
314
- *
315
- * @example
316
- * ```typescript
317
- * this.validateDisputeWindow(3600); // 1 hour - OK
318
- * this.validateDisputeWindow(86400); // 1 day - OK
319
- * this.validateDisputeWindow(100); // Too short - throws
320
- * this.validateDisputeWindow(31 * 86400); // Too long - throws
321
- * ```
322
- */
323
- protected validateDisputeWindow(disputeWindow?: number): number {
324
- if (disputeWindow === undefined) {
325
- return DEFAULT_DISPUTE_WINDOW_SECONDS;
326
- }
327
-
328
- if (disputeWindow < MIN_DISPUTE_WINDOW_SECONDS) {
329
- throw new ValidationError(
330
- `Dispute window too short: ${disputeWindow} seconds. ` +
331
- `Minimum is ${MIN_DISPUTE_WINDOW_SECONDS} seconds (1 hour).`
332
- );
333
- }
334
-
335
- if (disputeWindow > MAX_DISPUTE_WINDOW_SECONDS) {
336
- throw new ValidationError(
337
- `Dispute window too long: ${disputeWindow} seconds. ` +
338
- `Maximum is ${MAX_DISPUTE_WINDOW_SECONDS} seconds (30 days).`
339
- );
340
- }
341
-
342
- return disputeWindow;
343
- }
344
-
345
- /**
346
- * Validate bytes32 hex string format.
347
- *
348
- * SECURITY FIX (L-2): Validates that a string is a valid bytes32 hex.
349
- * Used for transaction IDs, escrow IDs, attestation UIDs, etc.
350
- *
351
- * @param value - Value to validate
352
- * @param paramName - Parameter name for error message
353
- * @returns Validated bytes32 string (normalized to lowercase)
354
- * @throws {ValidationError} If format is invalid
355
- *
356
- * @example
357
- * ```typescript
358
- * const txId = this.validateBytes32(id, 'transactionId');
359
- * ```
360
- */
361
- protected validateBytes32(value: string, paramName: string): string {
362
- if (typeof value !== 'string') {
363
- throw new ValidationError(
364
- `Invalid ${paramName}: expected string, got ${typeof value}`
365
- );
366
- }
367
-
368
- // Check 0x prefix
369
- if (!value.startsWith('0x')) {
370
- throw new ValidationError(
371
- `Invalid ${paramName}: "${value}". Expected 0x-prefixed bytes32 (66 characters total).`
372
- );
373
- }
374
-
375
- // Check length (0x + 64 hex chars = 66 total)
376
- if (value.length !== 66) {
377
- throw new ValidationError(
378
- `Invalid ${paramName}: "${value}". Expected 66 characters (0x + 64 hex), got ${value.length}.`
379
- );
380
- }
381
-
382
- // Check hex format
383
- if (!/^0x[0-9a-fA-F]{64}$/.test(value)) {
384
- throw new ValidationError(
385
- `Invalid ${paramName}: "${value}". Contains invalid hex characters.`
386
- );
387
- }
388
-
389
- // Normalize to lowercase
390
- return value.toLowerCase();
391
- }
392
-
393
- /**
394
- * Validate Unix timestamp is reasonable.
395
- *
396
- * SECURITY FIX (L-6): Validates timestamps to prevent overflow/underflow.
397
- *
398
- * @param timestamp - Unix timestamp in seconds
399
- * @param paramName - Parameter name for error message
400
- * @returns Validated timestamp
401
- * @throws {ValidationError} If timestamp is invalid
402
- */
403
- protected validateTimestamp(timestamp: number, paramName: string): number {
404
- // Check it's a number
405
- if (typeof timestamp !== 'number' || isNaN(timestamp)) {
406
- throw new ValidationError(
407
- `Invalid ${paramName}: expected number, got ${typeof timestamp}`
408
- );
409
- }
410
-
411
- // Check it's positive
412
- if (timestamp <= 0) {
413
- throw new ValidationError(
414
- `Invalid ${paramName}: timestamp must be positive`
415
- );
416
- }
417
-
418
- // Check it's not in the past (with 1 minute buffer)
419
- const now = Math.floor(Date.now() / 1000);
420
- const _oneMinuteAgo = now - 60; // Reserved for future validation
421
-
422
- // Only apply this check if it looks like a deadline/future timestamp
423
- // (e.g., createdAt can be in the past)
424
- // For now, just validate it's reasonable
425
-
426
- // Check for overflow (year 3000 = ~32503680000)
427
- const year3000 = 32503680000;
428
- if (timestamp > year3000) {
429
- throw new ValidationError(
430
- `Invalid ${paramName}: timestamp ${timestamp} is too far in the future (overflow prevention)`
431
- );
432
- }
433
-
434
- return timestamp;
435
- }
436
-
437
- /**
438
- * Format bigint amount to human-readable string.
439
- *
440
- * Converts USDC wei (6 decimals) to formatted string with 2 decimal places.
441
- * Uses proper rounding (round half up) for display purposes.
442
- *
443
- * @param amount - Amount as bigint (6 decimals) or string
444
- * @returns Formatted string like "100.00 USDC"
445
- *
446
- * @example
447
- * ```typescript
448
- * this.formatAmount(100_000_000n); // "100.00 USDC"
449
- * this.formatAmount(100_500_000n); // "100.50 USDC"
450
- * this.formatAmount(100_126_000n); // "100.13 USDC" (rounded)
451
- * ```
452
- */
453
- protected formatAmount(amount: bigint | string): string {
454
- const amountBigInt = typeof amount === 'string' ? BigInt(amount) : amount;
455
-
456
- // Convert from 6 decimals to decimal string
457
- const wholePart = amountBigInt / 1_000_000n;
458
- const decimalPart = amountBigInt % 1_000_000n;
459
-
460
- // M3 Fix: Proper rounding to 2 decimal places (round half up)
461
- // decimalPart is 0-999999, we need to round to nearest 10000 (cents)
462
- const decimalNum = Number(decimalPart);
463
- const roundedCents = Math.round(decimalNum / 10000); // 6 decimals → 2 decimals
464
-
465
- // Handle case where rounding causes overflow (e.g., 99.999999 → 100.00)
466
- if (roundedCents >= 100) {
467
- return `${wholePart + 1n}.00 USDC`;
468
- }
469
-
470
- const formattedDecimal = roundedCents.toString().padStart(2, '0');
471
- return `${wholePart}.${formattedDecimal} USDC`;
472
- }
473
-
474
- /**
475
- * Encode dispute window as ABI-encoded proof for DELIVERED transition.
476
- *
477
- * This helper centralizes proof encoding to prevent drift between
478
- * adapters and ensures consistency with on-chain expectations.
479
- *
480
- * @param disputeWindowSeconds - Dispute window in seconds
481
- * @returns ABI-encoded bytes32 proof
482
- *
483
- * @example
484
- * ```typescript
485
- * // Encode 2-hour dispute window
486
- * const proof = this.encodeDisputeWindowProof(7200);
487
- * await runtime.transitionState(txId, 'DELIVERED', proof);
488
- * ```
489
- */
490
- protected encodeDisputeWindowProof(disputeWindowSeconds: number): string {
491
- // Lazy import to avoid circular dependency issues
492
- const { ethers } = require('ethers');
493
- return ethers.AbiCoder.defaultAbiCoder().encode(
494
- ['uint256'],
495
- [disputeWindowSeconds]
496
- );
497
- }
498
- }