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

Properly display errors & Link external libraries #7

Merged
merged 5 commits into from
Feb 18, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 2 additions & 2 deletions packages/hardhat-zksync-solc/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@matterlabs/hardhat-zksync-solc",
"version": "0.2.1",
"version": "0.2.2",
"description": "Hardhat plugin to compile smart contracts for the zkSync network",
"repository": "github:matter-labs/hardhat-zksync",
"homepage": "https://github.com/matter-labs/hardhat-zksync/tree/main/packages/hardhat-zksync-solc",
Expand All @@ -21,7 +21,7 @@
"fmt": "yarn prettier --write",
"eslint": "eslint 'src/**/*.ts' 'test/**/*.ts'",
"prettier": "prettier 'src/**/*.ts' 'test/**/*.ts'",
"test": "mocha test/tests.ts --exit",
"test": "mocha test/tests.ts --no-timeout --exit",
"build": "tsc --build .",
"clean": "rimraf dist"
},
Expand Down
8 changes: 7 additions & 1 deletion packages/hardhat-zksync-solc/src/compile/docker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ async function runZksolcContainer(docker: Docker, image: Image, command: string[
stream: true,
stdin: true,
stdout: true,
stderr: true,
hijack: true,
});

Expand All @@ -60,7 +61,12 @@ async function runZksolcContainer(docker: Docker, image: Image, command: string[
dockerStream.end(input);
await container.wait();

return JSON.parse(output.toString('utf8'));
const compilerOutput = output.toString('utf8');
try {
return JSON.parse(compilerOutput);
} catch {
throw pluginError(compilerOutput);
}
}

// Notice: contents of this file were mostly copy-pasted from the official Hardhat Vyper plugin
Expand Down
2 changes: 1 addition & 1 deletion packages/hardhat-zksync-solc/src/compile/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export class DockerCompiler implements ICompiler {
public static async initialize(config: ZkSolcConfig): Promise<ICompiler> {
await validateDockerIsInstalled();

const image = dockerImage(config.settings.experimental.dockerImage);
const image = dockerImage(config.settings.experimental?.dockerImage);
const docker = await createDocker();
await pullImageIfNecessary(docker, image);

Expand Down
18 changes: 11 additions & 7 deletions packages/hardhat-zksync-solc/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { CompilerInput } from 'hardhat/types';
import './type-extensions';
import { ZkSyncArtifact, FactoryDeps } from './types';
import { compile } from './compile';
import { add0xPrefixIfNecessary } from './utils';
import { zeroxlify } from './utils';

const ARTIFACT_FORMAT_VERSION = 'hh-zksolc-artifact-1';

Expand All @@ -20,12 +20,12 @@ extendConfig((config) => {
optimizer: {
enabled: false,
},
},
experimental: {
dockerImage: null,
experimental: {},
libraries: {}
},
};
config.zksolc = { ...defaultConfig, ...config.zksolc };
config.zksolc.settings = { ...defaultConfig.settings, ...config.zksolc.settings };

// TODO: If solidity optimizer is not enabled, the libraries are not inlined and
// we have to manually pass them into zksolc. So for now we force the optimization.
Expand All @@ -48,12 +48,12 @@ subtask(
}): Promise<ZkSyncArtifact> => {
let bytecode: string =
contractOutput.evm?.bytecode?.object || contractOutput.evm?.deployedBytecode?.object || '';
bytecode = add0xPrefixIfNecessary(bytecode);
bytecode = zeroxlify(bytecode);

let factoryDeps: FactoryDeps = {};
let entries: Array<[string, string]> = Object.entries(contractOutput.factoryDependencies || {});
for (const [hash, dependency] of entries) {
factoryDeps[add0xPrefixIfNecessary(hash)] = dependency;
factoryDeps[zeroxlify(hash)] = dependency;
}

return {
Expand All @@ -65,6 +65,8 @@ subtask(
// but both fields are included just in case
bytecode,
deployedBytecode: bytecode,
// zksolc does not support unlinked objects,
// all external libraries are either linked during compilation or inlined
linkReferences: {},
deployedLinkReferences: {},

Expand All @@ -75,7 +77,9 @@ subtask(
);

subtask(TASK_COMPILE_SOLIDITY_RUN_SOLC, async ({ input }: { input: CompilerInput }, { config }) => {
// This plugin is experimental, so this task isn't split into multiple subtasks yet.
if (config.zksolc.settings.libraries) {
input.settings.libraries = config.zksolc.settings.libraries;
}
return await compile(config.zksolc, input);
});

Expand Down
8 changes: 7 additions & 1 deletion packages/hardhat-zksync-solc/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ export interface ZkSolcConfig {
optimizer: {
enabled: boolean;
};
experimental: {
// addresses of external libraries
libraries?: {
[file: string]: {
[library: string]: string;
};
}
experimental?: {
dockerImage?: string;
};
};
Expand Down
2 changes: 1 addition & 1 deletion packages/hardhat-zksync-solc/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { NomicLabsHardhatPluginError } from 'hardhat/plugins';

export function add0xPrefixIfNecessary(hex: string): string {
export function zeroxlify(hex: string): string {
hex = hex.toLowerCase();
return hex.slice(0, 2) === '0x' ? hex : `0x${hex}`;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma abicoder v2;

library Foo {
string public constant name = "Foo";
function answer() external pure returns (uint) {
return 42;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma abicoder v2;

// import Foo.sol from current directory
import "./Foo.sol";

contract Import {
// Test Foo.sol by getting it's name.
function getFooName() public pure returns (string memory) {
return Foo.name;
}

function getAnswer() public pure returns (uint) {
return Foo.answer();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
require("../../../src/index");

module.exports = {
zksolc: {
version: "0.1.0",
compilerSource: "docker",
settings: {
optimizer: {
enabled: true,
},
experimental: {
dockerImage: "zksyncrobot/test-build"
},
libraries: {
'contracts/Foo.sol': {
'Foo': '0x0123456789abcdef0123456789abcdef01234567'
}
}
},
},
solidity: {
version: "0.8.11"
}
};
20 changes: 15 additions & 5 deletions packages/hardhat-zksync-solc/test/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { ZkSyncArtifact } from '../src/types';
import { useEnvironment } from './helpers';

describe('zksolc plugin', async function () {
describe('Successful compilation', async function () {
useEnvironment('successful-compilation');
describe('Simple', async function () {
useEnvironment('simple');

it('Should successfully compile the simple contract', async function () {
it('Should successfully compile a simple contract', async function () {
await this.env.run(TASK_COMPILE);

const artifact = this.env.artifacts.readArtifactSync('Greeter') as ZkSyncArtifact;
Expand All @@ -20,10 +20,20 @@ describe('zksolc plugin', async function () {
});
});

describe('Library', async function () {
describe('Inlined library', async function () {
useEnvironment('library');

it('Should successfully compile the contract with library', async function () {
it('Should successfully compile the contract with inlined library', async function () {
await this.env.run(TASK_COMPILE);
assert.equal(this.env.artifacts.readArtifactSync('contracts/Foo.sol:Foo').contractName, 'Foo');
assert.equal(this.env.artifacts.readArtifactSync('contracts/Import.sol:Import').contractName, 'Import');
});
});

describe('Linked library', async function () {
useEnvironment('linked');

it('Should successfully compile the contract with linked library', async function () {
await this.env.run(TASK_COMPILE);
assert.equal(this.env.artifacts.readArtifactSync('contracts/Foo.sol:Foo').contractName, 'Foo');
assert.equal(this.env.artifacts.readArtifactSync('contracts/Import.sol:Import').contractName, 'Import');
Expand Down