diff --git a/contracts/src/deploy/Create3.sol b/contracts/src/deploy/Create3.sol index 6a459dce..4e5ad169 100644 --- a/contracts/src/deploy/Create3.sol +++ b/contracts/src/deploy/Create3.sol @@ -6,9 +6,11 @@ import { CREATE3 } from "solmate/src/utils/CREATE3.sol"; /** * @title Create3 * @notice Factory for deploying contracts to deterministic addresses via CREATE3 Enables deploying - * contracts using CREATE3. Each deployer (msg.sender) has its own namespace for deployed - * addresses. - * @author zefram.eth + * contracts using CREATE3. + * It is based on Zefram’s implementation and includes support for deployment using only a salt value. + * It support two deployment styles: + * 1. Each deployer (msg.sender) has its own namespace for deployed addresses. + * 2. Deterministic deployment using a single salt. * @custom:attribution zefram.eth (https://github.com/ZeframLou/create3-factory/blob/main/src/CREATE3Factory.sol) */ contract Create3 { @@ -37,4 +39,24 @@ contract Create3 { salt = keccak256(abi.encodePacked(deployer, salt)); return CREATE3.getDeployed(salt); } + + /** + * @notice Deploys a contract using CREATE3 + * @param salt The deployer-specific salt for determining the deployed contract's address + * @param creationCode The creation code of the contract to deploy + * @return deployed The address of the deployed contract + */ + function deployDeterministic(bytes memory creationCode, bytes32 salt) external payable returns (address deployed) { + return CREATE3.deploy(salt, creationCode, msg.value); + } + + /** + * @notice Predicts the address of a deployed contract + * @param salt The deployer-specific salt for determining the deployed contract's address + * @return deployed The address of the contract that will be deployed + */ + function predictDeterministicAddress(bytes32 salt) external view returns (address deployed) { + // hash salt with the deployer address to give each deployer its own namespace + return CREATE3.getDeployed(salt); + } } diff --git a/contracts/test/deploy/Create3.t.sol b/contracts/test/deploy/Create3.t.sol index da350866..4f909720 100644 --- a/contracts/test/deploy/Create3.t.sol +++ b/contracts/test/deploy/Create3.t.sol @@ -35,4 +35,29 @@ contract Create3Test is Test { expected = create3.getDeployed(address(this), otherSalt); assertEq(deployed, expected); } + + function testCreate3_deploy_onlySalt() public { + // deployDeterministic and predictDeterministicAddress return same address when deployed by the same salt. + bytes32 salt = 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef; + bytes memory creationCode = type(Create3).creationCode; + address deployed = create3.deployDeterministic(creationCode, salt); + address expected = create3.predictDeterministicAddress(salt); + assertEq(deployed, expected); + + // Network shall generate the same address for the same salt. + vm.expectRevert("DEPLOYMENT_FAILED"); + deployed = create3.deployDeterministic(creationCode, salt); + + // Network shall generate same addresses for different deployers. + address otherAddr = address(0xf398C12A45Bc409b6C652E25bb0a3e702492A4ab); + vm.prank(otherAddr); + vm.expectRevert("DEPLOYMENT_FAILED"); + deployed = create3.deployDeterministic(creationCode, salt); + + // Network shall generate different addresses for different salts. + bytes32 otherSalt = 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890fedcba; + deployed = create3.deployDeterministic(creationCode, otherSalt); + expected = create3.predictDeterministicAddress(otherSalt); + assertEq(deployed, expected); + } }