@agirails/sdk 2.5.2 → 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 (172) 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/cli/utils/client.d.ts.map +1 -1
  20. package/dist/cli/utils/client.js +1 -0
  21. package/dist/cli/utils/client.js.map +1 -1
  22. package/dist/config/networks.d.ts +2 -2
  23. package/dist/config/networks.d.ts.map +1 -1
  24. package/dist/config/networks.js +27 -22
  25. package/dist/config/networks.js.map +1 -1
  26. package/dist/level0/request.d.ts.map +1 -1
  27. package/dist/level0/request.js +2 -1
  28. package/dist/level0/request.js.map +1 -1
  29. package/dist/runtime/BlockchainRuntime.d.ts.map +1 -1
  30. package/dist/runtime/BlockchainRuntime.js +11 -5
  31. package/dist/runtime/BlockchainRuntime.js.map +1 -1
  32. package/dist/runtime/MockStateManager.d.ts.map +1 -1
  33. package/dist/runtime/MockStateManager.js +2 -1
  34. package/dist/runtime/MockStateManager.js.map +1 -1
  35. package/dist/utils/IPFSClient.d.ts +3 -1
  36. package/dist/utils/IPFSClient.d.ts.map +1 -1
  37. package/dist/utils/IPFSClient.js +27 -7
  38. package/dist/utils/IPFSClient.js.map +1 -1
  39. package/dist/wallet/AutoWalletProvider.d.ts.map +1 -1
  40. package/dist/wallet/AutoWalletProvider.js +52 -18
  41. package/dist/wallet/AutoWalletProvider.js.map +1 -1
  42. package/dist/wallet/SmartWalletRouter.d.ts +116 -0
  43. package/dist/wallet/SmartWalletRouter.d.ts.map +1 -0
  44. package/dist/wallet/SmartWalletRouter.js +212 -0
  45. package/dist/wallet/SmartWalletRouter.js.map +1 -0
  46. package/dist/wallet/aa/DualNonceManager.d.ts +19 -0
  47. package/dist/wallet/aa/DualNonceManager.d.ts.map +1 -1
  48. package/dist/wallet/aa/DualNonceManager.js +100 -5
  49. package/dist/wallet/aa/DualNonceManager.js.map +1 -1
  50. package/package.json +3 -6
  51. package/src/ACTPClient.ts +0 -1579
  52. package/src/abi/ACTPKernel.json +0 -1356
  53. package/src/abi/AgentRegistry.json +0 -915
  54. package/src/abi/ERC20.json +0 -40
  55. package/src/abi/EscrowVault.json +0 -134
  56. package/src/abi/IdentityRegistry.json +0 -316
  57. package/src/adapters/AdapterRegistry.ts +0 -173
  58. package/src/adapters/AdapterRouter.ts +0 -416
  59. package/src/adapters/BaseAdapter.ts +0 -498
  60. package/src/adapters/BasicAdapter.ts +0 -514
  61. package/src/adapters/IAdapter.ts +0 -292
  62. package/src/adapters/StandardAdapter.ts +0 -555
  63. package/src/adapters/X402Adapter.ts +0 -731
  64. package/src/adapters/index.ts +0 -60
  65. package/src/builders/DeliveryProofBuilder.ts +0 -327
  66. package/src/builders/QuoteBuilder.ts +0 -483
  67. package/src/builders/index.ts +0 -17
  68. package/src/cli/commands/balance.ts +0 -110
  69. package/src/cli/commands/batch.ts +0 -487
  70. package/src/cli/commands/config.ts +0 -231
  71. package/src/cli/commands/deploy-check.ts +0 -364
  72. package/src/cli/commands/deploy-env.ts +0 -120
  73. package/src/cli/commands/diff.ts +0 -141
  74. package/src/cli/commands/init.ts +0 -469
  75. package/src/cli/commands/mint.ts +0 -116
  76. package/src/cli/commands/pay.ts +0 -113
  77. package/src/cli/commands/publish.ts +0 -475
  78. package/src/cli/commands/pull.ts +0 -124
  79. package/src/cli/commands/register.ts +0 -247
  80. package/src/cli/commands/simulate.ts +0 -345
  81. package/src/cli/commands/time.ts +0 -302
  82. package/src/cli/commands/tx.ts +0 -448
  83. package/src/cli/commands/watch.ts +0 -211
  84. package/src/cli/index.ts +0 -134
  85. package/src/cli/utils/client.ts +0 -251
  86. package/src/cli/utils/config.ts +0 -389
  87. package/src/cli/utils/output.ts +0 -465
  88. package/src/cli/utils/wallet.ts +0 -109
  89. package/src/config/agirailsmd.ts +0 -262
  90. package/src/config/networks.ts +0 -275
  91. package/src/config/pendingPublish.ts +0 -237
  92. package/src/config/publishPipeline.ts +0 -359
  93. package/src/config/syncOperations.ts +0 -279
  94. package/src/erc8004/ERC8004Bridge.ts +0 -462
  95. package/src/erc8004/ReputationReporter.ts +0 -468
  96. package/src/erc8004/index.ts +0 -61
  97. package/src/errors/index.ts +0 -427
  98. package/src/index.ts +0 -364
  99. package/src/level0/Provider.ts +0 -117
  100. package/src/level0/ServiceDirectory.ts +0 -131
  101. package/src/level0/index.ts +0 -10
  102. package/src/level0/provide.ts +0 -132
  103. package/src/level0/request.ts +0 -432
  104. package/src/level1/Agent.ts +0 -1426
  105. package/src/level1/index.ts +0 -10
  106. package/src/level1/pricing/PriceCalculator.ts +0 -255
  107. package/src/level1/pricing/PricingStrategy.ts +0 -198
  108. package/src/level1/types/Job.ts +0 -179
  109. package/src/level1/types/Options.ts +0 -291
  110. package/src/level1/types/index.ts +0 -8
  111. package/src/protocol/ACTPKernel.ts +0 -808
  112. package/src/protocol/AgentRegistry.ts +0 -559
  113. package/src/protocol/DIDManager.ts +0 -629
  114. package/src/protocol/DIDResolver.ts +0 -554
  115. package/src/protocol/EASHelper.ts +0 -378
  116. package/src/protocol/EscrowVault.ts +0 -255
  117. package/src/protocol/EventMonitor.ts +0 -204
  118. package/src/protocol/MessageSigner.ts +0 -510
  119. package/src/protocol/ProofGenerator.ts +0 -339
  120. package/src/protocol/QuoteBuilder.ts +0 -15
  121. package/src/registry/AgentRegistryClient.ts +0 -202
  122. package/src/runtime/BlockchainRuntime.ts +0 -1015
  123. package/src/runtime/IACTPRuntime.ts +0 -306
  124. package/src/runtime/MockRuntime.ts +0 -1298
  125. package/src/runtime/MockStateManager.ts +0 -576
  126. package/src/runtime/index.ts +0 -25
  127. package/src/runtime/types/MockState.ts +0 -237
  128. package/src/storage/ArchiveBundleBuilder.ts +0 -561
  129. package/src/storage/ArweaveClient.ts +0 -946
  130. package/src/storage/FilebaseClient.ts +0 -790
  131. package/src/storage/index.ts +0 -96
  132. package/src/storage/types.ts +0 -348
  133. package/src/types/adapter.ts +0 -310
  134. package/src/types/agent.ts +0 -79
  135. package/src/types/did.ts +0 -223
  136. package/src/types/eip712.ts +0 -175
  137. package/src/types/erc8004.ts +0 -293
  138. package/src/types/escrow.ts +0 -27
  139. package/src/types/index.ts +0 -17
  140. package/src/types/message.ts +0 -145
  141. package/src/types/state.ts +0 -87
  142. package/src/types/transaction.ts +0 -69
  143. package/src/types/x402.ts +0 -251
  144. package/src/utils/ErrorRecoveryGuide.ts +0 -676
  145. package/src/utils/Helpers.ts +0 -688
  146. package/src/utils/IPFSClient.ts +0 -368
  147. package/src/utils/Logger.ts +0 -484
  148. package/src/utils/NonceManager.ts +0 -591
  149. package/src/utils/RateLimiter.ts +0 -534
  150. package/src/utils/ReceivedNonceTracker.ts +0 -567
  151. package/src/utils/SDKLifecycle.ts +0 -416
  152. package/src/utils/SecureNonce.ts +0 -78
  153. package/src/utils/Semaphore.ts +0 -276
  154. package/src/utils/UsedAttestationTracker.ts +0 -385
  155. package/src/utils/canonicalJson.ts +0 -38
  156. package/src/utils/circuitBreaker.ts +0 -324
  157. package/src/utils/computeTypeHash.ts +0 -48
  158. package/src/utils/fsSafe.ts +0 -80
  159. package/src/utils/index.ts +0 -80
  160. package/src/utils/retry.ts +0 -364
  161. package/src/utils/security.ts +0 -418
  162. package/src/utils/validation.ts +0 -540
  163. package/src/wallet/AutoWalletProvider.ts +0 -299
  164. package/src/wallet/EOAWalletProvider.ts +0 -69
  165. package/src/wallet/IWalletProvider.ts +0 -135
  166. package/src/wallet/aa/BundlerClient.ts +0 -274
  167. package/src/wallet/aa/DualNonceManager.ts +0 -173
  168. package/src/wallet/aa/PaymasterClient.ts +0 -174
  169. package/src/wallet/aa/TransactionBatcher.ts +0 -353
  170. package/src/wallet/aa/UserOpBuilder.ts +0 -246
  171. package/src/wallet/aa/constants.ts +0 -60
  172. 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
- }