truffle
Version:
Truffle - Simple development framework for Ethereum
1,383 lines (1,215 loc) • 43.9 kB
JavaScript
exports.id = 7017;
exports.ids = [7017];
exports.modules = {
/***/ 74269:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
const debug = __webpack_require__(15158)("compile-vyper");
const path = __webpack_require__(71017);
const exec = (__webpack_require__(32081).exec);
const fs = __webpack_require__(57147);
const colors = __webpack_require__(83196);
const minimatch = __webpack_require__(91171);
const semver = __webpack_require__(81249);
const findContracts = __webpack_require__(23542);
const Config = __webpack_require__(20553);
const { Profiler } = __webpack_require__(76273);
const { requiredSources } = __webpack_require__(53377);
const { Compilations } = __webpack_require__(29833);
const { compileJson } = __webpack_require__(13919);
const VYPER_PATTERN_STRICT = "**/*.{vy,v.py,vyper.py}"; //no JSON
// Check that vyper is available, return its version
function checkVyper() {
return new Promise((resolve, reject) => {
exec("vyper-json --version", function (err, stdout, _stderr) {
if (err) {
//vyper-json not available, check vyper
exec("vyper --version", function (err, stdout, stderr) {
if (err) {
//error: neither vyper nor vyper-json available
return reject(`${colors.red("Error executing vyper:")}\n${stderr}`);
}
const version = normalizeVersion(stdout.trim());
if (
semver.satisfies(version, ">=0.2.5", {
loose: true,
includePrerelase: true
})
) {
//if version is >=0.2.5, we can still use JSON via
//vyper --standard-json
resolve({
version,
json: true,
jsonCommand: "vyper --standard-json"
});
} else {
//otherwise, we're stuck using vyper w/o JSON
resolve({ version, json: false });
}
});
} else {
//no error: vyper-json is available
const version = normalizeVersion(stdout.trim());
resolve({ version, json: true, jsonCommand: "vyper-json" });
}
});
});
}
//HACK: alters prerelease versions so semver can understand them
function normalizeVersion(version) {
return version.replace(/^(\d+\.\d+\.\d+)b(\d+)/, "$1-beta.$2");
}
// Execute vyper for single source file
function execVyper(options, sourcePath, version, callback) {
const formats = ["abi", "bytecode", "bytecode_runtime"];
debug("version: %s", version);
if (
semver.satisfies(version, ">=0.1.0-beta.7", {
loose: true,
includePrerelase: true
})
) {
//Vyper chokes on unknown formats, so only include this for
//ones that support it (they were introduced in 0.1.0b7)
formats.push("source_map");
}
let evmVersionOption = "";
if (
options.compilers.vyper.settings &&
options.compilers.vyper.settings.evmVersion
) {
const evmVersion = options.compilers.vyper.settings.evmVersion;
if (evmVersion.includes("'")) {
throw new Error("Invalid EVM version");
}
evmVersionOption = `--evm-version '${evmVersion}'`;
}
if (options.contracts_directory.includes("'")) {
throw new Error("Contracts directory contains apostrophe");
}
const command = `vyper -f ${formats.join(
","
)} ${evmVersionOption} ${sourcePath} -p '${options.contracts_directory}'`;
exec(command, { maxBuffer: 600 * 1024 }, function (err, stdout, stderr) {
if (err)
return callback(
`${stderr}\n${colors.red(
`Compilation of ${sourcePath} failed. See above.`
)}`
);
var outputs = stdout.split(/\r?\n/);
debug("formats: %O", formats);
debug("outputs: %O", outputs);
const compiledContract = outputs.reduce((contract, output, index) => {
return Object.assign(contract, { [formats[index]]: output });
}, {});
callback(null, compiledContract);
});
}
/**
*
* read source contents from sourcePath
*/
function readSource(sourcePath) {
const sourceBuffer = fs.readFileSync(sourcePath);
return sourceBuffer.toString();
}
/**
* aggregate source information based on compiled output;
* this can include sources that are not contracts
*/
//note: this takes paths, rather than full source objects like compileJson!
async function compileNoJson({ paths: sources, options, version }) {
const compiler = { name: "vyper", version };
const promises = [];
const properSources = sources.filter(source => !source.endsWith(".json")); //filter out JSON interfaces
const targets = options.compilationTargets
? properSources.filter(sourcePath =>
options.compilationTargets.includes(sourcePath)
)
: properSources;
targets.forEach(sourcePath => {
promises.push(
new Promise((resolve, reject) => {
execVyper(
options,
sourcePath,
version,
function (error, compiledContract) {
if (error) return reject(error);
debug("compiledContract: %O", compiledContract);
// remove first extension from filename
const extension = path.extname(sourcePath);
const basename = path.basename(sourcePath, extension);
// if extension is .py, remove second extension from filename
const contractName =
extension !== ".py"
? basename
: path.basename(basename, path.extname(basename));
const sourceContents = readSource(sourcePath);
const deployedSourceMap = compiledContract.source_map //there is no constructor source map
? JSON.parse(compiledContract.source_map)
: undefined;
const contractDefinition = {
contractName: contractName,
sourcePath: sourcePath,
source: sourceContents,
abi: JSON.parse(compiledContract.abi),
bytecode: {
bytes: compiledContract.bytecode.slice(2), //remove "0x" prefix
linkReferences: [] //no libraries in Vyper
},
deployedBytecode: {
bytes: compiledContract.bytecode_runtime.slice(2), //remove "0x" prefix
linkReferences: [] //no libraries in Vyper
},
deployedSourceMap,
compiler
};
const compilation = {
sources: [
{
sourcePath,
contents: sourceContents,
language: "Vyper"
}
],
contracts: [contractDefinition],
compiler,
sourceIndexes: [sourcePath]
};
resolve(compilation);
}
);
})
);
});
const compilations = await Promise.all(promises);
return Compilations.promoteCompileResult({ compilations });
}
const Compile = {
// Check that vyper is available then forward to internal compile function
async sources({ sources = {}, options }) {
options = Config.default().merge(options);
const paths = Object.keys(sources);
const vyperFiles = paths.filter(path =>
minimatch(path, VYPER_PATTERN_STRICT, { dot: true })
);
// no vyper files found, no need to check vyper
// (note that JSON-only will not activate vyper)
if (vyperFiles.length === 0) {
return Compilations.emptyWorkflowCompileResult();
}
Compile.display(vyperFiles, options);
const { version, json: useJson, jsonCommand } = await checkVyper();
if (!useJson) {
//it might be possible to handle this case by writing the sources
//to a temporary directory (and possibly using some sort of remapping--
//a manual one I mean, Vyper doesn't have remappings),
//but for now I'll just have it throw for simplicity
throw new Error("Compiling literal Vyper sources requires vyper-json");
}
return compileJson({ sources, options, version, command: jsonCommand });
},
async sourcesWithDependencies({ paths = [], options }) {
options = Config.default().merge(options);
debug("paths: %O", paths);
const vyperFilesStrict = paths.filter(path =>
minimatch(path, VYPER_PATTERN_STRICT, { dot: true })
);
debug("vyperFilesStrict: %O", vyperFilesStrict);
// no vyper targets found, no need to check Vyper
if (vyperFilesStrict.length === 0) {
return Compilations.emptyWorkflowCompileResult();
}
const { allSources, compilationTargets } = await requiredSources(
options.with({
paths: vyperFilesStrict,
base_path: options.contracts_directory,
compiler: {
name: "vyper"
//HACK: we leave version empty because we haven't determined
//it at this point and we don't want to pay the cost of doing
//so, and nothing in the resolver sources currently uses
//precise vyper version
}
})
);
debug("allSources: %O", allSources);
debug("compilationTargets: %O", compilationTargets);
const vyperTargets = compilationTargets.filter(path =>
minimatch(path, VYPER_PATTERN_STRICT, { dot: true })
);
// no vyper targets found, no need to activate Vyper
if (vyperTargets.length === 0) {
return Compilations.emptyWorkflowCompileResult();
}
//having gotten the sources from the resolver, we invoke compileJson
//ourselves, rather than going through Compile.sources()
Compile.display(compilationTargets, options);
const { version, json: useJson, jsonCommand } = await checkVyper();
if (useJson) {
return compileJson({
sources: allSources,
options: options.with({
compilationTargets
}),
version,
command: jsonCommand
});
} else {
return await compileNoJson({
paths: Object.keys(allSources),
options: options.with({
compilationTargets
}),
version
});
}
},
// contracts_directory: String. Directory where contract files can be found.
// quiet: Boolean. Suppress output. Defaults to false.
// strict: Boolean. Return compiler warnings as errors. Defaults to false.
async all(options) {
options = Config.default().merge(options);
const files = await findContracts(options.contracts_directory);
const vyperFilesStrict = files.filter(path =>
minimatch(path, VYPER_PATTERN_STRICT, { dot: true })
);
// no vyper targets found, no need to check Vyper
if (vyperFilesStrict.length === 0) {
return Compilations.emptyWorkflowCompileResult();
}
return await Compile.sourcesWithDependencies({
paths: files,
options
});
},
// contracts_directory: String. Directory where contract files can be found.
// all: Boolean. Compile all sources found. Defaults to true. If false, will compare sources against built files
// in the build directory to see what needs to be compiled.
// quiet: Boolean. Suppress output. Defaults to false.
// strict: Boolean. Return compiler warnings as errors. Defaults to false.
async necessary(options) {
options = Config.default().merge(options);
const profiler = await new Profiler({});
const updated = await profiler.updated(options);
if (updated.length === 0) {
return Compilations.emptyWorkflowCompileResult();
}
return await Compile.sourcesWithDependencies({
paths: updated,
options
});
},
async display(paths, options) {
if (options.quiet !== true) {
if (!Array.isArray(paths)) {
paths = Object.keys(paths);
}
const sourceFileNames = paths.sort().map(contract => {
if (path.isAbsolute(contract)) {
return `.${path.sep}${path.relative(
options.working_directory,
contract
)}`;
}
return contract;
});
options.events.emit("compile:sourcesToCompile", { sourceFileNames });
}
}
};
module.exports = {
Compile
};
/***/ }),
/***/ 87359:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
const debug = __webpack_require__(15158)("compile-vyper:parser");
const OS = __webpack_require__(22037);
function parseImports(body) {
// WARNING: We're going to do this crudely with regexes!!
//
// Vyper has a rigid enough syntax that I think this is workable.
//
// We can't use the Solidity approach here of analyzing error messages
// because the Vyper compiler will only provide an error for the *first*
// failing import, not all of them.
// (before we do all that, though, we'll try parsing as JSON
// and return no imports if it parses, in case this gets passed
// a JSON file!)
try {
JSON.parse(body);
debug("was JSON, no imports");
return []; //if we reach this point it was a JSON file
} catch (_) {
//it was Vyper, proceed onward
}
const stripWhitespace = str => str.replace(/\s/g, ""); //remove even internal whitespace
//HACK: this isn't actually a correct way of handling line
//extensions and comments... but it should be good enough
//for our purposes! I can't think of any cases that this
//gets wrong *in a way that we care about*
return (
body
.replace(/(#.*)\\\r?\n/g, "$1") //remove backslashes from end of comments
// (this is the most-incorrect step; it will detect a "comment" even if
// the # is used in a string literal. but this shouldn't screw up imports,
// so...)
.replace(/\\\r?\n/g, " ") //process line extensions;
//for convenience we use \r?\n instead of OS.EOL
//(we don't care that this screws up string literals)
.split(OS.EOL) //split body into lines
.map(line => {
//extract imports!
const importRegex = /^import\b(.*?)\bas\b/;
const fromImportRegex = /^from\b(.*?)\bimport\b(.*?)($|\bas\b)/;
let matches;
if ((matches = line.match(importRegex))) {
const [_, path] = matches;
return stripWhitespace(path);
} else if ((matches = line.match(fromImportRegex))) {
const [_, basePath, endPath] = matches;
debug("basePath: %s; endPath: %s", basePath, endPath);
const strippedBasePath = stripWhitespace(basePath);
if (strippedBasePath === "vyper.interfaces") {
//built-in import; we should not attempt to resolve it
return null;
}
const strippedEndPath = stripWhitespace(endPath);
return strippedBasePath.endsWith(".")
? `${strippedBasePath}${strippedEndPath}` //don't add extra "." for "from . import", etc
: `${strippedBasePath}.${strippedEndPath}`;
//on the endPath because
} else {
return null;
}
})
.filter(moduleName => moduleName !== null)
);
}
module.exports = {
parseImports
};
/***/ }),
/***/ 53377:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
const debug = __webpack_require__(15158)("compile-vyper:profiler");
const { Profiler } = __webpack_require__(76273);
const { Resolver } = __webpack_require__(48511);
const { parseImports } = __webpack_require__(87359);
// Returns the minimal set of sources to pass to vyper-json as compilations targets,
// as well as the complete set of sources so vyper-json can resolve the comp targets' imports.
async function requiredSources(options) {
const resolver = new Resolver(options);
debug("resolver.sources.length: %d", resolver.sources.length);
// generate profiler
const profiler = new Profiler({
parseImports,
shouldIncludePath
});
// invoke profiler
debug("invoking profiler");
return await profiler.requiredSources(options.with({ resolver }));
}
function shouldIncludePath(path) {
return path.match(/\.(vy|json|v\.py|vyper\.py)$/) !== null;
}
module.exports = {
requiredSources
};
/***/ }),
/***/ 13919:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
const debug = __webpack_require__(15158)("compile-vyper:vyper-json");
const execSync = (__webpack_require__(32081).execSync);
const path = __webpack_require__(71017);
const semver = __webpack_require__(81249);
const Common = __webpack_require__(29833);
const partition = __webpack_require__(43174);
//NOTE: this file has a fair bit of copypaste-with-modifications
//from compile-solidity/run.js, so be warned...
//(some has since been factored into compile-common, but not all)
function compileJson({ sources: rawSources, options, version, command }) {
const compiler = { name: "vyper", version };
//in order to better support absolute Vyper imports, we pretend that
//the contracts directory is the root directory. note this means that
//if an imported source from somewhere other than FS uses an absolute
//import to refer to its own project root, it won't work. But, oh well.
const { sources, targets, originalSourcePaths } =
Common.Sources.collectSources(
rawSources,
options.compilationTargets,
options.contracts_directory
);
//Vyper complains if we give it a source that is not also a target,
//*unless* we give it as an interface. So we have to split that out.
//(JSON files also must always be interfaces)
const [properSourcePaths, interfacePaths] = partition(
Object.keys(sources),
targets.length > 0
? sourcePath =>
!sourcePath.endsWith(".json") && targets.includes(sourcePath)
: sourcePath => !sourcePath.endsWith(".json")
);
const properSources = Object.assign(
{},
...properSourcePaths.map(sourcePath => ({
[sourcePath]: sources[sourcePath]
}))
);
const interfaces = Object.assign(
{},
...interfacePaths.map(sourcePath => ({
[sourcePath]: sources[sourcePath]
}))
);
// construct compiler input
const compilerInput = prepareCompilerInput({
sources: properSources,
interfaces,
settings: options.compilers.vyper.settings || {},
version
});
// perform compilation
const rawCompilerOutput = invokeCompiler({
compilerInput,
command
});
debug("rawCompilerOutput: %O", rawCompilerOutput);
// handle warnings as errors if options.strict
// log if not options.quiet
const { warnings, errors } = detectErrors({
compilerOutput: rawCompilerOutput,
options
});
if (warnings.length > 0) {
options.events.emit("compile:warnings", { warnings });
}
if (errors.length > 0) {
if (!options.quiet) {
options.logger.log("");
}
throw new Common.Errors.CompileError(errors);
}
const compilerOutput = correctPaths(rawCompilerOutput);
const outputSources = processAllSources({
sources,
compilerOutput,
originalSourcePaths
});
const sourceIndexes = outputSources.map(source => source.sourcePath);
const compilation = {
sourceIndexes,
contracts: processContracts({
sources,
compilerOutput,
version,
originalSourcePaths
}),
sources: outputSources,
compiler
};
return Common.Compilations.promoteCompileResult({
compilations: [compilation]
});
}
function invokeCompiler({ compilerInput, command }) {
const inputString = JSON.stringify(compilerInput);
const outputString = execVyperJson(inputString, command);
return JSON.parse(outputString);
}
function execVyperJson(inputString, command) {
return execSync(command, {
input: inputString,
maxBuffer: 1024 * 1024 * 10 //I guess?? copied from compile-solidity
});
}
function prepareCompilerInput({ sources, settings, interfaces, version }) {
const outputSelection = prepareOutputSelection({ version });
return {
language: "Vyper",
sources: prepareSources({ sources }),
interfaces: prepareInterfaces({ interfaces }),
settings: {
...settings,
outputSelection
},
//older versions of vyper require outputSelection *outside* of settings.
//we'll put it in both places for compatibility.
outputSelection
};
}
function prepareSources({ sources }) {
return Object.entries(sources)
.map(([sourcePath, content]) => ({ [sourcePath]: { content } }))
.reduce((a, b) => Object.assign({}, a, b), {});
}
function prepareInterfaces({ interfaces }) {
return Object.entries(interfaces)
.map(([sourcePath, content]) =>
sourcePath.endsWith(".json") //for JSON we need the ABI *object*, not JSON!
? { [sourcePath]: { abi: JSON.parse(content) } }
: { [sourcePath]: { content } }
)
.reduce((a, b) => Object.assign({}, a, b), {});
}
function prepareOutputSelection({ version }) {
//Vyper uses a simpler output selection format
//than solc does; it also supports solc's format,
//but I've gone with the simpler version here
let defaultSelectors = [
"abi",
"ast",
"evm.bytecode.object",
//we have to omit sourceMap here, as annoyingly,
//Vyper errors if you give it a not-yet-supported output selection...
"evm.deployedBytecode.object",
"evm.deployedBytecode.sourceMap"
];
if (
semver.satisfies(version, ">=0.1.0-beta.17", {
loose: true,
includePrerelase: true
})
) {
//again, due to Vyper erroring if you ask for output it doesn't know about,
//we have to only add these to the output if we're on a sufficiently recent
//version
const additionalSelectors = ["userdoc", "devdoc"];
defaultSelectors = defaultSelectors.concat(additionalSelectors);
}
//because we've already filtered down the sources to match the targets,
//we can just say that the targets are everything
return {
"*": defaultSelectors
};
}
//this also is copy-pasted, but minus some complications
function detectErrors({ compilerOutput: { errors: outputErrors }, options }) {
outputErrors = outputErrors || [];
const rawErrors = options.strict
? outputErrors
: outputErrors.filter(({ severity }) => severity !== "warning");
const rawWarnings = options.strict
? [] // none of those in strict mode
: outputErrors.filter(({ severity }) => severity === "warning");
// extract messages
// NOTE: sufficiently old Vyper versions don't have formattedMessage, so we use message
// instead in those cases
let errors = rawErrors
.map(({ formattedMessage, message }) => formattedMessage || message)
.join();
const warnings = rawWarnings.map(
({ formattedMessage, message }) => formattedMessage || message
);
return { warnings, errors };
}
//warning: copypaste
function processAllSources({ sources, compilerOutput, originalSourcePaths }) {
if (!compilerOutput.sources) return [];
let outputSources = [];
for (const [sourcePath, { id, ast }] of Object.entries(
compilerOutput.sources
)) {
outputSources[id] = {
sourcePath: originalSourcePaths[sourcePath],
contents: sources[sourcePath],
ast,
language: "Vyper"
};
}
return outputSources;
}
function processContracts({
compilerOutput,
sources,
version,
originalSourcePaths
}) {
if (!compilerOutput.contracts) return [];
return (
Object.entries(compilerOutput.contracts)
// map to [[{ source, contractName, contract }]]
.map(([sourcePath, sourceContracts]) =>
Object.entries(sourceContracts).map(([contractName, contract]) => ({
// if extension is .py, remove second extension from contract name (HACK)
contractName:
path.extname(sourcePath) !== ".py"
? contractName
: path.basename(contractName, path.extname(contractName)),
contract,
source: {
ast: compilerOutput.sources[sourcePath].ast,
contents: sources[sourcePath],
sourcePath
}
}))
)
// and flatten
.reduce((a, b) => [...a, ...b], [])
// All source will have a key, but only the compiled source will have
// the evm output.
.filter(({ contract: { evm } }) => Object.keys(evm).length > 0)
// convert to output format
.map(
({
contractName,
contract: {
evm: {
bytecode: { object: bytecode },
deployedBytecode: {
sourceMap: deployedSourceMap,
object: deployedBytecode
}
},
abi,
devdoc,
userdoc
},
source: { ast, sourcePath: transformedSourcePath, contents: source }
}) => ({
contractName,
abi,
devdoc,
userdoc,
sourcePath: originalSourcePaths[transformedSourcePath],
source,
deployedSourceMap,
ast,
bytecode: {
bytes: bytecode.slice(2), //Vyper uses a "0x" prefix
linkReferences: [] //no libraries in Vyper
},
deployedBytecode: {
bytes: deployedBytecode.slice(2), //Vyper uses a "0x" prefix
linkReferences: [] //no libraries in Vyper
},
compiler: {
name: "vyper",
version
}
})
)
);
}
function correctPaths(compilerOutput) {
return {
compiler: compilerOutput.compiler,
errors: compilerOutput.errors,
sources: fixKeys(compilerOutput.sources),
contracts: fixKeys(compilerOutput.contracts)
};
}
function fixKeys(pathKeyedObject) {
return Object.assign(
{},
...Object.entries(pathKeyedObject).map(([key, value]) => ({
[fixPath(key)]: value
}))
);
}
function fixPath(path) {
if (path[0] === "/") {
return path;
} else {
return "/" + path;
}
}
module.exports = {
compileJson,
execVyperJson
};
/***/ }),
/***/ 96412:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
;
const debug = __webpack_require__(15158)("external-compile");
const { exec, execSync } = __webpack_require__(32081);
const resolve = (__webpack_require__(71017).resolve);
const { promisify } = __webpack_require__(73837);
const glob = promisify(__webpack_require__(12884));
const fs = __webpack_require__(57147);
const expect = __webpack_require__(14096);
const Schema = __webpack_require__(67078);
const web3Utils = __webpack_require__(18269);
const { Shims, Compilations } = __webpack_require__(29833);
const Config = __webpack_require__(20553);
const DEFAULT_ABI = [
{
payable: true,
stateMutability: "payable",
type: "fallback"
}
];
/**
* buffer a line of data, yielding each full line
*
* returned generator alternates between two states:
* 1. reset
* 2. read/write
*
* usage:
*
* let gen = bufferLines();
*
* // first reset
* gen.next(); // reset
*
* // pass string data with zero or more new lines
* // or pass `null` to signal EOF
* let { value, done } = gen.next(data);
*
* // if done, value possibly contains string value with unterminated output
* // otherwise, value contains any/all complete lines
*/
function* bufferLines() {
let buffer = [];
while (true) {
// read input string or null as eof
const input = yield;
// eof returns buffer
if (input == null) {
const unterminated = buffer.join("");
return unterminated ? [`${unterminated}%`] : [];
}
// split lines
// last element is always partial line
const data = input.split("\n");
// add first element to buffer
let [first] = data.slice(0);
buffer.push(first);
if (data.length > 1) {
// split off partial line to save as new buffer
const [last] = data.slice(-1);
const [...middle] = data.slice(1, -1);
// use buffer as first element (now complete line)
// and yield all complete lines
const lines = [buffer.join(""), ...middle];
yield lines;
// reset buffer
buffer = [last];
} else {
// nothing to see yet
yield [];
}
}
}
/**
* run a command, forwarding data to arbitrary logger.
* invokes callback when process exits, error on nonzero exit code.
*/
const runCommand = promisify(function (command, options, callback) {
const { cwd, logger, input } = options;
const child = exec(command, { cwd, input });
// wrap buffer generator for easy use
const buffer = func => {
const gen = bufferLines();
return data => {
gen.next();
let { value: lines } = gen.next(data);
for (let line of lines) {
func(line);
}
};
};
const log = buffer(logger.log);
const warn = buffer(logger.warn || logger.log);
child.stdout.on("data", data => log(data.toString()));
child.stderr.on("data", data => warn(data.toString()));
child.on("close", function (code) {
// close streams to flush unterminated lines
log(null);
warn(null);
// If the command didn't exit properly, show the output and throw.
if (code !== 0) {
var err = new Error("Unknown exit code: " + code);
return callback(err);
}
callback();
});
});
/**
* identify and process contents as one of:
* 1. JSON literal
* 2. Hex string
* 3. Raw binary data
*/
function decodeContents(contents) {
// JSON
try {
return JSON.parse(contents);
} catch (e) {
/* no-op */
}
// hex string
if (contents.toString().startsWith("0x")) {
return contents.toString();
}
// raw binary
return web3Utils.bytesToHex(contents);
}
async function processTargets(targets, cwd, logger) {
const contracts = [];
for (let target of targets) {
let targetContracts = await processTarget(target, cwd, logger);
for (let contract of Object.values(targetContracts)) {
contracts.push(Schema.validate(contract));
}
}
return contracts;
}
async function processTarget(target, cwd, logger) {
const usesPath = target.path != undefined;
const usesCommand = target.command != undefined;
const usesStdin = target.stdin || target.stdin == undefined; // default true
const usesProperties = target.properties || target.fileProperties;
if (usesProperties && usesPath) {
throw new Error(
"External compilation target cannot define both properties and path"
);
}
if (usesProperties && usesCommand) {
throw new Error(
"External compilation target cannot define both properties and command"
);
}
if (usesCommand && !usesPath) {
// just run command
const output = execSync(target.command, { cwd });
const contract = JSON.parse(output);
return { [contract.contractName]: contract };
}
if (usesPath && !glob.hasMagic(target.path)) {
// individual file
const filename = resolve(cwd, target.path);
let input, command, execOptions;
if (usesStdin) {
input = fs.readFileSync(filename).toString();
command = target.command;
execOptions = { cwd, input };
} else {
command = `${target.command} ${filename}`;
execOptions = { cwd };
}
const output = usesCommand ? execSync(command, execOptions) : input;
const contract = JSON.parse(output);
return { [contract.contractName]: contract };
}
if (usesPath && glob.hasMagic(target.path)) {
// glob expression, recurse after expansion
let paths = await glob(target.path, { cwd, follow: true });
// copy target properties, overriding path with expanded form
let targets = paths.map(path => Object.assign({}, target, { path }));
return await processTargets(targets, cwd, logger);
}
if (usesProperties) {
// contract properties listed individually
const contract = Object.assign({}, target.properties || {});
for (let [key, path] of Object.entries(target.fileProperties || {})) {
const contents = fs.readFileSync(resolve(cwd, path));
const value = decodeContents(contents);
contract[key] = value;
}
if (!contract.contractName) {
throw new Error("External compilation target must specify contractName");
}
if (!contract.abi) {
contract.abi = DEFAULT_ABI;
}
if (!contract.bytecode && logger) {
logger.log(
"Warning: contract " +
contract.contractName +
" does not specify bytecode. You won't be able to deploy it."
);
}
return { [contract.contractName]: contract };
}
}
const Compile = {
async all(options) {
return await Compile.sources({
// currently you cannot specify sources here
sources: undefined,
options
});
},
async necessary(options) {
return await Compile.sources({
// currently you cannot specify sources here
sources: undefined,
options
});
},
// compile-common defines object argument to include `sources`, but this is
// unused as the user is responsible for dealing with compiling their sources
async sources({ options }) {
options = Config.default().merge(options);
if (options.logger == null) {
options.logger = console;
}
expect.options(options, ["compilers"]);
expect.options(options.compilers, ["external"]);
expect.options(options.compilers.external, ["command", "targets"]);
const { command, targets } = options.compilers.external;
const cwd =
options.compilers.external.workingDirectory ||
options.compilers.external.working_directory || // just in case
options.working_directory;
const logger = options.logger;
debug("running compile command: %s", command);
await runCommand(command, { cwd, logger });
const contracts = await processTargets(targets, cwd, logger);
const compilations = [
{
contracts: contracts.map(Shims.LegacyToNew.forContract),
// sourceIndexes is empty because we have no way of
// knowing for certain the source paths for the contracts
sourceIndexes: [],
// since we don't know the sourcePaths, we can't really provide
// the source info reliably
sources: [],
compiler: {
name: "external",
version: undefined
}
}
];
return Compilations.promoteCompileResult({ compilations });
},
async sourcesWithDependencies({ options }) {
return await Compile.sources({ options });
}
};
module.exports = {
Compile,
DEFAULT_ABI,
processTarget
};
/***/ }),
/***/ 37017:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const debug_1 = __importDefault(__webpack_require__(15158));
const debug = (0, debug_1.default)("workflow-compile");
const fs_extra_1 = __importDefault(__webpack_require__(55674));
const utils_1 = __webpack_require__(80404);
const compile_common_1 = __webpack_require__(29833);
const db_loader_1 = __webpack_require__(70972);
const SUPPORTED_COMPILERS = {
solc: (__webpack_require__(4273).Compile),
vyper: (__webpack_require__(74269).Compile),
external: (__webpack_require__(96412).Compile)
};
function compile(config) {
return __awaiter(this, void 0, void 0, function* () {
// determine compiler(s) to use
const compilers = config.compiler
? config.compiler === "none"
? []
: [config.compiler]
: Object.keys(config.compilers);
// invoke compilers
const rawCompilations = yield Promise.all(compilers.map((name) => __awaiter(this, void 0, void 0, function* () {
const Compile = SUPPORTED_COMPILERS[name];
if (!Compile)
throw new Error("Unsupported compiler: " + name);
if (config.all === true || config.compileAll === true) {
return yield Compile.all(config);
}
else if (Array.isArray(config.paths) && config.paths.length > 0) {
// compile only user specified sources
return yield Compile.sourcesWithDependencies({
options: config,
paths: config.paths
});
}
else {
return yield Compile.necessary(config);
}
})));
// collect results - rawCompilations is CompilerResult[]
// flatten the array and remove compilations without results
const compilations = rawCompilations.reduce((a, compilerResult) => {
compilerResult.compilations.forEach((compilation) => {
if (compilation.contracts.length > 0) {
a = a.concat(compilation);
}
});
return a;
}, []);
// collect together contracts as well as compilations
const contracts = rawCompilations.flatMap(compilerResult => compilerResult.contracts);
// return WorkflowCompileResult
return { contracts, compilations };
});
}
exports["default"] = {
compile(options) {
return __awaiter(this, void 0, void 0, function* () {
const config = (0, utils_1.prepareConfig)(options);
if (config.events)
config.events.emit("compile:start");
const { contracts, compilations } = yield compile(config);
const compilers = compilations
.reduce((a, compilation) => {
return a.concat(compilation.compiler);
}, [])
.filter(compiler => compiler);
if (contracts.length === 0 && config.events) {
if (config.compileNone || config["compile-none"]) {
config.events.emit("compile:skipped");
}
else {
config.events.emit("compile:nothingToCompile");
}
}
const result = { contracts, compilations };
if (config.events) {
yield config.events.emit("compile:succeed", {
contractsBuildDirectory: config.contracts_build_directory,
compilers,
result
});
}
return result;
});
},
compileAndSave(options) {
return __awaiter(this, void 0, void 0, function* () {
const { contracts, compilations } = yield this.compile(options);
return yield this.save(options, { contracts, compilations });
});
},
save(options, { contracts, compilations }) {
return __awaiter(this, void 0, void 0, function* () {
const config = (0, utils_1.prepareConfig)(options);
yield fs_extra_1.default.ensureDir(config.contracts_build_directory);
if (options.db && options.db.enabled === true && contracts.length > 0) {
// currently if Truffle Db fails to load, getTruffleDb returns `null`
const Db = (0, db_loader_1.getTruffleDb)();
if (Db) {
debug("saving to @truffle/db");
const db = Db.connect(config.db);
const project = yield Db.Project.initialize({
db,
project: {
directory: config.working_directory
}
});
({ contracts, compilations } = yield project.loadCompile({
result: { contracts, compilations }
}));
}
}
const artifacts = contracts.map(compile_common_1.Shims.NewToLegacy.forContract);
yield config.artifactor.saveAll(artifacts);
return { contracts, compilations };
});
},
assignNames(options, { contracts }) {
return __awaiter(this, void 0, void 0, function* () {
// currently if Truffle Db fails to load, getTruffleDb returns `null`
const Db = (0, db_loader_1.getTruffleDb)();
const config = (0, utils_1.prepareConfig)(options);
if (!Db || !config.db || !config.db.enabled || contracts.length === 0) {
return;
}
const db = Db.connect(config.db);
const project = yield Db.Project.initialize({
db,
project: {
directory: config.working_directory
}
});
yield project.assignNames({
assignments: {
contracts: contracts.map(({ db: { contract } }) => contract)
}
});
});
}
};
//# sourceMappingURL=index.js.map
/***/ }),
/***/ 80404:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
;
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.multiPromisify = exports.prepareConfig = void 0;
const config_1 = __importDefault(__webpack_require__(20553));
const expect = __importStar(__webpack_require__(14096));
const resolver_1 = __webpack_require__(48511);
const artifactor_1 = __importDefault(__webpack_require__(29463));
function prepareConfig(options) {
expect.options(options, ["contracts_build_directory"]);
expect.one(options, ["contracts_directory", "files"]);
// Use a config object to ensure we get the default sources.
const config = config_1.default.default().merge(options);
config.compilersInfo = {};
if (!config.resolver)
config.resolver = new resolver_1.Resolver(config);
if (!config.artifactor) {
config.artifactor = new artifactor_1.default(config.contracts_build_directory);
}
return config;
}
exports.prepareConfig = prepareConfig;
function multiPromisify(func) {
return (...args) => new Promise((accept, reject) => {
const callback = (err, ...results) => {
if (err)
reject(err);
accept(results);
};
func(...args, callback);
});
}
exports.multiPromisify = multiPromisify;
//# sourceMappingURL=utils.js.map
/***/ })
};
;
//# sourceMappingURL=7017.bundled.js.map