-
Notifications
You must be signed in to change notification settings - Fork 103
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Made premint executor upgradeable via a proxy. (#168)
Moved some common factory setup logic to some library fixtures
- Loading branch information
Showing
8 changed files
with
278 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,12 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.17; | ||
|
||
interface IContractMetadata { | ||
interface IHasContractName { | ||
/// @notice Contract name returns the pretty contract name | ||
function contractName() external returns (string memory); | ||
} | ||
|
||
interface IContractMetadata is IHasContractName { | ||
/// @notice Contract URI returns the uri for more information about the given contract | ||
function contractURI() external returns (string memory); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.17; | ||
|
||
import {Enjoy} from "_imagine/mint/Enjoy.sol"; | ||
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; | ||
|
||
/* | ||
░░░░░░░░░░░░░░ | ||
░░▒▒░░░░░░░░░░░░░░░░░░░░ | ||
░░▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░ | ||
░░▒▒▒▒░░░░░░░░░░░░░░ ░░░░░░░░ | ||
░▓▓▒▒▒▒░░░░░░░░░░░░ ░░░░░░░ | ||
░▓▓▓▒▒▒▒░░░░░░░░░░░░ ░░░░░░░░ | ||
░▓▓▓▒▒▒▒░░░░░░░░░░░░░░ ░░░░░░░░░░ | ||
░▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░ | ||
░▓▓▓▓▓▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░ | ||
░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░ | ||
░░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░ | ||
░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒░░░░░░░░░▒▒▒▒▒░░ | ||
░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░ | ||
░░▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░ | ||
OURS TRULY, | ||
*/ | ||
|
||
/// Imagine. Mint. Enjoy. | ||
/// @notice Imagine. Mint. Enjoy. | ||
/// @author @oveddan | ||
contract Zora1155PremintExecutorProxy is Enjoy, ERC1967Proxy { | ||
constructor(address _logic, bytes memory _data) ERC1967Proxy(_logic, _data) {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.17; | ||
|
||
import {ZoraCreator1155Impl} from "../../src/nft/ZoraCreator1155Impl.sol"; | ||
import {ZoraCreatorFixedPriceSaleStrategy} from "../../src/minters/fixed-price/ZoraCreatorFixedPriceSaleStrategy.sol"; | ||
import {IZoraCreator1155} from "../../src/interfaces/IZoraCreator1155.sol"; | ||
import {IMinter1155} from "../../src/interfaces/IMinter1155.sol"; | ||
import {Zora1155Factory} from "../../src/proxies/Zora1155Factory.sol"; | ||
import {ZoraCreator1155FactoryImpl} from "../../src/factory/ZoraCreator1155FactoryImpl.sol"; | ||
import {ProtocolRewards} from "@zoralabs/protocol-rewards/src/ProtocolRewards.sol"; | ||
import {ProxyShim} from "../../src/utils/ProxyShim.sol"; | ||
|
||
library Zora1155FactoryFixtures { | ||
function setupZora1155Impl(uint256 mintFeeAmount, address zora, Zora1155Factory factoryProxy) internal returns (ZoraCreator1155Impl) { | ||
ProtocolRewards rewards = new ProtocolRewards(); | ||
return new ZoraCreator1155Impl(mintFeeAmount, zora, address(factoryProxy), address(rewards)); | ||
} | ||
|
||
function upgradeFactoryProxyToUse1155( | ||
Zora1155Factory factoryProxy, | ||
IZoraCreator1155 zoraCreator1155Impl, | ||
IMinter1155 fixedPriceMinter, | ||
address admin | ||
) internal returns (ZoraCreator1155FactoryImpl factoryImpl) { | ||
factoryImpl = new ZoraCreator1155FactoryImpl(zoraCreator1155Impl, IMinter1155(address(1)), fixedPriceMinter, IMinter1155(address(3))); | ||
|
||
ZoraCreator1155FactoryImpl factoryAtProxy = ZoraCreator1155FactoryImpl(address(factoryProxy)); | ||
|
||
factoryAtProxy.upgradeTo(address(factoryImpl)); | ||
factoryAtProxy.initialize(admin); | ||
} | ||
|
||
function setupFactoryProxy(address deployer) internal returns (Zora1155Factory factoryProxy) { | ||
address factoryShimAddress = address(new ProxyShim(deployer)); | ||
factoryProxy = new Zora1155Factory(factoryShimAddress, ""); | ||
} | ||
|
||
function setup1155AndFactoryProxy( | ||
uint256 mintFeeAmount, | ||
address zora, | ||
address deployer | ||
) internal returns (ZoraCreator1155Impl zoraCreator1155Impl, IMinter1155 fixedPriceMinter, Zora1155Factory factoryProxy) { | ||
factoryProxy = setupFactoryProxy(deployer); | ||
fixedPriceMinter = new ZoraCreatorFixedPriceSaleStrategy(); | ||
zoraCreator1155Impl = setupZora1155Impl(mintFeeAmount, zora, factoryProxy); | ||
upgradeFactoryProxyToUse1155(factoryProxy, zoraCreator1155Impl, fixedPriceMinter, deployer); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.17; | ||
|
||
import {ZoraCreator1155Impl} from "../../src/nft/ZoraCreator1155Impl.sol"; | ||
import {ZoraCreatorFixedPriceSaleStrategy} from "../../src/minters/fixed-price/ZoraCreatorFixedPriceSaleStrategy.sol"; | ||
import {IZoraCreator1155} from "../../src/interfaces/IZoraCreator1155.sol"; | ||
import {IMinter1155} from "../../src/interfaces/IMinter1155.sol"; | ||
import {ICreatorRoyaltiesControl} from "../../src/interfaces/ICreatorRoyaltiesControl.sol"; | ||
import {Zora1155Factory} from "../../src/proxies/Zora1155Factory.sol"; | ||
import {ZoraCreator1155FactoryImpl} from "../../src/factory/ZoraCreator1155FactoryImpl.sol"; | ||
import {ProtocolRewards} from "@zoralabs/protocol-rewards/src/ProtocolRewards.sol"; | ||
import {ProxyShim} from "../../src/utils/ProxyShim.sol"; | ||
import {ContractCreationConfig, TokenCreationConfig, PremintConfig} from "../../src/premint/ZoraCreator1155Attribution.sol"; | ||
|
||
library Zora1155PremintFixtures { | ||
function makeDefaultContractCreationConfig(address contractAdmin) internal pure returns (ContractCreationConfig memory) { | ||
return ContractCreationConfig({contractAdmin: contractAdmin, contractName: "blah", contractURI: "blah.contract"}); | ||
} | ||
|
||
function defaultRoyaltyConfig(address royaltyRecipient) internal pure returns (ICreatorRoyaltiesControl.RoyaltyConfiguration memory) { | ||
return ICreatorRoyaltiesControl.RoyaltyConfiguration({royaltyBPS: 10, royaltyRecipient: royaltyRecipient, royaltyMintSchedule: 100}); | ||
} | ||
|
||
function makeDefaultTokenCreationConfig(IMinter1155 fixedPriceMinter, address royaltyRecipient) internal pure returns (TokenCreationConfig memory) { | ||
ICreatorRoyaltiesControl.RoyaltyConfiguration memory royaltyConfig = defaultRoyaltyConfig(royaltyRecipient); | ||
return | ||
TokenCreationConfig({ | ||
tokenURI: "blah.token", | ||
maxSupply: 10, | ||
maxTokensPerAddress: 5, | ||
pricePerToken: 0, | ||
mintStart: 0, | ||
mintDuration: 0, | ||
royaltyMintSchedule: royaltyConfig.royaltyMintSchedule, | ||
royaltyBPS: royaltyConfig.royaltyBPS, | ||
royaltyRecipient: royaltyConfig.royaltyRecipient, | ||
fixedPriceMinter: address(fixedPriceMinter) | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.17; | ||
|
||
import "forge-std/Test.sol"; | ||
import {Zora1155FactoryFixtures} from "../fixtures/Zora1155FactoryFixtures.sol"; | ||
import {Zora1155PremintFixtures} from "../fixtures/Zora1155PremintFixtures.sol"; | ||
import {ZoraCreator1155FactoryImpl} from "../../src/factory/ZoraCreator1155FactoryImpl.sol"; | ||
import {Zora1155PremintExecutorProxy} from "../../src/proxies/Zora1155PremintExecutorProxy.sol"; | ||
import {ZoraCreator1155Impl} from "../../src/nft/ZoraCreator1155Impl.sol"; | ||
import {ZoraCreator1155PremintExecutor} from "../../src/premint/ZoraCreator1155PremintExecutor.sol"; | ||
import {Zora1155Factory} from "../../src/proxies/Zora1155Factory.sol"; | ||
import {IMinter1155} from "../../src/interfaces/IMinter1155.sol"; | ||
import {ProxyShim} from "../../src/utils/ProxyShim.sol"; | ||
import {ZoraCreator1155Attribution, ContractCreationConfig, TokenCreationConfig, PremintConfig} from "../../src/premint/ZoraCreator1155Attribution.sol"; | ||
import {IOwnable2StepUpgradeable} from "../../src/utils/ownable/IOwnable2StepUpgradeable.sol"; | ||
import {IHasContractName} from "../../src/interfaces/IContractMetadata.sol"; | ||
|
||
contract Zora1155PremintExecutorProxyTest is Test, IHasContractName { | ||
address internal owner; | ||
uint256 internal creatorPrivateKey; | ||
address internal creator; | ||
address internal collector; | ||
address internal zora; | ||
Zora1155Factory internal factoryProxy; | ||
ZoraCreator1155FactoryImpl factoryAtProxy; | ||
uint256 internal mintFeeAmount = 0.000777 ether; | ||
ZoraCreator1155PremintExecutor preminterAtProxy; | ||
|
||
function setUp() external { | ||
zora = makeAddr("zora"); | ||
owner = makeAddr("owner"); | ||
collector = makeAddr("collector"); | ||
(creator, creatorPrivateKey) = makeAddrAndKey("creator"); | ||
|
||
vm.startPrank(zora); | ||
(, , factoryProxy) = Zora1155FactoryFixtures.setup1155AndFactoryProxy(mintFeeAmount, zora, zora); | ||
factoryAtProxy = ZoraCreator1155FactoryImpl(address(factoryProxy)); | ||
vm.stopPrank(); | ||
|
||
// create preminter implementation | ||
ZoraCreator1155PremintExecutor preminterImplementation = new ZoraCreator1155PremintExecutor(ZoraCreator1155FactoryImpl(address(factoryProxy))); | ||
|
||
// build the proxy | ||
Zora1155PremintExecutorProxy proxy = new Zora1155PremintExecutorProxy(address(preminterImplementation), ""); | ||
|
||
// access the executor implementation via the proxy, and initialize the admin | ||
preminterAtProxy = ZoraCreator1155PremintExecutor(address(proxy)); | ||
preminterAtProxy.initialize(owner); | ||
} | ||
|
||
function test_canInvokeImplementationMethods() external { | ||
// create premint config | ||
IMinter1155 fixedPriceMinter = ZoraCreator1155FactoryImpl(address(factoryProxy)).fixedPriceMinter(); | ||
|
||
PremintConfig memory premintConfig = PremintConfig({ | ||
tokenConfig: Zora1155PremintFixtures.makeDefaultTokenCreationConfig(fixedPriceMinter, creator), | ||
uid: 100, | ||
version: 0, | ||
deleted: false | ||
}); | ||
|
||
// now interface with proxy preminter - sign and execute the premint | ||
ContractCreationConfig memory contractConfig = Zora1155PremintFixtures.makeDefaultContractCreationConfig(creator); | ||
address deterministicAddress = preminterAtProxy.getContractAddress(contractConfig); | ||
|
||
// sign the premint | ||
bytes32 digest = ZoraCreator1155Attribution.premintHashedTypeDataV4(premintConfig, deterministicAddress, block.chainid); | ||
|
||
(uint8 v, bytes32 r, bytes32 s) = vm.sign(creatorPrivateKey, digest); | ||
|
||
uint256 quantityToMint = 1; | ||
|
||
bytes memory signature = abi.encodePacked(r, s, v); | ||
|
||
// execute the premint | ||
vm.deal(collector, mintFeeAmount); | ||
vm.prank(collector); | ||
uint256 tokenId = preminterAtProxy.premint{value: mintFeeAmount}(contractConfig, premintConfig, signature, quantityToMint, ""); | ||
|
||
assertEq(ZoraCreator1155Impl(deterministicAddress).balanceOf(collector, tokenId), 1); | ||
} | ||
|
||
function test_onlyOwnerCanUpgrade() external { | ||
// try to upgrade as non-owner | ||
ZoraCreator1155PremintExecutor newImplementation = new ZoraCreator1155PremintExecutor(factoryAtProxy); | ||
|
||
vm.expectRevert(IOwnable2StepUpgradeable.ONLY_OWNER.selector); | ||
vm.prank(creator); | ||
preminterAtProxy.upgradeTo(address(newImplementation)); | ||
} | ||
|
||
/// giving this a contract name so that it can be used to fail upgrading preminter contract | ||
function contractName() public pure returns (string memory) { | ||
return "Test Contract"; | ||
} | ||
|
||
function test_canOnlyBeUpgradedToContractWithSameName() external { | ||
// upgrade to bad contract with has wrong name (this contract has mismatched name) | ||
vm.expectRevert( | ||
abi.encodeWithSelector(ZoraCreator1155PremintExecutor.UpgradeToMismatchedContractName.selector, preminterAtProxy.contractName(), contractName()) | ||
); | ||
vm.prank(owner); | ||
preminterAtProxy.upgradeTo(address(this)); | ||
|
||
// upgrade to good contract which has correct name - it shouldn't revert | ||
ZoraCreator1155PremintExecutor newImplementation = new ZoraCreator1155PremintExecutor(ZoraCreator1155FactoryImpl(address(factoryProxy))); | ||
|
||
vm.prank(owner); | ||
preminterAtProxy.upgradeTo(address(newImplementation)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters