@agirails/sdk 2.5.3 → 2.5.5

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