diff --git a/src/drops/token/HolographDropERC721V2.sol b/src/drops/token/HolographDropERC721V2.sol index a60eaa5b2..1b4164507 100644 --- a/src/drops/token/HolographDropERC721V2.sol +++ b/src/drops/token/HolographDropERC721V2.sol @@ -166,6 +166,10 @@ contract HolographDropERC721V2 is NonReentrant, ERC721H, IHolographDropERC721V2 */ mapping(address => uint256) public totalMintsByAddress; + /// @notice Getter for the init payload + /// @dev This storage variable is set only once in the init and can be considered as immutable + bytes private INIT_PAYLOAD; + /** * CUSTOM ERRORS */ @@ -225,6 +229,9 @@ contract HolographDropERC721V2 is NonReentrant, ERC721H, IHolographDropERC721V2 function init(bytes memory initPayload) external override returns (bytes4) { require(!_isInitialized(), "HOLOGRAPH: already initialized"); + // Store the init payload + INIT_PAYLOAD = initPayload; + DropsInitializerV2 memory initializer = abi.decode(initPayload, (DropsInitializerV2)); // Setup the owner role @@ -273,6 +280,13 @@ contract HolographDropERC721V2 is NonReentrant, ERC721H, IHolographDropERC721V2 return interfaceId == type(IHolographDropERC721V2).interfaceId; } + /** + * @notice Getter for the DropsInitializerV2 init payload + */ + function getInitProperties() external view returns (DropsInitializerV2 memory) { + return abi.decode(INIT_PAYLOAD, (DropsInitializerV2)); + } + /** * PUBLIC NON STATE CHANGING FUNCTIONS * dynamic diff --git a/src/enforcer/HolographERC721.sol b/src/enforcer/HolographERC721.sol index 44faff035..df1eafe25 100644 --- a/src/enforcer/HolographERC721.sol +++ b/src/enforcer/HolographERC721.sol @@ -138,7 +138,7 @@ contract HolographERC721 is Admin, Owner, HolographERC721Interface, Initializabl * @dev bytes32(uint256(keccak256('eip1967.Holograph.sourceContract')) - 1) */ bytes32 constant _sourceContractSlot = 0x27d542086d1e831d40b749e7f5509a626c3047a36d160781c40d5acc83e5b074; - + /** * @dev Configuration for events to trigger for source smart contract. */ @@ -254,6 +254,7 @@ contract HolographERC721 is Admin, Owner, HolographERC721Interface, Initializabl _symbol = contractSymbol; _bps = contractBps; _eventConfig = eventConfig; + if (!skipInit) { require(sourceContract.init(initCode) == InitializableInterface.init.selector, "ERC721: could not init source"); (bool success, bytes memory returnData) = _royalties().delegatecall( diff --git a/src/token/CountdownERC721.sol b/src/token/CountdownERC721.sol index a79b03fcc..3c7165c80 100644 --- a/src/token/CountdownERC721.sol +++ b/src/token/CountdownERC721.sol @@ -6,11 +6,8 @@ import {ERC721H} from "../abstract/ERC721H.sol"; import {NonReentrant} from "../abstract/NonReentrant.sol"; import {HolographERC721Interface} from "../interface/HolographERC721Interface.sol"; -import {HolographerInterface} from "../interface/HolographerInterface.sol"; -import {HolographInterface} from "../interface/HolographInterface.sol"; import {ICountdownERC721} from "../interface/ICountdownERC721.sol"; import {IDropsPriceOracle} from "../drops/interface/IDropsPriceOracle.sol"; -import {HolographTreasuryInterface} from "../interface/HolographTreasuryInterface.sol"; import {AddressMintDetails} from "../drops/struct/AddressMintDetails.sol"; import {CountdownERC721Initializer} from "src/struct/CountdownERC721Initializer.sol"; @@ -19,7 +16,6 @@ import {CustomERC721SalesConfiguration} from "src/struct/CustomERC721SalesConfig import {MetadataParams} from "src/struct/MetadataParams.sol"; import {Address} from "../drops/library/Address.sol"; -import {MerkleProof} from "../drops/library/MerkleProof.sol"; import {Strings} from "./../drops/library/Strings.sol"; import {NFTMetadataRenderer} from "../library/NFTMetadataRenderer.sol"; @@ -64,6 +60,10 @@ contract CountdownERC721 is NonReentrant, ERC721H, ICountdownERC721 { /// @dev This account tokens on behalf of those that purchase them offchain address public minter; + /// @notice Getter for the init payload + /// @dev This storage variable is set only once in the init and can be considered as immutable + bytes private INIT_PAYLOAD; + /* -------------------------------------------------------------------------- */ /* METADATA VARAIBLES */ /* -------------------------------------------------------------------------- */ @@ -188,6 +188,9 @@ contract CountdownERC721 is NonReentrant, ERC721H, ICountdownERC721 { sstore(_holographerSlot, caller()) } + // Store the init payload + INIT_PAYLOAD = initPayload; + // Decode the initializer payload to get the CountdownERC721Initializer struct CountdownERC721Initializer memory initializer = abi.decode(initPayload, (CountdownERC721Initializer)); @@ -286,6 +289,13 @@ contract CountdownERC721 is NonReentrant, ERC721H, ICountdownERC721 { return interfaceId == type(ICountdownERC721).interfaceId; } + /** + * @notice Getter for the CountdownERC721Initializer init payload + */ + function getInitProperties() external view returns (CountdownERC721Initializer memory) { + return abi.decode(INIT_PAYLOAD, (CountdownERC721Initializer)); + } + /* -------------------------------------------------------------------------- */ /* PUBLIC NON STATE CHANGING FUNCTIONS */ /* dynamic */ diff --git a/src/token/CustomERC721.sol b/src/token/CustomERC721.sol index ec45b8acb..887ac0880 100644 --- a/src/token/CustomERC721.sol +++ b/src/token/CustomERC721.sol @@ -62,6 +62,10 @@ contract CustomERC721 is NonReentrant, ContractMetadata, InitializableLazyMint, /// @notice Getter for the end date uint256 public END_DATE; + /// @notice Getter for the init payload + /// @dev This storage variable is set only once in the init and can be considered as immutable + bytes private INIT_PAYLOAD; + /// @notice Getter for the minter /// @dev This account tokens on behalf of those that purchase them offchain address public minter; @@ -145,6 +149,9 @@ contract CustomERC721 is NonReentrant, ContractMetadata, InitializableLazyMint, function init(bytes memory initPayload) external override returns (bytes4) { require(!_isInitialized(), "HOLOGRAPH: already initialized"); + // Store the init payload + INIT_PAYLOAD = initPayload; + // Enable sourceExternalCall to work on init, we set holographer here since it's only set after init assembly { sstore(_holographerSlot, caller()) @@ -293,6 +300,13 @@ contract CustomERC721 is NonReentrant, ContractMetadata, InitializableLazyMint, return (_getOwner() == user); } + /** + * @notice Getter for the CustomERC721Initializer init payload + */ + function getInitProperties() external view returns (CustomERC721Initializer memory) { + return abi.decode(INIT_PAYLOAD, (CustomERC721Initializer)); + } + /** * @notice Returns the theoretical maximum supply for the current time * @dev The max supply is calculated based on the current time and the mint interval, by subtracting diff --git a/src/token/CxipERC721.sol b/src/token/CxipERC721.sol index 5599681cd..d452b05b8 100644 --- a/src/token/CxipERC721.sol +++ b/src/token/CxipERC721.sol @@ -117,6 +117,10 @@ import "../interface/HolographerInterface.sol"; * @dev The entire logic and functionality of the smart contract is self-contained. */ contract CxipERC721 is ERC721H { + /// @notice Getter for the init payload + /// @dev This storage variable is set only once in the init and can be considered as immutable + bytes private INIT_PAYLOAD; + /** * @dev Internal reference used for minting incremental token ids. */ @@ -148,6 +152,9 @@ contract CxipERC721 is ERC721H { * @param initPayload abi encoded payload to use for contract initilaization */ function init(bytes memory initPayload) external override returns (bytes4) { + // Store the init payload + INIT_PAYLOAD = initPayload; + // we set this as default type since that's what Mint is currently using _uriType = TokenUriType.IPFS; address owner = abi.decode(initPayload, (address)); @@ -156,6 +163,13 @@ contract CxipERC721 is ERC721H { return _init(initPayload); } + /** + * @notice Getter for the CxipERC721 init payload + */ + function getInitProperties() external view returns (address) { + return abi.decode(INIT_PAYLOAD, (address)); + } + /** * @notice Get's the URI of the token. * @return string The URI. diff --git a/src/token/HolographLegacyERC721.sol b/src/token/HolographLegacyERC721.sol index dd886ce32..494f1b45e 100644 --- a/src/token/HolographLegacyERC721.sol +++ b/src/token/HolographLegacyERC721.sol @@ -18,6 +18,10 @@ import "../interface/HolographerInterface.sol"; * @dev The entire logic and functionality of the smart contract is self-contained. */ contract HolographLegacyERC721 is ERC721H { + /// @notice Getter for the init payload + /// @dev This storage variable is set only once in the init and can be considered as immutable + bytes private INIT_PAYLOAD; + /** * @dev Internal reference used for minting incremental token ids. */ @@ -49,6 +53,9 @@ contract HolographLegacyERC721 is ERC721H { * @param initPayload abi encoded payload to use for contract initilaization */ function init(bytes memory initPayload) external override returns (bytes4) { + // Store the init payload + INIT_PAYLOAD = initPayload; + // we set this as default type since that's what Mint is currently using _uriType = TokenUriType.IPFS; address owner = abi.decode(initPayload, (address)); @@ -57,6 +64,13 @@ contract HolographLegacyERC721 is ERC721H { return _init(initPayload); } + /** + * @notice Getter for the HolographLegacyERC721 init payload + */ + function getInitProperties() external view returns (address) { + return abi.decode(INIT_PAYLOAD, (address)); + } + /** * @notice Get's the URI of the token. * @return string The URI. diff --git a/src/token/HolographUtilityToken.sol b/src/token/HolographUtilityToken.sol index ea08f9da2..34cf0010d 100644 --- a/src/token/HolographUtilityToken.sol +++ b/src/token/HolographUtilityToken.sol @@ -115,6 +115,10 @@ import "../interface/HolographerInterface.sol"; * @dev The entire logic and functionality of the smart contract is self-contained. */ contract HolographUtilityToken is HLGERC20H { + /// @notice Getter for the init payload + /// @dev This storage variable is set only once in the init and can be considered as immutable + bytes private INIT_PAYLOAD; + /** * @dev Constructor is left empty and init is used instead */ @@ -126,6 +130,9 @@ contract HolographUtilityToken is HLGERC20H { * @param initPayload abi encoded payload to use for contract initilaization */ function init(bytes memory initPayload) external override returns (bytes4) { + // Store the init payload + INIT_PAYLOAD = initPayload; + (address contractOwner, uint256 tokenAmount, uint256 targetChain, address tokenRecipient) = abi.decode( initPayload, (address, uint256, uint256, address) @@ -150,4 +157,11 @@ contract HolographUtilityToken is HLGERC20H { function isHLG() external pure returns (bool) { return true; } + + /** + * @notice Getter for the CountdownERC721Initializer init payload + */ + function getInitProperties() external view returns (address, uint256, uint256, address) { + return abi.decode(INIT_PAYLOAD, (address, uint256, uint256, address)); + } } diff --git a/src/token/SampleERC20.sol b/src/token/SampleERC20.sol index 206b0c078..d52dba2c2 100644 --- a/src/token/SampleERC20.sol +++ b/src/token/SampleERC20.sol @@ -112,6 +112,10 @@ import "../interface/HolographERC20Interface.sol"; * @dev The entire logic and functionality of the smart contract is self-contained. */ contract SampleERC20 is StrictERC20H { + /// @notice Getter for the init payload + /// @dev This storage variable is set only once in the init and can be considered as immutable + bytes private INIT_PAYLOAD; + /** * @dev Just a dummy value for now to test transferring of data. */ @@ -133,6 +137,9 @@ contract SampleERC20 is StrictERC20H { * @param initPayload abi encoded payload to use for contract initilaization */ function init(bytes memory initPayload) external override returns (bytes4) { + // Store the init payload + INIT_PAYLOAD = initPayload; + // do your own custom logic here address contractOwner = abi.decode(initPayload, (address)); _setOwner(contractOwner); @@ -140,6 +147,13 @@ contract SampleERC20 is StrictERC20H { return _init(initPayload); } + /** + * @notice Getter for the CountdownERC721Initializer init payload + */ + function getInitProperties() external view returns (address) { + return abi.decode(INIT_PAYLOAD, (address)); + } + /** * @dev Sample mint where anyone can mint any amounts of tokens. */ diff --git a/src/token/SampleERC721.sol b/src/token/SampleERC721.sol index a1281681e..6e064a708 100644 --- a/src/token/SampleERC721.sol +++ b/src/token/SampleERC721.sol @@ -112,6 +112,10 @@ import "../interface/HolographERC721Interface.sol"; * @dev The entire logic and functionality of the smart contract is self-contained. */ contract SampleERC721 is StrictERC721H { + /// @notice Getter for the init payload + /// @dev This storage variable is set only once in the init and can be considered as immutable + bytes private INIT_PAYLOAD; + /** * @dev Mapping of all token URIs. */ @@ -138,6 +142,9 @@ contract SampleERC721 is StrictERC721H { * @param initPayload abi encoded payload to use for contract initilaization */ function init(bytes memory initPayload) external override returns (bytes4) { + // Store the init payload + INIT_PAYLOAD = initPayload; + // do your own custom logic here address contractOwner = abi.decode(initPayload, (address)); _setOwner(contractOwner); @@ -154,6 +161,13 @@ contract SampleERC721 is StrictERC721H { return _tokenURIs[_tokenId]; } + /** + * @notice Getter for the SampleERC721 init payload + */ + function getInitProperties() external view returns (address) { + return abi.decode(INIT_PAYLOAD, (address)); + } + /** * @dev Sample mint where anyone can mint specific token, with a custom URI */ diff --git a/src/token/hToken.sol b/src/token/hToken.sol index f5af32904..beebdb2e7 100644 --- a/src/token/hToken.sol +++ b/src/token/hToken.sol @@ -115,6 +115,10 @@ import "../interface/HolographerInterface.sol"; * @dev The entire logic and functionality of the smart contract is self-contained. */ contract hToken is ERC20H { + /// @notice Getter for the init payload + /// @dev This storage variable is set only once in the init and can be considered as immutable + bytes private INIT_PAYLOAD; + /** * @dev Sample fee for unwrapping. */ @@ -161,6 +165,9 @@ contract hToken is ERC20H { * @param initPayload abi encoded payload to use for contract initilaization */ function init(bytes memory initPayload) external override returns (bytes4) { + // Store the init payload + INIT_PAYLOAD = initPayload; + (address contractOwner, uint16 fee) = abi.decode(initPayload, (address, uint16)); assembly { /** @@ -174,6 +181,13 @@ contract hToken is ERC20H { return _init(initPayload); } + /** + * @notice Getter for the CountdownERC721Initializer init payload + */ + function getInitProperties() external view returns (address, uint16) { + return abi.decode(INIT_PAYLOAD, (address, uint16)); + } + /** * @dev Send native token value, get back hToken equivalent. * @param recipient Address of where to send the hToken(s) to. diff --git a/test/foundry/deploy/04_Erc721Enforcer.t.sol b/test/foundry/deploy/04_Erc721Enforcer.t.sol index b8183e89d..04fb6cba7 100644 --- a/test/foundry/deploy/04_Erc721Enforcer.t.sol +++ b/test/foundry/deploy/04_Erc721Enforcer.t.sol @@ -41,7 +41,6 @@ contract Erc721Enforcer is Test { string public constant tokenURI2 = "https://holograph.xyz/sample2.json"; string public constant tokenURI3 = "https://holograph.xyz/sample3.json"; - /// @notice Set up the testing environment by initializing all necessary contracts and accounts. function setUp() public { vm.createSelectFork(LOCALHOST_RPC_URL); @@ -284,7 +283,7 @@ contract Erc721Enforcer is Test { /// @notice Should return contract URI as base64 string function testContractURI() public { string - memory expectedURI = "data:application/json;base64,eyJuYW1lIjoiU2FtcGxlIEVSQzcyMSBDb250cmFjdCAobG9jYWxob3N0KSIsImRlc2NyaXB0aW9uIjoiU2FtcGxlIEVSQzcyMSBDb250cmFjdCAobG9jYWxob3N0KSIsImltYWdlIjoiIiwiZXh0ZXJuYWxfbGluayI6IiIsInNlbGxlcl9mZWVfYmFzaXNfcG9pbnRzIjoxMDAwLCJmZWVfcmVjaXBpZW50IjoiMHg4NDZhZjRjODdmNWFmMWYzMDNlNWE1ZDIxNWQ4M2E2MTFiMDgwNjljIn0"; + memory expectedURI = "data:application/json;base64,eyJuYW1lIjoiU2FtcGxlIEVSQzcyMSBDb250cmFjdCAobG9jYWxob3N0KSIsImRlc2NyaXB0aW9uIjoiU2FtcGxlIEVSQzcyMSBDb250cmFjdCAobG9jYWxob3N0KSIsImltYWdlIjoiIiwiZXh0ZXJuYWxfbGluayI6IiIsInNlbGxlcl9mZWVfYmFzaXNfcG9pbnRzIjoxMDAwLCJmZWVfcmVjaXBpZW50IjoiMHgxNGUwNjA1NDdhODQ4YjU0ODE5MTJmZGMzYTdiMGUyODdkN2I5MGZkIn0"; assertEq(holographERC721.contractURI(), expectedURI, "The contract URI does not match."); } @@ -348,7 +347,7 @@ contract Erc721Enforcer is Test { emit Transfer(address(0), bob, tokenId2); _mint(bob, tokenId2, tokenURI2); - + assertEq(holographERC721.totalSupply(), 2); } diff --git a/test/foundry/enforcers/HolographERC721/HolographERC721.sourceContractInitCode.t.sol b/test/foundry/enforcers/HolographERC721/HolographERC721.sourceContractInitCode.t.sol new file mode 100644 index 000000000..9beccd283 --- /dev/null +++ b/test/foundry/enforcers/HolographERC721/HolographERC721.sourceContractInitCode.t.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.13; + +import {Vm} from "forge-std/Test.sol"; +import {console} from "forge-std/console.sol"; + +import {ICustomERC721Errors} from "test/foundry/interface/ICustomERC721Errors.sol"; +import {HolographERC721Fixture} from "test/foundry/fixtures/HolographERC721Fixture.t.sol"; + +contract HolographERC721InitPayloadTest is HolographERC721Fixture, ICustomERC721Errors { + constructor() {} + + function setUp() public override { + super.setUp(); + } + + function test_CountdownERC721InitPayload() public { + console.log(usedInitPayload.length); + + (bool success, bytes memory initPayload) = address(countdownErc721).call(abi.encodeWithSignature("getInitProperties()")); + + assertEq(success, true, "getInitProperties() call should succeed"); + assertEq(initPayload, usedInitPayload, "initPayload should match usedInitPayload"); + } +} diff --git a/test/foundry/fixtures/HolographERC721Fixture.t.sol b/test/foundry/fixtures/HolographERC721Fixture.t.sol new file mode 100644 index 000000000..809c70de3 --- /dev/null +++ b/test/foundry/fixtures/HolographERC721Fixture.t.sol @@ -0,0 +1,218 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.13; + +import {Test, Vm} from "forge-std/Test.sol"; + +import {HolographTreasury} from "src/HolographTreasury.sol"; +import {DummyDropsPriceOracle} from "src/drops/oracle/DummyDropsPriceOracle.sol"; +import {CountdownERC721Initializer} from "src/struct/CountdownERC721Initializer.sol"; +import {DeploymentConfig} from "src/struct/DeploymentConfig.sol"; +import {CustomERC721SalesConfiguration} from "src/struct/CustomERC721SalesConfiguration.sol"; +import {Verification} from "src/struct/Verification.sol"; +import {HolographFactory} from "src/HolographFactory.sol"; +import {HolographerInterface} from "src/interface/HolographerInterface.sol"; +import {HolographERC721} from "src/enforcer/HolographERC721.sol"; +import {CountdownERC721} from "src/token/CountdownERC721.sol"; + +import {MockUser} from "../utils/MockUser.sol"; +import {Utils} from "../utils/Utils.sol"; + +import {Constants} from "test/foundry/utils/Constants.sol"; +import {DEFAULT_MINT_INTERVAL, DEFAULT_START_DATE} from "test/foundry/CountdownERC721/utils/Constants.sol"; + +contract HolographERC721Fixture is Test { + /* ----------------------------- Default values ----------------------------- */ + address public constant DEFAULT_OWNER_ADDRESS = address(0x1); + address public constant DEFAULT_MINTER_ADDRESS = address(0x11); + address payable public constant DEFAULT_FUNDS_RECIPIENT_ADDRESS = payable(address(0x2)); + string public DEFAULT_DESCRIPTION = "Description of the token"; + string public DEFAULT_IMAGE_URI = "ar://o8eyC27OuSZF0z-zIen5NTjJOKTzOQzKJzIe3F7Lmg0/1.png"; + string public DEFAULT_EXTERNAL_LINK = "https://example.com"; + string public DEFAULT_ENCRYPTED_MEDIA_URI = "xxx"; + string public DEFAULT_CONTRACT_URI = "https://example.com/metadata.json"; + + /* -------------------------------- Addresses ------------------------------- */ + address sourceContractAddress; + address payable public constant HOLOGRAPH_TREASURY_ADDRESS = payable(address(0x3)); + address payable constant TEST_ACCOUNT = payable(address(0x888)); + address public constant MEDIA_CONTRACT = address(0x666); + address public alice; + address public initialOwner = address(uint160(uint256(keccak256("initialOwner")))); + address public fundsRecipient = address(uint160(uint256(keccak256("fundsRecipient")))); + + /* -------------------------------- Contracts ------------------------------- */ + HolographERC721 erc721Enforcer; + MockUser public mockUser; + CountdownERC721 public countdownErc721; + HolographTreasury public treasury; + DummyDropsPriceOracle public dummyPriceOracle; + + /* ---------------------------- Test environment ---------------------------- */ + uint104 mintEthPrice = 0.1 ether; + uint256 public chainPrepend; + uint256 internal fuzzingMaxSupply; + uint256 public constant FIRST_TOKEN_ID = + 115792089183396302089269705419353877679230723318366275194376439045705909141505; // large 256 bit number due to chain id prefix + + /* --------------------------------- Storage -------------------------------- */ + bytes public usedInitPayload; + + constructor() {} + + function setUp() public virtual { + // Setup VM + // NOTE: These tests rely on the Holograph protocol being deployed to the local chain + // At the moment, the deploy pipeline is still managed by Hardhat, so we need to + // first run it via `npx hardhat deploy --network localhost` or `yarn deploy:localhost` if you need two local chains before running the tests. + uint256 forkId = vm.createFork("http://localhost:8545"); + vm.selectFork(forkId); + + // Setup signer wallet + // NOTE: This is the address that will be used to sign transactions + // A signature is required to deploy Holographable contracts via the HolographFactory + alice = vm.addr(1); + // vm.prank(HOLOGRAPH_TREASURY_ADDRESS); + dummyPriceOracle = DummyDropsPriceOracle(Constants.getDummyDropsPriceOracle()); + + // NOTE: This needs to be uncommented to inject the DropsPriceOracleProxy contract into the VM if it isn't done by the deploy script + // At the moment we have hardhat configured to deploy and inject the code approrpriately to match the hardcoded address in the HolographDropERC721V2 contract + // We deploy DropsPriceOracleProxy at specific address + // vm.etch(address(Constants.getDropsPriceOracleProxy()), address(new DropsPriceOracleProxy()).code); + // We set storage slot to point to actual drop implementation + // vm.store( + // address(Constants.getDropsPriceOracleProxy()), + // bytes32(uint256(keccak256("eip1967.Holograph.dropsPriceOracle")) - 1), + // bytes32(abi.encode(Constants.getDummyDropsPriceOracle())) + // ); + + try vm.envUint("FUZZING_MAX_SUPPLY") returns (uint256 result) { + fuzzingMaxSupply = result; + } catch { + fuzzingMaxSupply = 100; + } + + chainPrepend = deployAndSetupProtocol(uint32(fuzzingMaxSupply)); + } + + modifier setUpPurchase() { + _setUpPurchase(); + + _; + } + + /* -------------------------------------------------------------------------- */ + /* Test helpers */ + /* -------------------------------------------------------------------------- */ + + + function deployAndSetupProtocol(uint32 maxSupply) internal returns (uint256) { + _deployAndSetupProtocol(maxSupply); + + return chainPrepend; + } + + /** + * @notice Deploys the a HolopgraphERC721 contract and sets up the protocol + * @dev Using CountdownERC721 as the source contract + * @param maxSupply The max supply of the edition + */ + function _deployAndSetupProtocol(uint32 maxSupply) private { + // Setup sale config for edition + CustomERC721SalesConfiguration memory saleConfig = CustomERC721SalesConfiguration({ + publicSalePrice: uint104(mintEthPrice), + maxSalePurchasePerAddress: 0 // no limit + }); + + // Create initializer + CountdownERC721Initializer memory initializer = CountdownERC721Initializer({ + description: DEFAULT_DESCRIPTION, + imageURI: DEFAULT_IMAGE_URI, + animationURI: "", + externalLink: DEFAULT_EXTERNAL_LINK, + encryptedMediaURI: DEFAULT_ENCRYPTED_MEDIA_URI, + startDate: DEFAULT_START_DATE, + initialMaxSupply: maxSupply, + mintInterval: DEFAULT_MINT_INTERVAL, + initialOwner: payable(DEFAULT_OWNER_ADDRESS), + initialMinter: payable(DEFAULT_MINTER_ADDRESS), + fundsRecipient: payable(DEFAULT_FUNDS_RECIPIENT_ADDRESS), + contractURI: DEFAULT_CONTRACT_URI, + salesConfiguration: saleConfig + }); + + usedInitPayload = abi.encode(initializer); + + // Get deployment config, hash it, and then sign it + DeploymentConfig memory config = getDeploymentConfig( + "Contract Name", // contractName + "SYM", // contractSymbol + 1000, // contractBps + type(uint256).max, // eventConfig + false, // skipInit + initializer + ); + bytes32 hash = keccak256( + abi.encodePacked( + config.contractType, + config.chainType, + config.salt, + keccak256(config.byteCode), + keccak256(config.initCode), + alice + ) + ); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(1, hash); + Verification memory signature = Verification(r, s, v); + address signer = ecrecover(hash, v, r, s); + require(signer == alice, "Invalid signature"); + + HolographFactory factory = HolographFactory(payable(Constants.getHolographFactoryProxy())); + + // Deploy the drop / edition + vm.recordLogs(); + factory.deployHolographableContract(config, signature, alice); // Pass the payload hash, with the signature, and signer's address + Vm.Log[] memory entries = vm.getRecordedLogs(); + + address newCountdownERC721Address = address(uint160(uint256(entries[2].topics[1]))); + + // Connect the drop implementation to the drop proxy address + countdownErc721 = CountdownERC721(payable(newCountdownERC721Address)); + erc721Enforcer = HolographERC721(payable(address(countdownErc721))); + } + + function getDeploymentConfig( + string memory contractName, + string memory contractSymbol, + uint16 contractBps, + uint256 eventConfig, + bool skipInit, + CountdownERC721Initializer memory initializer + ) public returns (DeploymentConfig memory) { + bytes memory bytecode = abi.encodePacked(vm.getCode("CountdownERC721Proxy.sol:CountdownERC721Proxy")); + bytes memory initCode = abi.encode( + bytes32(0x0000000000000000000000000000000000436f756e74646f776e455243373231), // Source contract type CountdownERC721 + address(Constants.getHolographRegistryProxy()), // address of registry (to get source contract address from) + abi.encode(initializer) // actual init code for source contract (CountdownERC721) + ); + + return + DeploymentConfig({ + contractType: Utils.stringToBytes32("HolographERC721"), // HolographERC721 + chainType: 1338, // holograph.getChainId(), + salt: 0x0000000000000000000000000000000000000000000000000000000000000001, // random salt from user + byteCode: bytecode, // countdown contract bytecode + initCode: abi.encode(contractName, contractSymbol, contractBps, eventConfig, skipInit, initCode) // init code is used to initialize the HolographERC721 enforcer + }); + } + + function _setUpPurchase() internal { + // We assume that the amount is at least one and less than or equal to the edition size given in modifier + vm.prank(DEFAULT_OWNER_ADDRESS); + + HolographerInterface holographerInterface = HolographerInterface(address(countdownErc721)); + sourceContractAddress = holographerInterface.getSourceContract(); + + vm.warp(countdownErc721.START_DATE()); + } +} diff --git a/test/foundry/utils/Constants.sol b/test/foundry/utils/Constants.sol index c27f87c62..9e0f7d82f 100644 --- a/test/foundry/utils/Constants.sol +++ b/test/foundry/utils/Constants.sol @@ -101,11 +101,11 @@ library Constants { } function getCxipERC721() internal pure returns (address) { - return address(0xE7AD7a544fa0262256F035Da6F77e396A271eA4C); + return address(0x96169B7EEd0730C978152680A8CefFFE74D8AEa8); } function getHToken() internal pure returns (address) { - return address(0xEe7804e943659DB09338718F0B4123117A085109); + return address(0xcfE62d271Dd3Ea21BF824f7A61Ae9b2443b85480); } // NOTE: This has to be updated to the correct address every time a new contract is added to be @@ -121,7 +121,7 @@ library Constants { } function getSampleERC20() internal pure returns (address) { - return address(0x5a5DbB0515Cb2af1945E731B86BB5e34E4d0d3A3); + return address(0x5C713b4c94a426d12D82430EC48dac77A92b335f); } function getSampleERC20_L2() internal pure returns (address) { @@ -129,7 +129,7 @@ library Constants { } function getSampleERC721() internal pure returns (address) { - return address(0x846Af4c87F5Af1F303E5a5D215D83A611b08069c); + return address(0x14e060547a848b5481912Fdc3A7B0e287d7b90Fd); } function getSampleERC721_L2() internal pure returns (address) {