UNPKG

@tovarishfin/hardhat-yul

Version:

Hardhat plugin to develop smart contracts in Yul

192 lines (166 loc) 5.38 kB
import { Artifact, Artifacts, ProjectPathsConfig } from "hardhat/types"; import type { Artifacts as ArtifactsImpl } from "hardhat/internal/artifacts"; import { localPathToSourceName } from "hardhat/utils/source-names"; import path from "path"; import solc from "solc"; import yulp from "yulp"; import * as fs from "fs"; import { YulConfig } from "./types"; import util from "util"; export async function compileYul( _yulConfig: YulConfig, paths: ProjectPathsConfig, artifacts: Artifacts ) { const files = await getYulSources(paths); const allArtifacts = []; for (const file of files) { const cwdPath = path.relative(process.cwd(), file); console.log(`Compiling ${cwdPath}...`); const yulOutput = await _compileYul(cwdPath, file); const sourceName = await localPathToSourceName(paths.root, file); const artifact = getArtifactFromYulOutput(sourceName, yulOutput); await artifacts.saveArtifactAndDebugFile(artifact); allArtifacts.push({ ...artifact, artifacts: [artifact.contractName] }); const artifactsImpl = artifacts as ArtifactsImpl; artifactsImpl.addValidArtifacts(allArtifacts); } } export async function compileYulp( _yulConfig: YulConfig, paths: ProjectPathsConfig, artifacts: Artifacts ) { const files = await getYulpSources(paths); const allArtifacts = []; for (const file of files) { const cwdPath = path.relative(process.cwd(), file); console.log(`Compiling ${cwdPath}...`); const yulOutput = await _compileYulp(cwdPath, file); const sourceName = await localPathToSourceName(paths.root, file); const artifact = getArtifactFromYulOutput(sourceName, yulOutput); await artifacts.saveArtifactAndDebugFile(artifact); allArtifacts.push({ ...artifact, artifacts: [artifact.contractName] }); const artifactsImpl = artifacts as ArtifactsImpl; artifactsImpl.addValidArtifacts(allArtifacts); } } async function getYulSources(paths: ProjectPathsConfig) { const glob = await import("glob"); const yulFiles = glob.sync(path.join(paths.sources, "**", "*.yul")); return yulFiles; } async function getYulpSources(paths: ProjectPathsConfig) { const glob = await import("glob"); const yulpFiles = glob.sync(path.join(paths.sources, "**", "*.yulp")); return yulpFiles; } function pathToContractName(file: string) { const sourceName = path.basename(file); return sourceName.substring(0, sourceName.indexOf(".")); } function getArtifactFromYulOutput(sourceName: string, output: any): Artifact { const contractName = pathToContractName(sourceName); return { _format: "hh-sol-artifact-1", // sig"function add()" makes this work contractName, sourceName, abi: [], // FIXME: create a proper abi which will work with typechain etc... bytecode: output.bytecode, deployedBytecode: output.bytecode_runtime, linkReferences: {}, deployedLinkReferences: {}, }; } async function _compileYul(filepath: string, filename: string) { const data = fs.readFileSync(filepath, "utf8"); const output = JSON.parse( solc.compile( JSON.stringify({ language: "Yul", sources: { "Target.yul": { content: data } }, settings: { outputSelection: { "*": { "*": ["*"], "": ["*"] } }, optimizer: { enabled: true, runs: 0, details: { yul: true, }, }, }, }) ) ); if (output.errors && output.errors.length > 0) { throw new Error( `hardhat-yul: error compiling ${filename}: ${util.inspect( output, false, null, true )}` ); } const contractObjects = Object.keys(output.contracts["Target.yul"]); const bytecode = "0x" + output.contracts["Target.yul"][contractObjects[0]]["evm"]["bytecode"][ "object" ]; const contractCompiled = { _format: "hh-sol-artifact-1", sourceName: filename, abi: [], // needs to be an empty array to not cause issues with typechain bytecode: bytecode, }; return contractCompiled; } async function _compileYulp(filepath: string, filename: string) { const data = fs.readFileSync(filepath, "utf8"); const source = yulp.compile(data); const output = JSON.parse( solc.compile( JSON.stringify({ language: "Yul", sources: { "Target.yul": { content: yulp.print(source.results) } }, settings: { outputSelection: { "*": { "*": ["*"], "": ["*"] } }, optimizer: { enabled: true, runs: 0, details: { yul: true, }, }, }, }) ) ); if (output.errors && output.errors.length > 0) { throw new Error( `hardhat-yul: error compiling ${filename}: ${util.inspect( output, false, null, true )}` ); } const contractObjects = Object.keys(output.contracts["Target.yul"]); const bytecode = "0x" + output.contracts["Target.yul"][contractObjects[0]]["evm"]["bytecode"][ "object" ]; const abi = source.signatures .map((v: any) => v.abi.slice(4, -1)) .concat(source.topics.map((v: any) => v.abi.slice(6, -1))); const contractCompiled = { _format: "hh-sol-artifact-1", sourceName: filename, abi: abi, bytecode: bytecode, }; return contractCompiled; }