Skip to content

Commit

Permalink
feat: add zksync create2 lib (#41)
Browse files Browse the repository at this point in the history
* fix: chain id

* feat: zksync create2 lib

* fix: zksync script

* chore: zksync ci
  • Loading branch information
brotherlymite authored Aug 7, 2024
1 parent 4c76eb4 commit 5d728d5
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 12 deletions.
4 changes: 2 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ RPC_METIS=https://andromeda.metis.io/?owner=1088
RPC_METIS_TESTNET=https://andromeda.metis.io/?owner=1088
RPC_BINANCE=https://bsc-dataseed.binance.org/
RPC_BINANCE_TESTNET=https://data-seed-prebsc-1-s1.binance.org:8545/
RPC_ZK_SYNC=https://mainnet.era.zksync.io
RPC_ZK_SYNC_TESTNET=https://sepolia.era.zksync.dev
RPC_ZKSYNC=https://mainnet.era.zksync.io
RPC_ZKSYNC_TESTNET=https://sepolia.era.zksync.dev

# Etherscan api keys for verification & download utils
ETHERSCAN_API_KEY_MAINNET=
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/merge-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ on:
jobs:
test:
uses: bgd-labs/github-workflows/.github/workflows/foundry-test.yml@main
test-sol-zksync:
uses: bgd-labs/github-workflows/.github/workflows/foundry-test.yml@main
secrets: inherit
with:
mode: "CHANGED"
zksync: true
ROOT_DIR: "zksync"
release:
uses: bgd-labs/github-workflows/.github/workflows/release.yml@main
release-node:
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,10 @@ on:
jobs:
test:
uses: bgd-labs/github-workflows/.github/workflows/foundry-test.yml@main
test-sol-zksync:
uses: bgd-labs/github-workflows/.github/workflows/foundry-test.yml@main
secrets: inherit
with:
mode: "CHANGED"
zksync: true
ROOT_DIR: "zksync"
8 changes: 4 additions & 4 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ fantom = "${RPC_FANTOM}"
fantom-testnet = "${RPC_FANTOM_TESTNET}"
binance = "${RPC_BINANCE}"
binance-testnet = "${RPC_BINANCE_TESTNET}"
zksync = "${RPC_ZK_SYNC}"
zksync-testnet = "${RPC_ZK_SYNC_TESTNET}"
zksync = "${RPC_ZKSYNC}"
zksync-testnet = "${RPC_ZKSYNC_TESTNET}"

[etherscan]
ethereum = { key = "${ETHERSCAN_API_KEY_MAINNET}", chain = 1 }
Expand All @@ -56,8 +56,8 @@ fantom = { key = "${ETHERSCAN_API_KEY_FANTOM}", chain = 250 }
fantom-testnet = { key = "${ETHERSCAN_API_KEY_FANTOM}", chain = 250 }
binance = { key = "${ETHERSCAN_API_KEY_BINANCE}", chain = 56 }
binance-testnet = { key = "${ETHERSCAN_API_KEY_BINANCE}", chain = 56 }
zksync = { key = "${ETHERSCAN_API_KEY_ZK_SYNC}", chain = 324 }
zksync-testnet = { key = "${ETHERSCAN_API_KEY_ZK_SYNC}", chain = 300, url = 'https://api-sepolia-era.zksync.network/api'}
zksync = { key = "${ETHERSCAN_API_KEY_ZKSYNC}", chain = 324 }
zksync-testnet = { key = "${ETHERSCAN_API_KEY_ZKSYNC}", chain = 300, url = 'https://api-sepolia-era.zksync.network/api'}

[fuzz]
no_zksync_reserved_addresses = true
Expand Down
12 changes: 6 additions & 6 deletions src/contracts/utils/ChainHelpers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ library ChainIds {
uint256 internal constant BNB = 56;
uint256 internal constant POLYGON = 137;
uint256 internal constant FANTOM = 250;
uint256 internal constant ZK_SYNC = 324;
uint256 internal constant ZKSYNC = 324;
uint256 internal constant METIS = 1088;
uint256 internal constant ZK_EVM = 1101;
uint256 internal constant BASE = 8453;
Expand Down Expand Up @@ -37,7 +37,7 @@ library TestNetChainIds {
uint256 internal constant CELO_ALFAJORES = 44787;
uint256 internal constant OPTIMISM_SEPOLIA = 11155420;
uint256 internal constant ARBITRUM_SEPOLIA = 421614;
uint256 internal constant ZK_SYNC_SEPOLIA = 300;
uint256 internal constant ZKSYNC_SEPOLIA = 300;
}

library ChainHelpers {
Expand All @@ -57,7 +57,7 @@ library ChainHelpers {
newFork = vm.createSelectFork(vm.rpcUrl('polygon'));
} else if (chainId == ChainIds.FANTOM) {
newFork = vm.createSelectFork(vm.rpcUrl('fantom'));
} else if (chainId == ChainIds.ZK_SYNC) {
} else if (chainId == ChainIds.ZKSYNC) {
newFork = vm.createSelectFork(vm.rpcUrl('zkSync'));
} else if (chainId == ChainIds.METIS) {
newFork = vm.createSelectFork(vm.rpcUrl('metis'));
Expand All @@ -77,7 +77,7 @@ library ChainHelpers {
newFork = vm.createSelectFork(vm.rpcUrl('sepolia'));
} else if (chainId == ChainIds.HARMONY) {
newFork = vm.createSelectFork(vm.rpcUrl('harmony'));
} else if (chainId == ChainIds.ZK_SYNC) {
} else if (chainId == ChainIds.ZKSYNC) {
newFork = vm.createSelectFork(vm.rpcUrl('zksync'));
} else {
revert UnknownChainId();
Expand Down Expand Up @@ -111,7 +111,7 @@ library ChainHelpers {
networkName = 'scroll';
} else if (chainId == ChainIds.CELO) {
networkName = 'celo';
} else if (chainId == ChainIds.ZK_SYNC) {
} else if (chainId == ChainIds.ZKSYNC) {
networkName = 'zksync';
}
// testnets
Expand All @@ -137,7 +137,7 @@ library ChainHelpers {
networkName = 'scroll_sepolia';
} else if (chainId == TestNetChainIds.CELO_ALFAJORES) {
networkName = 'celo_alfajores';
} else if (chainId == TestNetChainIds.ZK_SYNC_SEPOLIA) {
} else if (chainId == TestNetChainIds.ZKSYNC_SEPOLIA) {
networkName = 'zksync_sepolia';
} else {
revert('chain id is not supported');
Expand Down
4 changes: 4 additions & 0 deletions src/contracts/utils/ScriptUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ abstract contract PolygonZkEvmScript is WithChainIdValidation {
constructor() WithChainIdValidation(ChainIds.ZK_EVM) {}
}

abstract contract ZkSyncScript is WithChainIdValidation {
constructor() WithChainIdValidation(ChainIds.ZKSYNC) {}
}

abstract contract SepoliaScript is WithChainIdValidation {
constructor() WithChainIdValidation(ChainIds.SEPOLIA) {}
}
Expand Down
113 changes: 113 additions & 0 deletions zksync/src/contracts/utils/ScriptUtilsZkSync.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {ICreate2Factory} from './interfaces/ICreate2Factory.sol';

library Create2UtilsZkSync {
// https://github.com/matter-labs/era-contracts/blob/main/system-contracts/contracts/Create2Factory.sol
address public constant CREATE2_FACTORY = 0x0000000000000000000000000000000000010000;

// @dev the bytecodeHash is the unsanitized input we get via `type(Contract).creationCode`
function create2Deploy(bytes32 salt, bytes memory bytecodeHash, bytes memory arguments) internal returns (address) {
return create2Deploy(salt, bytes32(sliceBytes(bytecodeHash, 36, 32)), arguments);
}

// @dev the bytecodeHash is the unsanitized input we get via `type(Contract).creationCode`
function create2Deploy(bytes32 salt, bytes memory bytecodeHash) internal returns (address) {
return create2Deploy(salt, bytes32(sliceBytes(bytecodeHash, 36, 32)));
}

function create2Deploy(
bytes32 salt,
bytes32 bytecodeHash,
bytes memory arguments
) internal returns (address) {
if (isContractDeployed(CREATE2_FACTORY) == false) {
revert('MISSING_CREATE2_FACTORY');
}
address computed = computeCreate2Address(salt, bytecodeHash, arguments);

if (isContractDeployed(computed)) {
return computed;
} else {
address deployedAt = ICreate2Factory(CREATE2_FACTORY).create2(
salt,
bytecodeHash,
arguments
);

require(deployedAt == computed, 'failure at create2 address derivation');
return deployedAt;
}
}

function create2Deploy(bytes32 salt, bytes32 bytecodeHash) internal returns (address) {
if (isContractDeployed(CREATE2_FACTORY) == false) {
revert('MISSING_CREATE2_FACTORY');
}
address computed = computeCreate2Address(salt, bytecodeHash);

if (isContractDeployed(computed)) {
return computed;
} else {
address deployedAt = ICreate2Factory(CREATE2_FACTORY).create2(
salt,
bytecodeHash,
''
);

require(deployedAt == computed, 'failure at create2 address derivation');
return deployedAt;
}
}

function computeCreate2Address(
bytes32 salt,
bytes32 bytecodeHash
) internal pure returns (address) {
return computeCreate2Address(salt, bytecodeHash, '');
}

function computeCreate2Address(
bytes32 salt,
bytes32 bytecodeHash,
bytes memory arguments
) internal pure returns (address) {
bytes32 addressHash = keccak256(
bytes.concat(
keccak256('zksyncCreate2'), // zkSync create2 prefix
bytes32(uint256(uint160(CREATE2_FACTORY))),
salt,
bytecodeHash,
keccak256(arguments)
)
);

return address(uint160(uint256(addressHash)));
}

function isContractDeployed(address _addr) internal view returns (bool isContract) {
return (_addr.code.length > 0);
}

function sliceBytes(bytes memory data, uint256 start, uint256 length) internal pure returns (bytes memory) {
require(start + length <= data.length, 'Slice out of bounds');
bytes memory result = new bytes(length);

assembly {
let dataPtr := add(data, 32)
let resultPtr := add(result, 32)

// Copy the slice
let words := div(add(length, 31), 32)
let srcPtr := add(dataPtr, start)

for { let i := 0 } lt(i, words) { i := add(i, 1) } {
mstore(add(resultPtr, mul(i, 32)), mload(add(srcPtr, mul(i, 32))))
}

mstore(result, length)
}
return result;
}
}
10 changes: 10 additions & 0 deletions zksync/src/contracts/utils/interfaces/ICreate2Factory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface ICreate2Factory {
function create2(
bytes32 _salt,
bytes32 _bytecodeHash,
bytes memory _input
) external payable returns (address);
}

0 comments on commit 5d728d5

Please sign in to comment.