0
# Artifact Management
1
2
Buidler's artifact management system handles compilation artifacts from Solidity contracts, providing utilities for reading, writing, and processing contract compilation results including ABI, bytecode, and metadata.
3
4
## Capabilities
5
6
### Artifact Structure
7
8
Standard artifact format containing all contract compilation information.
9
10
```typescript { .api }
11
/**
12
* Contract compilation artifact
13
*/
14
interface Artifact {
15
/** Contract name */
16
contractName: string;
17
/** Contract ABI (Application Binary Interface) */
18
abi: any;
19
/** Contract creation bytecode (0x-prefixed hex string) */
20
bytecode: string;
21
/** Contract runtime bytecode (0x-prefixed hex string) */
22
deployedBytecode: string;
23
/** Library link references in creation bytecode */
24
linkReferences: LinkReferences;
25
/** Library link references in deployed bytecode */
26
deployedLinkReferences: LinkReferences;
27
}
28
29
/**
30
* Library link references for contract libraries
31
*/
32
interface LinkReferences {
33
[libraryFileName: string]: {
34
[libraryName: string]: Array<{
35
/** Length of placeholder in bytes */
36
length: number;
37
/** Start position of placeholder */
38
start: number;
39
}>;
40
};
41
}
42
```
43
44
### Artifact Reading
45
46
Read contract artifacts from the artifacts directory.
47
48
```typescript { .api }
49
/**
50
* Asynchronously read an artifact by contract name
51
* @param artifactsPath - Path to artifacts directory
52
* @param contractName - Name of the contract
53
* @returns Promise resolving to contract artifact
54
* @throws BuidlerError if artifact not found
55
*/
56
function readArtifact(
57
artifactsPath: string,
58
contractName: string
59
): Promise<Artifact>;
60
61
/**
62
* Synchronously read an artifact by contract name
63
* @param artifactsPath - Path to artifacts directory
64
* @param contractName - Name of the contract
65
* @returns Contract artifact
66
* @throws BuidlerError if artifact not found
67
*/
68
function readArtifactSync(
69
artifactsPath: string,
70
contractName: string
71
): Artifact;
72
```
73
74
**Usage Examples:**
75
76
```typescript
77
import { readArtifact, readArtifactSync } from "@nomiclabs/buidler/plugins";
78
79
// Async reading
80
task("deploy", async (taskArgs, hre) => {
81
const artifact = await readArtifact(hre.config.paths.artifacts, "MyContract");
82
83
console.log("Contract:", artifact.contractName);
84
console.log("ABI:", artifact.abi);
85
console.log("Bytecode length:", artifact.bytecode.length);
86
87
// Use artifact for deployment
88
const contract = new web3.eth.Contract(artifact.abi);
89
const deployment = await contract.deploy({
90
data: artifact.bytecode,
91
arguments: [/* constructor args */]
92
}).send({ from: accounts[0] });
93
});
94
95
// Sync reading (for utility functions)
96
function getContractABI(contractName: string): any {
97
const artifact = readArtifactSync("./artifacts", contractName);
98
return artifact.abi;
99
}
100
101
// Error handling
102
try {
103
const artifact = await readArtifact("./artifacts", "NonExistent");
104
} catch (error) {
105
if (error.message.includes("NOT_FOUND")) {
106
console.log("Contract artifact not found - compile first");
107
}
108
}
109
```
110
111
### Artifact Writing
112
113
Save compilation artifacts to the artifacts directory.
114
115
```typescript { .api }
116
/**
117
* Save an artifact to the artifacts directory
118
* @param artifactsPath - Path to artifacts directory
119
* @param artifact - Artifact to save
120
* @returns Promise that resolves when artifact is saved
121
*/
122
function saveArtifact(
123
artifactsPath: string,
124
artifact: Artifact
125
): Promise<void>;
126
```
127
128
**Usage Examples:**
129
130
```typescript
131
import { saveArtifact } from "@nomiclabs/buidler/plugins";
132
133
// Save custom artifact
134
task("save-custom-artifact", async (taskArgs, hre) => {
135
const customArtifact: Artifact = {
136
contractName: "CustomContract",
137
abi: [
138
{
139
"inputs": [],
140
"name": "test",
141
"outputs": [],
142
"stateMutability": "pure",
143
"type": "function"
144
}
145
],
146
bytecode: "0x608060405234801561001057600080fd5b50...",
147
deployedBytecode: "0x608060405234801561001057600080fd5b50...",
148
linkReferences: {},
149
deployedLinkReferences: {}
150
};
151
152
await saveArtifact(hre.config.paths.artifacts, customArtifact);
153
console.log("Custom artifact saved");
154
});
155
156
// Process and save modified artifact
157
task("optimize-artifact", async (taskArgs, hre) => {
158
const original = await readArtifact(hre.config.paths.artifacts, "MyContract");
159
160
// Create optimized version
161
const optimized: Artifact = {
162
...original,
163
contractName: `${original.contractName}_Optimized`,
164
// Apply optimizations to bytecode
165
bytecode: optimizeBytecode(original.bytecode),
166
deployedBytecode: optimizeBytecode(original.deployedBytecode)
167
};
168
169
await saveArtifact(hre.config.paths.artifacts, optimized);
170
});
171
```
172
173
### Manual Artifact Creation
174
175
Create artifacts manually when needed for custom compilation workflows.
176
177
**Usage Examples:**
178
179
```typescript
180
// Custom compilation task with manual artifact creation
181
task("custom-compile", async (taskArgs, hre) => {
182
const solc = require("solc");
183
184
// Prepare compiler input
185
const input = {
186
language: "Solidity",
187
sources: {
188
"MyContract.sol": {
189
content: fs.readFileSync("contracts/MyContract.sol", "utf8")
190
}
191
},
192
settings: {
193
outputSelection: {
194
"*": {
195
"*": ["abi", "evm.bytecode", "evm.deployedBytecode"]
196
}
197
}
198
}
199
};
200
201
// Compile
202
const output = JSON.parse(solc.compile(JSON.stringify(input)));
203
204
// Convert to artifacts manually
205
for (const sourceFile in output.contracts) {
206
for (const contractName in output.contracts[sourceFile]) {
207
const contractOutput = output.contracts[sourceFile][contractName];
208
209
// Manually create artifact from compiler output
210
const artifact: Artifact = {
211
contractName,
212
abi: contractOutput.abi,
213
bytecode: contractOutput.evm.bytecode.object,
214
deployedBytecode: contractOutput.evm.deployedBytecode.object,
215
linkReferences: contractOutput.evm.bytecode.linkReferences || {},
216
deployedLinkReferences: contractOutput.evm.deployedBytecode.linkReferences || {}
217
};
218
219
await saveArtifact(hre.config.paths.artifacts, artifact);
220
console.log(`Saved artifact for ${contractName}`);
221
}
222
}
223
});
224
```
225
226
### Runtime Environment Integration
227
228
Access artifacts through the Buidler runtime environment.
229
230
**Usage Examples:**
231
232
```typescript
233
// Extend environment with artifact utilities
234
extendEnvironment((hre) => {
235
hre.artifacts = {
236
readArtifact: async (contractName: string) => {
237
return readArtifact(hre.config.paths.artifacts, contractName);
238
},
239
240
readArtifactSync: (contractName: string) => {
241
return readArtifactSync(hre.config.paths.artifacts, contractName);
242
},
243
244
saveArtifact: async (artifact: Artifact) => {
245
return saveArtifact(hre.config.paths.artifacts, artifact);
246
}
247
};
248
});
249
250
// Use in tasks
251
task("contract-info", async (taskArgs, hre) => {
252
const artifact = await hre.artifacts.readArtifact("MyContract");
253
254
console.log("Contract Information:");
255
console.log(`Name: ${artifact.contractName}`);
256
console.log(`Functions: ${artifact.abi.filter(item => item.type === 'function').length}`);
257
console.log(`Events: ${artifact.abi.filter(item => item.type === 'event').length}`);
258
console.log(`Bytecode size: ${(artifact.bytecode.length - 2) / 2} bytes`);
259
260
// Check for libraries
261
const hasLibraries = Object.keys(artifact.linkReferences).length > 0;
262
if (hasLibraries) {
263
console.log("Required libraries:", Object.keys(artifact.linkReferences));
264
}
265
});
266
```
267
268
### Artifact Processing Utilities
269
270
Common utilities for working with artifacts.
271
272
**Usage Examples:**
273
274
```typescript
275
// Extract function signatures
276
function getFunctionSignatures(artifact: Artifact): string[] {
277
return artifact.abi
278
.filter(item => item.type === 'function')
279
.map(func => {
280
const inputs = func.inputs.map(input => input.type).join(',');
281
return `${func.name}(${inputs})`;
282
});
283
}
284
285
// Get contract size
286
function getContractSize(artifact: Artifact): { creation: number; deployed: number } {
287
return {
288
creation: (artifact.bytecode.length - 2) / 2,
289
deployed: (artifact.deployedBytecode.length - 2) / 2
290
};
291
}
292
293
// Check if contract needs libraries
294
function requiresLibraries(artifact: Artifact): boolean {
295
return Object.keys(artifact.linkReferences).length > 0 ||
296
Object.keys(artifact.deployedLinkReferences).length > 0;
297
}
298
299
// Usage in task
300
task("analyze-contracts", async (taskArgs, hre) => {
301
const contractNames = ["Token", "Crowdsale", "Vault"];
302
303
for (const name of contractNames) {
304
const artifact = await hre.artifacts.readArtifact(name);
305
const signatures = getFunctionSignatures(artifact);
306
const size = getContractSize(artifact);
307
const needsLibs = requiresLibraries(artifact);
308
309
console.log(`\n${name}:`);
310
console.log(` Functions: ${signatures.length}`);
311
console.log(` Size: ${size.deployed} bytes`);
312
console.log(` Needs libraries: ${needsLibs}`);
313
314
if (signatures.length < 10) {
315
console.log(` Signatures: ${signatures.join(', ')}`);
316
}
317
}
318
});
319
```
320
321
### Error Handling
322
323
Handle common artifact-related errors gracefully.
324
325
**Usage Examples:**
326
327
```typescript
328
import { BuidlerError } from "@nomiclabs/buidler/plugins";
329
330
task("safe-read-artifact", async (taskArgs, hre) => {
331
try {
332
const artifact = await readArtifact(hre.config.paths.artifacts, taskArgs.contract);
333
console.log("Artifact loaded successfully");
334
return artifact;
335
} catch (error) {
336
if (error instanceof BuidlerError && error.number === 'ARTIFACTS_NOT_FOUND') {
337
console.log("Artifact not found. Compiling contracts...");
338
await hre.run("compile");
339
340
// Retry after compilation
341
return readArtifact(hre.config.paths.artifacts, taskArgs.contract);
342
} else {
343
console.error("Unexpected error:", error.message);
344
throw error;
345
}
346
}
347
});
348
349
// Batch artifact operations with error handling
350
task("batch-process-artifacts", async (taskArgs, hre) => {
351
const contractNames = ["Token", "Crowdsale", "NonExistent"];
352
const results = [];
353
354
for (const name of contractNames) {
355
try {
356
const artifact = await readArtifact(hre.config.paths.artifacts, name);
357
results.push({ name, success: true, artifact });
358
} catch (error) {
359
results.push({ name, success: false, error: error.message });
360
}
361
}
362
363
// Report results
364
const successful = results.filter(r => r.success);
365
const failed = results.filter(r => !r.success);
366
367
console.log(`Processed ${successful.length} artifacts successfully`);
368
if (failed.length > 0) {
369
console.log(`Failed to process: ${failed.map(f => f.name).join(", ")}`);
370
}
371
});
372
```