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

test(zk): add test for create2 computation with L2Contract #549

Merged
merged 5 commits into from
Aug 29, 2024
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
64 changes: 64 additions & 0 deletions crates/forge/tests/fixtures/zk/Create2.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

import "forge-std/Test.sol";
import {L2ContractHelper} from "era-contracts/l2-contracts/contracts/L2ContractHelper.sol"; // =0.8.20

import {Greeter} from "../src/Greeter.sol";
import {CustomNumber} from "../src/CustomNumber.sol";

import {Create2Utils} from "../src/Create2Utils.sol";

contract Create2Test is Test {
function getBytecodeHash(string memory path) internal returns (bytes32 bytecodeHash) {
string memory artifact = vm.readFile(path);
bytecodeHash = vm.parseJsonBytes32(artifact, ".hash");
}

function testCanDeployViaCreate2() public {
bytes32 bytecodeHash = getBytecodeHash("zkout/Greeter.sol/Greeter.json");
address sender = address(0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496);
bytes32 salt = "12345";
bytes32 constructorInputHash = keccak256(abi.encode());

address computedAddress =
Create2Utils.computeCreate2Address(sender, salt, bytes32(bytecodeHash), constructorInputHash);

// deploy via create2
address actualAddress = address(new Greeter{salt: salt}());

assertEq(actualAddress, computedAddress);
}

function testComputeCreate2WithNoArgs() external {
bytes32 salt = bytes32(0x0);

bytes32 bytecodeHash = getBytecodeHash("zkout/Greeter.sol/Greeter.json");

address computedAddress =
Karrq marked this conversation as resolved.
Show resolved Hide resolved
Create2Utils.computeCreate2Address(address(this), salt, bytes32(bytecodeHash), keccak256(abi.encode()));
address expectedAddress =
L2ContractHelper.computeCreate2Address(address(this), salt, bytes32(bytecodeHash), keccak256(abi.encode()));

address actualAddress = address(new Greeter{salt: salt}());
assertEq(actualAddress, expectedAddress);
assertEq(computedAddress, expectedAddress);
}

function testComputeCreate2WithArgs() external {
bytes32 salt = bytes32(0x0);
uint8 value = 42;

bytes32 bytecodeHash = getBytecodeHash("zkout/CustomNumber.sol/CustomNumber.json");

address computedAddress =
Create2Utils.computeCreate2Address(address(this), salt, bytecodeHash, keccak256(abi.encode(value)));
address expectedAddress =
L2ContractHelper.computeCreate2Address(address(this), salt, bytecodeHash, keccak256(abi.encode(value)));

CustomNumber num = new CustomNumber{salt: salt}(value);
assertEq(address(num), expectedAddress);
assertEq(computedAddress, expectedAddress);
assertEq(num.number(), value);
}
}
33 changes: 27 additions & 6 deletions crates/forge/tests/it/zk/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use crate::{config::*, test_helpers::TEST_DATA_DEFAULT};
use forge::revm::primitives::SpecId;
use foundry_config::fs_permissions::PathPermission;
use foundry_test_utils::Filter;
use foundry_test_utils::{util, Filter};

#[tokio::test(flavor = "multi_thread")]
async fn test_zk_contract_can_call_function() {
Expand Down Expand Up @@ -52,12 +52,33 @@ async fn test_zk_contract_deployment_balance_transfer() {

#[tokio::test(flavor = "multi_thread")]
async fn test_zk_contract_create2() {
let mut zk_config = TEST_DATA_DEFAULT.zk_test_data.zk_config.clone();
zk_config.fs_permissions.add(PathPermission::read_write("./zk/zkout/ConstantNumber.sol"));
let runner = TEST_DATA_DEFAULT.runner_with_zksync_config(zk_config);
let filter = Filter::new("testZkContractsCreate2", "ZkContractsTest", ".*");
let (prj, mut cmd) = util::setup_forge(
"test_zk_contract_create2_with_deps",
foundry_test_utils::foundry_compilers::PathStyle::Dapptools,
);
util::initialize(prj.root());

TestConfig::with_filter(runner, filter).evm_spec(SpecId::SHANGHAI).run().await;
cmd.args(["install", "matter-labs/era-contracts", "--no-commit", "--shallow"])
.ensure_execute_success()
.expect("able to install dependencies");
cmd.forge_fuse();

let mut config = cmd.config();
config.fs_permissions.add(PathPermission::read("./zkout"));
prj.write_config(config);

prj.add_source("Greeter.sol", include_str!("../../../../../testdata/zk/Greeter.sol")).unwrap();

prj.add_source("CustomNumber.sol", include_str!("../../../../../testdata/zk/CustomNumber.sol"))
.unwrap();

prj.add_source("Create2Utils.sol", include_str!("../../../../../testdata/zk/Create2Utils.sol"))
.unwrap();

prj.add_test("Create2.t.sol", include_str!("../../fixtures/zk/Create2.t.sol")).unwrap();

cmd.args(["test", "--zk-startup", "--evm-version", "shanghai", "--mc", "Create2Test"]);
assert!(cmd.stdout_lossy().contains("Suite result: ok"));
}

#[tokio::test(flavor = "multi_thread")]
Expand Down
46 changes: 1 addition & 45 deletions testdata/zk/Contracts.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import "../cheats/Vm.sol";

import {ConstantNumber} from "./ConstantNumber.sol";
import {Greeter} from "./Greeter.sol";
import {CustomNumber} from "./CustomNumber.sol";
import {Globals} from "./Globals.sol";

interface ISystemContractDeployer {
Expand Down Expand Up @@ -65,18 +66,6 @@ contract PayableFixedNumber {
}
}

contract CustomNumber {
uint8 value;

constructor(uint8 _value) {
value = _value;
}

function number() public view returns (uint8) {
return value;
}
}

contract CustomStorage {
uint8 num;
string str;
Expand Down Expand Up @@ -209,23 +198,6 @@ contract ZkContractsTest is DSTest {
require(customStorage.getNum() == 10, "era inline contract value mismatch (complex args)");
}

function testZkContractsCreate2() public {
vm.selectFork(forkEra);

string memory artifact = vm.readFile("zk/zkout/ConstantNumber.sol/ConstantNumber.json");
bytes32 bytecodeHash = vm.parseJsonBytes32(artifact, ".hash");
address sender = address(0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496);
bytes32 salt = "12345";
bytes32 constructorInputHash = keccak256(abi.encode());
address expectedDeployedAddress =
_computeCreate2Address(sender, salt, bytes32(bytecodeHash), constructorInputHash);

// deploy via create2
address actualDeployedAddress = address(new ConstantNumber{salt: salt}());

assertEq(expectedDeployedAddress, actualDeployedAddress);
}

function testZkContractsCallSystemContract() public {
(bool success,) = address(vm).call(abi.encodeWithSignature("zkVm(bool)", true));
require(success, "zkVm() call failed");
Expand Down Expand Up @@ -274,20 +246,4 @@ contract ZkContractsTest is DSTest {
assert(vm.getNonce(sender) == startingNonce + 3);
vm.stopBroadcast();
}

function _computeCreate2Address(
address sender,
bytes32 salt,
bytes32 creationCodeHash,
bytes32 constructorInputHash
) private pure returns (address) {
bytes32 zksync_create2_prefix = keccak256("zksyncCreate2");
bytes32 address_hash = keccak256(
bytes.concat(
zksync_create2_prefix, bytes32(uint256(uint160(sender))), salt, creationCodeHash, constructorInputHash
)
);

return address(uint160(uint256(address_hash)));
}
}
20 changes: 20 additions & 0 deletions testdata/zk/Create2Utils.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: UNLICENSED

pragma solidity >=0.8.7 <0.9.0;

library Create2Utils {
function computeCreate2Address(address sender, bytes32 salt, bytes32 creationCodeHash, bytes32 constructorInputHash)
internal
pure
returns (address)
{
bytes32 zksync_create2_prefix = keccak256("zksyncCreate2");
bytes32 address_hash = keccak256(
bytes.concat(
zksync_create2_prefix, bytes32(uint256(uint160(sender))), salt, creationCodeHash, constructorInputHash
)
);

return address(uint160(uint256(address_hash)));
}
}
14 changes: 14 additions & 0 deletions testdata/zk/CustomNumber.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.7 <0.9.0;

contract CustomNumber {
uint8 value;

constructor(uint8 _value) {
value = _value;
}

function number() public view returns (uint8) {
return value;
}
}