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.
- package/dist/artifacts/converter.d.ts +4 -2
- package/dist/artifacts/converter.d.ts.map +1 -1
- package/dist/artifacts/converter.js +225 -181
- package/dist/artifacts/converter.js.map +1 -1
- package/dist/artifacts/types.d.ts +20 -2
- package/dist/artifacts/types.d.ts.map +1 -1
- package/dist/artifacts/types.js +19 -3
- package/dist/artifacts/types.js.map +1 -1
- package/dist/hooks/network.js +3 -3
- package/dist/hooks/network.js.map +1 -1
- package/package.json +6 -3
- package/src/artifacts/converter.test.ts +294 -0
- package/src/artifacts/converter.ts +260 -205
- package/src/artifacts/types.ts +26 -4
- package/src/hooks/network.ts +3 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type {ExternalArtifact, RichArtifact, LinkReferences} from './types.js';
|
|
2
|
-
import {
|
|
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
|
-
*
|
|
96
|
-
*
|
|
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
|
-
|
|
100
|
-
|
|
111
|
+
function extractCompilationContext(
|
|
112
|
+
artifact: ExternalArtifact,
|
|
101
113
|
defaultSolcVersion: string,
|
|
102
114
|
debug: boolean = false,
|
|
103
|
-
):
|
|
104
|
-
//
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
-
//
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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
|
-
*
|
|
143
|
-
* Uses the embedded solcInput directly for maximum fidelity.
|
|
167
|
+
* Extract solc version from metadata string.
|
|
144
168
|
*/
|
|
145
|
-
function
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
-
|
|
154
|
-
|
|
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
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
|
|
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
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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
|
-
//
|
|
188
|
-
const
|
|
189
|
-
|
|
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
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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
|
-
//
|
|
239
|
-
|
|
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
|
-
|
|
260
|
-
const
|
|
261
|
-
|
|
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
|
-
*
|
|
280
|
-
*
|
|
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
|
|
299
|
+
function buildCompilation(
|
|
283
300
|
artifacts: ExternalArtifact[],
|
|
284
|
-
|
|
301
|
+
context: CompilationContext,
|
|
285
302
|
debug: boolean = false,
|
|
286
303
|
): SyntheticCompilation {
|
|
287
|
-
|
|
288
|
-
const
|
|
289
|
-
|
|
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
|
-
//
|
|
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
|
|
307
|
-
let
|
|
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
|
-
//
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
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
|
-
|
|
321
|
-
contractNodes.push({name, nodeId});
|
|
362
|
+
contractNodes.push({name, nodeId: nextNodeId++});
|
|
322
363
|
}
|
|
323
364
|
|
|
324
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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]
|
|
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: ${
|
|
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
|
-
|
|
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
|
|
package/src/artifacts/types.ts
CHANGED
|
@@ -83,12 +83,34 @@ export interface LinkReferences {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
/**
|
|
86
|
-
* Type guard to check if an 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
|
|
91
|
+
export function hasSolcInput(
|
|
89
92
|
artifact: ExternalArtifact,
|
|
90
|
-
): artifact is RichArtifact {
|
|
91
|
-
return 'solcInput' in artifact && artifact.solcInput
|
|
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
|
/**
|
package/src/hooks/network.ts
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
artifactsToCompilations,
|
|
6
6
|
type SyntheticCompilation,
|
|
7
7
|
} from '../artifacts/converter.js';
|
|
8
|
-
import {
|
|
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
|
|
53
|
+
const hasSolc = hasSolcInput(artifact);
|
|
54
54
|
const deployedBytecodeLength = artifact.deployedBytecode?.length || 0;
|
|
55
55
|
log(
|
|
56
|
-
` - ${artifact.sourceName}:${artifact.contractName} (${
|
|
56
|
+
` - ${artifact.sourceName}:${artifact.contractName} (${hasSolc ? 'with solcInput' : 'minimal'}, deployedBytecode: ${deployedBytecodeLength} chars)`,
|
|
57
57
|
);
|
|
58
58
|
}
|
|
59
59
|
|