hardhat
Version:
Hardhat is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.
681 lines (679 loc) • 29.5 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getArtifactFromContractOutput = exports.Artifacts = void 0;
const debug_1 = __importDefault(require("debug"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const os = __importStar(require("os"));
const path = __importStar(require("path"));
const promises_1 = __importDefault(require("fs/promises"));
const contract_names_1 = require("../utils/contract-names");
const source_names_1 = require("../utils/source-names");
const constants_1 = require("./constants");
const errors_1 = require("./core/errors");
const errors_list_1 = require("./core/errors-list");
const hash_1 = require("./util/hash");
const fs_utils_1 = require("./util/fs-utils");
const log = (0, debug_1.default)("hardhat:core:artifacts");
class Artifacts {
constructor(_artifactsPath) {
this._artifactsPath = _artifactsPath;
// Undefined means that the cache is disabled.
this._cache = {
artifactNameToArtifactPathCache: new Map(),
artifactFQNToBuildInfoPathCache: new Map(),
};
this._validArtifacts = [];
}
addValidArtifacts(validArtifacts) {
this._validArtifacts.push(...validArtifacts);
}
async readArtifact(name) {
const artifactPath = await this._getArtifactPath(name);
return fs_extra_1.default.readJson(artifactPath);
}
readArtifactSync(name) {
const artifactPath = this._getArtifactPathSync(name);
return fs_extra_1.default.readJsonSync(artifactPath);
}
async artifactExists(name) {
let artifactPath;
try {
artifactPath = await this._getArtifactPath(name);
}
catch (e) {
if (errors_1.HardhatError.isHardhatError(e)) {
return false;
}
// eslint-disable-next-line @nomicfoundation/hardhat-internal-rules/only-hardhat-error
throw e;
}
return fs_extra_1.default.pathExists(artifactPath);
}
async getAllFullyQualifiedNames() {
const paths = await this.getArtifactPaths();
return paths.map((p) => this._getFullyQualifiedNameFromPath(p)).sort();
}
async getBuildInfo(fullyQualifiedName) {
let buildInfoPath = this._cache?.artifactFQNToBuildInfoPathCache.get(fullyQualifiedName);
if (buildInfoPath === undefined) {
const artifactPath = this.formArtifactPathFromFullyQualifiedName(fullyQualifiedName);
const debugFilePath = this._getDebugFilePath(artifactPath);
buildInfoPath = await this._getBuildInfoFromDebugFile(debugFilePath);
if (buildInfoPath === undefined) {
return undefined;
}
this._cache?.artifactFQNToBuildInfoPathCache.set(fullyQualifiedName, buildInfoPath);
}
return fs_extra_1.default.readJSON(buildInfoPath);
}
getBuildInfoSync(fullyQualifiedName) {
let buildInfoPath = this._cache?.artifactFQNToBuildInfoPathCache.get(fullyQualifiedName);
if (buildInfoPath === undefined) {
const artifactPath = this.formArtifactPathFromFullyQualifiedName(fullyQualifiedName);
const debugFilePath = this._getDebugFilePath(artifactPath);
buildInfoPath = this._getBuildInfoFromDebugFileSync(debugFilePath);
if (buildInfoPath === undefined) {
return undefined;
}
this._cache?.artifactFQNToBuildInfoPathCache.set(fullyQualifiedName, buildInfoPath);
}
return fs_extra_1.default.readJSONSync(buildInfoPath);
}
async getArtifactPaths() {
const cached = this._cache?.artifactPaths;
if (cached !== undefined) {
return cached;
}
const paths = await (0, fs_utils_1.getAllFilesMatching)(this._artifactsPath, (f) => this._isArtifactPath(f));
const result = paths.sort();
if (this._cache !== undefined) {
this._cache.artifactPaths = result;
}
return result;
}
async getBuildInfoPaths() {
const cached = this._cache?.buildInfoPaths;
if (cached !== undefined) {
return cached;
}
const paths = await (0, fs_utils_1.getAllFilesMatching)(path.join(this._artifactsPath, constants_1.BUILD_INFO_DIR_NAME), (f) => f.endsWith(".json"));
const result = paths.sort();
if (this._cache !== undefined) {
this._cache.buildInfoPaths = result;
}
return result;
}
async getDebugFilePaths() {
const cached = this._cache?.debugFilePaths;
if (cached !== undefined) {
return cached;
}
const paths = await (0, fs_utils_1.getAllFilesMatching)(path.join(this._artifactsPath), (f) => f.endsWith(".dbg.json"));
const result = paths.sort();
if (this._cache !== undefined) {
this._cache.debugFilePaths = result;
}
return result;
}
async saveArtifactAndDebugFile(artifact, pathToBuildInfo) {
try {
// artifact
const fullyQualifiedName = (0, contract_names_1.getFullyQualifiedName)(artifact.sourceName, artifact.contractName);
const artifactPath = this.formArtifactPathFromFullyQualifiedName(fullyQualifiedName);
await fs_extra_1.default.ensureDir(path.dirname(artifactPath));
await Promise.all([
fs_extra_1.default.writeJSON(artifactPath, artifact, {
spaces: 2,
}),
(async () => {
if (pathToBuildInfo === undefined) {
return;
}
// save debug file
const debugFilePath = this._getDebugFilePath(artifactPath);
const debugFile = this._createDebugFile(artifactPath, pathToBuildInfo);
await fs_extra_1.default.writeJSON(debugFilePath, debugFile, {
spaces: 2,
});
})(),
]);
}
finally {
this.clearCache();
}
}
async saveBuildInfo(solcVersion, solcLongVersion, input, output) {
try {
const buildInfoDir = path.join(this._artifactsPath, constants_1.BUILD_INFO_DIR_NAME);
await fs_extra_1.default.ensureDir(buildInfoDir);
const buildInfoName = this._getBuildInfoName(solcVersion, solcLongVersion, input);
const buildInfo = this._createBuildInfo(buildInfoName, solcVersion, solcLongVersion, input, output);
const buildInfoPath = path.join(buildInfoDir, `${buildInfoName}.json`);
// JSON.stringify of the entire build info can be really slow
// in larger projects, so we stringify per part and incrementally create
// the JSON in the file.
//
// We split this code into different curly-brace-enclosed scopes so that
// partial JSON strings get out of scope sooner and hence can be reclaimed
// by the GC if needed.
const file = await promises_1.default.open(buildInfoPath, "w");
try {
{
const withoutOutput = JSON.stringify({
...buildInfo,
output: undefined,
});
// We write the JSON (without output) except the last }
await file.write(withoutOutput.slice(0, -1));
}
{
const outputWithoutSourcesAndContracts = JSON.stringify({
...buildInfo.output,
sources: undefined,
contracts: undefined,
});
// We start writing the output
await file.write(',"output":');
// Write the output object except for the last }
await file.write(outputWithoutSourcesAndContracts.slice(0, -1));
// If there were other field apart from sources and contracts we need
// a comma
if (outputWithoutSourcesAndContracts.length > 2) {
await file.write(",");
}
}
// Writing the sources
await file.write('"sources":{');
let isFirst = true;
for (const [name, value] of Object.entries(buildInfo.output.sources ?? {})) {
if (isFirst) {
isFirst = false;
}
else {
await file.write(",");
}
await file.write(`${JSON.stringify(name)}:${JSON.stringify(value)}`);
}
// Close sources object
await file.write("}");
// Writing the contracts
await file.write(',"contracts":{');
isFirst = true;
for (const [name, value] of Object.entries(buildInfo.output.contracts ?? {})) {
if (isFirst) {
isFirst = false;
}
else {
await file.write(",");
}
await file.write(`${JSON.stringify(name)}:${JSON.stringify(value)}`);
}
// close contracts object
await file.write("}");
// close output object
await file.write("}");
// close build info object
await file.write("}");
}
finally {
await file.close();
}
return buildInfoPath;
}
finally {
this.clearCache();
}
}
/**
* Remove all artifacts that don't correspond to the current solidity files
*/
async removeObsoleteArtifacts() {
// We clear the cache here, as we want to be sure this runs correctly
this.clearCache();
try {
const validArtifactPaths = await Promise.all(this._validArtifacts.flatMap(({ sourceName, artifacts }) => artifacts.map((artifactName) => this._getArtifactPath((0, contract_names_1.getFullyQualifiedName)(sourceName, artifactName)))));
const validArtifactsPathsSet = new Set(validArtifactPaths);
for (const { sourceName, artifacts } of this._validArtifacts) {
for (const artifactName of artifacts) {
validArtifactsPathsSet.add(this.formArtifactPathFromFullyQualifiedName((0, contract_names_1.getFullyQualifiedName)(sourceName, artifactName)));
}
}
const existingArtifactsPaths = await this.getArtifactPaths();
await Promise.all(existingArtifactsPaths
.filter((artifactPath) => !validArtifactsPathsSet.has(artifactPath))
.map((artifactPath) => this._removeArtifactFiles(artifactPath)));
await this._removeObsoleteBuildInfos();
}
finally {
// We clear the cache here, as this may have non-existent paths now
this.clearCache();
}
}
/**
* Returns the absolute path to the given artifact
* @throws {HardhatError} If the name is not fully qualified.
*/
formArtifactPathFromFullyQualifiedName(fullyQualifiedName) {
const { sourceName, contractName } = (0, contract_names_1.parseFullyQualifiedName)(fullyQualifiedName);
return path.join(this._artifactsPath, sourceName, `${contractName}.json`);
}
clearCache() {
// Avoid accidentally re-enabling the cache
if (this._cache === undefined) {
return;
}
this._cache = {
artifactFQNToBuildInfoPathCache: new Map(),
artifactNameToArtifactPathCache: new Map(),
};
}
disableCache() {
this._cache = undefined;
}
/**
* Remove all build infos that aren't used by any debug file
*/
async _removeObsoleteBuildInfos() {
const debugFiles = await this.getDebugFilePaths();
const buildInfos = await Promise.all(debugFiles.map(async (debugFile) => {
const buildInfoFile = await this._getBuildInfoFromDebugFile(debugFile);
if (buildInfoFile !== undefined) {
return path.resolve(path.dirname(debugFile), buildInfoFile);
}
}));
const filteredBuildInfos = buildInfos.filter((bf) => typeof bf === "string");
const validBuildInfos = new Set(filteredBuildInfos);
const buildInfoFiles = await this.getBuildInfoPaths();
await Promise.all(buildInfoFiles
.filter((buildInfoFile) => !validBuildInfos.has(buildInfoFile))
.map(async (buildInfoFile) => {
log(`Removing buildInfo '${buildInfoFile}'`);
await fs_extra_1.default.unlink(buildInfoFile);
}));
}
_getBuildInfoName(solcVersion, solcLongVersion, input) {
const json = JSON.stringify({
_format: constants_1.BUILD_INFO_FORMAT_VERSION,
solcVersion,
solcLongVersion,
input,
});
return (0, hash_1.createNonCryptographicHashBasedIdentifier)(Buffer.from(json)).toString("hex");
}
/**
* Returns the absolute path to the artifact that corresponds to the given
* name.
*
* If the name is fully qualified, the path is computed from it. If not, an
* artifact that matches the given name is searched in the existing artifacts.
* If there is an ambiguity, an error is thrown.
*
* @throws {HardhatError} with descriptor:
* - {@link ERRORS.ARTIFACTS.WRONG_CASING} if the path case doesn't match the one in the filesystem.
* - {@link ERRORS.ARTIFACTS.MULTIPLE_FOUND} if there are multiple artifacts matching the given contract name.
* - {@link ERRORS.ARTIFACTS.NOT_FOUND} if the artifact is not found.
*/
async _getArtifactPath(name) {
const cached = this._cache?.artifactNameToArtifactPathCache.get(name);
if (cached !== undefined) {
return cached;
}
let result;
if ((0, contract_names_1.isFullyQualifiedName)(name)) {
result = await this._getValidArtifactPathFromFullyQualifiedName(name);
}
else {
const files = await this.getArtifactPaths();
result = this._getArtifactPathFromFiles(name, files);
}
this._cache?.artifactNameToArtifactPathCache.set(name, result);
return result;
}
_createBuildInfo(id, solcVersion, solcLongVersion, input, output) {
return {
id,
_format: constants_1.BUILD_INFO_FORMAT_VERSION,
solcVersion,
solcLongVersion,
input,
output,
};
}
_createDebugFile(artifactPath, pathToBuildInfo) {
const relativePathToBuildInfo = path.relative(path.dirname(artifactPath), pathToBuildInfo);
const debugFile = {
_format: constants_1.DEBUG_FILE_FORMAT_VERSION,
buildInfo: relativePathToBuildInfo,
};
return debugFile;
}
_getArtifactPathsSync() {
const cached = this._cache?.artifactPaths;
if (cached !== undefined) {
return cached;
}
const paths = (0, fs_utils_1.getAllFilesMatchingSync)(this._artifactsPath, (f) => this._isArtifactPath(f));
const result = paths.sort();
if (this._cache !== undefined) {
this._cache.artifactPaths = result;
}
return result;
}
/**
* Sync version of _getArtifactPath
*/
_getArtifactPathSync(name) {
const cached = this._cache?.artifactNameToArtifactPathCache.get(name);
if (cached !== undefined) {
return cached;
}
let result;
if ((0, contract_names_1.isFullyQualifiedName)(name)) {
result = this._getValidArtifactPathFromFullyQualifiedNameSync(name);
}
else {
const files = this._getArtifactPathsSync();
result = this._getArtifactPathFromFiles(name, files);
}
this._cache?.artifactNameToArtifactPathCache.set(name, result);
return result;
}
/**
* DO NOT DELETE OR CHANGE
*
* use this.formArtifactPathFromFullyQualifiedName instead
* @deprecated until typechain migrates to public version
* @see https://github.com/dethcrypto/TypeChain/issues/544
*/
_getArtifactPathFromFullyQualifiedName(fullyQualifiedName) {
const { sourceName, contractName } = (0, contract_names_1.parseFullyQualifiedName)(fullyQualifiedName);
return path.join(this._artifactsPath, sourceName, `${contractName}.json`);
}
/**
* Returns the absolute path to the artifact that corresponds to the given
* fully qualified name.
* @param fullyQualifiedName The fully qualified name of the contract.
* @returns The absolute path to the artifact.
* @throws {HardhatError} with descriptor:
* - {@link ERRORS.CONTRACT_NAMES.INVALID_FULLY_QUALIFIED_NAME} If the name is not fully qualified.
* - {@link ERRORS.ARTIFACTS.WRONG_CASING} If the path case doesn't match the one in the filesystem.
* - {@link ERRORS.ARTIFACTS.NOT_FOUND} If the artifact is not found.
*/
async _getValidArtifactPathFromFullyQualifiedName(fullyQualifiedName) {
const artifactPath = this.formArtifactPathFromFullyQualifiedName(fullyQualifiedName);
try {
const trueCasePath = path.join(this._artifactsPath, await (0, fs_utils_1.getFileTrueCase)(this._artifactsPath, path.relative(this._artifactsPath, artifactPath)));
if (artifactPath !== trueCasePath) {
throw new errors_1.HardhatError(errors_list_1.ERRORS.ARTIFACTS.WRONG_CASING, {
correct: this._getFullyQualifiedNameFromPath(trueCasePath),
incorrect: fullyQualifiedName,
});
}
return trueCasePath;
}
catch (e) {
if (e instanceof fs_utils_1.FileNotFoundError) {
return this._handleWrongArtifactForFullyQualifiedName(fullyQualifiedName);
}
// eslint-disable-next-line @nomicfoundation/hardhat-internal-rules/only-hardhat-error
throw e;
}
}
_getAllContractNamesFromFiles(files) {
return files.map((file) => {
const fqn = this._getFullyQualifiedNameFromPath(file);
return (0, contract_names_1.parseFullyQualifiedName)(fqn).contractName;
});
}
_getAllFullyQualifiedNamesSync() {
const paths = this._getArtifactPathsSync();
return paths.map((p) => this._getFullyQualifiedNameFromPath(p)).sort();
}
_formatSuggestions(names, contractName) {
switch (names.length) {
case 0:
return "";
case 1:
return `Did you mean "${names[0]}"?`;
default:
return `We found some that were similar:
${names.map((n) => ` * ${n}`).join(os.EOL)}
Please replace "${contractName}" for the correct contract name wherever you are trying to read its artifact.
`;
}
}
/**
* @throws {HardhatError} with a list of similar contract names.
*/
_handleWrongArtifactForFullyQualifiedName(fullyQualifiedName) {
const names = this._getAllFullyQualifiedNamesSync();
const similarNames = this._getSimilarContractNames(fullyQualifiedName, names);
throw new errors_1.HardhatError(errors_list_1.ERRORS.ARTIFACTS.NOT_FOUND, {
contractName: fullyQualifiedName,
suggestion: this._formatSuggestions(similarNames, fullyQualifiedName),
});
}
/**
* @throws {HardhatError} with a list of similar contract names.
*/
_handleWrongArtifactForContractName(contractName, files) {
const names = this._getAllContractNamesFromFiles(files);
let similarNames = this._getSimilarContractNames(contractName, names);
if (similarNames.length > 1) {
similarNames = this._filterDuplicatesAsFullyQualifiedNames(files, similarNames);
}
throw new errors_1.HardhatError(errors_list_1.ERRORS.ARTIFACTS.NOT_FOUND, {
contractName,
suggestion: this._formatSuggestions(similarNames, contractName),
});
}
/**
* If the project has these contracts:
* - 'contracts/Greeter.sol:Greeter'
* - 'contracts/Meeter.sol:Greeter'
* - 'contracts/Greater.sol:Greater'
* And the user tries to get an artifact with the name 'Greter', then
* the suggestions will be 'Greeter', 'Greeter', and 'Greater'.
*
* We don't want to show duplicates here, so we use FQNs for those. The
* suggestions will then be:
* - 'contracts/Greeter.sol:Greeter'
* - 'contracts/Meeter.sol:Greeter'
* - 'Greater'
*/
_filterDuplicatesAsFullyQualifiedNames(files, similarNames) {
const outputNames = [];
const groups = similarNames.reduce((obj, cur) => {
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
obj[cur] = obj[cur] ? obj[cur] + 1 : 1;
return obj;
}, {});
for (const [name, occurrences] of Object.entries(groups)) {
if (occurrences > 1) {
for (const file of files) {
if (path.basename(file) === `${name}.json`) {
outputNames.push(this._getFullyQualifiedNameFromPath(file));
}
}
continue;
}
outputNames.push(name);
}
return outputNames;
}
/**
*
* @param givenName can be FQN or contract name
* @param names MUST match type of givenName (i.e. array of FQN's if givenName is FQN)
* @returns
*/
_getSimilarContractNames(givenName, names) {
let shortestDistance = constants_1.EDIT_DISTANCE_THRESHOLD;
let mostSimilarNames = [];
for (const name of names) {
const distance = (0, contract_names_1.findDistance)(givenName, name);
if (distance < shortestDistance) {
shortestDistance = distance;
mostSimilarNames = [name];
continue;
}
if (distance === shortestDistance) {
mostSimilarNames.push(name);
continue;
}
}
return mostSimilarNames;
}
_getValidArtifactPathFromFullyQualifiedNameSync(fullyQualifiedName) {
const artifactPath = this.formArtifactPathFromFullyQualifiedName(fullyQualifiedName);
try {
const trueCasePath = path.join(this._artifactsPath, (0, fs_utils_1.getFileTrueCaseSync)(this._artifactsPath, path.relative(this._artifactsPath, artifactPath)));
if (artifactPath !== trueCasePath) {
throw new errors_1.HardhatError(errors_list_1.ERRORS.ARTIFACTS.WRONG_CASING, {
correct: this._getFullyQualifiedNameFromPath(trueCasePath),
incorrect: fullyQualifiedName,
});
}
return trueCasePath;
}
catch (e) {
if (e instanceof fs_utils_1.FileNotFoundError) {
return this._handleWrongArtifactForFullyQualifiedName(fullyQualifiedName);
}
// eslint-disable-next-line @nomicfoundation/hardhat-internal-rules/only-hardhat-error
throw e;
}
}
_getDebugFilePath(artifactPath) {
return artifactPath.replace(/\.json$/, ".dbg.json");
}
/**
* Gets the path to the artifact file for the given contract name.
* @throws {HardhatError} with descriptor:
* - {@link ERRORS.ARTIFACTS.NOT_FOUND} if there are no artifacts matching the given contract name.
* - {@link ERRORS.ARTIFACTS.MULTIPLE_FOUND} if there are multiple artifacts matching the given contract name.
*/
_getArtifactPathFromFiles(contractName, files) {
const matchingFiles = files.filter((file) => {
return path.basename(file) === `${contractName}.json`;
});
if (matchingFiles.length === 0) {
return this._handleWrongArtifactForContractName(contractName, files);
}
if (matchingFiles.length > 1) {
const candidates = matchingFiles.map((file) => this._getFullyQualifiedNameFromPath(file));
throw new errors_1.HardhatError(errors_list_1.ERRORS.ARTIFACTS.MULTIPLE_FOUND, {
contractName,
candidates: candidates.join(os.EOL),
});
}
return matchingFiles[0];
}
/**
* Returns the FQN of a contract giving the absolute path to its artifact.
*
* For example, given a path like
* `/path/to/project/artifacts/contracts/Foo.sol/Bar.json`, it'll return the
* FQN `contracts/Foo.sol:Bar`
*/
_getFullyQualifiedNameFromPath(absolutePath) {
const sourceName = (0, source_names_1.replaceBackslashes)(path.relative(this._artifactsPath, path.dirname(absolutePath)));
const contractName = path.basename(absolutePath).replace(".json", "");
return (0, contract_names_1.getFullyQualifiedName)(sourceName, contractName);
}
/**
* Remove the artifact file and its debug file.
*/
async _removeArtifactFiles(artifactPath) {
await fs_extra_1.default.remove(artifactPath);
const debugFilePath = this._getDebugFilePath(artifactPath);
await fs_extra_1.default.remove(debugFilePath);
}
/**
* Given the path to a debug file, returns the absolute path to its
* corresponding build info file if it exists, or undefined otherwise.
*/
async _getBuildInfoFromDebugFile(debugFilePath) {
if (await fs_extra_1.default.pathExists(debugFilePath)) {
const { buildInfo } = await fs_extra_1.default.readJson(debugFilePath);
return path.resolve(path.dirname(debugFilePath), buildInfo);
}
return undefined;
}
/**
* Sync version of _getBuildInfoFromDebugFile
*/
_getBuildInfoFromDebugFileSync(debugFilePath) {
if (fs_extra_1.default.pathExistsSync(debugFilePath)) {
const { buildInfo } = fs_extra_1.default.readJsonSync(debugFilePath);
return path.resolve(path.dirname(debugFilePath), buildInfo);
}
return undefined;
}
_isArtifactPath(file) {
return (file.endsWith(".json") &&
file !== path.join(this._artifactsPath, "package.json") &&
!file.startsWith(path.join(this._artifactsPath, constants_1.BUILD_INFO_DIR_NAME)) &&
!file.endsWith(".dbg.json"));
}
}
exports.Artifacts = Artifacts;
/**
* Retrieves an artifact for the given `contractName` from the compilation output.
*
* @param sourceName The contract's source name.
* @param contractName the contract's name.
* @param contractOutput the contract's compilation output as emitted by `solc`.
*/
function getArtifactFromContractOutput(sourceName, contractName, contractOutput) {
const evmBytecode = contractOutput.evm?.bytecode;
let bytecode = evmBytecode?.object ?? "";
if (bytecode.slice(0, 2).toLowerCase() !== "0x") {
bytecode = `0x${bytecode}`;
}
const evmDeployedBytecode = contractOutput.evm?.deployedBytecode;
let deployedBytecode = evmDeployedBytecode?.object ?? "";
if (deployedBytecode.slice(0, 2).toLowerCase() !== "0x") {
deployedBytecode = `0x${deployedBytecode}`;
}
const linkReferences = evmBytecode?.linkReferences ?? {};
const deployedLinkReferences = evmDeployedBytecode?.linkReferences ?? {};
return {
_format: constants_1.ARTIFACT_FORMAT_VERSION,
contractName,
sourceName,
abi: contractOutput.abi,
bytecode,
deployedBytecode,
linkReferences,
deployedLinkReferences,
};
}
exports.getArtifactFromContractOutput = getArtifactFromContractOutput;
//# sourceMappingURL=artifacts.js.map