Skip to content

Commit

Permalink
using create 3
Browse files Browse the repository at this point in the history
  • Loading branch information
oveddan committed Jul 20, 2023
1 parent c03ca12 commit 3d25a6e
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 9 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
"@openzeppelin/contracts": "4.8.3",
"@zoralabs/openzeppelin-contracts-upgradeable": "^4.8.4",
"ds-test": "https://github.com/dapphub/ds-test#cd98eff28324bfac652e63a239a60632a761790b",
"forge-std": "https://github.com/foundry-rs/forge-std#cd7d533f9a0ee0ec02ad81e0a8f262bc4203c653"
"forge-std": "https://github.com/foundry-rs/forge-std#cd7d533f9a0ee0ec02ad81e0a8f262bc4203c653",
"solmate": "^6.1.0"
},
"devDependencies": {
"@changesets/cli": "^2.26.1",
Expand All @@ -50,8 +51,8 @@
"prettier": "^2.8.8",
"prettier-plugin-solidity": "^1.1.3",
"tsup": "^6.7.0",
"viem": "^0.3.49",
"typescript": "^5.0.4",
"viem": "^0.3.49",
"vite": "^4.1.4",
"vitest": "~0.30.1"
}
Expand Down
3 changes: 2 additions & 1 deletion remappings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ ds-test/=node_modules/ds-test/src/
forge-std/=node_modules/forge-std/src/
@zoralabs/openzeppelin-contracts-upgradeable/=node_modules/@zoralabs/openzeppelin-contracts-upgradeable/
@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/
_imagine=_imagine/
_imagine=_imagine/
solemate/=/node_modules/solemate/src/
67 changes: 67 additions & 0 deletions script/TestCreateDeterministic.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import "forge-std/Script.sol";
import "forge-std/console2.sol";

import {ZoraDeployerBase} from "./ZoraDeployerBase.sol";
import {ChainConfig, Deployment} from "../src/deployment/DeploymentConfig.sol";

import {ZoraCreator1155FactoryImpl} from "../src/factory/ZoraCreator1155FactoryImpl.sol";
import {Zora1155Factory} from "../src/proxies/Zora1155Factory.sol";
import {ZoraCreator1155Impl} from "../src/nft/ZoraCreator1155Impl.sol";
import {ICreatorRoyaltiesControl} from "../src/interfaces/ICreatorRoyaltiesControl.sol";
import {IZoraCreator1155Factory} from "../src/interfaces/IZoraCreator1155Factory.sol";
import {IMinter1155} from "../src/interfaces/IMinter1155.sol";
import {IZoraCreator1155} from "../src/interfaces/IZoraCreator1155.sol";
import {ProxyShim} from "../src/utils/ProxyShim.sol";
import {ZoraCreatorFixedPriceSaleStrategy} from "../src/minters/fixed-price/ZoraCreatorFixedPriceSaleStrategy.sol";
import {ZoraCreatorMerkleMinterStrategy} from "../src/minters/merkle/ZoraCreatorMerkleMinterStrategy.sol";
import {ZoraCreatorRedeemMinterFactory} from "../src/minters/redeem/ZoraCreatorRedeemMinterFactory.sol";

contract DeployScript is ZoraDeployerBase {
function run() public {
// ChainConfig memory chainConfig = getChainConfig();

// console2.log("zoraFeeAmount", chainConfig.mintFeeAmount);
// console2.log("zoraFeeRecipient", chainConfig.mintFeeRecipient);
// console2.log("factoryOwner", chainConfig.factoryOwner);

uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
address deployer = vm.addr(deployerPrivateKey);

ICreatorRoyaltiesControl.RoyaltyConfiguration memory royaltyConfig = ICreatorRoyaltiesControl.RoyaltyConfiguration({
royaltyBPS: 10,
royaltyRecipient: vm.addr(5),
royaltyMintSchedule: 100
});
bytes[] memory initSetup = new bytes[](1);
initSetup[0] = abi.encodeWithSelector(IZoraCreator1155.setupNewToken.selector, "ipfs://asdfadsf", 100);
string memory uri = "ipfs://asdfadsf";
string memory nameA = "nameA";

vm.startBroadcast(deployerPrivateKey);

ZoraCreator1155Impl zoraCreator1155Impl = new ZoraCreator1155Impl(0, address(0), address(0));
// get above constructor args encoded for verification later:
ZoraCreator1155FactoryImpl factory = new ZoraCreator1155FactoryImpl(
zoraCreator1155Impl,
IMinter1155(address(1)),
IMinter1155(address(2)),
IMinter1155(address(3))
);

address factoryOwner = deployer;

// 1. create the proxy, pointing it to the factory implentation and setting the owner
ZoraCreator1155FactoryImpl proxy = ZoraCreator1155FactoryImpl(
payable(new Zora1155Factory(address(factory), abi.encodeWithSelector(ZoraCreator1155FactoryImpl.initialize.selector, factoryOwner)))
);

address createdErc1155 = proxy.createContractDeterministic(uri, nameA, royaltyConfig, payable(deployer), initSetup);

console.log("deployed erc1155 at", createdErc1155);
console.log("constructor args", string(abi.encode(0, address(0), address(0))));
vm.stopBroadcast();
}
}
11 changes: 5 additions & 6 deletions src/factory/ZoraCreator1155FactoryImpl.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {Ownable2StepUpgradeable} from "../utils/ownable/Ownable2StepUpgradeable.
import {FactoryManagedUpgradeGate} from "../upgrades/FactoryManagedUpgradeGate.sol";
import {Zora1155} from "../proxies/Zora1155.sol";
import {Create2Upgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/utils/Create2Upgradeable.sol";
import {CREATE3} from "solmate/src/utils/CREATE3.sol";

import {ContractVersionBase} from "../version/ContractVersionBase.sol";

Expand Down Expand Up @@ -89,7 +90,9 @@ contract ZoraCreator1155FactoryImpl is IZoraCreator1155Factory, ContractVersionB
) external returns (address) {
bytes32 digest = _hashContract(newContractURI, name, defaultAdmin);

Zora1155 newContract = new Zora1155{salt: digest}(address(implementation));
address createdContract = CREATE3.deploy(digest, abi.encodePacked(type(Zora1155).creationCode, abi.encode(implementation)), 0);

Zora1155 newContract = Zora1155(payable(createdContract));

_initializeContract(newContract, newContractURI, name, defaultRoyaltyConfiguration, defaultAdmin, setupActions);

Expand All @@ -99,11 +102,7 @@ contract ZoraCreator1155FactoryImpl is IZoraCreator1155Factory, ContractVersionB
function deterministicContractAddress(string calldata newContractURI, string calldata name, address contractAdmin) external view returns (address) {
bytes32 digest = _hashContract(newContractURI, name, contractAdmin);

bytes memory bytecode = type(Zora1155).creationCode;

bytes32 contractCodeHash = keccak256(abi.encodePacked(bytecode, abi.encode(address(implementation))));

return Create2Upgradeable.computeAddress(digest, contractCodeHash);
return CREATE3.getDeployed(digest);
}

function _initializeContract(
Expand Down
115 changes: 115 additions & 0 deletions test/factory/ZoraCreator1155Factory.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {IZoraCreator1155Factory} from "../../src/interfaces/IZoraCreator1155Fact
import {IZoraCreator1155} from "../../src/interfaces/IZoraCreator1155.sol";
import {IMinter1155} from "../../src/interfaces/IMinter1155.sol";
import {ICreatorRoyaltiesControl} from "../../src/interfaces/ICreatorRoyaltiesControl.sol";
import {Zora1155} from "../../src/proxies/Zora1155.sol";
import {MockContractMetadata} from "../mock/MockContractMetadata.sol";

contract ZoraCreator1155FactoryTest is Test {
Expand Down Expand Up @@ -120,4 +121,118 @@ contract ZoraCreator1155FactoryTest is Test {
vm.expectRevert(abi.encodeWithSignature("UpgradeToMismatchedContractName(string,string)", "ZORA 1155 Contract Factory", "name"));
proxy.upgradeTo(address(mockContractMetadata));
}

function test_createContractDeterminisitc_createsContractAtSameAddressForNameAndUri(
string calldata nameA,
string calldata uri,
address contractAdmin,
// this number will determine how transactions the factory makes before
// creating the deterministic contract. it should not affect the address
uint16 numberOfCallsBeforeCreation
) external {
vm.assume(contractAdmin != address(0));

// we can know ahead of time the expected address
address expectedContractAddress = factory.deterministicContractAddress(uri, nameA, contractAdmin);

// create parameters for contract creation
ICreatorRoyaltiesControl.RoyaltyConfiguration memory royaltyConfig = ICreatorRoyaltiesControl.RoyaltyConfiguration({
royaltyBPS: 10,
royaltyRecipient: vm.addr(5),
royaltyMintSchedule: 100
});
bytes[] memory initSetup = new bytes[](1);
initSetup[0] = abi.encodeWithSelector(IZoraCreator1155.setupNewToken.selector, "ipfs://asdfadsf", 100);

// create x number of contracts via the factory, this should affect the nonce.
for (uint256 i = 0; i < numberOfCallsBeforeCreation; i++) {
factory.createContract("ipfs://someOtherUri", "someOtherName", royaltyConfig, payable(vm.addr(3)), initSetup);
}

// now create deterministically, address should match expected address
address createdAddress = factory.createContractDeterministic(uri, nameA, royaltyConfig, payable(contractAdmin), new bytes[](0));

assertEq(createdAddress, expectedContractAddress);
}

function test_createContractDeterministic_whenContractUpgraded_stillHasSameAddress() external {
string memory uri = "ipfs://asdfadsf";
string memory nameA = "nameA";
address contractAdmin = vm.addr(1);

address factoryOwner = vm.addr(10);

// 1. create the proxy, pointing it to the factory implentation and setting the owner
ZoraCreator1155FactoryImpl proxy = ZoraCreator1155FactoryImpl(
payable(new Zora1155Factory(address(factory), abi.encodeWithSelector(ZoraCreator1155FactoryImpl.initialize.selector, factoryOwner)))
);

// get the deterministic address of the contract before its created
address expectedContractAddress = proxy.deterministicContractAddress(uri, nameA, contractAdmin);

uint256 newMintFeeAmount = 1 ether;

// 2. update the erc1155 implementation:
// * create a new version of the erc1155 implementation
// * create a new factory that points to that new erc1155 implementation,
// * upgrade the proxy to point to the new factory
IZoraCreator1155 newZoraCreator = new ZoraCreator1155Impl(newMintFeeAmount, address(0), address(0));

ZoraCreator1155FactoryImpl newFactoryImpl = new ZoraCreator1155FactoryImpl(
newZoraCreator,
IMinter1155(address(0)),
IMinter1155(address(0)),
IMinter1155(address(0))
);

vm.prank(factoryOwner);
proxy.upgradeTo(address(newFactoryImpl));

// sanity check - make sure that the proxy erc1155 implementation is pointing to the new implementation
assertEq(address(proxy.implementation()), address(newZoraCreator));

// 3. Create a contract with a deterministic address, it should match the address from before the upgrade
ICreatorRoyaltiesControl.RoyaltyConfiguration memory royaltyConfig = ICreatorRoyaltiesControl.RoyaltyConfiguration({
royaltyBPS: 10,
royaltyRecipient: vm.addr(5),
royaltyMintSchedule: 100
});
bytes[] memory initSetup = new bytes[](1);
initSetup[0] = abi.encodeWithSelector(IZoraCreator1155.setupNewToken.selector, "ipfs://asdfadsf", 100);

// now create deterministically, address should match expected address
address createdAddress = proxy.createContractDeterministic(uri, nameA, royaltyConfig, payable(contractAdmin), initSetup);

assertEq(createdAddress, expectedContractAddress);
}

function test_createContractDeterministic_createdContractcontractCanBeUpgraded() external {
string memory uri = "ipfs://asdfadsf";
string memory nameA = "nameA";
address contractAdmin = vm.addr(1);

// 1. Have the factory the contract deterministically
ICreatorRoyaltiesControl.RoyaltyConfiguration memory royaltyConfig = ICreatorRoyaltiesControl.RoyaltyConfiguration({
royaltyBPS: 10,
royaltyRecipient: vm.addr(5),
royaltyMintSchedule: 100
});
bytes[] memory initSetup = new bytes[](1);
initSetup[0] = abi.encodeWithSelector(IZoraCreator1155.setupNewToken.selector, "ipfs://asdfadsf", 100);

// now create deterministically, address should match expected address
address createdAddress = factory.createContractDeterministic(uri, nameA, royaltyConfig, payable(contractAdmin), initSetup);

ZoraCreator1155Impl creatorProxy = ZoraCreator1155Impl(createdAddress);

// 2. upgrade the created contract by creating a new contract and upgrading the existing one to point to it.
uint256 newMintFeeAmount = 1 ether;
IZoraCreator1155 newZoraCreator = new ZoraCreator1155Impl(newMintFeeAmount, address(0), address(0));

vm.prank(creatorProxy.owner());
creatorProxy.upgradeTo(address(newZoraCreator));

// 3. check that proxy contract was upgraded
assertEq(creatorProxy.mintFee(), newMintFeeAmount);
}
}
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3291,6 +3291,11 @@ solidity-comments-extractor@^0.0.7:
resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz#99d8f1361438f84019795d928b931f4e5c39ca19"
integrity sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==

solmate@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/solmate/-/solmate-6.1.0.tgz#b85aaa8c2b34afe9c6d6d5a015c369267c576313"
integrity sha512-gxG4YU5nnAQ+Ac23R44GS3Xo3+X0+8XCe4/P1KvVobL5ERBzQBG/xMv7NSvVo/pkHSYGufgUAPjiueYxujKJAA==

source-map-js@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
Expand Down

0 comments on commit 3d25a6e

Please sign in to comment.