This PR will allow the usage of custom singleton factories that support zkSync.
For this all code related to ContractFactory instances and address calculation have been moved into a separate class (DeploymentFactory).
Following methods have been added/moved into this class:
getCreate2Address
extractFactoryDeps
getDeployTransaction -> Generate a TransactionRequest to deploy the contract
compareDeploymentTransaction -> Compares to deployment transactions for differences
Also most check on the deployment transaction have been moved to this class.
The getCreate2Address is separated into logic for EVM and zkSync. The logic assumes that the salt provided by hardhat-deploy is used and overrides the one provided by default by the zkSync ContractFactory.
An example for a deterministic deployment factory that works on zkSync is
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol";
import "@matterlabs/zksync-contracts/l2/system-contracts/libraries/SystemContractsCaller.sol";
/**
* The purpose of this contract is to provide a factory that deterministically deploys arbitrary contracts.
* The advantage is that once such a contract has been deployed and verified, deployment flows can be
* easily reproduced in a deterministic way. This removed centralization (reliance on a specific deployment key)
* and improves security (as it is easy to verify deployed code).
* The factory should follow the same pattern as https://github.com/Arachnid/deterministic-deployment-proxy:
* - only the `to` of a transaction has to be adjusted
* - allow to specify a `salt` by prepending it to the deployment data
*/
contract DeploymentFactory {
fallback() external payable {
// The expected data format is <salt:bytes32><deploymentCalldata:bytes>
// Where deploymenCalldata is a call to create/create2 of the DEPLOYER_SYSTEM_CONTRACT contract.
bytes32 salt = bytes32(msg.data[:32]);
bytes32 calldataSalt = bytes32(msg.data[36:68]);
// The factory overrides the salt provided in the deploymentCalldata,
// Therefore it is checked that both are the same or
// that the salt in the deploymentCalldata was not set (is a zero hash)
require(calldataSalt == bytes32(0) || calldataSalt == salt, "Unexpected salt");
// We cut off the method id (4 bytes) and salt (32 bytes) of the deploymentCalldata
// as we overwrite it with the salt provided to the factory.
bytes memory truncatedDeploymentCalldata = msg.data[68:];
(bool success,) = SystemContractsCaller
.systemCallWithReturndata(
uint32(gasleft()),
address(DEPLOYER_SYSTEM_CONTRACT),
uint128(msg.value),
abi.encodePacked(
DEPLOYER_SYSTEM_CONTRACT.create2.selector,
salt,
truncatedDeploymentCalldata
)
);
require(success, "Deployment failed");
}
}
This PR will allow the usage of custom singleton factories that support zkSync.
For this all code related to ContractFactory instances and address calculation have been moved into a separate class (DeploymentFactory).
Following methods have been added/moved into this class:
getCreate2Address
extractFactoryDeps
getDeployTransaction
-> Generate aTransactionRequest
to deploy the contractcompareDeploymentTransaction
-> Compares to deployment transactions for differences Also most check on the deployment transaction have been moved to this class.The
getCreate2Address
is separated into logic for EVM and zkSync. The logic assumes that the salt provided by hardhat-deploy is used and overrides the one provided by default by the zkSync ContractFactory.An example for a deterministic deployment factory that works on zkSync is
the Safe team will include one into their safe-singleton-factory repository.
For reference see: