@agirails/sdk 2.5.3 → 2.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ACTPClient.d.ts +18 -0
- package/dist/ACTPClient.d.ts.map +1 -1
- package/dist/ACTPClient.js +67 -22
- package/dist/ACTPClient.js.map +1 -1
- package/dist/adapters/BasicAdapter.d.ts +12 -0
- package/dist/adapters/BasicAdapter.d.ts.map +1 -1
- package/dist/adapters/BasicAdapter.js +30 -4
- package/dist/adapters/BasicAdapter.js.map +1 -1
- package/dist/adapters/StandardAdapter.d.ts +20 -3
- package/dist/adapters/StandardAdapter.d.ts.map +1 -1
- package/dist/adapters/StandardAdapter.js +45 -11
- package/dist/adapters/StandardAdapter.js.map +1 -1
- package/dist/cli/commands/publish.js +16 -4
- package/dist/cli/commands/publish.js.map +1 -1
- package/dist/cli/commands/register.js +16 -4
- package/dist/cli/commands/register.js.map +1 -1
- package/dist/cli/commands/tx.js +31 -3
- package/dist/cli/commands/tx.js.map +1 -1
- package/dist/config/networks.d.ts +2 -2
- package/dist/config/networks.d.ts.map +1 -1
- package/dist/config/networks.js +27 -22
- package/dist/config/networks.js.map +1 -1
- package/dist/level0/request.d.ts.map +1 -1
- package/dist/level0/request.js +2 -1
- package/dist/level0/request.js.map +1 -1
- package/dist/runtime/BlockchainRuntime.d.ts.map +1 -1
- package/dist/runtime/BlockchainRuntime.js +11 -5
- package/dist/runtime/BlockchainRuntime.js.map +1 -1
- package/dist/utils/IPFSClient.d.ts +3 -1
- package/dist/utils/IPFSClient.d.ts.map +1 -1
- package/dist/utils/IPFSClient.js +27 -7
- package/dist/utils/IPFSClient.js.map +1 -1
- package/dist/wallet/AutoWalletProvider.d.ts.map +1 -1
- package/dist/wallet/AutoWalletProvider.js +52 -18
- package/dist/wallet/AutoWalletProvider.js.map +1 -1
- package/dist/wallet/SmartWalletRouter.d.ts +116 -0
- package/dist/wallet/SmartWalletRouter.d.ts.map +1 -0
- package/dist/wallet/SmartWalletRouter.js +212 -0
- package/dist/wallet/SmartWalletRouter.js.map +1 -0
- package/dist/wallet/aa/DualNonceManager.d.ts +19 -0
- package/dist/wallet/aa/DualNonceManager.d.ts.map +1 -1
- package/dist/wallet/aa/DualNonceManager.js +100 -5
- package/dist/wallet/aa/DualNonceManager.js.map +1 -1
- package/package.json +3 -6
- package/src/ACTPClient.ts +0 -1579
- package/src/abi/ACTPKernel.json +0 -1356
- package/src/abi/AgentRegistry.json +0 -915
- package/src/abi/ERC20.json +0 -40
- package/src/abi/EscrowVault.json +0 -134
- package/src/abi/IdentityRegistry.json +0 -316
- package/src/adapters/AdapterRegistry.ts +0 -173
- package/src/adapters/AdapterRouter.ts +0 -416
- package/src/adapters/BaseAdapter.ts +0 -498
- package/src/adapters/BasicAdapter.ts +0 -514
- package/src/adapters/IAdapter.ts +0 -292
- package/src/adapters/StandardAdapter.ts +0 -555
- package/src/adapters/X402Adapter.ts +0 -731
- package/src/adapters/index.ts +0 -60
- package/src/builders/DeliveryProofBuilder.ts +0 -327
- package/src/builders/QuoteBuilder.ts +0 -483
- package/src/builders/index.ts +0 -17
- package/src/cli/commands/balance.ts +0 -110
- package/src/cli/commands/batch.ts +0 -487
- package/src/cli/commands/config.ts +0 -231
- package/src/cli/commands/deploy-check.ts +0 -364
- package/src/cli/commands/deploy-env.ts +0 -120
- package/src/cli/commands/diff.ts +0 -141
- package/src/cli/commands/init.ts +0 -469
- package/src/cli/commands/mint.ts +0 -116
- package/src/cli/commands/pay.ts +0 -113
- package/src/cli/commands/publish.ts +0 -475
- package/src/cli/commands/pull.ts +0 -124
- package/src/cli/commands/register.ts +0 -247
- package/src/cli/commands/simulate.ts +0 -345
- package/src/cli/commands/time.ts +0 -302
- package/src/cli/commands/tx.ts +0 -448
- package/src/cli/commands/watch.ts +0 -211
- package/src/cli/index.ts +0 -134
- package/src/cli/utils/client.ts +0 -252
- package/src/cli/utils/config.ts +0 -389
- package/src/cli/utils/output.ts +0 -465
- package/src/cli/utils/wallet.ts +0 -109
- package/src/config/agirailsmd.ts +0 -262
- package/src/config/networks.ts +0 -275
- package/src/config/pendingPublish.ts +0 -237
- package/src/config/publishPipeline.ts +0 -359
- package/src/config/syncOperations.ts +0 -279
- package/src/erc8004/ERC8004Bridge.ts +0 -462
- package/src/erc8004/ReputationReporter.ts +0 -468
- package/src/erc8004/index.ts +0 -61
- package/src/errors/index.ts +0 -427
- package/src/index.ts +0 -364
- package/src/level0/Provider.ts +0 -117
- package/src/level0/ServiceDirectory.ts +0 -131
- package/src/level0/index.ts +0 -10
- package/src/level0/provide.ts +0 -132
- package/src/level0/request.ts +0 -432
- package/src/level1/Agent.ts +0 -1426
- package/src/level1/index.ts +0 -10
- package/src/level1/pricing/PriceCalculator.ts +0 -255
- package/src/level1/pricing/PricingStrategy.ts +0 -198
- package/src/level1/types/Job.ts +0 -179
- package/src/level1/types/Options.ts +0 -291
- package/src/level1/types/index.ts +0 -8
- package/src/protocol/ACTPKernel.ts +0 -808
- package/src/protocol/AgentRegistry.ts +0 -559
- package/src/protocol/DIDManager.ts +0 -629
- package/src/protocol/DIDResolver.ts +0 -554
- package/src/protocol/EASHelper.ts +0 -378
- package/src/protocol/EscrowVault.ts +0 -255
- package/src/protocol/EventMonitor.ts +0 -204
- package/src/protocol/MessageSigner.ts +0 -510
- package/src/protocol/ProofGenerator.ts +0 -339
- package/src/protocol/QuoteBuilder.ts +0 -15
- package/src/registry/AgentRegistryClient.ts +0 -202
- package/src/runtime/BlockchainRuntime.ts +0 -1015
- package/src/runtime/IACTPRuntime.ts +0 -306
- package/src/runtime/MockRuntime.ts +0 -1298
- package/src/runtime/MockStateManager.ts +0 -577
- package/src/runtime/index.ts +0 -25
- package/src/runtime/types/MockState.ts +0 -237
- package/src/storage/ArchiveBundleBuilder.ts +0 -561
- package/src/storage/ArweaveClient.ts +0 -946
- package/src/storage/FilebaseClient.ts +0 -790
- package/src/storage/index.ts +0 -96
- package/src/storage/types.ts +0 -348
- package/src/types/adapter.ts +0 -310
- package/src/types/agent.ts +0 -79
- package/src/types/did.ts +0 -223
- package/src/types/eip712.ts +0 -175
- package/src/types/erc8004.ts +0 -293
- package/src/types/escrow.ts +0 -27
- package/src/types/index.ts +0 -17
- package/src/types/message.ts +0 -145
- package/src/types/state.ts +0 -87
- package/src/types/transaction.ts +0 -69
- package/src/types/x402.ts +0 -251
- package/src/utils/ErrorRecoveryGuide.ts +0 -676
- package/src/utils/Helpers.ts +0 -688
- package/src/utils/IPFSClient.ts +0 -368
- package/src/utils/Logger.ts +0 -484
- package/src/utils/NonceManager.ts +0 -591
- package/src/utils/RateLimiter.ts +0 -534
- package/src/utils/ReceivedNonceTracker.ts +0 -567
- package/src/utils/SDKLifecycle.ts +0 -416
- package/src/utils/SecureNonce.ts +0 -78
- package/src/utils/Semaphore.ts +0 -276
- package/src/utils/UsedAttestationTracker.ts +0 -385
- package/src/utils/canonicalJson.ts +0 -38
- package/src/utils/circuitBreaker.ts +0 -324
- package/src/utils/computeTypeHash.ts +0 -48
- package/src/utils/fsSafe.ts +0 -80
- package/src/utils/index.ts +0 -80
- package/src/utils/retry.ts +0 -364
- package/src/utils/security.ts +0 -418
- package/src/utils/validation.ts +0 -540
- package/src/wallet/AutoWalletProvider.ts +0 -299
- package/src/wallet/EOAWalletProvider.ts +0 -69
- package/src/wallet/IWalletProvider.ts +0 -135
- package/src/wallet/aa/BundlerClient.ts +0 -274
- package/src/wallet/aa/DualNonceManager.ts +0 -173
- package/src/wallet/aa/PaymasterClient.ts +0 -174
- package/src/wallet/aa/TransactionBatcher.ts +0 -353
- package/src/wallet/aa/UserOpBuilder.ts +0 -246
- package/src/wallet/aa/constants.ts +0 -60
- 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
|
-
}
|