@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,339 +0,0 @@
1
- import { keccak256, toUtf8Bytes, AbiCoder, BytesLike } from 'ethers';
2
- import { DeliveryProof } from '../types';
3
- import { DeliveryProofData, deliveryProofDataFromProof } from '../types/eip712';
4
-
5
- /**
6
- * SECURITY FIX (MEDIUM-2): URL validation configuration for SSRF prevention
7
- */
8
- export interface URLValidationConfig {
9
- /**
10
- * Allowed URL protocols (default: ['https:'])
11
- * Set to ['https:', 'http:'] to allow HTTP in development
12
- */
13
- allowedProtocols?: string[];
14
-
15
- /**
16
- * Allow localhost URLs (default: false in production, true in dev)
17
- */
18
- allowLocalhost?: boolean;
19
-
20
- /**
21
- * Maximum response size in bytes (default: 10MB)
22
- */
23
- maxSize?: number;
24
-
25
- /**
26
- * Request timeout in milliseconds (default: 30000)
27
- */
28
- timeout?: number;
29
-
30
- /**
31
- * Blocked hostnames (e.g., internal services)
32
- */
33
- blockedHosts?: string[];
34
- }
35
-
36
- /**
37
- * Default URL validation config - SECURE by default
38
- */
39
- const DEFAULT_URL_CONFIG: Required<URLValidationConfig> = {
40
- allowedProtocols: ['https:'],
41
- allowLocalhost: false,
42
- maxSize: 10 * 1024 * 1024, // 10MB
43
- timeout: 30000, // 30 seconds
44
- blockedHosts: [
45
- 'metadata.google.internal',
46
- '169.254.169.254', // AWS/GCP metadata
47
- 'metadata.aws.internal',
48
- 'localhost',
49
- '127.0.0.1',
50
- '0.0.0.0',
51
- '[::1]',
52
- ],
53
- };
54
-
55
- /**
56
- * ProofGenerator - Content hashing and delivery proofs
57
- * Reference: Yellow Paper §11.4.1
58
- *
59
- * SECURITY FIX (MEDIUM-2): Now includes URL validation for SSRF prevention
60
- */
61
- export class ProofGenerator {
62
- private readonly urlConfig: Required<URLValidationConfig>;
63
-
64
- /**
65
- * Create ProofGenerator with optional URL validation config
66
- *
67
- * @param urlConfig - URL validation configuration for hashFromUrl()
68
- */
69
- constructor(urlConfig?: URLValidationConfig) {
70
- this.urlConfig = {
71
- ...DEFAULT_URL_CONFIG,
72
- ...urlConfig,
73
- };
74
-
75
- // If localhost is explicitly allowed, remove from blocked hosts
76
- if (urlConfig?.allowLocalhost) {
77
- this.urlConfig.blockedHosts = this.urlConfig.blockedHosts.filter(
78
- (h) => !['localhost', '127.0.0.1', '0.0.0.0', '[::1]'].includes(h)
79
- );
80
- }
81
- }
82
- /**
83
- * Hash deliverable content
84
- * Uses Keccak256 per Yellow Paper §11.4.1
85
- */
86
- hashContent(content: string | Buffer): string {
87
- const buffer = typeof content === 'string' ? toUtf8Bytes(content) : content;
88
-
89
- return keccak256(buffer);
90
- }
91
-
92
- /**
93
- * Generate delivery proof (AIP-4)
94
- * Reference: Yellow Paper §8.2
95
- * Complete schema with type field for AIP compliance
96
- * Computed fields (size, mimeType) cannot be overwritten
97
- */
98
- generateDeliveryProof(params: {
99
- txId: string;
100
- deliverable: string | Buffer;
101
- deliveryUrl?: string;
102
- metadata?: Record<string, any>;
103
- }): DeliveryProof {
104
- const { txId, deliverable, deliveryUrl, metadata = {} } = params;
105
-
106
- const contentHash = this.hashContent(deliverable);
107
- const size =
108
- typeof deliverable === 'string'
109
- ? Buffer.from(deliverable).length
110
- : deliverable.length;
111
-
112
- // Spread user metadata first, then enforce computed fields
113
- // This prevents users from spoofing size/mimeType
114
- const { size: _ignoredSize, mimeType: _ignoredMimeType, ...userMetadata } = metadata;
115
-
116
- return {
117
- type: 'delivery.proof', // Required per AIP-4
118
- txId,
119
- contentHash,
120
- timestamp: Date.now(),
121
- deliveryUrl, // Optional: IPFS/Arweave link
122
- metadata: {
123
- ...userMetadata, // User-supplied fields (excluding reserved)
124
- size, // Enforced: computed from deliverable
125
- mimeType: metadata.mimeType || 'application/octet-stream' // Enforced with fallback
126
- }
127
- };
128
- }
129
-
130
- /**
131
- * Convert a generated delivery proof into typed EIP-712 data
132
- */
133
- toDeliveryProofTypedData(proof: DeliveryProof): DeliveryProofData {
134
- return deliveryProofDataFromProof(proof);
135
- }
136
-
137
- /**
138
- * Encode proof for on-chain submission
139
- */
140
- encodeProof(proof: DeliveryProof): BytesLike {
141
- const abiCoder = AbiCoder.defaultAbiCoder();
142
- return abiCoder.encode(
143
- ['bytes32', 'bytes32', 'uint256'],
144
- [proof.txId, proof.contentHash, proof.timestamp]
145
- );
146
- }
147
-
148
- /**
149
- * Decode proof from on-chain data
150
- */
151
- decodeProof(proofData: BytesLike): {
152
- txId: string;
153
- contentHash: string;
154
- timestamp: number;
155
- } {
156
- const abiCoder = AbiCoder.defaultAbiCoder();
157
- const [txId, contentHash, timestamp] = abiCoder.decode(
158
- ['bytes32', 'bytes32', 'uint256'],
159
- proofData
160
- );
161
-
162
- return {
163
- txId,
164
- contentHash,
165
- timestamp: Number(timestamp)
166
- };
167
- }
168
-
169
- /**
170
- * Verify deliverable matches expected hash
171
- */
172
- verifyDeliverable(deliverable: string | Buffer, expectedHash: string): boolean {
173
- const actualHash = this.hashContent(deliverable);
174
- return actualHash.toLowerCase() === expectedHash.toLowerCase();
175
- }
176
-
177
- /**
178
- * Generate content hash from URL (for IPFS/Arweave)
179
- *
180
- * SECURITY FIX (MEDIUM-2): Now includes:
181
- * - Protocol validation (HTTPS only by default)
182
- * - Hostname blocklist (prevents SSRF to internal services)
183
- * - Size limits (prevents DoS via large responses)
184
- * - Request timeout
185
- *
186
- * @param url - URL to fetch content from
187
- * @returns Keccak256 hash of content
188
- * @throws Error if URL is blocked, too large, or fetch fails
189
- */
190
- async hashFromUrl(url: string): Promise<string> {
191
- // SECURITY FIX (MEDIUM-2): Validate URL before fetching
192
- this.validateUrl(url);
193
-
194
- // In browser/Node.js environment with fetch
195
- try {
196
- // Create AbortController for timeout
197
- const controller = new AbortController();
198
- const timeoutId = setTimeout(() => controller.abort(), this.urlConfig.timeout);
199
-
200
- try {
201
- const response = await fetch(url, {
202
- signal: controller.signal,
203
- // Prevent following redirects to blocked hosts
204
- redirect: 'follow',
205
- });
206
-
207
- clearTimeout(timeoutId);
208
-
209
- if (!response.ok) {
210
- throw new Error(`HTTP error: ${response.status} ${response.statusText}`);
211
- }
212
-
213
- // SECURITY FIX (MEDIUM-2): Check Content-Length header first
214
- const contentLength = response.headers.get('content-length');
215
- if (contentLength) {
216
- const size = parseInt(contentLength, 10);
217
- if (size > this.urlConfig.maxSize) {
218
- throw new Error(
219
- `Content too large: ${size} bytes exceeds maximum of ${this.urlConfig.maxSize} bytes`
220
- );
221
- }
222
- }
223
-
224
- // SECURITY FIX (MEDIUM-2): Read response with size limit
225
- const chunks: Uint8Array[] = [];
226
- let totalSize = 0;
227
- const reader = response.body?.getReader();
228
-
229
- if (!reader) {
230
- throw new Error('Response body is not readable');
231
- }
232
-
233
- // eslint-disable-next-line no-constant-condition
234
- while (true) {
235
- const { done, value } = await reader.read();
236
-
237
- if (done) break;
238
-
239
- totalSize += value.length;
240
-
241
- // Check size limit during streaming
242
- if (totalSize > this.urlConfig.maxSize) {
243
- reader.cancel();
244
- throw new Error(
245
- `Content too large: ${totalSize}+ bytes exceeds maximum of ${this.urlConfig.maxSize} bytes`
246
- );
247
- }
248
-
249
- chunks.push(value);
250
- }
251
-
252
- // Concatenate chunks
253
- const buffer = Buffer.concat(chunks.map(c => Buffer.from(c)));
254
- return this.hashContent(buffer);
255
- } finally {
256
- clearTimeout(timeoutId);
257
- }
258
- } catch (error) {
259
- if (error instanceof Error && error.name === 'AbortError') {
260
- throw new Error(`Request timed out after ${this.urlConfig.timeout}ms for ${url}`);
261
- }
262
- throw new Error(`Failed to fetch content from ${url}: ${error}`);
263
- }
264
- }
265
-
266
- /**
267
- * SECURITY FIX (MEDIUM-2): Validate URL against security rules
268
- *
269
- * @param url - URL to validate
270
- * @throws Error if URL is not allowed
271
- */
272
- private validateUrl(url: string): void {
273
- let parsed: URL;
274
-
275
- try {
276
- parsed = new URL(url);
277
- } catch {
278
- throw new Error(`Invalid URL: ${url}`);
279
- }
280
-
281
- // Check protocol
282
- if (!this.urlConfig.allowedProtocols.includes(parsed.protocol)) {
283
- throw new Error(
284
- `URL protocol "${parsed.protocol}" not allowed. ` +
285
- `Allowed protocols: ${this.urlConfig.allowedProtocols.join(', ')}`
286
- );
287
- }
288
-
289
- // Check blocked hosts
290
- const hostname = parsed.hostname.toLowerCase();
291
- if (this.urlConfig.blockedHosts.includes(hostname)) {
292
- throw new Error(
293
- `URL hostname "${hostname}" is blocked for security reasons. ` +
294
- `This prevents SSRF attacks to internal services.`
295
- );
296
- }
297
-
298
- // Check for private IP ranges (additional SSRF protection)
299
- if (this.isPrivateIP(hostname)) {
300
- throw new Error(
301
- `URL hostname "${hostname}" resolves to a private IP address. ` +
302
- `This is blocked for security reasons (SSRF prevention).`
303
- );
304
- }
305
- }
306
-
307
- /**
308
- * Check if hostname is a private IP address
309
- *
310
- * @param hostname - Hostname to check
311
- * @returns true if hostname is a private IP
312
- */
313
- private isPrivateIP(hostname: string): boolean {
314
- // IPv4 private ranges
315
- const ipv4PrivateRanges = [
316
- /^10\./, // 10.0.0.0 - 10.255.255.255
317
- /^172\.(1[6-9]|2[0-9]|3[0-1])\./, // 172.16.0.0 - 172.31.255.255
318
- /^192\.168\./, // 192.168.0.0 - 192.168.255.255
319
- /^127\./, // 127.0.0.0 - 127.255.255.255 (loopback)
320
- /^169\.254\./, // 169.254.0.0 - 169.254.255.255 (link-local)
321
- /^0\./, // 0.0.0.0/8
322
- ];
323
-
324
- for (const range of ipv4PrivateRanges) {
325
- if (range.test(hostname)) {
326
- return true;
327
- }
328
- }
329
-
330
- return false;
331
- }
332
-
333
- /**
334
- * Get the URL validation config (for testing/inspection)
335
- */
336
- getUrlConfig(): Required<URLValidationConfig> {
337
- return { ...this.urlConfig };
338
- }
339
- }
@@ -1,15 +0,0 @@
1
- /**
2
- * QuoteBuilder - AIP-2 Price Quote Construction
3
- *
4
- * This module re-exports the full QuoteBuilder implementation from builders/
5
- * Reference: AIP-2 §6.1
6
- *
7
- * @deprecated Import from builders/QuoteBuilder directly
8
- */
9
-
10
- export {
11
- QuoteBuilder,
12
- QuoteMessage,
13
- QuoteParams,
14
- AIP2QuoteTypes
15
- } from '../builders/QuoteBuilder';
@@ -1,202 +0,0 @@
1
- /**
2
- * AgentRegistryClient - Thin wrapper for AgentRegistry v2 config operations
3
- *
4
- * Provides methods for:
5
- * - Publishing AGIRAILS.md config (CID + hash) on-chain
6
- * - Managing launchpad listing visibility
7
- * - Reading config state for any agent
8
- *
9
- * @module registry/AgentRegistryClient
10
- */
11
-
12
- import { Contract, Signer, Provider } from 'ethers';
13
- import AgentRegistryABI from '../abi/AgentRegistry.json';
14
- import { ValidationError, TransactionRevertedError } from '../errors';
15
-
16
- // ============================================================================
17
- // Types
18
- // ============================================================================
19
-
20
- export interface AgentConfigState {
21
- configHash: string;
22
- configCID: string;
23
- listed: boolean;
24
- isActive: boolean;
25
- updatedAt: number;
26
- }
27
-
28
- export interface PublishConfigResult {
29
- txHash: string;
30
- }
31
-
32
- interface GasOptions {
33
- maxFeePerGas?: bigint;
34
- maxPriorityFeePerGas?: bigint;
35
- }
36
-
37
- // ============================================================================
38
- // Client
39
- // ============================================================================
40
-
41
- export class AgentRegistryClient {
42
- private contract: Contract;
43
- private readonlyContract: Contract;
44
-
45
- constructor(
46
- private readonly registryAddress: string,
47
- private readonly signer: Signer,
48
- private readonly gasSettings?: GasOptions
49
- ) {
50
- this.contract = new Contract(registryAddress, AgentRegistryABI, signer);
51
- this.readonlyContract = this.contract;
52
- }
53
-
54
- /**
55
- * Create a read-only client (no signer required)
56
- */
57
- static readOnly(registryAddress: string, provider: Provider): AgentRegistryClient {
58
- // Create a minimal signer-like object for the contract
59
- // but only the readonly contract will be used
60
- const contract = new Contract(registryAddress, AgentRegistryABI, provider);
61
- const client = Object.create(AgentRegistryClient.prototype);
62
- client.registryAddress = registryAddress;
63
- client.readonlyContract = contract;
64
- client.contract = null; // Write operations will throw
65
- return client;
66
- }
67
-
68
- // ========== WRITE OPERATIONS ==========
69
-
70
- /**
71
- * Publish config (AGIRAILS.md) on-chain
72
- *
73
- * @param cid - IPFS CID pointing to the AGIRAILS.md file
74
- * @param hash - keccak256 of canonical AGIRAILS.md content (bytes32)
75
- * @returns Transaction hash
76
- */
77
- async publishConfig(cid: string, hash: string): Promise<PublishConfigResult> {
78
- if (!this.contract) {
79
- throw new Error('Write operations require a signer. Use AgentRegistryClient constructor, not readOnly().');
80
- }
81
-
82
- if (!cid || cid.length === 0) {
83
- throw new ValidationError('cid', 'IPFS CID is required');
84
- }
85
- if (cid.length > 128) {
86
- throw new ValidationError('cid', 'CID too long (max 128 characters)');
87
- }
88
- if (!hash || hash === '0x' + '0'.repeat(64)) {
89
- throw new ValidationError('hash', 'Config hash is required (cannot be zero)');
90
- }
91
- if (!/^0x[a-fA-F0-9]{64}$/.test(hash)) {
92
- throw new ValidationError('hash', 'Config hash must be a valid bytes32 hex string');
93
- }
94
-
95
- try {
96
- const estimatedGas = await this.contract.publishConfig.estimateGas(cid, hash);
97
- const gasLimit = (estimatedGas * 120n) / 100n; // 20% buffer
98
-
99
- const txOptions: Record<string, unknown> = { gasLimit };
100
- if (this.gasSettings?.maxFeePerGas) {
101
- txOptions.maxFeePerGas = this.gasSettings.maxFeePerGas;
102
- }
103
- if (this.gasSettings?.maxPriorityFeePerGas) {
104
- txOptions.maxPriorityFeePerGas = this.gasSettings.maxPriorityFeePerGas;
105
- }
106
-
107
- const tx = await this.contract.publishConfig(cid, hash, txOptions);
108
- const receipt = await tx.wait();
109
-
110
- return { txHash: receipt.hash };
111
- } catch (error: unknown) {
112
- if (error instanceof Error && error.message.includes('Not registered')) {
113
- throw new TransactionRevertedError(
114
- 'Agent not registered. Register first using the AgentRegistry before publishing config.',
115
- 'publishConfig'
116
- );
117
- }
118
- throw error;
119
- }
120
- }
121
-
122
- /**
123
- * Set launchpad listing visibility
124
- *
125
- * @param listed - Whether agent should be visible on launchpad
126
- * @returns Transaction hash
127
- */
128
- async setListed(listed: boolean): Promise<string> {
129
- if (!this.contract) {
130
- throw new Error('Write operations require a signer. Use AgentRegistryClient constructor, not readOnly().');
131
- }
132
-
133
- try {
134
- const estimatedGas = await this.contract.setListed.estimateGas(listed);
135
- const gasLimit = (estimatedGas * 115n) / 100n; // 15% buffer
136
-
137
- const txOptions: Record<string, unknown> = { gasLimit };
138
- if (this.gasSettings?.maxFeePerGas) {
139
- txOptions.maxFeePerGas = this.gasSettings.maxFeePerGas;
140
- }
141
- if (this.gasSettings?.maxPriorityFeePerGas) {
142
- txOptions.maxPriorityFeePerGas = this.gasSettings.maxPriorityFeePerGas;
143
- }
144
-
145
- const tx = await this.contract.setListed(listed, txOptions);
146
- const receipt = await tx.wait();
147
-
148
- return receipt.hash;
149
- } catch (error: unknown) {
150
- if (error instanceof Error && error.message.includes('Not registered')) {
151
- throw new TransactionRevertedError(
152
- 'Agent not registered. Register first before setting listing status.',
153
- 'setListed'
154
- );
155
- }
156
- throw error;
157
- }
158
- }
159
-
160
- // ========== READ OPERATIONS ==========
161
-
162
- /**
163
- * Get config state for an agent
164
- *
165
- * @param agentAddress - Agent's Ethereum address
166
- * @returns Config state (hash, CID, listed, isActive, updatedAt)
167
- */
168
- async getConfig(agentAddress: string): Promise<AgentConfigState> {
169
- const contract = this.readonlyContract || this.contract;
170
- const profile = await contract.getAgent(agentAddress);
171
-
172
- return {
173
- configHash: profile.configHash,
174
- configCID: profile.configCID,
175
- listed: profile.listed,
176
- isActive: profile.isActive,
177
- updatedAt: Number(profile.updatedAt),
178
- };
179
- }
180
-
181
- /**
182
- * Check if an agent is listed on the launchpad
183
- *
184
- * @param agentAddress - Agent's Ethereum address
185
- * @returns true if agent is listed
186
- */
187
- async isListed(agentAddress: string): Promise<boolean> {
188
- const config = await this.getConfig(agentAddress);
189
- return config.listed;
190
- }
191
-
192
- /**
193
- * Get the on-chain config hash for an agent
194
- *
195
- * @param agentAddress - Agent's Ethereum address
196
- * @returns Config hash (bytes32) or zero hash if not published
197
- */
198
- async getConfigHash(agentAddress: string): Promise<string> {
199
- const config = await this.getConfig(agentAddress);
200
- return config.configHash;
201
- }
202
- }