This repository has been archived by the owner on Feb 26, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Draft basics of Hardhat compatibility
The idea being to expose, roughly: - detectHardhat() - to performantly check if it's a Hardhat project - prepareConfig() - to produce a TruffleConfig with networks - prepareCompilation() - to get the good stuff
- Loading branch information
Showing
6 changed files
with
731 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
dist | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
{ | ||
"name": "@truffle/from-hardhat", | ||
"description": "Import Hardhat project information into Truffle-native formats", | ||
"license": "MIT", | ||
"author": "g. nicholas d'andrea <gnidan@trufflesuite.com>", | ||
"homepage": "https://github.com/trufflesuite/truffle/tree/master/packages/from-hardhat#readme", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/trufflesuite/truffle.git", | ||
"directory": "packages/from-hardhat" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/trufflesuite/truffle/issues" | ||
}, | ||
"version": "0.1.0-0", | ||
"main": "dist/src/index.js", | ||
"scripts": { | ||
"build": "ttsc", | ||
"prepare": "yarn build", | ||
"test": "exit 0" | ||
}, | ||
"dependencies": { | ||
"@truffle/compile-common": "^0.7.32", | ||
"@truffle/compile-solidity": "^6.0.38", | ||
"@truffle/config": "^1.3.34", | ||
"debug": "^4.3.1", | ||
"find-up": "^2.1.0" | ||
}, | ||
"devDependencies": { | ||
"@types/find-up": "^2.1.0", | ||
"@types/node": "^18.6.5", | ||
"hardhat": "^2.10.1", | ||
"ttypescript": "1.5.13", | ||
"typescript": "^4.3.5", | ||
"typescript-transform-paths": "3.3.1" | ||
}, | ||
"keywords": [ | ||
"compile", | ||
"ethereum", | ||
"solidity", | ||
"truffle" | ||
], | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"babel": { | ||
"presets": [ | ||
"env" | ||
] | ||
}, | ||
"gitHead": "6b84be7849142588ef2e3224d8a9d7c2ceeb6e4a" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import type * as Hardhat from "hardhat/types"; | ||
import type * as Common from "@truffle/compile-common"; | ||
import findUp from "find-up"; | ||
import Config from "@truffle/config"; | ||
import { spawn } from "child_process"; | ||
import { promises as fs } from "fs"; | ||
|
||
import { buildInfoCompilation } from "./shims"; | ||
|
||
const validHardhatConfigFilenames = ["hardhat.config.js", "hardhat.config.ts"]; | ||
|
||
// import type * as Hardhat from "hardhat"; | ||
|
||
export async function detectHardhat(): Promise<boolean> { | ||
// search recursively up for a hardhat config | ||
const hardhatConfigPath = await findUp(validHardhatConfigFilenames); | ||
|
||
return !!hardhatConfigPath; | ||
} | ||
|
||
export async function prepareConfig(): Promise<Config> { | ||
const config = Config.default(); | ||
|
||
const networks = (await askHardhatConsole( | ||
`hre.config.networks` | ||
)) as Hardhat.NetworksUserConfig; | ||
|
||
for (const [networkName, networkConfig] of Object.entries(networks)) { | ||
if (networkName === "hardhat") { | ||
continue; | ||
} | ||
|
||
if (networkConfig && "url" in networkConfig) { | ||
const { url } = networkConfig; | ||
config.networks[networkName] = { | ||
url, | ||
network_id: "*" | ||
}; | ||
} | ||
} | ||
|
||
return config; | ||
} | ||
|
||
export async function prepareCompilations(): Promise<Common.Compilation[]> { | ||
const compilations = []; | ||
|
||
const buildInfoPaths = (await askHardhatConsole( | ||
`artifacts.getBuildInfoPaths()` | ||
)) as string[]; | ||
|
||
for (const buildInfoPath of buildInfoPaths) { | ||
const buildInfo: Hardhat.BuildInfo = JSON.parse( | ||
(await fs.readFile(buildInfoPath)).toString() | ||
); | ||
|
||
const compilation = buildInfoCompilation(buildInfo); | ||
|
||
compilations.push(compilation); | ||
} | ||
|
||
return compilations; | ||
} | ||
|
||
interface AskHardhatConsoleOptions { | ||
// turn off json stringify/parse | ||
raw?: boolean; | ||
} | ||
|
||
async function askHardhatConsole( | ||
expression: string, | ||
options: AskHardhatConsoleOptions = {} | ||
): Promise<string | unknown> { | ||
const { raw = false } = options; | ||
|
||
return new Promise((accept, reject) => { | ||
const hardhat = spawn(`npx`, ["hardhat", "console"], { | ||
stdio: ["pipe", "pipe", "inherit"] | ||
}); | ||
|
||
// we'll capture the stdout | ||
let output = ""; | ||
hardhat.stdout.on("data", data => { | ||
output = `${output}${data}`; | ||
}); | ||
|
||
// setup close event before writing to stdin because we're sending eof | ||
hardhat.on("close", code => { | ||
if (code !== 0) { | ||
return reject(new Error(`Hardhat exited with non-zero code ${code}`)); | ||
} | ||
|
||
if (raw) { | ||
return accept(output); | ||
} | ||
|
||
try { | ||
return accept(JSON.parse(output)); | ||
} catch (error) { | ||
return reject(error); | ||
} | ||
}); | ||
|
||
hardhat.stdin.write(` | ||
Promise.resolve(${expression}) | ||
.then(${ | ||
raw | ||
? `console.log` | ||
: `(resolved) => console.log(JSON.stringify(resolved))` | ||
}) | ||
`); | ||
hardhat.stdin.end(); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
import type * as Hardhat from "hardhat/types"; | ||
|
||
import type { Compilation, CompiledContract } from "@truffle/compile-common"; | ||
import * as CompileSolidity from "@truffle/compile-solidity"; | ||
|
||
const supportedFormats = new Set(["hh-sol-build-info-1"]); | ||
|
||
export function buildInfoCompilation( | ||
buildInfo: Hardhat.BuildInfo | ||
): Compilation { | ||
const { _format } = buildInfo; | ||
|
||
if (!supportedFormats.has(_format)) { | ||
throw new Error(`Unsupported build info format: ${_format}`); | ||
} | ||
|
||
const sourceIndexes = buildInfoSourceIndexes(buildInfo); | ||
|
||
return { | ||
sourceIndexes, | ||
sources: buildInfoSources(buildInfo, sourceIndexes), | ||
contracts: buildInfoContracts(buildInfo), | ||
compiler: { | ||
name: "solc", | ||
version: buildInfo.solcLongVersion | ||
} | ||
}; | ||
} | ||
|
||
function buildInfoSourceIndexes( | ||
buildInfo: Hardhat.BuildInfo | ||
): Compilation["sourceIndexes"] { | ||
const sourceIndexes = []; | ||
for (const { index, sourcePath } of Object.entries( | ||
buildInfo.output.sources | ||
).map(([sourcePath, source]) => ({ index: source.id, sourcePath }))) { | ||
sourceIndexes[index] = sourcePath; | ||
} | ||
|
||
return sourceIndexes; | ||
} | ||
|
||
function buildInfoSources( | ||
buildInfo: Hardhat.BuildInfo, | ||
sourceIndexes: Compilation["sourceIndexes"] | ||
): Compilation["sources"] { | ||
return sourceIndexes.map(sourcePath => { | ||
// to handle if sourceIndexes is a sparse array | ||
if (!sourcePath) { | ||
return; | ||
} | ||
|
||
const inputSource = buildInfo.input.sources[sourcePath]; | ||
const outputSource = buildInfo.output.sources[sourcePath]; | ||
|
||
return { | ||
sourcePath, | ||
contents: inputSource.content, | ||
ast: outputSource.ast, | ||
language: buildInfo.input.language | ||
}; | ||
}); | ||
} | ||
|
||
function buildInfoContracts(buildInfo: Hardhat.BuildInfo): CompiledContract[] { | ||
const contracts = []; | ||
for (const [sourcePath, sourceContracts] of Object.entries( | ||
buildInfo.output.contracts | ||
)) { | ||
for (const [contractName, compilerOutputContract] of Object.entries( | ||
sourceContracts | ||
)) { | ||
const contract: CompiledContract = { | ||
contractName, | ||
sourcePath, | ||
source: buildInfo.input.sources[sourcePath].content, | ||
sourceMap: compilerOutputContract.evm.bytecode.sourceMap, | ||
deployedSourceMap: | ||
compilerOutputContract.evm.deployedBytecode.sourceMap, | ||
legacyAST: undefined, | ||
ast: buildInfo.output.sources[sourcePath].ast, | ||
abi: compilerOutputContract.abi, | ||
metadata: (compilerOutputContract as any).metadata, | ||
bytecode: CompileSolidity.Shims.zeroLinkReferences({ | ||
bytes: compilerOutputContract.evm.bytecode.object, | ||
linkReferences: CompileSolidity.Shims.formatLinkReferences( | ||
compilerOutputContract.evm.bytecode.linkReferences | ||
) | ||
}), | ||
deployedBytecode: CompileSolidity.Shims.zeroLinkReferences({ | ||
bytes: compilerOutputContract.evm.deployedBytecode.object, | ||
linkReferences: CompileSolidity.Shims.formatLinkReferences( | ||
compilerOutputContract.evm.deployedBytecode.linkReferences | ||
) | ||
}), | ||
compiler: { | ||
name: "solc", | ||
version: buildInfo.solcLongVersion | ||
}, | ||
devdoc: undefined, | ||
userdoc: undefined, | ||
immutableReferences: | ||
compilerOutputContract.evm.deployedBytecode.immutableReferences, | ||
generatedSources: (compilerOutputContract.evm.bytecode as any) | ||
.generatedSources, | ||
deployedGeneratedSources: ( | ||
compilerOutputContract.evm.deployedBytecode as any | ||
).generatedSources | ||
}; | ||
|
||
contracts.push(contract); | ||
} | ||
} | ||
|
||
return contracts; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
{ | ||
"compilerOptions": { | ||
"sourceMap": true, | ||
"declaration": true, | ||
"allowJs": false, | ||
"esModuleInterop": true, | ||
"lib": ["esnext", "dom"], | ||
"skipLibCheck": true, | ||
"target": "es2016", | ||
"moduleResolution": "node", | ||
"downlevelIteration": true, | ||
"allowSyntheticDefaultImports": true, | ||
"module": "commonjs", | ||
"outDir": "./dist", | ||
"strictBindCallApply": true, | ||
"paths": { | ||
"@truffle/from-hardhat": ["./src"], | ||
"@truffle/from-hardhat/*": ["./src/*"], | ||
"test/*": ["./test/*"] | ||
}, | ||
"rootDir": ".", | ||
"baseUrl": ".", | ||
"typeRoots": ["../../node_modules/@types/node"], | ||
"types": [ | ||
"mocha" | ||
], | ||
"plugins": [ | ||
{ "transform": "typescript-transform-paths" }, | ||
{ "transform": "typescript-transform-paths", "afterDeclarations": true } | ||
] | ||
}, | ||
"include": [ | ||
"src/**/*" | ||
], | ||
"exclude": [ | ||
"dist", | ||
"node_modules" | ||
] | ||
} |
Oops, something went wrong.