@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,559 +0,0 @@
1
- import { Contract, Signer, keccak256, toUtf8Bytes } from 'ethers';
2
- import AgentRegistryABI from '../abi/AgentRegistry.json';
3
- import {
4
- AgentProfile,
5
- ServiceDescriptor,
6
- RegisterAgentParams,
7
- QueryAgentsParams
8
- } from '../types';
9
- import { TransactionRevertedError, ValidationError, QueryCapExceededError } from '../errors';
10
- import { validateAddress, validateEndpointURL } from '../utils/validation';
11
-
12
- /**
13
- * Gas options for transactions
14
- */
15
- interface GasOptions {
16
- maxFeePerGas?: bigint;
17
- maxPriorityFeePerGas?: bigint;
18
- }
19
-
20
- /**
21
- * AgentRegistry - Agent Identity & Reputation SDK Module (AIP-7)
22
- *
23
- * Provides methods for:
24
- * - Registering AI agents on-chain
25
- * - Managing agent profiles and services
26
- * - Querying agents by service type
27
- * - Reading reputation scores
28
- *
29
- * Reference: AIP-7 Agent Identity, Registry & Storage System
30
- */
31
- export class AgentRegistry {
32
- private contract: Contract;
33
- private readonly gasSettings?: GasOptions;
34
-
35
- constructor(
36
- private readonly address: string,
37
- signer: Signer,
38
- gasSettings?: GasOptions
39
- ) {
40
- this.contract = new Contract(address, AgentRegistryABI, signer);
41
- this.gasSettings = gasSettings;
42
- }
43
-
44
- /**
45
- * Get gas buffer multiplier based on operation complexity
46
- */
47
- private getGasBufferMultiplier(operation: string): number {
48
- const buffers: Record<string, number> = {
49
- 'registerAgent': 1.40, // 40% - Complex storage writes
50
- 'addServiceType': 1.25, // 25% - Storage update
51
- 'removeServiceType': 1.25,
52
- 'updateEndpoint': 1.20, // 20% - Simple storage update
53
- 'setActiveStatus': 1.15 // 15% - Boolean update
54
- };
55
-
56
- return buffers[operation] || 1.20;
57
- }
58
-
59
- /**
60
- * Build transaction options with gas settings
61
- */
62
- private buildTxOptions(estimatedGas: bigint, operation: string = 'default'): any {
63
- const bufferMultiplier = this.getGasBufferMultiplier(operation);
64
- let gasLimit = (estimatedGas * BigInt(Math.round(bufferMultiplier * 100))) / 100n;
65
-
66
- // Cap gas limit (Base L2 safety)
67
- const MAX_GAS_LIMIT = 10_000_000n;
68
- if (gasLimit > MAX_GAS_LIMIT) {
69
- throw new ValidationError('gasLimit', `Estimated gas exceeds maximum safe limit (${MAX_GAS_LIMIT})`);
70
- }
71
-
72
- const options: any = { gasLimit };
73
-
74
- if (this.gasSettings?.maxFeePerGas) {
75
- options.maxFeePerGas = this.gasSettings.maxFeePerGas;
76
- }
77
- if (this.gasSettings?.maxPriorityFeePerGas) {
78
- options.maxPriorityFeePerGas = this.gasSettings.maxPriorityFeePerGas;
79
- }
80
-
81
- return options;
82
- }
83
-
84
- /**
85
- * Get registry contract address
86
- */
87
- getAddress(): string {
88
- return this.address;
89
- }
90
-
91
- /**
92
- * Compute service type hash
93
- * Service types must be lowercase with only a-z, 0-9, and hyphens
94
- *
95
- * @param serviceType - Human-readable service type (e.g., "text-generation")
96
- * @returns keccak256 hash of the service type
97
- */
98
- computeServiceTypeHash(serviceType: string): string {
99
- // Validate length
100
- const MAX_SERVICE_TYPE_LENGTH = 64;
101
- if (serviceType.length > MAX_SERVICE_TYPE_LENGTH) {
102
- throw new ValidationError(
103
- 'serviceType',
104
- `Service type exceeds maximum length (${MAX_SERVICE_TYPE_LENGTH} characters)`
105
- );
106
- }
107
-
108
- // Validate format
109
- if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(serviceType)) {
110
- throw new ValidationError(
111
- 'serviceType',
112
- 'Must be lowercase alphanumeric with hyphens (e.g., "text-generation")'
113
- );
114
- }
115
- return keccak256(toUtf8Bytes(serviceType));
116
- }
117
-
118
- // ========== WRITE FUNCTIONS ==========
119
-
120
- /**
121
- * Register a new agent profile
122
- *
123
- * @param params - Registration parameters
124
- * @returns Transaction hash
125
- *
126
- * @example
127
- * ```typescript
128
- * await registry.registerAgent({
129
- * endpoint: 'https://myagent.example.com/webhook',
130
- * serviceDescriptors: [{
131
- * serviceTypeHash: registry.computeServiceTypeHash('text-generation'),
132
- * serviceType: 'text-generation',
133
- * schemaURI: 'ipfs://Qm...',
134
- * minPrice: 1_000_000n, // 1 USDC
135
- * maxPrice: 100_000_000n, // 100 USDC
136
- * avgCompletionTime: 60,
137
- * metadataCID: 'Qm...'
138
- * }]
139
- * });
140
- * ```
141
- */
142
- async registerAgent(params: RegisterAgentParams): Promise<string> {
143
- // SECURITY FIX (H-1): Await async endpoint validation (DNS resolution + SSRF check)
144
- await validateEndpointURL(params.endpoint, 'endpoint');
145
-
146
- if (!params.serviceDescriptors || params.serviceDescriptors.length === 0) {
147
- throw new ValidationError('serviceDescriptors', 'At least one service descriptor required');
148
- }
149
-
150
- const MAX_SERVICE_DESCRIPTORS = 100;
151
- if (params.serviceDescriptors.length > MAX_SERVICE_DESCRIPTORS) {
152
- throw new ValidationError(
153
- 'serviceDescriptors',
154
- `Too many service descriptors (max: ${MAX_SERVICE_DESCRIPTORS})`
155
- );
156
- }
157
-
158
- // Validate each service descriptor
159
- for (const sd of params.serviceDescriptors) {
160
- const expectedHash = this.computeServiceTypeHash(sd.serviceType);
161
- if (sd.serviceTypeHash !== expectedHash) {
162
- throw new ValidationError(
163
- 'serviceTypeHash',
164
- `Hash mismatch for ${sd.serviceType}. Expected ${expectedHash}`
165
- );
166
- }
167
-
168
- // C-2: Validate price range
169
- if (sd.minPrice < 0n) {
170
- throw new ValidationError('minPrice', 'Minimum price cannot be negative');
171
- }
172
- if (sd.maxPrice < 0n) {
173
- throw new ValidationError('maxPrice', 'Maximum price cannot be negative');
174
- }
175
- if (sd.minPrice > sd.maxPrice) {
176
- throw new ValidationError('priceRange', `minPrice (${sd.minPrice}) cannot exceed maxPrice (${sd.maxPrice})`);
177
- }
178
-
179
- // Sanity check: max $1M USDC
180
- const MAX_PRICE = 1_000_000_000_000n;
181
- if (sd.maxPrice > MAX_PRICE) {
182
- throw new ValidationError('maxPrice', 'Price exceeds maximum reasonable value ($1M USDC)');
183
- }
184
-
185
- // Validate completion time
186
- if (sd.avgCompletionTime <= 0) {
187
- throw new ValidationError('avgCompletionTime', 'Average completion time must be positive');
188
- }
189
- const MAX_COMPLETION_TIME = 30 * 24 * 60 * 60; // 30 days
190
- if (sd.avgCompletionTime > MAX_COMPLETION_TIME) {
191
- throw new ValidationError('avgCompletionTime', 'Completion time exceeds maximum (30 days)');
192
- }
193
- }
194
-
195
- try {
196
- const registerFunc = this.contract.getFunction('registerAgent');
197
-
198
- // Convert to contract format
199
- const descriptors = params.serviceDescriptors.map(sd => ({
200
- serviceTypeHash: sd.serviceTypeHash,
201
- serviceType: sd.serviceType,
202
- schemaURI: sd.schemaURI,
203
- minPrice: sd.minPrice,
204
- maxPrice: sd.maxPrice,
205
- avgCompletionTime: sd.avgCompletionTime,
206
- metadataCID: sd.metadataCID
207
- }));
208
-
209
- const estimatedGas = await registerFunc.estimateGas(params.endpoint, descriptors);
210
- const txOptions = this.buildTxOptions(estimatedGas, 'registerAgent');
211
-
212
- const tx = await registerFunc(params.endpoint, descriptors, txOptions);
213
- const receipt = await tx.wait(2); // L-2: Wait for 2 confirmations
214
-
215
- return receipt.hash;
216
- } catch (error: any) {
217
- throw new TransactionRevertedError(
218
- error.transactionHash,
219
- `Agent registration failed: ${error.reason || error.message}`
220
- );
221
- }
222
- }
223
-
224
- /**
225
- * Update agent endpoint URL
226
- *
227
- * @param newEndpoint - New webhook/IPFS gateway URL
228
- */
229
- async updateEndpoint(newEndpoint: string): Promise<string> {
230
- // SECURITY FIX (H-1): Await async endpoint validation (DNS resolution + SSRF check)
231
- await validateEndpointURL(newEndpoint, 'newEndpoint');
232
-
233
- try {
234
- const updateFunc = this.contract.getFunction('updateEndpoint');
235
- const estimatedGas = await updateFunc.estimateGas(newEndpoint);
236
- const txOptions = this.buildTxOptions(estimatedGas, 'updateEndpoint');
237
-
238
- const tx = await updateFunc(newEndpoint, txOptions);
239
- const receipt = await tx.wait(2); // L-2: Wait for 2 confirmations
240
-
241
- return receipt.hash;
242
- } catch (error: any) {
243
- throw new TransactionRevertedError(
244
- error.transactionHash,
245
- `Endpoint update failed: ${error.reason || error.message}`
246
- );
247
- }
248
- }
249
-
250
- /**
251
- * Add a new service type to agent profile
252
- *
253
- * @param serviceType - Lowercase service type (e.g., "code-review")
254
- */
255
- async addServiceType(serviceType: string): Promise<string> {
256
- // Validate format
257
- this.computeServiceTypeHash(serviceType);
258
-
259
- try {
260
- const addFunc = this.contract.getFunction('addServiceType');
261
- const estimatedGas = await addFunc.estimateGas(serviceType);
262
- const txOptions = this.buildTxOptions(estimatedGas, 'addServiceType');
263
-
264
- const tx = await addFunc(serviceType, txOptions);
265
- const receipt = await tx.wait(2); // L-2: Wait for 2 confirmations
266
-
267
- return receipt.hash;
268
- } catch (error: any) {
269
- throw new TransactionRevertedError(
270
- error.transactionHash,
271
- `Add service type failed: ${error.reason || error.message}`
272
- );
273
- }
274
- }
275
-
276
- /**
277
- * Remove a service type from agent profile
278
- *
279
- * @param serviceTypeHash - Hash of service type to remove
280
- */
281
- async removeServiceType(serviceTypeHash: string): Promise<string> {
282
- // C-3: Validate hash format (bytes32)
283
- if (!serviceTypeHash || !/^0x[a-fA-F0-9]{64}$/.test(serviceTypeHash)) {
284
- throw new ValidationError('serviceTypeHash', 'Must be valid bytes32 hex string (0x + 64 hex chars)');
285
- }
286
- if (serviceTypeHash === '0x0000000000000000000000000000000000000000000000000000000000000000') {
287
- throw new ValidationError('serviceTypeHash', 'Cannot be zero hash');
288
- }
289
-
290
- try {
291
- const removeFunc = this.contract.getFunction('removeServiceType');
292
- const estimatedGas = await removeFunc.estimateGas(serviceTypeHash);
293
- const txOptions = this.buildTxOptions(estimatedGas, 'removeServiceType');
294
-
295
- const tx = await removeFunc(serviceTypeHash, txOptions);
296
- const receipt = await tx.wait(2); // L-2: Wait for 2 confirmations
297
-
298
- return receipt.hash;
299
- } catch (error: any) {
300
- throw new TransactionRevertedError(
301
- error.transactionHash,
302
- `Remove service type failed: ${error.reason || error.message}`
303
- );
304
- }
305
- }
306
-
307
- /**
308
- * Set agent active/inactive status
309
- *
310
- * @param isActive - Whether agent is accepting new requests
311
- */
312
- async setActiveStatus(isActive: boolean): Promise<string> {
313
- try {
314
- const setFunc = this.contract.getFunction('setActiveStatus');
315
- const estimatedGas = await setFunc.estimateGas(isActive);
316
- const txOptions = this.buildTxOptions(estimatedGas, 'setActiveStatus');
317
-
318
- const tx = await setFunc(isActive, txOptions);
319
- const receipt = await tx.wait(2); // L-2: Wait for 2 confirmations
320
-
321
- return receipt.hash;
322
- } catch (error: any) {
323
- throw new TransactionRevertedError(
324
- error.transactionHash,
325
- `Set active status failed: ${error.reason || error.message}`
326
- );
327
- }
328
- }
329
-
330
- // ========== READ FUNCTIONS ==========
331
-
332
- /**
333
- * Get agent profile by address
334
- *
335
- * @param agentAddress - Agent's Ethereum address
336
- * @returns Agent profile or null if not registered
337
- */
338
- async getAgent(agentAddress: string): Promise<AgentProfile | null> {
339
- validateAddress(agentAddress, 'agentAddress');
340
-
341
- const profile = await this.contract.getAgent(agentAddress);
342
-
343
- // Check if registered (registeredAt > 0)
344
- if (profile.registeredAt === 0n) {
345
- return null;
346
- }
347
-
348
- return this._mapProfile(profile);
349
- }
350
-
351
- /**
352
- * Get agent profile by DID
353
- *
354
- * @param did - Agent's DID (e.g., "did:ethr:8453:0x...")
355
- * @returns Agent profile or null if not found
356
- */
357
- async getAgentByDID(did: string): Promise<AgentProfile | null> {
358
- // H-2: Strengthen DID validation
359
- const didPattern = /^did:ethr:(\d+):(0x[a-fA-F0-9]{40})$/;
360
- const match = did.match(didPattern);
361
-
362
- if (!match) {
363
- throw new ValidationError(
364
- 'did',
365
- 'Invalid DID format. Expected did:ethr:<chainId>:<address> (e.g., did:ethr:84532:0x1234...)'
366
- );
367
- }
368
-
369
- const [, chainIdStr] = match;
370
-
371
- // Validate chain ID matches
372
- const currentChainId = await this.getChainId();
373
- if (parseInt(chainIdStr, 10) !== currentChainId) {
374
- throw new ValidationError(
375
- 'did',
376
- `DID chain ID (${chainIdStr}) does not match registry chain ID (${currentChainId})`
377
- );
378
- }
379
-
380
- const profile = await this.contract.getAgentByDID(did);
381
-
382
- if (profile.registeredAt === 0n) {
383
- return null;
384
- }
385
-
386
- return this._mapProfile(profile);
387
- }
388
-
389
- /**
390
- * Query agents by service type
391
- *
392
- * **IMPORTANT - Query Cap Limitation (L-4)**:
393
- *
394
- * This method will throw `QueryCapExceededError` when the registry contains
395
- * more than 1000 agents. This is an intentional DoS prevention measure.
396
- *
397
- * When you encounter this error, migrate to an off-chain indexer:
398
- * - The Graph: https://thegraph.com/
399
- * - Goldsky: https://goldsky.com/
400
- * - Alchemy Subgraphs: https://docs.alchemy.com/docs/subgraphs-overview
401
- *
402
- * See `QueryCapExceededError` documentation for event schemas to index.
403
- *
404
- * @param params - Query parameters
405
- * @returns List of agent addresses matching criteria
406
- * @throws {QueryCapExceededError} When registry exceeds 1000 agents
407
- * @throws {ValidationError} For invalid parameters
408
- *
409
- * @example
410
- * ```typescript
411
- * try {
412
- * const agents = await registry.queryAgentsByService({
413
- * serviceTypeHash: registry.computeServiceTypeHash('text-generation'),
414
- * minReputation: 5000,
415
- * limit: 50
416
- * });
417
- * } catch (error) {
418
- * if (error instanceof QueryCapExceededError) {
419
- * console.log('Registry too large, use off-chain indexer');
420
- * // Fallback to your indexer implementation
421
- * }
422
- * }
423
- * ```
424
- */
425
- async queryAgentsByService(params: QueryAgentsParams): Promise<string[]> {
426
- // H-3: Add pagination bounds and validation
427
- // Validate serviceTypeHash format
428
- if (!params.serviceTypeHash || !/^0x[a-fA-F0-9]{64}$/.test(params.serviceTypeHash)) {
429
- throw new ValidationError('serviceTypeHash', 'Must be valid bytes32 hex string');
430
- }
431
-
432
- // Validate reputation bounds (0-10000 scale)
433
- const reputation = params.minReputation ?? 0;
434
- if (reputation < 0 || reputation > 10000) {
435
- throw new ValidationError('minReputation', 'Must be between 0 and 10000');
436
- }
437
-
438
- // Validate offset
439
- const offset = params.offset ?? 0;
440
- if (offset < 0) {
441
- throw new ValidationError('offset', 'Cannot be negative');
442
- }
443
-
444
- // Validate and cap limit
445
- const MAX_LIMIT = 1000;
446
- let limit = params.limit ?? 100;
447
- if (limit <= 0) {
448
- throw new ValidationError('limit', 'Must be positive');
449
- }
450
- if (limit > MAX_LIMIT) {
451
- limit = MAX_LIMIT; // Cap silently
452
- }
453
-
454
- try {
455
- const agents = await this.contract.queryAgentsByService(
456
- params.serviceTypeHash,
457
- reputation,
458
- offset,
459
- limit
460
- );
461
-
462
- return agents;
463
- } catch (error: any) {
464
- // [L-4] Catch query cap exceeded revert and throw descriptive error
465
- const message = error.message || error.reason || '';
466
- if (message.includes('Too many agents')) {
467
- // Extract approximate size from error or use default
468
- throw new QueryCapExceededError(1001, 1000);
469
- }
470
- throw error;
471
- }
472
- }
473
-
474
- /**
475
- * Get service descriptors for an agent
476
- *
477
- * @param agentAddress - Agent's Ethereum address
478
- * @returns List of service descriptors
479
- */
480
- async getServiceDescriptors(agentAddress: string): Promise<ServiceDescriptor[]> {
481
- validateAddress(agentAddress, 'agentAddress');
482
-
483
- const descriptors = await this.contract.getServiceDescriptors(agentAddress);
484
-
485
- return descriptors.map((d: any) => ({
486
- serviceTypeHash: d.serviceTypeHash,
487
- serviceType: d.serviceType,
488
- schemaURI: d.schemaURI,
489
- minPrice: d.minPrice,
490
- maxPrice: d.maxPrice,
491
- avgCompletionTime: Number(d.avgCompletionTime),
492
- metadataCID: d.metadataCID
493
- }));
494
- }
495
-
496
- /**
497
- * Check if agent supports a service type
498
- *
499
- * @param agentAddress - Agent's Ethereum address
500
- * @param serviceTypeHash - Service type hash
501
- * @returns True if supported
502
- */
503
- async supportsService(agentAddress: string, serviceTypeHash: string): Promise<boolean> {
504
- validateAddress(agentAddress, 'agentAddress');
505
- return await this.contract.supportsService(agentAddress, serviceTypeHash);
506
- }
507
-
508
- /**
509
- * Get the chain ID used for DID generation
510
- */
511
- async getChainId(): Promise<number> {
512
- return Number(await this.contract.chainId());
513
- }
514
-
515
- /**
516
- * Build a DID for an address on the current chain
517
- *
518
- * @param address - Ethereum address
519
- * @returns DID string (e.g., "did:ethr:8453:0x...")
520
- */
521
- async buildDID(address: string): Promise<string> {
522
- validateAddress(address, 'address');
523
- const chainId = await this.getChainId();
524
- return `did:ethr:${chainId}:${address.toLowerCase()}`;
525
- }
526
-
527
- // ========== PRIVATE HELPERS ==========
528
-
529
- /**
530
- * Safely convert bigint to number, throwing if precision would be lost
531
- */
532
- private safeToNumber(value: bigint | number, fieldName: string): number {
533
- const bigIntValue = typeof value === 'bigint' ? value : BigInt(value);
534
- if (bigIntValue > BigInt(Number.MAX_SAFE_INTEGER)) {
535
- throw new Error(`${fieldName} exceeds JavaScript MAX_SAFE_INTEGER`);
536
- }
537
- if (bigIntValue < BigInt(Number.MIN_SAFE_INTEGER)) {
538
- throw new Error(`${fieldName} below JavaScript MIN_SAFE_INTEGER`);
539
- }
540
- return Number(bigIntValue);
541
- }
542
-
543
- private _mapProfile(profile: any): AgentProfile {
544
- return {
545
- agentAddress: profile.agentAddress,
546
- did: profile.did,
547
- endpoint: profile.endpoint,
548
- serviceTypes: [...profile.serviceTypes], // H-4: Clone array
549
- stakedAmount: profile.stakedAmount,
550
- reputationScore: this.safeToNumber(profile.reputationScore, 'reputationScore'),
551
- totalTransactions: this.safeToNumber(profile.totalTransactions, 'totalTransactions'),
552
- disputedTransactions: this.safeToNumber(profile.disputedTransactions, 'disputedTransactions'),
553
- totalVolumeUSDC: profile.totalVolumeUSDC,
554
- registeredAt: this.safeToNumber(profile.registeredAt, 'registeredAt'),
555
- updatedAt: this.safeToNumber(profile.updatedAt, 'updatedAt'),
556
- isActive: Boolean(profile.isActive)
557
- };
558
- }
559
- }