Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate from Buidler to Hardhat except docs #214

Merged
merged 23 commits into from
Nov 12, 2020
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ module.exports = {
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
},
{
files: ['buidler.config.js'],
files: ['hardhat.config.js'],
globals: {
usePlugin: 'readonly',
},
martriay marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
matrix:
package:
- core
- plugin-buidler
- plugin-hardhat
- plugin-truffle

runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion bundle-pack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ yarn prepare

mv packages/core/node_modules core-node_modules

for t in buidler truffle; do
for t in hardhat truffle; do
mkdir -p "packages/plugin-$t/node_modules/@openzeppelin"
ln -srf packages/core "packages/plugin-$t/node_modules/@openzeppelin/upgrades-core"
cd "packages/plugin-$t"
Expand Down
5 changes: 0 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
"coverage": "nyc yarn test"
},
"devDependencies": {
"@nomiclabs/buidler-ethers": "^2.0.0",
"@openzeppelin/docs-utils": "^0.1.0",
"@typescript-eslint/eslint-plugin": "^4.1.0",
"@typescript-eslint/parser": "^4.1.0",
Expand All @@ -31,10 +30,6 @@
"packages": [
"packages/*",
"packages/plugin-truffle/test"
],
"nohoist": [
"**/buidler-ethers",
"**/ethers"
]
}
}
1 change: 1 addition & 0 deletions packages/core/ava.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export default {
verbose: true,
ignoredByWatcher: ['**/*.{ts,map,tsbuildinfo}', 'artifacts', 'cache'],
typescript: { rewritePaths: { 'src/': 'dist/' } },
require: 'ts-node/register',
};
5 changes: 0 additions & 5 deletions packages/core/buidler.config.js

This file was deleted.

5 changes: 5 additions & 0 deletions packages/core/hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default {
solidity: {
version: '0.6.8',
},
};
9 changes: 5 additions & 4 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@
"scripts": {
"prepublish": "rimraf artifacts cache dist *.tsbuildinfo",
"prepare": "tsc -b && yarn prepare:contracts",
"prepare:contracts": "buidler compile",
"test": "tsc -b && buidler compile --force && ava",
"test:watch": "buidler compile --force && fgbg 'ava --watch' 'tsc -b --watch'",
"prepare:contracts": "hardhat compile",
"test": "tsc -b && hardhat compile --force && ava",
"test:watch": "hardhat compile --force && fgbg 'ava --watch' 'tsc -b --watch'",
"version": "node ../../scripts/bump-changelog.js"
},
"devDependencies": {
"@ava/typescript": "^1.1.1",
"@nomiclabs/buidler": "^1.3.6",
"@openzeppelin/contracts": "^3.1.0",
"@types/bn.js": "^4.11.6",
"@types/cbor": "^5.0.0",
Expand All @@ -33,7 +32,9 @@
"@types/rimraf": "^3.0.0",
"ava": "^3.9.0",
"fgbg": "^0.1.4",
"hardhat": "^2.0.2",
"rimraf": "^3.0.2",
"ts-node": "^9.0.0",
"typescript": "^4.0.0"
},
"dependencies": {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/deployment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ test('errors if tx is not found', async t => {
});

test('redeploys if tx is not found on dev network', async t => {
const provider = stubProvider(31337); // Buidler EVM chainId
const provider = stubProvider(31337); // Hardhat Network chainId
const fakeDeployment: Deployment = {
address: '0x1aec6468218510f19bb19f52c4767996895ce711',
txHash: '0xc48e21ac9c051922f5ccf1b47b62000f567ef9bbc108d274848b44351a6872cb',
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,6 @@ export const networkNames: { [chainId in number]?: string } = Object.freeze({
export async function isDevelopmentNetwork(provider: EthereumProvider): Promise<boolean> {
const chainId = await getChainId(provider);
// 1337 => ganache and geth --dev
// 31337 => buidler evm
// 31337 => hardhat network
return chainId === 1337 || chainId === 31337;
}
2 changes: 1 addition & 1 deletion packages/core/src/scripts/migrate-oz-cli-project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ function getNetworkName(filename: string): string {

function isDevelopmentNetwork(network: string): boolean {
// 13+ digits => ganache timestamp
// 31337 => buidler evm
// 31337 => hardhat network
return /^dev-(31337|\d{13,})$/.test(network);
}

Expand Down
8 changes: 6 additions & 2 deletions packages/core/src/storage.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import _test, { TestInterface } from 'ava';
import { promises as fs } from 'fs';
import { ContractDefinition } from 'solidity-ast';
import { findAll } from 'solidity-ast/utils';
import { artifacts } from 'hardhat';

import { SolcOutput } from './solc-api';
import { extractStorageLayout, getStorageUpgradeErrors, stabilizeTypeIdentifier, StorageLayout } from './storage';
Expand All @@ -13,7 +13,11 @@ interface Context {
const test = _test as TestInterface<Context>;

test.before(async t => {
const solcOutput: SolcOutput = JSON.parse(await fs.readFile('cache/solc-output.json', 'utf8'));
const buildInfo = await artifacts.getBuildInfo('contracts/test/Storage.sol:Storage1');
if (buildInfo === undefined) {
throw new Error('Build info not found');
}
const solcOutput: SolcOutput = buildInfo.output;
t.context.contracts = {};
for (const def of findAll('ContractDefinition', solcOutput.sources['contracts/test/Storage.sol'].ast)) {
t.context.contracts[def.name] = def;
Expand Down
28 changes: 16 additions & 12 deletions packages/core/src/validate.test.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,46 @@
import _test, { TestInterface } from 'ava';
import { promises as fs } from 'fs';
import { artifacts } from 'hardhat';

import {
validate,
isUpgradeSafe,
getStorageLayout,
getContractVersion,
Validation,
assertUpgradeSafe,
ValidationOptions,
Validations,
} from './validate';
import { solcInputOutputDecoder } from './src-decoder';

interface Context {
validation: Validation;
validations: Validations;
}

const test = _test as TestInterface<Context>;

test.before(async t => {
const solcInput = JSON.parse(await fs.readFile('cache/solc-input.json', 'utf8'));
const solcOutput = JSON.parse(await fs.readFile('cache/solc-output.json', 'utf8'));
const buildInfo = await artifacts.getBuildInfo('contracts/test/Validations.sol:HasStruct');
if (buildInfo === undefined) {
throw new Error('Build info not found');
}
const solcOutput = buildInfo.output;
const solcInput = buildInfo.input;
const decodeSrc = solcInputOutputDecoder(solcInput, solcOutput);
t.context.validation = validate(solcOutput, decodeSrc);
t.context.validations = [validate(solcOutput, decodeSrc)];
});

function testValid(name: string, valid: boolean) {
test(name, t => {
const version = getContractVersion(t.context.validation, name);
t.is(isUpgradeSafe(t.context.validation, version), valid);
const version = getContractVersion(t.context.validations, name, 0);
t.is(isUpgradeSafe(t.context.validations, version), valid);
});
}

function testOverride(name: string, opts: ValidationOptions, valid: boolean) {
const testName = name.concat(valid ? '_Allowed' : '_NotAllowed');
test(testName, t => {
const version = getContractVersion(t.context.validation, name);
const assertUpgSafe = () => assertUpgradeSafe(t.context.validation, version, opts);
const version = getContractVersion(t.context.validations, name, 0);
const assertUpgSafe = () => assertUpgradeSafe(t.context.validations, version, opts);
if (valid) {
t.notThrows(assertUpgSafe);
} else {
Expand Down Expand Up @@ -79,8 +83,8 @@ testValid('ParentHasEnum', false);
testValid('UsesLibraryWithEnum', false);

test('inherited storage', t => {
const version = getContractVersion(t.context.validation, 'StorageInheritChild');
const layout = getStorageLayout(t.context.validation, version);
const version = getContractVersion(t.context.validations, 'StorageInheritChild', 0);
const layout = getStorageLayout(t.context.validations, version);
t.is(layout.storage.length, 8);
for (let i = 0; i < layout.storage.length; i++) {
t.is(layout.storage[i].label, `v${i}`);
Expand Down
77 changes: 48 additions & 29 deletions packages/core/src/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import { UpgradesError, ErrorDescriptions } from './error';
import { SrcDecoder } from './src-decoder';
import { isNullish } from './utils/is-nullish';

export type Validation = Record<string, ValidationResult>;
export type Validations = Array<ValidationSet>;
export type ValidationSet = Record<string, ValidationResult>;

export interface ValidationResult {
version?: Version;
Expand Down Expand Up @@ -58,8 +59,8 @@ export function withValidationDefaults(opts: ValidationOptions): Required<Valida
};
}

export function validate(solcOutput: SolcOutput, decodeSrc: SrcDecoder): Validation {
const validation: Validation = {};
export function validate(solcOutput: SolcOutput, decodeSrc: SrcDecoder): ValidationSet {
const validation: ValidationSet = {};
const fromId: Record<number, string> = {};
const inheritIds: Record<string, number[]> = {};
const libraryIds: Record<string, number[]> = {};
Expand Down Expand Up @@ -120,57 +121,75 @@ export function validate(solcOutput: SolcOutput, decodeSrc: SrcDecoder): Validat
return validation;
}

export function getContractVersion(validation: Validation, contractName: string): Version {
const { version } = validation[contractName];
export function getContractVersion(validations: Validations, contractName: string, compilationRun: number): Version {
const { version } = validations[compilationRun][contractName];
if (version === undefined) {
throw new Error(`Contract ${contractName} is abstract`);
}
return version;
}

function getContractName(validation: Validation, version: Version): string {
const contractName = Object.keys(validation).find(
name => validation[name].version?.withMetadata === version.withMetadata,
);
function getContractNameAndCompilerRun(validations: Validations, version: Version): [string, number] {
let compilerRun = 0;
let contractName;

for (const [index, validation] of validations.entries()) {
contractName = Object.keys(validation).find(
name => validation[name].version?.withMetadata === version.withMetadata,
);
if (contractName !== undefined) {
compilerRun = index;
break;
}
}

if (contractName === undefined) {
throw new Error('The requested contract was not found. Make sure the source code is available for compilation');
}

return contractName;
return [contractName, compilerRun];
}

export function getStorageLayout(validation: Validation, version: Version): StorageLayout {
const contractName = getContractName(validation, version);
const c = validation[contractName];
export function getStorageLayout(validations: Validations, version: Version): StorageLayout {
const [contractName, compilerRun] = getContractNameAndCompilerRun(validations, version);
const c = validations[compilerRun][contractName];
const layout: StorageLayout = { storage: [], types: {} };
for (const name of [contractName].concat(c.inherit)) {
layout.storage.unshift(...validation[name].layout.storage);
Object.assign(layout.types, validation[name].layout.types);
layout.storage.unshift(...validations[compilerRun][name].layout.storage);
Object.assign(layout.types, validations[compilerRun][name].layout.types);
}
return layout;
}

export function getUnlinkedBytecode(validation: Validation, bytecode: string): string {
const linkableContracts = Object.keys(validation).filter(name => validation[name].linkReferences.length > 0);
export function getUnlinkedBytecode(validations: Validations, bytecode: string): string {
let compilerRun = 0;
let linkableContracts: string[] = [];

for (const [index, validation] of validations.entries()) {
linkableContracts = Object.keys(validation).filter(name => validation[name].linkReferences.length > 0);
if (linkableContracts !== undefined) {
compilerRun = index;
break;
}
}

for (const name of linkableContracts) {
const { linkReferences } = validation[name];
const { linkReferences } = validations[compilerRun][name];
const unlinkedBytecode = unlinkBytecode(bytecode, linkReferences);
const version = getVersion(unlinkedBytecode);

if (validation[name].version?.withMetadata === version.withMetadata) {
if (validations[compilerRun][name].version?.withMetadata === version.withMetadata) {
return unlinkedBytecode;
}
}

return bytecode;
}

export function assertUpgradeSafe(validation: Validation, version: Version, opts: ValidationOptions): void {
const contractName = getContractName(validation, version);
export function assertUpgradeSafe(validations: Validations, version: Version, opts: ValidationOptions): void {
const [contractName] = getContractNameAndCompilerRun(validations, version);

let errors = getErrors(validation, version);
let errors = getErrors(validations, version);
errors = processExceptions(contractName, errors, opts);

if (errors.length > 0) {
Expand Down Expand Up @@ -302,16 +321,16 @@ function describeError(e: ValidationError): string {
return log.join('\n ');
}

export function getErrors(validation: Validation, version: Version): ValidationError[] {
const contractName = getContractName(validation, version);
const c = validation[contractName];
export function getErrors(validations: Validations, version: Version): ValidationError[] {
const [contractName, compilerRun] = getContractNameAndCompilerRun(validations, version);
const c = validations[compilerRun][contractName];
return c.errors
.concat(...c.inherit.map(name => validation[name].errors))
.concat(...c.libraries.map(name => validation[name].errors));
.concat(...c.inherit.map(name => validations[compilerRun][name].errors))
.concat(...c.libraries.map(name => validations[compilerRun][name].errors));
}

export function isUpgradeSafe(validation: Validation, version: Version): boolean {
return getErrors(validation, version).length == 0;
export function isUpgradeSafe(validations: Validations, version: Version): boolean {
return getErrors(validations, version).length == 0;
}

function* getConstructorErrors(contractDef: ContractDefinition, decodeSrc: SrcDecoder): Generator<ValidationError> {
Expand Down
8 changes: 6 additions & 2 deletions packages/core/src/version.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import test from 'ava';
import { promises as fs } from 'fs';
import { artifacts } from 'hardhat';
import { hashBytecodeWithoutMetadata, hashBytecode } from './version';

const contractBytecode = '01234567890abcdef';

test('same code different formatting produces different metadata', async t => {
async function getBytecodeByContractName(contractName: string): Promise<string> {
const solcOutput = JSON.parse(await fs.readFile('cache/solc-output.json', 'utf8'));
const buildInfo = await artifacts.getBuildInfo('contracts/test/Version.sol:Greeter');
if (buildInfo === undefined) {
throw new Error('Build info not found');
}
const solcOutput = buildInfo.output;
return solcOutput.contracts['contracts/test/Version.sol'][contractName].evm.bytecode.object;
}

Expand Down
13 changes: 0 additions & 13 deletions packages/plugin-buidler/buidler.config.js

This file was deleted.

Loading