hardhat-external-artifacts 0.0.5 → 0.0.6

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.
@@ -1,5 +1,5 @@
1
1
  import type {ExternalArtifact, RichArtifact, LinkReferences} from './types.js';
2
- import {isRichArtifact} from './types.js';
2
+ import {hasSolcInput, hasMetadata, hasEvmData} from './types.js';
3
3
 
4
4
  export interface SyntheticCompilation {
5
5
  solcVersion: string;
@@ -15,6 +15,8 @@ interface CompilerInput {
15
15
  outputSelection: Record<string, Record<string, string[]>>;
16
16
  remappings?: string[];
17
17
  metadata?: {useLiteralContent?: boolean; bytecodeHash?: string};
18
+ evmVersion?: string;
19
+ viaIR?: boolean;
18
20
  };
19
21
  }
20
22
 
@@ -50,6 +52,17 @@ interface BytecodeOutput {
50
52
  functionDebugData?: Record<string, any>;
51
53
  }
52
54
 
55
+ /**
56
+ * Extracted compilation context from an artifact.
57
+ * Used to group artifacts that share the same compilation settings.
58
+ */
59
+ interface CompilationContext {
60
+ solcVersion: string;
61
+ compilerInput: CompilerInput | null;
62
+ /** Key for grouping artifacts with same compilation context */
63
+ groupKey: string;
64
+ }
65
+
53
66
  /**
54
67
  * Creates a minimal valid AST for a source file.
55
68
  * This is needed because Hardhat's contract decoder expects a valid AST structure.
@@ -92,203 +105,222 @@ function createMinimalAst(
92
105
  }
93
106
 
94
107
  /**
95
- * Convert artifacts to compilation format.
96
- * If artifacts are "rich" (have solcInput), use the embedded data.
97
- * Otherwise, synthesize a minimal compilation.
108
+ * Extract compilation context from an artifact.
109
+ * Tries solcInput first, then falls back to metadata, then defaults.
98
110
  */
99
- export function artifactsToCompilations(
100
- artifacts: ExternalArtifact[],
111
+ function extractCompilationContext(
112
+ artifact: ExternalArtifact,
101
113
  defaultSolcVersion: string,
102
114
  debug: boolean = false,
103
- ): SyntheticCompilation[] {
104
- // Group artifacts by whether they have solcInput
105
- const richArtifacts = artifacts.filter(isRichArtifact);
106
- const simpleArtifacts = artifacts.filter((a) => !isRichArtifact(a));
107
-
108
- if (debug) {
109
- console.log(`[external-artifacts] Processing ${artifacts.length} artifacts:`);
110
- console.log(` - Rich artifacts (with solcInput): ${richArtifacts.length}`);
111
- console.log(` - Simple artifacts: ${simpleArtifacts.length}`);
112
- for (const artifact of artifacts) {
113
- const isRich = isRichArtifact(artifact);
114
- const richArt = artifact as Partial<RichArtifact>;
115
- const immRefs = richArt.evm?.deployedBytecode?.immutableReferences ?? artifact.immutableReferences;
116
- const immCount = immRefs ? Object.keys(immRefs).length : 0;
117
- console.log(` - ${artifact.contractName}: ${isRich ? 'rich' : 'simple'}, immutableReferences: ${immCount} keys`);
115
+ ): CompilationContext {
116
+ // Try to extract from solcInput first (most complete)
117
+ if (hasSolcInput(artifact)) {
118
+ try {
119
+ const compilerInput: CompilerInput = JSON.parse(artifact.solcInput);
120
+ const solcVersion = extractVersionFromMetadata(artifact.metadata) ?? defaultSolcVersion;
121
+ // Use a hash of settings to group artifacts with same compilation context
122
+ const settingsKey = JSON.stringify(compilerInput.settings);
123
+ return {
124
+ solcVersion,
125
+ compilerInput,
126
+ groupKey: `solcInput:${solcVersion}:${hashString(settingsKey)}`,
127
+ };
128
+ } catch (e) {
129
+ if (debug) {
130
+ console.log(`[external-artifacts] Failed to parse solcInput for ${artifact.contractName}: ${e}`);
131
+ }
132
+ // Fall through to metadata extraction
118
133
  }
119
134
  }
120
135
 
121
- const compilations: SyntheticCompilation[] = [];
122
-
123
- // Process rich artifacts - these have embedded solcInput
124
- for (const artifact of richArtifacts) {
125
- const compilation = richArtifactToCompilation(artifact, debug);
126
- if (compilation) {
127
- compilations.push(compilation);
136
+ // Try to extract from metadata (partial but useful)
137
+ if (hasMetadata(artifact)) {
138
+ try {
139
+ const metadata = JSON.parse(artifact.metadata);
140
+ const solcVersion = extractVersionFromMetadataObject(metadata) ?? defaultSolcVersion;
141
+ const compilerInput = metadataToCompilerInput(metadata);
142
+ if (compilerInput) {
143
+ const settingsKey = JSON.stringify(compilerInput.settings);
144
+ return {
145
+ solcVersion,
146
+ compilerInput,
147
+ groupKey: `metadata:${solcVersion}:${hashString(settingsKey)}`,
148
+ };
149
+ }
150
+ } catch (e) {
151
+ if (debug) {
152
+ console.log(`[external-artifacts] Failed to parse metadata for ${artifact.contractName}: ${e}`);
153
+ }
154
+ // Fall through to defaults
128
155
  }
129
156
  }
130
157
 
131
- // Process simple artifacts - synthesize compilation
132
- if (simpleArtifacts.length > 0) {
133
- compilations.push(
134
- synthesizeCompilation(simpleArtifacts, defaultSolcVersion, debug),
135
- );
136
- }
137
-
138
- return compilations;
158
+ // Default: no compiler input available, use defaults
159
+ return {
160
+ solcVersion: defaultSolcVersion,
161
+ compilerInput: null,
162
+ groupKey: `default:${defaultSolcVersion}`,
163
+ };
139
164
  }
140
165
 
141
166
  /**
142
- * Convert a rich artifact (with embedded solcInput) to a compilation.
143
- * Uses the embedded solcInput directly for maximum fidelity.
167
+ * Extract solc version from metadata string.
144
168
  */
145
- function richArtifactToCompilation(
146
- artifact: RichArtifact,
147
- debug: boolean = false,
148
- ): SyntheticCompilation | null {
149
- if (!artifact.solcInput) {
169
+ function extractVersionFromMetadata(metadataStr?: string): string | null {
170
+ if (!metadataStr) return null;
171
+ try {
172
+ const metadata = JSON.parse(metadataStr);
173
+ return extractVersionFromMetadataObject(metadata);
174
+ } catch {
150
175
  return null;
151
176
  }
177
+ }
152
178
 
153
- // Parse the embedded solcInput
154
- const compilerInput: CompilerInput = JSON.parse(artifact.solcInput);
179
+ /**
180
+ * Extract solc version from parsed metadata object.
181
+ */
182
+ function extractVersionFromMetadataObject(metadata: any): string | null {
183
+ if (metadata?.compiler?.version) {
184
+ // Format: "0.8.10+commit.fc410830" -> extract "0.8.10"
185
+ return metadata.compiler.version.split('+')[0];
186
+ }
187
+ return null;
188
+ }
155
189
 
156
- // Extract solc version from metadata
157
- let solcVersion = '0.8.20'; // Default
158
- if (artifact.metadata) {
159
- try {
160
- const metadata = JSON.parse(artifact.metadata);
161
- if (metadata.compiler?.version) {
162
- // Format: "0.8.10+commit.fc410830" -> extract "0.8.10"
163
- solcVersion = metadata.compiler.version.split('+')[0];
164
- }
165
- } catch {
166
- // Ignore parsing errors, use default
190
+ /**
191
+ * Convert metadata to compiler input.
192
+ * Metadata contains settings but not full source content.
193
+ */
194
+ function metadataToCompilerInput(metadata: any): CompilerInput | null {
195
+ if (!metadata?.settings) return null;
196
+
197
+ const settings = metadata.settings;
198
+ const sources: Record<string, {content: string}> = {};
199
+
200
+ // Metadata has source hashes but not content
201
+ // We'll add empty placeholders that get filled in later
202
+ if (metadata.sources) {
203
+ for (const sourceName of Object.keys(metadata.sources)) {
204
+ // Some metadata includes content in keccak256 only
205
+ // We use empty content as placeholder
206
+ sources[sourceName] = {content: ''};
167
207
  }
168
208
  }
169
209
 
170
- // Build compiler output from the artifact
171
- // Only include sources that we have contract data for
172
- // Including empty sources/contracts can cause EDR selector fixup issues
173
- const compilerOutput: CompilerOutput = {
174
- sources: {},
175
- contracts: {},
210
+ return {
211
+ language: metadata.language ?? 'Solidity',
212
+ sources,
213
+ settings: {
214
+ optimizer: settings.optimizer ?? {enabled: false},
215
+ outputSelection: settings.outputSelection ?? {
216
+ '*': {'*': ['abi', 'evm.bytecode', 'evm.deployedBytecode']},
217
+ },
218
+ remappings: settings.remappings,
219
+ metadata: settings.metadata,
220
+ evmVersion: settings.evmVersion,
221
+ viaIR: settings.viaIR,
222
+ },
176
223
  };
224
+ }
177
225
 
178
- const sourceName = artifact.sourceName;
226
+ /**
227
+ * Simple string hash for grouping.
228
+ */
229
+ function hashString(str: string): string {
230
+ let hash = 0;
231
+ for (let i = 0; i < str.length; i++) {
232
+ const char = str.charCodeAt(i);
233
+ hash = ((hash << 5) - hash) + char;
234
+ hash = hash & hash; // Convert to 32-bit integer
235
+ }
236
+ return hash.toString(16);
237
+ }
179
238
 
180
- // Track source IDs for all input sources (needed for consistent source indexing)
181
- let sourceId = 0;
182
- const sourceIds: Record<string, number> = {};
183
- for (const srcName of Object.keys(compilerInput.sources)) {
184
- sourceIds[srcName] = sourceId++;
239
+ /**
240
+ * Convert artifacts to compilation format.
241
+ * Flexibly extracts data from each artifact - uses solcInput if available,
242
+ * falls back to metadata for settings, or synthesizes minimal compilation.
243
+ */
244
+ export function artifactsToCompilations(
245
+ artifacts: ExternalArtifact[],
246
+ defaultSolcVersion: string,
247
+ debug: boolean = false,
248
+ ): SyntheticCompilation[] {
249
+ if (debug) {
250
+ console.log(`[external-artifacts] Processing ${artifacts.length} artifacts`);
185
251
  }
186
252
 
187
- // Only include the source that contains our contract
188
- const contractSourceId = sourceIds[sourceName] ?? sourceId++;
189
- const contractNodeId = contractSourceId + 1000; // Use an offset to avoid ID conflicts
253
+ // Extract context from each artifact and group by compilation context
254
+ const artifactsByContext: Map<string, {
255
+ context: CompilationContext;
256
+ artifacts: ExternalArtifact[];
257
+ }> = new Map();
190
258
 
191
- compilerOutput.sources[sourceName] = {
192
- id: contractSourceId,
193
- ast: createMinimalAst(sourceName, contractSourceId, [
194
- {name: artifact.contractName, nodeId: contractNodeId},
195
- ]),
196
- };
197
- compilerOutput.contracts[sourceName] = {};
259
+ for (const artifact of artifacts) {
260
+ const context = extractCompilationContext(artifact, defaultSolcVersion, debug);
261
+ const richArt = artifact as Partial<RichArtifact>;
262
+ const immRefs = richArt.evm?.deployedBytecode?.immutableReferences ?? artifact.immutableReferences;
263
+ const immCount = immRefs ? Object.keys(immRefs).length : 0;
198
264
 
199
- // Ensure the source is in compilerInput as well
200
- if (!compilerInput.sources[sourceName]) {
201
- compilerInput.sources[sourceName] = {content: ''};
202
- }
265
+ if (debug) {
266
+ console.log(` - ${artifact.contractName}: solcInput=${hasSolcInput(artifact)}, metadata=${hasMetadata(artifact)}, immutableReferences=${immCount} keys, group=${context.groupKey}`);
267
+ }
203
268
 
204
- // Build bytecode output, ensuring proper format
205
- // Standard solc output has bytecode.object without 0x prefix
206
- const bytecode: BytecodeOutput = {
207
- object: stripHexPrefix(
208
- artifact.evm?.bytecode?.object ?? artifact.bytecode ?? '0x',
209
- ),
210
- opcodes: artifact.evm?.bytecode?.opcodes ?? '',
211
- sourceMap: artifact.evm?.bytecode?.sourceMap ?? '',
212
- linkReferences:
213
- artifact.evm?.bytecode?.linkReferences ?? artifact.linkReferences ?? {},
214
- generatedSources: artifact.evm?.bytecode?.generatedSources,
215
- functionDebugData: artifact.evm?.bytecode?.functionDebugData,
216
- };
269
+ const existing = artifactsByContext.get(context.groupKey);
270
+ if (existing) {
271
+ existing.artifacts.push(artifact);
272
+ } else {
273
+ artifactsByContext.set(context.groupKey, {
274
+ context,
275
+ artifacts: [artifact],
276
+ });
277
+ }
278
+ }
217
279
 
218
- const deployedBytecode: BytecodeOutput = {
219
- object: stripHexPrefix(
220
- artifact.evm?.deployedBytecode?.object ??
221
- artifact.deployedBytecode ??
222
- '0x',
223
- ),
224
- opcodes: artifact.evm?.deployedBytecode?.opcodes ?? '',
225
- sourceMap: artifact.evm?.deployedBytecode?.sourceMap ?? '',
226
- linkReferences:
227
- artifact.evm?.deployedBytecode?.linkReferences ??
228
- artifact.deployedLinkReferences ??
229
- {},
230
- immutableReferences:
231
- artifact.evm?.deployedBytecode?.immutableReferences ??
232
- artifact.immutableReferences ??
233
- {},
234
- generatedSources: artifact.evm?.deployedBytecode?.generatedSources,
235
- functionDebugData: artifact.evm?.deployedBytecode?.functionDebugData,
236
- };
280
+ if (debug) {
281
+ console.log(`[external-artifacts] Grouped into ${artifactsByContext.size} compilations`);
282
+ }
237
283
 
238
- // IMPORTANT: Do NOT provide method identifiers - let EDR compute them
239
- // EDR has internal "selector fixup" logic for function overloading that can fail
240
- // if we provide method identifiers that it then tries to reconcile with AST info.
241
- // The error "Failed to fix up the selector for ... #supportsInterface" happens
242
- // when EDR can't match provided selectors with overloaded functions.
243
- // By providing an empty object, EDR will compute selectors from the ABI directly.
244
- const methodIdentifiers: Record<string, string> = {};
245
-
246
- compilerOutput.contracts[sourceName][artifact.contractName] = {
247
- abi: artifact.abi,
248
- evm: {
249
- bytecode,
250
- deployedBytecode,
251
- methodIdentifiers,
252
- },
253
- metadata: artifact.metadata,
254
- devdoc: artifact.devdoc,
255
- userdoc: artifact.userdoc,
256
- storageLayout: artifact.storageLayout,
257
- };
284
+ // Convert each group to a compilation
285
+ const compilations: SyntheticCompilation[] = [];
258
286
 
259
- if (debug) {
260
- const immRefKeys = Object.keys(deployedBytecode.immutableReferences ?? {});
261
- console.log(`[external-artifacts] Rich artifact: ${artifact.contractName}`);
262
- console.log(` - sourceName: ${sourceName}`);
263
- console.log(` - solcVersion: ${solcVersion}`);
264
- console.log(` - immutableReferences keys: ${immRefKeys.length}`);
265
- if (immRefKeys.length > 0) {
266
- console.log(` - immutableReferences sample:`, JSON.stringify(deployedBytecode.immutableReferences, null, 2).slice(0, 500));
267
- }
268
- console.log(` - deployedBytecode length: ${deployedBytecode.object.length / 2} bytes`);
287
+ for (const {context, artifacts: groupArtifacts} of artifactsByContext.values()) {
288
+ const compilation = buildCompilation(groupArtifacts, context, debug);
289
+ compilations.push(compilation);
269
290
  }
270
291
 
271
- return {
272
- solcVersion,
273
- compilerInput,
274
- compilerOutput,
275
- };
292
+ return compilations;
276
293
  }
277
294
 
278
295
  /**
279
- * Synthesize a minimal compilation from simple artifacts.
280
- * Used when artifacts don't have embedded solcInput.
296
+ * Build a compilation from a group of artifacts sharing the same context.
297
+ * Flexibly extracts available data from each artifact.
281
298
  */
282
- function synthesizeCompilation(
299
+ function buildCompilation(
283
300
  artifacts: ExternalArtifact[],
284
- solcVersion: string,
301
+ context: CompilationContext,
285
302
  debug: boolean = false,
286
303
  ): SyntheticCompilation {
287
- const sources: CompilerInput['sources'] = {};
288
- const outputSources: CompilerOutput['sources'] = {};
289
- const contracts: CompilerOutput['contracts'] = {};
304
+ // Start with context's compiler input or create a minimal one
305
+ const compilerInput: CompilerInput = context.compilerInput
306
+ ? {...context.compilerInput, sources: {...context.compilerInput.sources}}
307
+ : {
308
+ language: 'Solidity',
309
+ sources: {},
310
+ settings: {
311
+ optimizer: {enabled: false},
312
+ outputSelection: {
313
+ '*': {'*': ['abi', 'evm.bytecode', 'evm.deployedBytecode']},
314
+ },
315
+ },
316
+ };
317
+
318
+ const compilerOutput: CompilerOutput = {
319
+ sources: {},
320
+ contracts: {},
321
+ };
290
322
 
291
- // First, group artifacts by source
323
+ // Group artifacts by source for AST generation
292
324
  const contractsBySource: Record<
293
325
  string,
294
326
  Array<{name: string; artifact: ExternalArtifact}>
@@ -303,92 +335,115 @@ function synthesizeCompilation(
303
335
  });
304
336
  }
305
337
 
306
- // Track IDs for AST nodes
307
- let nextId = 0;
338
+ // Track source IDs - use existing ones from compiler input if available
339
+ let nextSourceId = 0;
340
+ const sourceIds: Record<string, number> = {};
341
+ for (const srcName of Object.keys(compilerInput.sources)) {
342
+ sourceIds[srcName] = nextSourceId++;
343
+ }
308
344
 
309
- // Create sources with contract definitions in AST
310
- for (const [sourceName, sourceContracts] of Object.entries(
311
- contractsBySource,
312
- )) {
313
- const sourceId = nextId++;
314
- sources[sourceName] = {content: ''};
315
- contracts[sourceName] = {};
345
+ // Track node IDs for AST
346
+ let nextNodeId = nextSourceId + 1000; // Offset to avoid conflicts
347
+
348
+ // Process each source
349
+ for (const [sourceName, sourceContracts] of Object.entries(contractsBySource)) {
350
+ // Ensure source exists in compiler input
351
+ if (!compilerInput.sources[sourceName]) {
352
+ compilerInput.sources[sourceName] = {content: ''};
353
+ }
354
+
355
+ // Get or assign source ID
356
+ const sourceId = sourceIds[sourceName] ?? nextSourceId++;
357
+ sourceIds[sourceName] = sourceId;
316
358
 
317
359
  // Create contract nodes for AST
318
360
  const contractNodes: Array<{name: string; nodeId: number}> = [];
319
361
  for (const {name} of sourceContracts) {
320
- const nodeId = nextId++;
321
- contractNodes.push({name, nodeId});
362
+ contractNodes.push({name, nodeId: nextNodeId++});
322
363
  }
323
364
 
324
- outputSources[sourceName] = {
365
+ compilerOutput.sources[sourceName] = {
325
366
  id: sourceId,
326
367
  ast: createMinimalAst(sourceName, sourceId, contractNodes),
327
368
  };
328
369
 
370
+ compilerOutput.contracts[sourceName] = {};
371
+
329
372
  // Add contract outputs
330
373
  for (const {name, artifact} of sourceContracts) {
331
- // Cast to access optional evm property that may exist on artifacts
332
- // without solcInput (partial RichArtifact)
333
374
  const richArtifact = artifact as Partial<RichArtifact>;
334
375
 
376
+ // Build bytecode output, extracting from evm if available
377
+ const bytecode: BytecodeOutput = {
378
+ object: stripHexPrefix(
379
+ richArtifact.evm?.bytecode?.object ?? artifact.bytecode ?? '0x',
380
+ ),
381
+ opcodes: richArtifact.evm?.bytecode?.opcodes ?? '',
382
+ sourceMap: richArtifact.evm?.bytecode?.sourceMap ?? '',
383
+ linkReferences:
384
+ richArtifact.evm?.bytecode?.linkReferences ?? artifact.linkReferences ?? {},
385
+ generatedSources: richArtifact.evm?.bytecode?.generatedSources,
386
+ functionDebugData: richArtifact.evm?.bytecode?.functionDebugData,
387
+ };
388
+
335
389
  const immutableReferences =
336
390
  richArtifact.evm?.deployedBytecode?.immutableReferences ??
337
391
  artifact.immutableReferences ??
338
392
  {};
339
393
 
340
- contracts[sourceName][name] = {
394
+ const deployedBytecode: BytecodeOutput = {
395
+ object: stripHexPrefix(
396
+ richArtifact.evm?.deployedBytecode?.object ??
397
+ artifact.deployedBytecode ??
398
+ '0x',
399
+ ),
400
+ opcodes: richArtifact.evm?.deployedBytecode?.opcodes ?? '',
401
+ sourceMap: richArtifact.evm?.deployedBytecode?.sourceMap ?? '',
402
+ linkReferences:
403
+ richArtifact.evm?.deployedBytecode?.linkReferences ??
404
+ artifact.deployedLinkReferences ??
405
+ {},
406
+ immutableReferences,
407
+ generatedSources: richArtifact.evm?.deployedBytecode?.generatedSources,
408
+ functionDebugData: richArtifact.evm?.deployedBytecode?.functionDebugData,
409
+ };
410
+
411
+ // IMPORTANT: Do NOT provide method identifiers - let EDR compute them
412
+ // EDR has internal "selector fixup" logic for function overloading that can fail
413
+ // if we provide method identifiers that it then tries to reconcile with AST info.
414
+ compilerOutput.contracts[sourceName][name] = {
341
415
  abi: artifact.abi,
342
416
  evm: {
343
- bytecode: {
344
- object: stripHexPrefix(artifact.bytecode),
345
- opcodes: '',
346
- sourceMap: '',
347
- linkReferences: artifact.linkReferences ?? {},
348
- },
349
- deployedBytecode: {
350
- object: stripHexPrefix(artifact.deployedBytecode),
351
- opcodes: '',
352
- sourceMap: '',
353
- linkReferences: artifact.deployedLinkReferences ?? {},
354
- // Check both evm.deployedBytecode.immutableReferences and top-level
355
- immutableReferences,
356
- },
357
- // Empty object - let EDR compute selectors to avoid selector fixup issues
358
- // with overloaded functions (consistent with richArtifactToCompilation)
417
+ bytecode,
418
+ deployedBytecode,
359
419
  methodIdentifiers: {},
360
420
  },
421
+ metadata: richArtifact.metadata,
422
+ devdoc: richArtifact.devdoc,
423
+ userdoc: richArtifact.userdoc,
424
+ storageLayout: richArtifact.storageLayout,
361
425
  };
362
426
 
363
427
  if (debug) {
364
428
  const immRefKeys = Object.keys(immutableReferences);
365
- console.log(`[external-artifacts] Simple artifact: ${name}`);
429
+ console.log(`[external-artifacts] Built artifact: ${name}`);
366
430
  console.log(` - sourceName: ${sourceName}`);
431
+ console.log(` - hasSolcInput: ${hasSolcInput(artifact)}`);
432
+ console.log(` - hasMetadata: ${hasMetadata(artifact)}`);
433
+ console.log(` - hasEvmData: ${hasEvmData(artifact)}`);
367
434
  console.log(` - immutableReferences keys: ${immRefKeys.length}`);
368
435
  if (immRefKeys.length > 0) {
369
436
  console.log(` - immutableReferences sample:`, JSON.stringify(immutableReferences, null, 2).slice(0, 500));
370
437
  }
371
- console.log(` - deployedBytecode length: ${artifact.deployedBytecode.length / 2} bytes`);
438
+ console.log(` - deployedBytecode length: ${deployedBytecode.object.length / 2} bytes`);
372
439
  }
373
440
  }
374
441
  }
375
442
 
376
443
  return {
377
- solcVersion,
378
- compilerInput: {
379
- language: 'Solidity',
380
- sources,
381
- settings: {
382
- optimizer: {enabled: false},
383
- outputSelection: {
384
- '*': {'*': ['abi', 'evm.bytecode', 'evm.deployedBytecode']},
385
- },
386
- },
387
- },
388
- compilerOutput: {
389
- sources: outputSources,
390
- contracts,
391
- },
444
+ solcVersion: context.solcVersion,
445
+ compilerInput,
446
+ compilerOutput,
392
447
  };
393
448
  }
394
449
 
@@ -83,12 +83,34 @@ export interface LinkReferences {
83
83
  }
84
84
 
85
85
  /**
86
- * Type guard to check if an artifact is a rich artifact
86
+ * Type guard to check if an artifact has solcInput.
87
+ * Note: The converter now handles artifacts flexibly, extracting
88
+ * available data from solcInput, metadata, or evm fields without
89
+ * requiring a strict "rich" vs "simple" classification.
87
90
  */
88
- export function isRichArtifact(
91
+ export function hasSolcInput(
89
92
  artifact: ExternalArtifact,
90
- ): artifact is RichArtifact {
91
- return 'solcInput' in artifact && artifact.solcInput !== undefined;
93
+ ): artifact is RichArtifact & {solcInput: string} {
94
+ return 'solcInput' in artifact && typeof (artifact as RichArtifact).solcInput === 'string';
95
+ }
96
+
97
+ /**
98
+ * Type guard to check if an artifact has metadata.
99
+ * Metadata can be used as a fallback for compiler settings when solcInput is not available.
100
+ */
101
+ export function hasMetadata(
102
+ artifact: ExternalArtifact,
103
+ ): artifact is RichArtifact & {metadata: string} {
104
+ return 'metadata' in artifact && typeof (artifact as RichArtifact).metadata === 'string';
105
+ }
106
+
107
+ /**
108
+ * Type guard to check if an artifact has EVM data.
109
+ */
110
+ export function hasEvmData(
111
+ artifact: ExternalArtifact,
112
+ ): artifact is RichArtifact & {evm: NonNullable<RichArtifact['evm']>} {
113
+ return 'evm' in artifact && (artifact as RichArtifact).evm !== undefined;
92
114
  }
93
115
 
94
116
  /**
@@ -5,7 +5,7 @@ import {
5
5
  artifactsToCompilations,
6
6
  type SyntheticCompilation,
7
7
  } from '../artifacts/converter.js';
8
- import {isRichArtifact} from '../artifacts/types.js';
8
+ import {hasSolcInput} from '../artifacts/types.js';
9
9
 
10
10
  export default async (): Promise<Partial<NetworkHooks>> => {
11
11
  const handlers: Partial<NetworkHooks> = {
@@ -50,10 +50,10 @@ export default async (): Promise<Partial<NetworkHooks>> => {
50
50
  `[hardhat-external-artifacts] Loaded ${artifacts.length} artifact(s):`,
51
51
  );
52
52
  for (const artifact of artifacts) {
53
- const isRich = isRichArtifact(artifact);
53
+ const hasSolc = hasSolcInput(artifact);
54
54
  const deployedBytecodeLength = artifact.deployedBytecode?.length || 0;
55
55
  log(
56
- ` - ${artifact.sourceName}:${artifact.contractName} (${isRich ? 'rich' : 'simple'}, deployedBytecode: ${deployedBytecodeLength} chars)`,
56
+ ` - ${artifact.sourceName}:${artifact.contractName} (${hasSolc ? 'with solcInput' : 'minimal'}, deployedBytecode: ${deployedBytecodeLength} chars)`,
57
57
  );
58
58
  }
59
59