Skip to content

Commit

Permalink
Premint deploy determinstic fix tests (#213)
Browse files Browse the repository at this point in the history
* fixed tests by just making it more dyanmic

* fix stack too deep error for coverage

* ignore deployment folder for coverage
  • Loading branch information
oveddan authored Sep 29, 2023
1 parent acab71c commit 0b6db23
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 133 deletions.
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

0 comments on commit 0b6db23

Please sign in to comment.