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

Premint deploy determinstic fix tests #213

Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
run: |
lcov --rc lcov_branch_coverage=1 \
--remove lcov.info \
--output-file lcov.info "*node_modules*" "*test*" "*script*" "*DeploymentConfig*" "*Redeem*"
--output-file lcov.info "*node_modules*" "*test*" "*script*" "*DeploymentConfig*" "*Redeem*" "*deployment"

- name: Report code coverage
uses: zgosalvez/github-actions-report-lcov@v2
Expand Down
12 changes: 6 additions & 6 deletions deterministicConfig/factoryProxy/params.json

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions deterministicConfig/factoryProxy/signatures.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"1": "0x2933443bc97517731893d612ce5d51bc980b9185efce2826e58721fa59ad517123e72be886717639b75eb30380f8b0feee3b36c94c4bb31b2e99ad3b1f0e1bd81c",
"5": "0xaef23e2b095dcdd758e3c57f75e3b96245ec5f4339175946aa2abd829f8f389935e365987c1dfe3ef3fbf12ff30810351cbc3af6e7f225abfee9d8d11d15abb51b",
"10": "0x7bceed3c7695faaed17d15c52f9153b5faa94b8144d8517437d334578a41f98269d78cfefe0b4869c3c5098cc495f9ea4e8b8f4a530e6d8f28c7bf35c52ea7971b",
"420": "0x303b4c1d43bdaf0985e82f97e31ed69af5b00f979d6b2d9bbf4ad41f16ba525e319198f63ebc6aeff44f70bc12b04578d12fd39e2b830e47d6477f9b5eae9d8d1b",
"424": "0x1cf2cfb0a1bbfee57ad8e72e5e6c81262c6892e3726350bcf069d035c74e70f57dcbe7dfba5ab64c7e440fb5faacd31a798e453094c3de34a6ebb26db644acce1b",
"999": "0x16546150074572fa72cf1e66b635b196c02e4cc95f0d465dbfe5cf09a452fe6b4b748990ed760be3b1620b6df53787baac3bc3f1755ebcc228690ff5b7744de81c",
"8453": "0xda5c219fab6e1be7ad156d002cca90af281dd17a003a9719c76e99ac34568bb62b726d72d025b852dddaae26d26dc1a2508b24a803e7338615df532b49b8d0ed1c",
"58008": "0x00bbddd17272d09cdc81521daa09101777017ed1662077a46215b4bc9136622c1574d5768b95310d7fe5fff9d1803653dbb70dba5fdcf1a442af9893431f64dc1b",
"84531": "0x2bd795e9c7dc06c52d52626d5ce93b8ab5dab38c64dd2527d3d07be053c5d2f679648c00c302bc684abbae1b517eaf4435edf1873d74ecbd12d2c160fa8001ec1c",
"7777777": "0x0d33c46e997d3487f08bc153c5d6dac7dbff21057bd2d6ec857e7140f51879ce73e2fb23ae705c2d1bd1316caaaf5f8258ad404a595cafd3a28a622d0dba18b51b",
"11155111": "0x3e09018c6aa6ef37fdade862ef28d9799debd800552a80a0748adaa967d20a095463dbdcaeecf61a6fd9aa2514b24d01947bbb05c8ca7a5383e00da47d52fd941c"
}
12 changes: 6 additions & 6 deletions deterministicConfig/premintExecutorProxy/params.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions deterministicConfig/premintExecutorProxy/signatures.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"999": "0x18ec8191bac7a5d1751104f4ef1b817df5b307c9ce0d4ea68af4fc00a429cf8c30483b3cb0278e8cf28a9c1af97f9a9f59bb05863aeb5adc0b7897e604afec931c"
}
93 changes: 55 additions & 38 deletions src/deployment/DeterministicDeployerScript.sol
Original file line number Diff line number Diff line change
Expand Up @@ -99,62 +99,79 @@ contract DeterministicDeployerScript is Script {
signature = signatures.readBytes(string.concat(".", string.concat(vm.toString(chain))));
}

function getDeterministicDeploymentParams(
address deployerAddress,
bytes memory proxyCreationCode,
uint256 proxyShimSaltSuffix
) internal returns (DeterministicParams memory) {
// 1. Get salt with first bytes that match address, and resulting determinisitic factory proxy deployer address
function getProxyDeployerParams() internal returns (bytes32 proxyDeployerSalt, bytes memory proxyDeployerCreationCode, address proxyDeployerAddress) {
proxyDeployerSalt = ZoraDeployerUtils.FACTORY_DEPLOYER_DEPLOYMENT_SALT;

// replace first 20 characters of salt with deployer address, so that the salt can be used with
// ImmutableCreate2Factory.safeCreate2 when called by this deployer's account:
bytes32 proxyDeployerSalt = ZoraDeployerUtils.FACTORY_DEPLOYER_DEPLOYMENT_SALT;

bytes memory proxyDeployerCreationCode = type(DeterministicProxyDeployer).creationCode;
proxyDeployerCreationCode = type(DeterministicProxyDeployer).creationCode;

// we can know deterministically what the address of the new factory proxy deployer will be, given it's deployed from with the salt and init code,
// from the ImmutableCreate2Factory
address proxyDeployerAddress = ZoraDeployerUtils.IMMUTABLE_CREATE2_FACTORY.findCreate2Address(proxyDeployerSalt, proxyDeployerCreationCode);

console2.log("expected factory deployer address:", proxyDeployerAddress);

// 2. Get random proxy shim salt, and resulting deterministic address
proxyDeployerAddress = ZoraDeployerUtils.IMMUTABLE_CREATE2_FACTORY.findCreate2Address(proxyDeployerSalt, proxyDeployerCreationCode);
}

// Proxy shim will be initialized with the factory deployer address as the owner, allowing only the factory deployer to upgrade the proxy,
// to the eventual factory implementation
bytes memory proxyShimInitCode = abi.encodePacked(type(ProxyShim).creationCode, abi.encode(proxyDeployerAddress));
function getProxyShimParams(
address proxyDeployerAddress,
address deployerAddress,
uint256 proxyShimSaltSuffix
) internal returns (bytes memory proxyShimInitCode, bytes32 proxyShimSalt, address proxyShimAddress) {
proxyShimInitCode = abi.encodePacked(type(ProxyShim).creationCode, abi.encode(proxyDeployerAddress));

// create any arbitrary salt for proxy shim (this can be anything, we just care about the resulting address)
bytes32 proxyShimSalt = saltWithAddressInFirst20Bytes(deployerAddress, proxyShimSaltSuffix);
proxyShimSalt = saltWithAddressInFirst20Bytes(deployerAddress, proxyShimSaltSuffix);

// now get deterministic proxy shim address based on salt, deployer address, which will be DeterministicProxyDeployer address and init code
address proxyShimAddress = Create2.computeAddress(proxyShimSalt, keccak256(proxyShimInitCode), proxyDeployerAddress);

console2.log("proxy shim address:");
console2.log(proxyShimAddress);

// 3. Mine for a salt that can be used to deterministically create the factory proxy, given the proxy shim address, which is passed as the
// constructor argument, and the deployer, which is the new factory proxy deployer, which we know the address of deterministically
proxyShimAddress = Create2.computeAddress(proxyShimSalt, keccak256(proxyShimInitCode), proxyDeployerAddress);
}

function getProxyParams(
bytes memory proxyCreationCode,
address proxyShimAddress,
address proxyDeployerAddress
) internal returns (bytes32 proxySalt, address deterministicProxyAddress) {
bytes memory factoryProxyInitCode = abi.encodePacked(proxyCreationCode, abi.encode(proxyShimAddress, ""));
bytes32 creationCodeHash = keccak256(factoryProxyInitCode);

console.log("init code hash: ", LibString.toHexStringNoPrefix(uint256(creationCodeHash), 32));
(proxySalt, deterministicProxyAddress) = mineSalt(proxyDeployerAddress, creationCodeHash, "777777");
}

(bytes32 proxySalt, address deterministicProxyAddress) = mineSalt(proxyDeployerAddress, creationCodeHash, "777777");
function getDeterministicDeploymentParams(
address deployerAddress,
bytes memory proxyCreationCode,
uint256 proxyShimSaltSuffix
) internal returns (DeterministicParams memory) {
// 1. Get salt with first bytes that match address, and resulting determinisitic factory proxy deployer address
(bytes32 proxyDeployerSalt, bytes memory proxyDeployerCreationCode, address proxyDeployerAddress) = getProxyDeployerParams();
// replace first 20 characters of salt with deployer address, so that the salt can be used with
// ImmutableCreate2Factory.safeCreate2 when called by this deployer's account:

DeterministicParams memory result = DeterministicParams({
proxyDeployerCreationCode: proxyDeployerCreationCode,
proxyCreationCode: proxyCreationCode,
deployerAddress: deployerAddress,
// 2. Get random proxy shim salt, and resulting deterministic address
// Proxy shim will be initialized with the factory deployer address as the owner, allowing only the factory deployer to upgrade the proxy,
// to the eventual factory implementation
(bytes memory proxyShimInitCode, bytes32 proxyShimSalt, address proxyShimAddress) = getProxyShimParams({
proxyDeployerAddress: proxyDeployerAddress,
proxyDeployerSalt: proxyDeployerSalt,
proxyShimSalt: proxyShimSalt,
proxySalt: proxySalt,
deterministicProxyAddress: deterministicProxyAddress
deployerAddress: deployerAddress,
proxyShimSaltSuffix: proxyShimSaltSuffix
});

return result;
// 3. Mine for a salt that can be used to deterministically create the factory proxy, given the proxy shim address, which is passed as the
// constructor argument, and the deployer, which is the new factory proxy deployer, which we know the address of deterministically
(bytes32 proxySalt, address deterministicProxyAddress) = getProxyParams({
proxyCreationCode: proxyCreationCode,
proxyShimAddress: proxyShimAddress,
proxyDeployerAddress: proxyDeployerAddress
});

return
DeterministicParams({
proxyDeployerCreationCode: proxyDeployerCreationCode,
proxyCreationCode: proxyCreationCode,
deployerAddress: deployerAddress,
proxyDeployerAddress: proxyDeployerAddress,
proxyDeployerSalt: proxyDeployerSalt,
proxyShimSalt: proxyShimSalt,
proxySalt: proxySalt,
deterministicProxyAddress: deterministicProxyAddress
});
}

error MismatchedAddress(address expected, address actual);
Expand Down
120 changes: 38 additions & 82 deletions test/deployer/NewFactoryProxyDeployer.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,127 +10,77 @@ import {UpgradeGate} from "../../src/upgrades/UpgradeGate.sol";
import {Deployment, ChainConfig} from "../../src/deployment/DeploymentConfig.sol";
import {IMinter1155} from "../../src/interfaces/IMinter1155.sol";
import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
import {DeterministicDeployerScript, DeterministicParams} from "../../src/deployment/DeterministicDeployerScript.sol";

contract DeterministicProxyDeployerTest is Test {
contract DeterministicProxyDeployerTest is DeterministicDeployerScript, Test {
using stdJson for string;

// the values in this test can be determined by running the script GetDeterministicParam.s.sol,
// and copying the output values here.
bytes32 DeterministicProxyDeployerCreationSalt = bytes32(0x0000000000000000000000000000000000000000668d7f9eb18e35000dbaba0e);
bytes32 proxyShimSalt = bytes32(0xf69fec6d858c77e969509843852178bd24cad2b6000000000000000000000000);
bytes32 factoryProxySalt = bytes32(0xe06d3223ede55655f68ce124bc16c9c311a20c31806ca2b04056664a574e2f1d);

function setUp() public {
string memory deployConfig = vm.readFile(string.concat(string.concat(vm.projectRoot(), "/deterministicConfig/factoryProxy", "/params.json")));

DeterministicProxyDeployerCreationSalt = deployConfig.readBytes32(".proxyDeployerSalt");
proxyShimSalt = deployConfig.readBytes32(".proxyShimSalt");
factoryProxySalt = deployConfig.readBytes32(".proxyDeployerSalt");
function _deployKnownZoraFactoryProxy(bytes32 salt) internal returns (DeterministicProxyDeployer) {
// create new factory deployer using ImmutableCreate2Factory
return DeterministicProxyDeployer(ZoraDeployerUtils.IMMUTABLE_CREATE2_FACTORY.safeCreate2(salt, type(DeterministicProxyDeployer).creationCode));
}

function _deployKnownZoraFactoryProxy() internal returns (DeterministicProxyDeployer factoryProxyDeployer) {
bytes memory DeterministicProxyDeployerInitCode = type(DeterministicProxyDeployer).creationCode;

address computedFactoryDeployerAddress = ZoraDeployerUtils.IMMUTABLE_CREATE2_FACTORY.findCreate2Address(
DeterministicProxyDeployerCreationSalt,
DeterministicProxyDeployerInitCode
);

address expectedFactoryDeployerAddress = 0x9868a3FFe92C44c4Ce1db8033C6f55a674D511D8;
assertEq(computedFactoryDeployerAddress, expectedFactoryDeployerAddress, "deterministic factory deployer address wrong");
function create1155FactoryImpl() internal returns (address) {
address mintFeeRecipient = makeAddr("mintFeeRecipient");
address factoryOwner = makeAddr("factorOwner");
address protocolRewards = makeAddr("protocolRewards");

address computedFactoryProxyAddress = ZoraDeployerUtils.deterministicFactoryProxyAddress({
proxyShimSalt: proxyShimSalt,
factoryProxySalt: factoryProxySalt,
proxyDeployerAddress: computedFactoryDeployerAddress
(address factoryImplAddress, ) = ZoraDeployerUtils.deployNew1155AndFactoryImpl({
factoryProxyAddress: address(0),
mintFeeRecipient: mintFeeRecipient,
protocolRewards: protocolRewards,
merkleMinter: IMinter1155(address(0)),
redeemMinterFactory: IMinter1155(address(0)),
fixedPriceMinter: IMinter1155(address(0))
});

address expectedFactoryProxyAddress = 0x77777718F04F2f9d9082a5AC853cBA682b19fB48;
assertEq(computedFactoryProxyAddress, expectedFactoryProxyAddress, "deterministic factory proxy address wrong");

// create new factory deployer using ImmutableCreate2Factory
address DeterministicProxyDeployerAddress = ZoraDeployerUtils.IMMUTABLE_CREATE2_FACTORY.safeCreate2(
DeterministicProxyDeployerCreationSalt,
DeterministicProxyDeployerInitCode
);

assertEq(DeterministicProxyDeployerAddress, computedFactoryDeployerAddress, "factory deployer address wrong");

assertEq(computedFactoryDeployerAddress, address(0x77777718F04F2f9d9082a5AC853cBA682b19fB48));

// create factory proxy at deterministic address:
factoryProxyDeployer = DeterministicProxyDeployer(DeterministicProxyDeployerAddress);
return factoryImplAddress;
}

function test_proxyCanByDeployedAtDesiredAddress(uint32 nonce) external {
function test_proxyCanByDeployedAtDesiredAddress(bytes32 proxySalt) external {
vm.createSelectFork("zora_goerli", 1252119);
// ensure nonce is greater than current account's nonce

(address deployerAddress, uint256 deployerPrivateKey) = makeAddrAndKey("deployer");

// address expectedFactoryDeployerAddress = 0x9868a3FFe92C44c4Ce1db8033C6f55a674D511D8;
address expectedFactoryProxyAddress = 0x77777718F04F2f9d9082a5AC853cBA682b19fB48;
bytes32 proxyDeployerSalt = ZoraDeployerUtils.FACTORY_DEPLOYER_DEPLOYMENT_SALT;

// now we can create the implementation, pointing it to the expected deterministic address:
address mintFeeRecipient = makeAddr("mintFeeRecipient");
address factoryOwner = makeAddr("factorOwner");
address protocolRewards = makeAddr("protocolRewards");
bytes32 proxyShimSalt = saltWithAddressInFirst20Bytes(deployerAddress, 10);

// 1. Create implementation contracts based on deterministic factory proxy address

// create 1155 and factory impl, we can know the deterministic factor proxy address ahead of time:
(address factoryImplAddress, ) = ZoraDeployerUtils.deployNew1155AndFactoryImpl({
factoryProxyAddress: expectedFactoryProxyAddress,
mintFeeRecipient: mintFeeRecipient,
protocolRewards: protocolRewards,
merkleMinter: IMinter1155(address(0)),
redeemMinterFactory: IMinter1155(address(0)),
fixedPriceMinter: IMinter1155(address(0))
});

vm.assume(nonce > vm.getNonce(deployerAddress));
// we set the nonce to a random value, to prove this doesn't affect the deterministic addrss
vm.setNonce(deployerAddress, nonce);
address factoryImplAddress = create1155FactoryImpl();

// 2. Create factory deployer at deterministic address
DeterministicProxyDeployer factoryProxyDeployer = _deployKnownZoraFactoryProxy();

// // try to create and initialize factory proxy as another account, it should revert, as only original deployer should be
// // able to call this:
// vm.prank(makeAddr("other"));
// vm.expectRevert();
// factoryProxyDeployer.createAndInitializeNewFactoryProxyDeterministic(
// proxyShimSalt,
// factoryProxySalt,
// deterministicFactoryProxyAddress,
// factoryImplAddress,
// factoryOwner
// );
DeterministicProxyDeployer factoryProxyDeployer = _deployKnownZoraFactoryProxy(proxyDeployerSalt);

bytes memory factoryProxyCreationCode = type(Zora1155Factory).creationCode;
address mintFeeRecipient = makeAddr("mintFeeRecipient ");

bytes32 digest = factoryProxyDeployer.hashedDigestFactoryProxy(
proxyShimSalt,
factoryProxySalt,
proxySalt,
factoryProxyCreationCode,
factoryImplAddress,
factoryOwner
mintFeeRecipient
);

// sign the message
(uint8 v, bytes32 r, bytes32 s) = vm.sign(deployerPrivateKey, digest);
bytes memory signature = signAndMakeBytes(digest, deployerPrivateKey);

// combine into a single bytes array
bytes memory signature = abi.encodePacked(r, s, v);
address expectedFactoryProxyAddress = ZoraDeployerUtils.deterministicFactoryProxyAddress(proxyShimSalt, proxySalt, address(factoryProxyDeployer));

// now do it as original deployer, it should succeed:
address factoryProxyAddress = factoryProxyDeployer.createFactoryProxyDeterministic(
proxyShimSalt,
factoryProxySalt,
proxySalt,
factoryProxyCreationCode,
expectedFactoryProxyAddress,
factoryImplAddress,
factoryOwner,
mintFeeRecipient,
signature
);

Expand All @@ -139,6 +89,13 @@ contract DeterministicProxyDeployerTest is Test {
assertEq(factoryProxyAddress, expectedFactoryProxyAddress, "factory proxy address wrong");
}

function signAndMakeBytes(bytes32 digest, uint256 privateKey) internal returns (bytes memory) {
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest);

// combine into a single bytes array
return abi.encodePacked(r, s, v);
}

function test_genericContractCanByDeployedAtDesiredAddress(uint32 nonce) external {
vm.createSelectFork("zora_goerli", 1252119);

Expand All @@ -148,16 +105,15 @@ contract DeterministicProxyDeployerTest is Test {
// we set the nonce to a random value, to prove this doesn't affect the deterministic addrss
vm.setNonce(deployerAddress, nonce);

DeterministicProxyDeployer factoryProxyDeployer = _deployKnownZoraFactoryProxy();
DeterministicProxyDeployer factoryProxyDeployer = _deployKnownZoraFactoryProxy(bytes32(0));

address gateAdmin = makeAddr("gateAdmin");

bytes memory upgradeGateDeployCode = type(UpgradeGate).creationCode;

bytes memory initCall = abi.encodeWithSignature("initialize(address)", gateAdmin);

bytes32 genericTestDeploySalt = bytes32(0x0000000000000000000000000000000000000000baaaaaacafeaaaaaacafef00) &
bytes32(uint256(uint160(address(deployerAddress))) << 96);
bytes32 genericTestDeploySalt = saltWithAddressInFirst20Bytes(deployerAddress, 20);

bytes32 digest = factoryProxyDeployer.hashedDigestGenericCreation(genericTestDeploySalt, upgradeGateDeployCode, initCall);

Expand Down
Loading