From bb8069e578e5d869185fb4a45df025d132c7fc68 Mon Sep 17 00:00:00 2001 From: Dan Oved Date: Thu, 14 Sep 2023 09:48:02 -0700 Subject: [PATCH] Premint: first minter rewards (#162) * refactor: remove legacy mint fee contracts * refactor: remove unusued import * chore: update tests * chore: lint * chore: update runs * chore: update storage layout * style: update natspec * chore: update tests * chore: remove unused var * chore: update tests * fix: move hardcoded fork vars to constants * added first minter changeset * * Added changeset that depreates redeem minters. * Remove Redeem minter from coverage. --------- Co-authored-by: Rohan Kulkarni --- .changeset/happy-socks-melt.md | 5 + .changeset/spotty-horses-battle.md | 5 + .github/workflows/coverage.yml | 2 +- .storage-layout | 3 +- foundry.toml | 4 +- package.json | 2 +- src/deployment/DeploymentConfig.sol | 1 - src/fee/MintFeeManager.sol | 39 - src/nft/ZoraCreator1155Impl.sol | 61 +- test/factory/ZoraCreator1155Factory.t.sol | 3 - .../factory/ZoraCreator1155Factory_Fork.t.sol | 19 +- test/fee/MintFeeManager.t.sol | 90 - .../ZoraCreatorFixedPriceSaleStrategy.t.sol | 80 +- .../ZoraCreatorMerkleMinterStrategy.t.sol | 63 +- .../ZoraCreatorRedeemMinterFactory.t.sol | 101 +- .../ZoraCreatorRedeemMinterStrategy.t.sol | 2965 +++++++++-------- test/nft/ZoraCreator1155.t.sol | 165 +- yarn.lock | 8 +- 18 files changed, 1828 insertions(+), 1788 deletions(-) create mode 100644 .changeset/happy-socks-melt.md create mode 100644 .changeset/spotty-horses-battle.md delete mode 100644 src/fee/MintFeeManager.sol delete mode 100644 test/fee/MintFeeManager.t.sol diff --git a/.changeset/happy-socks-melt.md b/.changeset/happy-socks-melt.md new file mode 100644 index 000000000..f6319738c --- /dev/null +++ b/.changeset/happy-socks-melt.md @@ -0,0 +1,5 @@ +--- +"@zoralabs/zora-1155-contracts": minor +--- + +Adds first minter rewards diff --git a/.changeset/spotty-horses-battle.md b/.changeset/spotty-horses-battle.md new file mode 100644 index 000000000..e018133bf --- /dev/null +++ b/.changeset/spotty-horses-battle.md @@ -0,0 +1,5 @@ +--- +"@zoralabs/zora-1155-contracts": patch +--- + +Deprecate ZoraCreatorRedeemMinterStrategy at v1.0.1, a newer version will soon be released diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index cba87e066..879b2facd 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -42,7 +42,7 @@ jobs: run: | lcov --rc lcov_branch_coverage=1 \ --remove lcov.info \ - --output-file lcov.info "*node_modules*" "*test*" "*script*" "*DeploymentConfig*" + --output-file lcov.info "*node_modules*" "*test*" "*script*" "*DeploymentConfig*" "*Redeem*" - name: Report code coverage uses: zgosalvez/github-actions-report-lcov@v2 diff --git a/.storage-layout b/.storage-layout index 6859a1da5..c8795d895 100644 --- a/.storage-layout +++ b/.storage-layout @@ -33,7 +33,8 @@ | permissions | mapping(uint256 => mapping(address => uint256)) | 510 | 0 | 32 | src/nft/ZoraCreator1155Impl.sol:ZoraCreator1155Impl | | __gap | uint256[50] | 511 | 0 | 1600 | src/nft/ZoraCreator1155Impl.sol:ZoraCreator1155Impl | | createReferrals | mapping(uint256 => address) | 561 | 0 | 32 | src/nft/ZoraCreator1155Impl.sol:ZoraCreator1155Impl | -| delegatedTokenId | mapping(uint32 => uint256) | 562 | 0 | 32 | src/nft/ZoraCreator1155Impl.sol:ZoraCreator1155Impl | +| firstMinters | mapping(uint256 => address) | 562 | 0 | 32 | src/nft/ZoraCreator1155Impl.sol:ZoraCreator1155Impl | +| delegatedTokenId | mapping(uint32 => uint256) | 563 | 0 | 32 | src/nft/ZoraCreator1155Impl.sol:ZoraCreator1155Impl | ======================= ➡ ZoraCreator1155FactoryImpl diff --git a/foundry.toml b/foundry.toml index 2d32d4992..d5d3af477 100644 --- a/foundry.toml +++ b/foundry.toml @@ -2,7 +2,7 @@ fs_permissions = [{access = "read", path = "./addresses"}, {access = "read", path = "./chainConfigs"}, {access = "read", path = "./package.json"}] libs = ['_imagine', 'node_modules', 'script'] optimizer = true -optimizer_runs = 500 +optimizer_runs = 250 out = 'out' solc_version = '0.8.17' src = 'src' @@ -10,7 +10,7 @@ via_ir = true [profile.optimized] optimizer = true -optimizer_runs = 3000 +optimizer_runs = 250 out = 'out' script = 'src' solc_version = '0.8.17' diff --git a/package.json b/package.json index d65ab59c6..b56769811 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "dependencies": { "@openzeppelin/contracts": "4.9.2", "@zoralabs/openzeppelin-contracts-upgradeable": "4.8.4", - "@zoralabs/protocol-rewards": "1.1.1", + "@zoralabs/protocol-rewards": "1.1.2", "ds-test": "https://github.com/dapphub/ds-test#cd98eff28324bfac652e63a239a60632a761790b", "forge-std": "https://github.com/foundry-rs/forge-std#705263c95892a906d7af65f0f73ce8a4a0c80b80", "solmate": "^6.1.0" diff --git a/src/deployment/DeploymentConfig.sol b/src/deployment/DeploymentConfig.sol index 055f7c167..348aae27d 100644 --- a/src/deployment/DeploymentConfig.sol +++ b/src/deployment/DeploymentConfig.sol @@ -3,7 +3,6 @@ pragma solidity 0.8.17; import "forge-std/Test.sol"; import {CommonBase} from "forge-std/Base.sol"; -import {MintFeeManager} from "../../src/fee/MintFeeManager.sol"; import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; /// @notice Chain configuration for constants set manually during deploy. Does not get written to after deploys. diff --git a/src/fee/MintFeeManager.sol b/src/fee/MintFeeManager.sol deleted file mode 100644 index e4ded27e9..000000000 --- a/src/fee/MintFeeManager.sol +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.17; - -import {TransferHelperUtils} from "../utils/TransferHelperUtils.sol"; -import {IMintFeeManager} from "../interfaces/IMintFeeManager.sol"; - -/// @title MintFeeManager -/// @notice Manages mint fees for an 1155 contract -contract MintFeeManager is IMintFeeManager { - uint256 public immutable mintFee; - address public immutable mintFeeRecipient; - - constructor(uint256 _mintFee, address _mintFeeRecipient) { - // Set fixed finders fee - if (_mintFee >= 0.1 ether) { - revert MintFeeCannotBeMoreThanZeroPointOneETH(_mintFee); - } - if (_mintFeeRecipient == address(0) && _mintFee > 0) { - revert CannotSetMintFeeToZeroAddress(); - } - mintFeeRecipient = _mintFeeRecipient; - mintFee = _mintFee; - } - - /// @notice Sends the mint fee to the mint fee recipient and returns the amount of ETH remaining that can be used in this transaction - /// @param _quantity The amount of toknens being minted - function _handleFeeAndGetValueSent(uint256 _quantity) internal returns (uint256 ethValueSent) { - ethValueSent = msg.value; - - // Handle mint fee - if (mintFeeRecipient != address(0)) { - uint256 totalFee = mintFee * _quantity; - ethValueSent -= totalFee; - if (!TransferHelperUtils.safeSendETH(mintFeeRecipient, totalFee, TransferHelperUtils.FUNDS_SEND_LOW_GAS_LIMIT)) { - revert CannotSendMintFee(mintFeeRecipient, totalFee); - } - } - } -} diff --git a/src/nft/ZoraCreator1155Impl.sol b/src/nft/ZoraCreator1155Impl.sol index b89a6514c..bf62db80c 100644 --- a/src/nft/ZoraCreator1155Impl.sol +++ b/src/nft/ZoraCreator1155Impl.sol @@ -26,7 +26,6 @@ import {ITransferHookReceiver} from "../interfaces/ITransferHookReceiver.sol"; import {IFactoryManagedUpgradeGate} from "../interfaces/IFactoryManagedUpgradeGate.sol"; import {IZoraCreator1155} from "../interfaces/IZoraCreator1155.sol"; import {LegacyNamingControl} from "../legacy-naming/LegacyNamingControl.sol"; -import {MintFeeManager} from "../fee/MintFeeManager.sol"; import {PublicMulticall} from "../utils/PublicMulticall.sol"; import {SharedBaseConstants} from "../shared/SharedBaseConstants.sol"; import {TransferHelperUtils} from "../utils/TransferHelperUtils.sol"; @@ -44,7 +43,6 @@ contract ZoraCreator1155Impl is ReentrancyGuardUpgradeable, PublicMulticall, ERC1155Upgradeable, - MintFeeManager, UUPSUpgradeable, CreatorRendererControl, LegacyNamingControl, @@ -69,11 +67,11 @@ contract ZoraCreator1155Impl is IFactoryManagedUpgradeGate internal immutable factory; constructor( - uint256 _mintFeeAmount, + uint256, // TODO remove address _mintFeeRecipient, address _factory, address _protocolRewards - ) MintFeeManager(_mintFeeAmount, _mintFeeRecipient) ERC1155Rewards(_protocolRewards, _mintFeeRecipient) initializer { + ) ERC1155Rewards(_protocolRewards, _mintFeeRecipient) initializer { factory = IFactoryManagedUpgradeGate(_factory); } @@ -413,8 +411,18 @@ contract ZoraCreator1155Impl is // Require admin from the minter to mint _requireAdminOrRole(address(minter), tokenId, PERMISSION_BIT_MINTER); + // Get the token's first minter + address firstMinter = _handleFirstMinter(tokenId, minterArguments); + // Get value sent and handle mint fee - uint256 ethValueSent = _handleFeeAndGetValueSent(quantity); + uint256 ethValueSent = _handleRewardsAndGetValueSent( + msg.value, + quantity, + getCreatorRewardRecipient(), + createReferrals[tokenId], + address(0), + firstMinter + ); // Execute commands returned from minter _executeCommands(minter.requestMint(msg.sender, tokenId, quantity, ethValueSent, minterArguments).commands, ethValueSent, tokenId); @@ -422,13 +430,7 @@ contract ZoraCreator1155Impl is emit Purchased(msg.sender, address(minter), tokenId, quantity, msg.value); } - /// @notice Get the creator reward recipient address - /// @dev The creator is not enforced to set a funds recipient address, so in that case the reward would be claimable by creator's contract - function getCreatorRewardRecipient() public view returns (address payable) { - return config.fundsRecipient != address(0) ? config.fundsRecipient : payable(address(this)); - } - - /// @notice Mint tokens and payout rewards given a minter contract, minter arguments, a finder, and a origin + /// @notice Mint tokens and payout rewards given a minter contract, minter arguments, and a mint referral /// @param minter The minter contract to use /// @param tokenId The token ID to mint /// @param quantity The quantity of tokens to mint @@ -444,8 +446,18 @@ contract ZoraCreator1155Impl is // Require admin from the minter to mint _requireAdminOrRole(address(minter), tokenId, PERMISSION_BIT_MINTER); + // Get the token's first minter + address firstMinter = _handleFirstMinter(tokenId, minterArguments); + // Get value sent and handle mint rewards - uint256 ethValueSent = _handleRewardsAndGetValueSent(msg.value, quantity, getCreatorRewardRecipient(), createReferrals[tokenId], mintReferral); + uint256 ethValueSent = _handleRewardsAndGetValueSent( + msg.value, + quantity, + getCreatorRewardRecipient(), + createReferrals[tokenId], + mintReferral, + firstMinter + ); // Execute commands returned from minter _executeCommands(minter.requestMint(msg.sender, tokenId, quantity, ethValueSent, minterArguments).commands, ethValueSent, tokenId); @@ -453,6 +465,29 @@ contract ZoraCreator1155Impl is emit Purchased(msg.sender, address(minter), tokenId, quantity, msg.value); } + /// @dev Get and/or set the first minter a token + function _handleFirstMinter(uint256 tokenId, bytes calldata data) internal returns (address) { + // If this is the first mint for the token: + if (firstMinters[tokenId] == address(0)) { + // Decode the address of the reward recipient + // Assume the first argument is an address + address rewardRecipient = abi.decode(data, (address)); + + // Store the address to lookup for future mints + firstMinters[tokenId] = rewardRecipient; + + return rewardRecipient; + } + + return firstMinters[tokenId]; + } + + /// @notice Get the creator reward recipient address + /// @dev The creator is not enforced to set a funds recipient address, so in that case the reward would be claimable by creator's contract + function getCreatorRewardRecipient() public view returns (address payable) { + return config.fundsRecipient != address(0) ? config.fundsRecipient : payable(address(this)); + } + /// @notice Set a metadata renderer for a token /// @param tokenId The token ID to set the renderer for /// @param renderer The renderer to set diff --git a/test/factory/ZoraCreator1155Factory.t.sol b/test/factory/ZoraCreator1155Factory.t.sol index 8e79b0584..47b1c405a 100644 --- a/test/factory/ZoraCreator1155Factory.t.sol +++ b/test/factory/ZoraCreator1155Factory.t.sol @@ -256,8 +256,5 @@ contract ZoraCreator1155FactoryTest is Test { vm.prank(creatorProxy.owner()); creatorProxy.upgradeTo(address(newZoraCreator)); - - // 3. check that proxy contract was upgraded - assertEq(creatorProxy.mintFee(), newMintFeeAmount); } } diff --git a/test/factory/ZoraCreator1155Factory_Fork.t.sol b/test/factory/ZoraCreator1155Factory_Fork.t.sol index 894b55c6d..8c2d87bf9 100644 --- a/test/factory/ZoraCreator1155Factory_Fork.t.sol +++ b/test/factory/ZoraCreator1155Factory_Fork.t.sol @@ -4,17 +4,23 @@ pragma solidity 0.8.17; import "forge-std/Test.sol"; import {IZoraCreator1155Factory} from "../../src/interfaces/IZoraCreator1155Factory.sol"; import {IZoraCreator1155} from "../../src/interfaces/IZoraCreator1155.sol"; +import {ZoraCreator1155Impl} from "../../src/nft/ZoraCreator1155Impl.sol"; import {IMinter1155} from "../../src/interfaces/IMinter1155.sol"; import {IOwnable} from "../../src/interfaces/IOwnable.sol"; import {ICreatorRoyaltiesControl} from "../../src/interfaces/ICreatorRoyaltiesControl.sol"; import {MockContractMetadata} from "../mock/MockContractMetadata.sol"; import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {ZoraCreatorFixedPriceSaleStrategy} from "../../src/minters/fixed-price/ZoraCreatorFixedPriceSaleStrategy.sol"; -import {MintFeeManager} from "../../src/fee/MintFeeManager.sol"; - import {ForkDeploymentConfig} from "../../src/deployment/DeploymentConfig.sol"; contract ZoraCreator1155FactoryForkTest is ForkDeploymentConfig, Test { + uint256 constant mintFee = 0.000777 ether; + uint96 constant tokenPrice = 1 ether; + uint256 constant quantityToMint = 3; + uint256 constant tokenMaxSupply = 100; + uint32 constant royaltyMintSchedule = 10; + uint32 constant royaltyBPS = 100; + address collector; address creator; @@ -38,7 +44,6 @@ contract ZoraCreator1155FactoryForkTest is ForkDeploymentConfig, Test { function _setupToken(IZoraCreator1155 target, IMinter1155 fixedPrice, uint96 tokenPrice) private returns (uint256 tokenId) { string memory tokenURI = "ipfs://token"; - uint256 tokenMaxSupply = 100; tokenId = target.setupNewToken(tokenURI, tokenMaxSupply); @@ -119,15 +124,7 @@ contract ZoraCreator1155FactoryForkTest is ForkDeploymentConfig, Test { // ** 3. Mint on that contract ** - // get the mint fee from the contract - uint256 mintFee = MintFeeManager(address(target)).mintFee(); - - // make sure the mint fee amount matches the configured mint fee amount - assertEq(mintFee, getChainConfig().mintFeeAmount, chainName); - // mint 3 tokens - - uint256 quantityToMint = 3; uint256 valueToSend = quantityToMint * (tokenPrice + mintFee); // mint the token diff --git a/test/fee/MintFeeManager.t.sol b/test/fee/MintFeeManager.t.sol deleted file mode 100644 index 12c903e5d..000000000 --- a/test/fee/MintFeeManager.t.sol +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.17; - -import "forge-std/Test.sol"; -import {ProtocolRewards} from "@zoralabs/protocol-rewards/src/ProtocolRewards.sol"; -import {ZoraCreator1155Impl} from "../../src/nft/ZoraCreator1155Impl.sol"; -import {Zora1155} from "../../src/proxies/Zora1155.sol"; -import {IZoraCreator1155} from "../../src/interfaces/IZoraCreator1155.sol"; -import {IZoraCreator1155TypesV1} from "../../src/nft/IZoraCreator1155TypesV1.sol"; -import {ICreatorRoyaltiesControl} from "../../src/interfaces/ICreatorRoyaltiesControl.sol"; -import {IZoraCreator1155Factory} from "../../src/interfaces/IZoraCreator1155Factory.sol"; -import {IMintFeeManager} from "../../src/interfaces/IMintFeeManager.sol"; -import {SimpleMinter} from "../mock/SimpleMinter.sol"; - -contract MintFeeManagerTest is Test { - ZoraCreator1155Impl internal zoraCreator1155Impl; - ZoraCreator1155Impl internal target; - ProtocolRewards internal protocolRewards; - address payable internal admin; - address internal recipient; - uint256 internal adminRole; - uint256 internal minterRole; - uint256 internal fundsManagerRole; - - function setUp() external { - protocolRewards = new ProtocolRewards(); - admin = payable(vm.addr(0x1)); - recipient = vm.addr(0x2); - } - - function _emptyInitData() internal pure returns (bytes[] memory response) { - response = new bytes[](0); - } - - function test_mintFeeSent(uint32 mintFee, uint256 quantity) external { - vm.assume(quantity < 100); - vm.assume(mintFee < 0.1 ether); - uint256 mintPrice = mintFee * quantity; - zoraCreator1155Impl = new ZoraCreator1155Impl(mintFee, recipient, address(0), address(protocolRewards)); - target = ZoraCreator1155Impl(address(new Zora1155(address(zoraCreator1155Impl)))); - adminRole = target.PERMISSION_BIT_ADMIN(); - target.initialize("test", "test", ICreatorRoyaltiesControl.RoyaltyConfiguration(0, 0, address(0)), admin, _emptyInitData()); - - vm.prank(admin); - uint256 tokenId = target.setupNewToken("test", quantity); - - address minter = address(new SimpleMinter()); - vm.prank(admin); - target.addPermission(tokenId, minter, adminRole); - - vm.deal(admin, mintPrice); - vm.prank(admin); - target.mint{value: mintPrice}(SimpleMinter(payable(minter)), tokenId, quantity, abi.encode(recipient)); - - vm.prank(admin); - target.withdraw(); - - // Mint fee is not paid if the recipient is address(0) - assertEq(recipient.balance, recipient == address(0) ? 0 : mintPrice); - assertEq(admin.balance, recipient == address(0) ? mintPrice : mintPrice - (mintFee * quantity)); - } - - function test_mintFeeSent_revertCannotSendMintFee(uint32 mintFee, uint256 quantity) external { - vm.assume(quantity < 100); - - uint256 mintPrice = mintFee * quantity; - - // Use this mock contract as a recipient so we can reject ETH payments. - SimpleMinter _recip = new SimpleMinter(); - _recip.setReceiveETH(false); - address _recipient = address(_recip); - - zoraCreator1155Impl = new ZoraCreator1155Impl(mintFee, _recipient, address(0), address(protocolRewards)); - target = ZoraCreator1155Impl(address(new Zora1155(address(zoraCreator1155Impl)))); - adminRole = target.PERMISSION_BIT_ADMIN(); - target.initialize("test", "test", ICreatorRoyaltiesControl.RoyaltyConfiguration(0, 0, address(0)), admin, _emptyInitData()); - - vm.prank(admin); - uint256 tokenId = target.setupNewToken("test", quantity); - - address minter = address(new SimpleMinter()); - vm.prank(admin); - target.addPermission(tokenId, minter, adminRole); - - vm.deal(admin, mintPrice); - vm.expectRevert(abi.encodeWithSelector(IMintFeeManager.CannotSendMintFee.selector, _recipient, mintPrice)); - vm.prank(admin); - target.mint{value: mintPrice}(SimpleMinter(payable(minter)), tokenId, quantity, abi.encode(recipient)); - } -} diff --git a/test/minters/fixed-price/ZoraCreatorFixedPriceSaleStrategy.t.sol b/test/minters/fixed-price/ZoraCreatorFixedPriceSaleStrategy.t.sol index caa87907b..c4f432707 100644 --- a/test/minters/fixed-price/ZoraCreatorFixedPriceSaleStrategy.t.sol +++ b/test/minters/fixed-price/ZoraCreatorFixedPriceSaleStrategy.t.sol @@ -17,12 +17,17 @@ contract ZoraCreatorFixedPriceSaleStrategyTest is Test { ZoraCreatorFixedPriceSaleStrategy internal fixedPrice; address payable internal admin = payable(address(0x999)); address internal zora; + address internal tokenRecipient; + address internal fundsRecipient; event SaleSet(address indexed mediaContract, uint256 indexed tokenId, ZoraCreatorFixedPriceSaleStrategy.SalesConfig salesConfig); event MintComment(address indexed sender, address indexed tokenContract, uint256 indexed tokenId, uint256 quantity, string comment); function setUp() external { zora = makeAddr("zora"); + tokenRecipient = makeAddr("tokenRecipient"); + fundsRecipient = makeAddr("fundsRecipient"); + bytes[] memory emptyData = new bytes[](0); ProtocolRewards protocolRewards = new ProtocolRewards(); ZoraCreator1155Impl targetImpl = new ZoraCreator1155Impl(0, zora, address(0), address(protocolRewards)); @@ -73,11 +78,14 @@ contract ZoraCreatorFixedPriceSaleStrategyTest is Test { ); vm.stopPrank(); - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); + uint256 numTokens = 10; + uint256 totalReward = target.computeTotalReward(numTokens); + uint256 totalValue = (1 ether * numTokens) + totalReward; + + vm.deal(tokenRecipient, totalValue); vm.startPrank(tokenRecipient); - target.mint{value: 10 ether}(fixedPrice, newTokenId, 10, abi.encode(tokenRecipient, "")); + target.mint{value: totalValue}(fixedPrice, newTokenId, 10, abi.encode(tokenRecipient, "")); assertEq(target.balanceOf(tokenRecipient, newTokenId), 10); assertEq(address(target).balance, 10 ether); @@ -118,11 +126,14 @@ contract ZoraCreatorFixedPriceSaleStrategyTest is Test { ); vm.stopPrank(); - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); + uint256 numTokens = 10; + uint256 totalReward = target.computeTotalReward(numTokens); + uint256 totalValue = (1 ether * numTokens) + totalReward; + + vm.deal(tokenRecipient, totalValue); vm.startPrank(tokenRecipient); - target.mint{value: 10 ether}(fixedPrice, newTokenId, 10, abi.encode(tokenRecipient)); + target.mint{value: totalValue}(fixedPrice, newTokenId, 10, abi.encode(tokenRecipient)); assertEq(target.balanceOf(tokenRecipient, newTokenId), 10); assertEq(address(target).balance, 10 ether); @@ -163,13 +174,16 @@ contract ZoraCreatorFixedPriceSaleStrategyTest is Test { ); vm.stopPrank(); - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); + uint256 numTokens = 10; + uint256 totalReward = target.computeTotalReward(numTokens); + uint256 totalValue = (1 ether * numTokens) + totalReward; + + vm.deal(tokenRecipient, totalValue); vm.startPrank(tokenRecipient); vm.expectEmit(true, true, true, true); emit MintComment(tokenRecipient, address(target), newTokenId, 10, "test comment"); - target.mint{value: 10 ether}(fixedPrice, newTokenId, 10, abi.encode(tokenRecipient, "test comment")); + target.mint{value: totalValue}(fixedPrice, newTokenId, 10, abi.encode(tokenRecipient, "test comment")); assertEq(target.balanceOf(tokenRecipient, newTokenId), 10); assertEq(address(target).balance, 10 ether); @@ -198,7 +212,6 @@ contract ZoraCreatorFixedPriceSaleStrategyTest is Test { ); vm.stopPrank(); - address tokenRecipient = address(322); vm.deal(tokenRecipient, 20 ether); vm.expectRevert(abi.encodeWithSignature("SaleHasNotStarted()")); @@ -229,7 +242,6 @@ contract ZoraCreatorFixedPriceSaleStrategyTest is Test { ); vm.stopPrank(); - address tokenRecipient = address(322); vm.deal(tokenRecipient, 20 ether); vm.expectRevert(abi.encodeWithSignature("SaleEnded()")); @@ -260,12 +272,15 @@ contract ZoraCreatorFixedPriceSaleStrategyTest is Test { ); vm.stopPrank(); - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); + uint256 numTokens = 6; + uint256 totalReward = target.computeTotalReward(numTokens); + uint256 totalValue = (1 ether * numTokens) + totalReward; + + vm.deal(tokenRecipient, totalValue); vm.prank(tokenRecipient); vm.expectRevert(abi.encodeWithSelector(ILimitedMintPerAddress.UserExceedsMintLimit.selector, tokenRecipient, 5, 6)); - target.mint{value: 6 ether}(fixedPrice, newTokenId, 6, abi.encode(tokenRecipient, "")); + target.mint{value: totalValue}(fixedPrice, newTokenId, numTokens, abi.encode(tokenRecipient, "")); } function testFail_setupMint() external { @@ -289,7 +304,6 @@ contract ZoraCreatorFixedPriceSaleStrategyTest is Test { ); vm.stopPrank(); - address tokenRecipient = address(322); vm.deal(tokenRecipient, 20 ether); vm.startPrank(tokenRecipient); @@ -324,19 +338,19 @@ contract ZoraCreatorFixedPriceSaleStrategyTest is Test { ); vm.stopPrank(); - address tokenRecipient = address(322); vm.deal(tokenRecipient, 20 ether); vm.startPrank(tokenRecipient); - vm.expectRevert(abi.encodeWithSignature("WrongValueSent()")); - target.mint{value: 0.9 ether}(fixedPrice, newTokenId, 1, abi.encode(tokenRecipient, "")); - vm.expectRevert(abi.encodeWithSignature("WrongValueSent()")); - target.mint{value: 1.1 ether}(fixedPrice, newTokenId, 1, abi.encode(tokenRecipient, "")); - target.mint{value: 1 ether}(fixedPrice, newTokenId, 1, abi.encode(tokenRecipient, "")); + + target.mint{value: 1.000777 ether}(fixedPrice, newTokenId, 1, abi.encode(tokenRecipient, "")); + vm.stopPrank(); } function test_FundsRecipient() external { + uint96 pricePerToken = 1 ether; + uint256 numTokens = 10; + vm.startPrank(admin); uint256 newTokenId = target.setupNewToken("https://zora.co/testing/token.json", 10); target.addPermission(newTokenId, address(fixedPrice), target.PERMISSION_BIT_MINTER()); @@ -347,22 +361,25 @@ contract ZoraCreatorFixedPriceSaleStrategyTest is Test { ZoraCreatorFixedPriceSaleStrategy.setSale.selector, newTokenId, ZoraCreatorFixedPriceSaleStrategy.SalesConfig({ - pricePerToken: 1 ether, + pricePerToken: pricePerToken, saleStart: 0, saleEnd: type(uint64).max, maxTokensPerAddress: 0, - fundsRecipient: address(1) + fundsRecipient: fundsRecipient }) ) ); vm.stopPrank(); - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); + uint256 totalReward = target.computeTotalReward(numTokens); + uint256 totalValue = (pricePerToken * numTokens) + totalReward; + + vm.deal(tokenRecipient, totalValue); + vm.prank(tokenRecipient); - target.mint{value: 10 ether}(fixedPrice, newTokenId, 10, abi.encode(tokenRecipient, "")); + target.mint{value: totalValue}(fixedPrice, newTokenId, numTokens, abi.encode(tokenRecipient, "")); - assertEq(address(1).balance, 10 ether); + assertEq(fundsRecipient.balance, 10 ether); } function test_MintedPerRecipientGetter() external { @@ -386,10 +403,13 @@ contract ZoraCreatorFixedPriceSaleStrategyTest is Test { ); vm.stopPrank(); - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); + uint256 numTokens = 10; + uint256 totalReward = target.computeTotalReward(numTokens); + + vm.deal(tokenRecipient, totalReward); + vm.prank(tokenRecipient); - target.mint{value: 0 ether}(fixedPrice, newTokenId, 10, abi.encode(tokenRecipient, "")); + target.mint{value: totalReward}(fixedPrice, newTokenId, 10, abi.encode(tokenRecipient, "")); assertEq(fixedPrice.getMintedPerWallet(address(target), newTokenId, tokenRecipient), 10); } diff --git a/test/minters/merkle/ZoraCreatorMerkleMinterStrategy.t.sol b/test/minters/merkle/ZoraCreatorMerkleMinterStrategy.t.sol index 60c4c7781..ce7c9a289 100644 --- a/test/minters/merkle/ZoraCreatorMerkleMinterStrategy.t.sol +++ b/test/minters/merkle/ZoraCreatorMerkleMinterStrategy.t.sol @@ -18,11 +18,13 @@ contract ZoraCreatorMerkleMinterStrategyTest is Test { ZoraCreatorMerkleMinterStrategy internal merkleMinter; address payable internal admin = payable(address(0x999)); address internal zora; + address internal mintTo; event SaleSet(address indexed sender, uint256 indexed tokenId, ZoraCreatorMerkleMinterStrategy.MerkleSaleSettings merkleSaleSettings); function setUp() external { zora = makeAddr("zora"); + mintTo = address(1); bytes[] memory emptyData = new bytes[](0); protocolRewards = new ProtocolRewards(); ZoraCreator1155Impl targetImpl = new ZoraCreator1155Impl(0, zora, address(0), address(protocolRewards)); @@ -71,16 +73,19 @@ contract ZoraCreatorMerkleMinterStrategyTest is Test { ); vm.stopPrank(); - address mintTo = address(0x0000000000000000000000000000000000000001); - vm.deal(mintTo, 20 ether); + uint256 totalSale = 10 ether; + uint256 totalReward = target.computeTotalReward(10); + uint256 totalValue = totalSale + totalReward; + + vm.deal(mintTo, totalValue); uint256 maxQuantity = 10; - uint256 pricePerToken = 1000000000000000000; + uint256 pricePerToken = 1 ether; bytes32[] memory merkleProof = new bytes32[](1); merkleProof[0] = bytes32(0x71013e6ce1f439aaa91aa706ddd0769517fbaa4d72a936af4a7c75d29b1ca862); vm.startPrank(mintTo); - target.mint{value: 10 ether}(merkleMinter, newTokenId, 10, abi.encode(mintTo, maxQuantity, pricePerToken, merkleProof)); + target.mint{value: totalValue}(merkleMinter, newTokenId, 10, abi.encode(mintTo, maxQuantity, pricePerToken, merkleProof)); assertEq(target.balanceOf(mintTo, newTokenId), 10); assertEq(address(target).balance, 10 ether); @@ -109,17 +114,20 @@ contract ZoraCreatorMerkleMinterStrategyTest is Test { ); vm.stopPrank(); - address mintTo = address(0x0000000000000000000000000000000000000001); - vm.deal(mintTo, 20 ether); + uint256 totalSale = 10 ether; + uint256 totalReward = target.computeTotalReward(10); + uint256 totalValue = totalSale + totalReward; + + vm.deal(mintTo, totalValue); uint256 maxQuantity = 10; - uint256 pricePerToken = 1000000000000000000; + uint256 pricePerToken = 1 ether; bytes32[] memory merkleProof = new bytes32[](1); merkleProof[0] = bytes32(0x71013e6ce1f439aaa91aa706ddd0769517fbaa4d72a936af4a7c75d29b1ca862); vm.prank(mintTo); vm.expectRevert(abi.encodeWithSignature("SaleHasNotStarted()")); - target.mint{value: 10 ether}(merkleMinter, newTokenId, 10, abi.encode(mintTo, maxQuantity, pricePerToken, merkleProof)); + target.mint{value: totalValue}(merkleMinter, newTokenId, 10, abi.encode(mintTo, maxQuantity, pricePerToken, merkleProof)); } function test_PreSaleEnd() external { @@ -144,7 +152,6 @@ contract ZoraCreatorMerkleMinterStrategyTest is Test { ); vm.stopPrank(); - address mintTo = address(0x0000000000000000000000000000000000000001); vm.deal(mintTo, 20 ether); uint256 maxQuantity = 10; @@ -184,8 +191,11 @@ contract ZoraCreatorMerkleMinterStrategyTest is Test { ); vm.stopPrank(); - address mintTo = address(0x0000000000000000000000000000000000000001); - vm.deal(mintTo, 20 ether); + uint256 totalSale = 10 ether; + uint256 totalReward = target.computeTotalReward(10); + uint256 totalValue = totalSale + totalReward; + + vm.deal(mintTo, totalValue); uint256 maxQuantity = 10; uint256 pricePerToken = 1000000000000000000; @@ -193,7 +203,7 @@ contract ZoraCreatorMerkleMinterStrategyTest is Test { merkleProof[0] = bytes32(0x71013e6ce1f439aaa91aa706ddd0769517fbaa4d72a936af4a7c75d29b1ca862); vm.prank(mintTo); - target.mint{value: 10 ether}(merkleMinter, newTokenId, 10, abi.encode(mintTo, maxQuantity, pricePerToken, merkleProof)); + target.mint{value: totalValue}(merkleMinter, newTokenId, 10, abi.encode(mintTo, maxQuantity, pricePerToken, merkleProof)); assertEq(address(1234).balance, 10 ether); } @@ -225,7 +235,6 @@ contract ZoraCreatorMerkleMinterStrategyTest is Test { ); vm.stopPrank(); - address mintTo = address(0x0000000000000000000000000000000000000001); vm.deal(mintTo, 20 ether); uint256 maxQuantity = 10; @@ -265,8 +274,11 @@ contract ZoraCreatorMerkleMinterStrategyTest is Test { ); vm.stopPrank(); - address mintTo = address(0x0000000000000000000000000000000000000001); - vm.deal(mintTo, 20 ether); + uint256 totalSale = 10 ether; + uint256 totalReward = target.computeTotalReward(10); + uint256 totalValue = totalSale + totalReward; + + vm.deal(mintTo, totalValue); uint256 maxQuantity = 10; uint256 pricePerToken = 1000000000000000000; @@ -274,15 +286,17 @@ contract ZoraCreatorMerkleMinterStrategyTest is Test { merkleProof[0] = bytes32(0x71013e6ce1f439aaa91aa706ddd0769517fbaa4d72a936af4a7c75d29b1ca862); vm.startPrank(mintTo); - target.mint{value: 10 ether}(merkleMinter, newTokenId, 10, abi.encode(mintTo, maxQuantity, pricePerToken, merkleProof)); + target.mint{value: totalValue}(merkleMinter, newTokenId, 10, abi.encode(mintTo, maxQuantity, pricePerToken, merkleProof)); + + vm.deal(mintTo, 1.000777 ether); + vm.expectRevert(abi.encodeWithSelector(ILimitedMintPerAddress.UserExceedsMintLimit.selector, mintTo, 10, 11)); - target.mint{value: 1 ether}(merkleMinter, newTokenId, 1, abi.encode(mintTo, maxQuantity, pricePerToken, merkleProof)); + target.mint{value: 1.000777 ether}(merkleMinter, newTokenId, 1, abi.encode(mintTo, maxQuantity, pricePerToken, merkleProof)); vm.stopPrank(); } - function test_PricePerToken(uint256 ethToSend) external { - vm.assume(ethToSend != 10 ether); + function test_PricePerToken() external { vm.startPrank(admin); uint256 newTokenId = target.setupNewToken("https://zora.co/testing/token.json", 10); target.addPermission(newTokenId, address(merkleMinter), target.PERMISSION_BIT_MINTER()); @@ -309,17 +323,20 @@ contract ZoraCreatorMerkleMinterStrategyTest is Test { ); vm.stopPrank(); - address mintTo = address(0x0000000000000000000000000000000000000001); - vm.deal(mintTo, ethToSend); + uint256 totalSale = 10 ether; + uint256 totalReward = target.computeTotalReward(10); + uint256 totalValue = totalSale + totalReward; + + vm.deal(mintTo, totalValue); uint256 maxQuantity = 10; - uint256 pricePerToken = 1000000000000000000; + uint256 pricePerToken = 1 ether; bytes32[] memory merkleProof = new bytes32[](1); merkleProof[0] = bytes32(0x71013e6ce1f439aaa91aa706ddd0769517fbaa4d72a936af4a7c75d29b1ca862); vm.startPrank(mintTo); vm.expectRevert(abi.encodeWithSignature("WrongValueSent()")); - target.mint{value: ethToSend}(merkleMinter, newTokenId, 10, abi.encode(mintTo, maxQuantity, pricePerToken, merkleProof)); + target.mint{value: totalValue - 1}(merkleMinter, newTokenId, 10, abi.encode(mintTo, maxQuantity, pricePerToken, merkleProof)); } function test_ResetSale() external { diff --git a/test/minters/redeem/ZoraCreatorRedeemMinterFactory.t.sol b/test/minters/redeem/ZoraCreatorRedeemMinterFactory.t.sol index 92a9f26fb..c06a49df8 100644 --- a/test/minters/redeem/ZoraCreatorRedeemMinterFactory.t.sol +++ b/test/minters/redeem/ZoraCreatorRedeemMinterFactory.t.sol @@ -16,64 +16,65 @@ import {IZoraCreator1155Factory} from "../../../src/interfaces/IZoraCreator1155F import {ZoraCreatorRedeemMinterStrategy} from "../../../src/minters/redeem/ZoraCreatorRedeemMinterStrategy.sol"; import {ZoraCreatorRedeemMinterFactory} from "../../../src/minters/redeem/ZoraCreatorRedeemMinterFactory.sol"; -contract ZoraCreatorRedeemMinterFactoryTest is Test { - ProtocolRewards internal protocolRewards; - ZoraCreator1155Impl internal target; - ZoraCreatorRedeemMinterFactory internal minterFactory; - address payable internal tokenAdmin = payable(address(0x999)); - address payable internal factoryAdmin = payable(address(0x888)); - address internal zora; +/// @notice Contract versions after v1.4.0 will not support the current burn to redeem minter +// contract ZoraCreatorRedeemMinterFactoryTest is Test { +// ProtocolRewards internal protocolRewards; +// ZoraCreator1155Impl internal target; +// ZoraCreatorRedeemMinterFactory internal minterFactory; +// address payable internal tokenAdmin = payable(address(0x999)); +// address payable internal factoryAdmin = payable(address(0x888)); +// address internal zora; - event RedeemMinterDeployed(address indexed creatorContract, address indexed minterContract); +// event RedeemMinterDeployed(address indexed creatorContract, address indexed minterContract); - function setUp() public { - zora = makeAddr("zora"); - bytes[] memory emptyData = new bytes[](0); - protocolRewards = new ProtocolRewards(); - ZoraCreator1155Impl targetImpl = new ZoraCreator1155Impl(0, zora, address(0), address(protocolRewards)); - Zora1155 proxy = new Zora1155(address(targetImpl)); - target = ZoraCreator1155Impl(address(proxy)); - target.initialize("test", "test", ICreatorRoyaltiesControl.RoyaltyConfiguration(0, 0, address(0)), tokenAdmin, emptyData); +// function setUp() public { +// zora = makeAddr("zora"); +// bytes[] memory emptyData = new bytes[](0); +// protocolRewards = new ProtocolRewards(); +// ZoraCreator1155Impl targetImpl = new ZoraCreator1155Impl(0, zora, address(0), address(protocolRewards)); +// Zora1155 proxy = new Zora1155(address(targetImpl)); +// target = ZoraCreator1155Impl(address(proxy)); +// target.initialize("test", "test", ICreatorRoyaltiesControl.RoyaltyConfiguration(0, 0, address(0)), tokenAdmin, emptyData); - minterFactory = new ZoraCreatorRedeemMinterFactory(); - } +// minterFactory = new ZoraCreatorRedeemMinterFactory(); +// } - function test_contractVersion() public { - assertEq(minterFactory.contractVersion(), "1.0.1"); - } +// function test_contractVersion() public { +// assertEq(minterFactory.contractVersion(), "1.0.1"); +// } - function test_createMinterIfNoneExists() public { - vm.startPrank(tokenAdmin); - target.addPermission(0, address(minterFactory), target.PERMISSION_BIT_MINTER()); - address predictedAddress = minterFactory.predictMinterAddress(address(target)); - vm.expectEmit(false, false, false, false); - emit RedeemMinterDeployed(address(target), predictedAddress); - target.callSale(0, minterFactory, abi.encodeWithSelector(ZoraCreatorRedeemMinterFactory.createMinterIfNoneExists.selector)); - vm.stopPrank(); +// function test_createMinterIfNoneExists() public { +// vm.startPrank(tokenAdmin); +// target.addPermission(0, address(minterFactory), target.PERMISSION_BIT_MINTER()); +// address predictedAddress = minterFactory.predictMinterAddress(address(target)); +// vm.expectEmit(false, false, false, false); +// emit RedeemMinterDeployed(address(target), predictedAddress); +// target.callSale(0, minterFactory, abi.encodeWithSelector(ZoraCreatorRedeemMinterFactory.createMinterIfNoneExists.selector)); +// vm.stopPrank(); - ZoraCreatorRedeemMinterStrategy minter = ZoraCreatorRedeemMinterStrategy(predictedAddress); - assertTrue(address(minter).code.length > 0); - } +// ZoraCreatorRedeemMinterStrategy minter = ZoraCreatorRedeemMinterStrategy(predictedAddress); +// assertTrue(address(minter).code.length > 0); +// } - function test_createMinterRequiresIZoraCreator1155Caller() public { - ERC1155PresetMinterPauser randomToken = new ERC1155PresetMinterPauser("https://uri.com"); +// function test_createMinterRequiresIZoraCreator1155Caller() public { +// ERC1155PresetMinterPauser randomToken = new ERC1155PresetMinterPauser("https://uri.com"); - vm.expectRevert(abi.encodeWithSignature("CallerNotZoraCreator1155()")); - vm.prank(address(randomToken)); - minterFactory.createMinterIfNoneExists(); - } +// vm.expectRevert(abi.encodeWithSignature("CallerNotZoraCreator1155()")); +// vm.prank(address(randomToken)); +// minterFactory.createMinterIfNoneExists(); +// } - function test_getDeployedMinterForCreatorContract() public { - vm.prank(address(target)); - minterFactory.createMinterIfNoneExists(); - address minterAddress = minterFactory.predictMinterAddress(address(target)); +// function test_getDeployedMinterForCreatorContract() public { +// vm.prank(address(target)); +// minterFactory.createMinterIfNoneExists(); +// address minterAddress = minterFactory.predictMinterAddress(address(target)); - assertEq(minterAddress, minterFactory.getDeployedRedeemMinterForCreatorContract(address(target))); - } +// assertEq(minterAddress, minterFactory.getDeployedRedeemMinterForCreatorContract(address(target))); +// } - function test_supportsInterface() public { - assertTrue(minterFactory.supportsInterface(0x01ffc9a7)); // ERC165 - assertTrue(minterFactory.supportsInterface(type(IMinter1155).interfaceId)); - assertTrue(!minterFactory.supportsInterface(0x6467a6fc)); // old IMinter1155 - } -} +// function test_supportsInterface() public { +// assertTrue(minterFactory.supportsInterface(0x01ffc9a7)); // ERC165 +// assertTrue(minterFactory.supportsInterface(type(IMinter1155).interfaceId)); +// assertTrue(!minterFactory.supportsInterface(0x6467a6fc)); // old IMinter1155 +// } +// } diff --git a/test/minters/redeem/ZoraCreatorRedeemMinterStrategy.t.sol b/test/minters/redeem/ZoraCreatorRedeemMinterStrategy.t.sol index 3be42ba5b..8625af8fc 100644 --- a/test/minters/redeem/ZoraCreatorRedeemMinterStrategy.t.sol +++ b/test/minters/redeem/ZoraCreatorRedeemMinterStrategy.t.sol @@ -14,1485 +14,1486 @@ import {ICreatorRoyaltiesControl} from "../../../src/interfaces/ICreatorRoyaltie import {IZoraCreator1155Factory} from "../../../src/interfaces/IZoraCreator1155Factory.sol"; import {ZoraCreatorRedeemMinterStrategy} from "../../../src/minters/redeem/ZoraCreatorRedeemMinterStrategy.sol"; -contract ZoraCreatorRedeemMinterStrategyTest is Test { - ProtocolRewards internal protocolRewards; - ZoraCreator1155Impl internal target; - ZoraCreatorRedeemMinterStrategy internal redeemMinter; - address payable internal admin = payable(address(0x999)); - uint256 internal newTokenId; - address internal zora; - - event RedeemSet(address indexed target, bytes32 indexed redeemsInstructionsHash, ZoraCreatorRedeemMinterStrategy.RedeemInstructions data); - event RedeemProcessed(address indexed target, bytes32 indexed redeemsInstructionsHash, address sender, uint256[][] tokenIds, uint256[][] amounts); - event RedeemsCleared(address indexed target, bytes32[] indexed redeemInstructionsHashes); - - function setUp() external { - zora = makeAddr("zora"); - bytes[] memory emptyData = new bytes[](0); - protocolRewards = new ProtocolRewards(); - ZoraCreator1155Impl targetImpl = new ZoraCreator1155Impl(0, zora, address(0), address(protocolRewards)); - Zora1155 proxy = new Zora1155(address(targetImpl)); - target = ZoraCreator1155Impl(address(proxy)); - target.initialize("test", "test", ICreatorRoyaltiesControl.RoyaltyConfiguration(0, 0, address(0)), admin, emptyData); - redeemMinter = new ZoraCreatorRedeemMinterStrategy(); - redeemMinter.initialize(address(target)); - vm.startPrank(admin); - newTokenId = target.setupNewToken("https://zora.co/testing/token.json", 10); - target.addPermission(newTokenId, address(redeemMinter), target.PERMISSION_BIT_MINTER()); - vm.stopPrank(); - } - - function test_ContractURI() external { - assertEq(redeemMinter.contractURI(), "https://github.com/ourzora/zora-1155-contracts/"); - } - - function test_ContractName() external { - assertEq(redeemMinter.contractName(), "Redeem Minter Sale Strategy"); - } - - function test_Version() external { - assertEq(redeemMinter.contractVersion(), "1.0.1"); - } - - function test_OnlyDropContractCanCallWriteFunctions() external { - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions; - vm.startPrank(address(admin)); - - vm.expectRevert(abi.encodeWithSignature("CallerNotCreatorContract()")); - redeemMinter.setRedeem(redeemInstructions); - - bytes32[] memory hashes = new bytes32[](0); - vm.expectRevert(abi.encodeWithSignature("CallerNotCreatorContract()")); - redeemMinter.clearRedeem(hashes); - - vm.expectRevert(abi.encodeWithSignature("CallerNotCreatorContract()")); - redeemMinter.requestMint(address(0), 0, 0, 0, bytes("")); - - vm.expectRevert(abi.encodeWithSignature("CallerNotCreatorContract()")); - redeemMinter.resetSale(0); - - vm.stopPrank(); - } - - ///////// SET REDEEM ///////// - - function test_SetRedeem() external { - vm.startPrank(admin); - - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - - ERC20PresetMinterPauser burnToken = new ERC20PresetMinterPauser("Random Token", "RAND"); - burnToken.mint(address(tokenRecipient), 1000); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, - amount: 500, - tokenIdStart: 0, - tokenIdEnd: 0, - tokenContract: address(burnToken), - transferRecipient: address(0), - burnFunction: bytes4(keccak256(bytes("burnFrom(address,uint256)"))) - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: address(0) - }); - vm.stopPrank(); - - vm.expectEmit(true, true, false, true); - emit RedeemSet(address(target), keccak256(abi.encode(redeemInstructions)), redeemInstructions); - vm.startPrank(address(target)); - redeemMinter.setRedeem(redeemInstructions); - vm.expectRevert(abi.encodeWithSignature("RedeemInstructionAlreadySet()")); - redeemMinter.setRedeem(redeemInstructions); - vm.stopPrank(); - - assertTrue(redeemMinter.redeemInstructionsHashIsAllowed(keccak256(abi.encode(redeemInstructions)))); - } - - function test_SetRedeemInstructionValidation() external { - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - - ERC20PresetMinterPauser burnToken = new ERC20PresetMinterPauser("Random Token", "RAND"); - burnToken.mint(address(tokenRecipient), 1000); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.NULL, - amount: 500, - tokenIdStart: 0, - tokenIdEnd: 0, - tokenContract: address(burnToken), - transferRecipient: address(0), - burnFunction: bytes4(keccak256(bytes("burnFrom(address,uint256)"))) - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: address(0) - }); - - vm.startPrank(address(target)); - - // InvalidTokenIdsForTokenType: ERC20 w/ nonzero tokenId start or end - redeemInstructions.instructions[0].tokenType = ZoraCreatorRedeemMinterStrategy.TokenType.ERC20; - redeemInstructions.instructions[0].tokenIdStart = 1; - redeemInstructions.instructions[0].tokenIdEnd = 0; - vm.expectRevert(abi.encodeWithSignature("InvalidTokenIdsForTokenType()")); - redeemMinter.setRedeem(redeemInstructions); - redeemInstructions.instructions[0].tokenIdStart = 0; - redeemInstructions.instructions[0].tokenIdEnd = 1; - vm.expectRevert(abi.encodeWithSignature("InvalidTokenIdsForTokenType()")); - redeemMinter.setRedeem(redeemInstructions); - - // InvalidTokenIdsForTokenType: non ERC20 w/ tokenID start > end - redeemInstructions.instructions[0].tokenType = ZoraCreatorRedeemMinterStrategy.TokenType.ERC721; - redeemInstructions.instructions[0].tokenIdStart = 4; - redeemInstructions.instructions[0].tokenIdEnd = 2; - vm.expectRevert(abi.encodeWithSignature("InvalidTokenIdsForTokenType()")); - redeemMinter.setRedeem(redeemInstructions); - redeemInstructions.mintToken.tokenType = ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155; - vm.expectRevert(abi.encodeWithSignature("InvalidTokenIdsForTokenType()")); - redeemMinter.setRedeem(redeemInstructions); - redeemInstructions.instructions[0].tokenIdStart = 0; - redeemInstructions.instructions[0].tokenIdEnd = 0; - - // InvalidTokenType: tokenType is NULL - redeemInstructions.instructions[0].tokenType = ZoraCreatorRedeemMinterStrategy.TokenType.NULL; - vm.expectRevert(abi.encodeWithSignature("InvalidTokenType()")); - redeemMinter.setRedeem(redeemInstructions); - redeemInstructions.instructions[0].tokenType = ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155; - - // MustBurnOrTransfer: both transferRecipient and burnFunction are 0 - redeemInstructions.instructions[0].transferRecipient = address(0); - redeemInstructions.instructions[0].burnFunction = bytes4(0); - vm.expectRevert(abi.encodeWithSignature("MustBurnOrTransfer()")); - redeemMinter.setRedeem(redeemInstructions); - - // MustBurnOrTransfer: both transferRecipient and burnFunction are non-zero - redeemInstructions.instructions[0].transferRecipient = address(1); - redeemInstructions.instructions[0].burnFunction = bytes4(keccak256(bytes("burnFrom(address,uint256)"))); - vm.expectRevert(abi.encodeWithSignature("MustBurnOrTransfer()")); - redeemMinter.setRedeem(redeemInstructions); - redeemInstructions.instructions[0].transferRecipient = address(0); - - // IncorrectMintAmount - redeemInstructions.instructions[0].amount = 0; - vm.expectRevert(abi.encodeWithSignature("IncorrectMintAmount()")); - redeemMinter.setRedeem(redeemInstructions); - redeemInstructions.instructions[0].amount = 500; - - // InvalidSaleEndOrStart: start > end - redeemInstructions.saleStart = 1; - redeemInstructions.saleEnd = 0; - vm.expectRevert(abi.encodeWithSignature("InvalidSaleEndOrStart()")); - redeemMinter.setRedeem(redeemInstructions); - redeemInstructions.saleStart = 0; - redeemInstructions.saleEnd = type(uint64).max; - - // InvalidSaleEndOrStart: block.timestamp > end - redeemInstructions.saleStart = 0; - redeemInstructions.saleEnd = 1 days; - vm.warp(2 days); - vm.expectRevert(abi.encodeWithSignature("InvalidSaleEndOrStart()")); - redeemMinter.setRedeem(redeemInstructions); - redeemInstructions.saleEnd = type(uint64).max; - - // EmptyRedeemInstructions(); - redeemInstructions.instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](0); - vm.expectRevert(abi.encodeWithSignature("EmptyRedeemInstructions()")); - redeemMinter.setRedeem(redeemInstructions); - redeemInstructions.instructions = instructions; - - // MintTokenContractMustBeCreatorContract - redeemInstructions.mintToken.tokenContract = address(0); - vm.expectRevert(abi.encodeWithSignature("MintTokenContractMustBeCreatorContract()")); - redeemMinter.setRedeem(redeemInstructions); - redeemInstructions.mintToken.tokenContract = address(target); - - // MintTokenTypeMustBeERC1155: - redeemInstructions.mintToken.tokenType = ZoraCreatorRedeemMinterStrategy.TokenType.ERC721; - vm.expectRevert(abi.encodeWithSignature("MintTokenTypeMustBeERC1155()")); - redeemMinter.setRedeem(redeemInstructions); - } - - ///////// REQUEST MINT ///////// - - function test_MintFlowERC20() external { - vm.startPrank(admin); - - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - - ERC20PresetMinterPauser burnToken = new ERC20PresetMinterPauser("Random Token", "RAND"); - burnToken.mint(address(tokenRecipient), 1000); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, - amount: 500, - tokenIdStart: 0, - tokenIdEnd: 0, - tokenContract: address(burnToken), - transferRecipient: address(0), - burnFunction: bytes4(keccak256(bytes("burnFrom(address,uint256)"))) - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: address(0) - }); - - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); - vm.stopPrank(); - - vm.startPrank(tokenRecipient); - burnToken.approve(address(redeemMinter), 500); - uint256[][] memory tokenIds = new uint256[][](1); - tokenIds[0] = new uint256[](0); - uint256[][] memory amounts = new uint256[][](1); - amounts[0] = new uint256[](1); - amounts[0][0] = 500; - vm.expectEmit(true, true, false, false); - emit RedeemProcessed(address(target), keccak256(abi.encode(redeemInstructions)), tokenRecipient, tokenIds, amounts); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - assertEq(address(target).balance, 1 ether); - assertEq(target.balanceOf(tokenRecipient, newTokenId), 10); - assertEq(burnToken.balanceOf(tokenRecipient), 500); - vm.stopPrank(); - } - - function test_MintFlowERC1155() external { - vm.startPrank(admin); - - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - - ERC1155PresetMinterPauser burnToken = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); - burnToken.mint(address(tokenRecipient), 1, 1000, ""); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155, - amount: 500, - tokenIdStart: 1, - tokenIdEnd: 1, - tokenContract: address(burnToken), - transferRecipient: address(0), - burnFunction: bytes4(keccak256(bytes("burnBatch(address,uint256[],uint256[])"))) - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: address(0) - }); - - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); - vm.stopPrank(); - - vm.startPrank(tokenRecipient); - burnToken.setApprovalForAll(address(redeemMinter), true); - uint256[][] memory tokenIds = new uint256[][](1); - tokenIds[0] = new uint256[](1); - tokenIds[0][0] = 1; - uint256[][] memory amounts = new uint256[][](1); - amounts[0] = new uint256[](1); - amounts[0][0] = 500; - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - assertEq(address(target).balance, 1 ether); - assertEq(target.balanceOf(tokenRecipient, newTokenId), 10); - assertEq(burnToken.balanceOf(tokenRecipient, 1), 500); - vm.stopPrank(); - } - - function test_MintFlowERC721() external { - vm.startPrank(admin); - - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - - ERC721PresetMinterPauserAutoId burnToken = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); - burnToken.mint(address(tokenRecipient)); - burnToken.mint(address(tokenRecipient)); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC721, - amount: 2, - tokenIdStart: 0, - tokenIdEnd: 1, - tokenContract: address(burnToken), - transferRecipient: address(0), - burnFunction: bytes4(keccak256(bytes("burn(uint256)"))) - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: address(0) - }); - - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); - vm.stopPrank(); - - vm.startPrank(tokenRecipient); - burnToken.setApprovalForAll(address(redeemMinter), true); - uint256[][] memory tokenIds = new uint256[][](1); - tokenIds[0] = new uint256[](2); - tokenIds[0][0] = 0; - tokenIds[0][1] = 1; - uint256[][] memory amounts = new uint256[][](1); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - assertEq(address(target).balance, 1 ether); - assertEq(target.balanceOf(tokenRecipient, newTokenId), 10); - vm.expectRevert(); - burnToken.ownerOf(0); - vm.expectRevert(); - burnToken.ownerOf(1); - vm.stopPrank(); - } - - function test_MintFlowMultiple() external { - vm.startPrank(admin); - - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - - ERC20PresetMinterPauser burnTokenERC20 = new ERC20PresetMinterPauser("Random Token", "RAND"); - burnTokenERC20.mint(address(tokenRecipient), 1000); - ERC1155PresetMinterPauser burnTokenERC1155 = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); - burnTokenERC1155.mint(address(tokenRecipient), 1, 1000, ""); - ERC721PresetMinterPauserAutoId burnTokenERC721 = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); - burnTokenERC721.mint(address(tokenRecipient)); - burnTokenERC721.mint(address(tokenRecipient)); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](3); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, - amount: 500, - tokenIdStart: 0, - tokenIdEnd: 0, - tokenContract: address(burnTokenERC20), - transferRecipient: address(0), - burnFunction: bytes4(keccak256(bytes("burnFrom(address,uint256)"))) - }); - instructions[1] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155, - amount: 500, - tokenIdStart: 1, - tokenIdEnd: 1, - tokenContract: address(burnTokenERC1155), - transferRecipient: address(0), - burnFunction: bytes4(keccak256(bytes("burnBatch(address,uint256[],uint256[])"))) - }); - instructions[2] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC721, - amount: 2, - tokenIdStart: 0, - tokenIdEnd: 1, - tokenContract: address(burnTokenERC721), - transferRecipient: address(0), - burnFunction: bytes4(keccak256(bytes("burn(uint256)"))) - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: address(0) - }); - - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); - vm.stopPrank(); - - vm.startPrank(tokenRecipient); - burnTokenERC20.approve(address(redeemMinter), 500); - burnTokenERC1155.setApprovalForAll(address(redeemMinter), true); - burnTokenERC721.setApprovalForAll(address(redeemMinter), true); - - uint256[][] memory tokenIds = new uint256[][](3); - uint256[][] memory amounts = new uint256[][](3); - - amounts[0] = new uint256[](1); - amounts[0][0] = 500; - - tokenIds[1] = new uint256[](1); - tokenIds[1][0] = 1; - amounts[1] = new uint256[](1); - amounts[1][0] = 500; - - tokenIds[2] = new uint256[](2); - tokenIds[2][0] = 0; - tokenIds[2][1] = 1; - - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - assertEq(address(target).balance, 1 ether); - assertEq(target.balanceOf(tokenRecipient, newTokenId), 10); - assertEq(burnTokenERC20.balanceOf(tokenRecipient), 500); - assertEq(burnTokenERC1155.balanceOf(tokenRecipient, 1), 500); - assertEq(burnTokenERC721.balanceOf(address(tokenRecipient)), 0); - vm.stopPrank(); - } - - function test_MintFlowMultipleWithTransferInsteadOfBurn() external { - vm.startPrank(admin); - - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - address redeemTokenRecipient = address(323); - - ERC20PresetMinterPauser burnTokenERC20 = new ERC20PresetMinterPauser("Random Token", "RAND"); - burnTokenERC20.mint(address(tokenRecipient), 1000); - ERC1155PresetMinterPauser burnTokenERC1155 = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); - burnTokenERC1155.mint(address(tokenRecipient), 1, 1000, ""); - ERC721PresetMinterPauserAutoId burnTokenERC721 = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); - burnTokenERC721.mint(address(tokenRecipient)); - burnTokenERC721.mint(address(tokenRecipient)); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](3); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, - amount: 500, - tokenIdStart: 0, - tokenIdEnd: 0, - tokenContract: address(burnTokenERC20), - transferRecipient: redeemTokenRecipient, - burnFunction: 0 - }); - instructions[1] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155, - amount: 500, - tokenIdStart: 1, - tokenIdEnd: 1, - tokenContract: address(burnTokenERC1155), - transferRecipient: redeemTokenRecipient, - burnFunction: 0 - }); - instructions[2] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC721, - amount: 2, - tokenIdStart: 0, - tokenIdEnd: 1, - tokenContract: address(burnTokenERC721), - transferRecipient: redeemTokenRecipient, - burnFunction: 0 - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: address(0) - }); - - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); - vm.stopPrank(); - - vm.startPrank(tokenRecipient); - burnTokenERC20.approve(address(redeemMinter), 500); - burnTokenERC1155.setApprovalForAll(address(redeemMinter), true); - burnTokenERC721.setApprovalForAll(address(redeemMinter), true); - - uint256[][] memory tokenIds = new uint256[][](3); - uint256[][] memory amounts = new uint256[][](3); - - amounts[0] = new uint256[](1); - amounts[0][0] = 500; - - tokenIds[1] = new uint256[](1); - tokenIds[1][0] = 1; - amounts[1] = new uint256[](1); - amounts[1][0] = 500; - - tokenIds[2] = new uint256[](2); - tokenIds[2][0] = 0; - tokenIds[2][1] = 1; - - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - assertEq(address(target).balance, 1 ether); - assertEq(target.balanceOf(tokenRecipient, newTokenId), 10); - assertEq(burnTokenERC20.balanceOf(tokenRecipient), 500); - assertEq(burnTokenERC20.balanceOf(redeemTokenRecipient), 500); - assertEq(burnTokenERC1155.balanceOf(tokenRecipient, 1), 500); - assertEq(burnTokenERC1155.balanceOf(redeemTokenRecipient, 1), 500); - assertEq(burnTokenERC721.balanceOf(address(tokenRecipient)), 0); - assertEq(burnTokenERC721.balanceOf(redeemTokenRecipient), 2); - - vm.stopPrank(); - } - - function test_MintFlowTokenIdRangesForERC1155AndERC721() external { - vm.startPrank(admin); - - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - address redeemTokenRecipient = address(323); - - ERC1155PresetMinterPauser burnTokenERC1155 = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); - burnTokenERC1155.mint(address(tokenRecipient), 7, 100, ""); - burnTokenERC1155.mint(address(tokenRecipient), 8, 100, ""); - burnTokenERC1155.mint(address(tokenRecipient), 9, 100, ""); - ERC721PresetMinterPauserAutoId burnTokenERC721 = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); - burnTokenERC721.mint(address(tokenRecipient)); - burnTokenERC721.mint(address(tokenRecipient)); - burnTokenERC721.mint(address(tokenRecipient)); - burnTokenERC721.mint(address(tokenRecipient)); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](2); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155, - amount: 300, - tokenIdStart: 7, - tokenIdEnd: 9, - tokenContract: address(burnTokenERC1155), - transferRecipient: redeemTokenRecipient, - burnFunction: 0 - }); - instructions[1] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC721, - amount: 3, - tokenIdStart: 1, - tokenIdEnd: 3, - tokenContract: address(burnTokenERC721), - transferRecipient: redeemTokenRecipient, - burnFunction: 0 - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: address(0) - }); - - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); - vm.stopPrank(); - - vm.startPrank(tokenRecipient); - burnTokenERC1155.setApprovalForAll(address(redeemMinter), true); - burnTokenERC721.setApprovalForAll(address(redeemMinter), true); - - uint256[][] memory tokenIds = new uint256[][](2); - uint256[][] memory amounts = new uint256[][](2); - - tokenIds[0] = new uint256[](3); - tokenIds[0][0] = 7; - tokenIds[0][1] = 8; - tokenIds[0][2] = 9; - amounts[0] = new uint256[](3); - amounts[0][0] = 100; - amounts[0][1] = 100; - amounts[0][2] = 100; - - tokenIds[1] = new uint256[](3); - tokenIds[1][0] = 1; - tokenIds[1][1] = 2; - tokenIds[1][2] = 3; - - // detour: tokenId out of range - tokenIds[0][0] = 6; - vm.expectRevert(abi.encodeWithSignature("TokenIdOutOfRange()")); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - tokenIds[0][0] = 10; - vm.expectRevert(abi.encodeWithSignature("TokenIdOutOfRange()")); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - tokenIds[0][0] = 7; - tokenIds[1][0] = 0; - vm.expectRevert(abi.encodeWithSignature("TokenIdOutOfRange()")); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - tokenIds[1][0] = 4; - vm.expectRevert(abi.encodeWithSignature("TokenIdOutOfRange()")); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - tokenIds[1][0] = 1; - - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - assertEq(address(target).balance, 1 ether); - assertEq(target.balanceOf(tokenRecipient, newTokenId), 10); - assertEq(burnTokenERC1155.balanceOf(redeemTokenRecipient, 7), 100); - assertEq(burnTokenERC1155.balanceOf(redeemTokenRecipient, 8), 100); - assertEq(burnTokenERC1155.balanceOf(redeemTokenRecipient, 9), 100); - assertEq(burnTokenERC721.balanceOf(redeemTokenRecipient), 3); - - vm.stopPrank(); - } - - function test_MintFlowRedeemStart() external { - vm.startPrank(admin); - - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - - ERC20PresetMinterPauser burnToken = new ERC20PresetMinterPauser("Random Token", "RAND"); - burnToken.mint(address(tokenRecipient), 1000); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, - amount: 500, - tokenIdStart: 0, - tokenIdEnd: 0, - tokenContract: address(burnToken), - transferRecipient: address(0), - burnFunction: bytes4(keccak256(bytes("burnFrom(address,uint256)"))) - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: uint64(block.timestamp + 1 days), - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: address(0) - }); - - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); - vm.stopPrank(); - - vm.startPrank(tokenRecipient); - burnToken.approve(address(redeemMinter), 500); - uint256[][] memory tokenIds = new uint256[][](1); - tokenIds[0] = new uint256[](0); - uint256[][] memory amounts = new uint256[][](1); - amounts[0] = new uint256[](1); - amounts[0][0] = 500; - vm.expectRevert(abi.encodeWithSignature("SaleHasNotStarted()")); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 1, abi.encode(redeemInstructions, tokenIds, amounts)); - vm.stopPrank(); - } - - function test_MintFlowRedeemEnd() external { - vm.startPrank(admin); - - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - - ERC20PresetMinterPauser burnToken = new ERC20PresetMinterPauser("Random Token", "RAND"); - burnToken.mint(address(tokenRecipient), 1000); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, - amount: 500, - tokenIdStart: 0, - tokenIdEnd: 0, - tokenContract: address(burnToken), - transferRecipient: address(0), - burnFunction: bytes4(keccak256(bytes("burnFrom(address,uint256)"))) - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: uint64(1 days), - ethAmount: 1 ether, - ethRecipient: address(0) - }); - - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); - vm.stopPrank(); - - vm.warp(2 days); - - vm.startPrank(tokenRecipient); - burnToken.approve(address(redeemMinter), 1000); - uint256[] memory tokenIds = new uint256[](0); - uint256[][] memory amounts = new uint256[][](1); - amounts[0] = new uint256[](1); - amounts[0][0] = 500; - vm.expectRevert(abi.encodeWithSignature("SaleEnded()")); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 1, abi.encode(redeemInstructions, tokenIds, amounts)); - vm.stopPrank(); - } - - function test_MintFlowEthValue() external { - vm.startPrank(admin); - - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - - ERC20PresetMinterPauser burnToken = new ERC20PresetMinterPauser("Random Token", "RAND"); - burnToken.mint(address(tokenRecipient), 1000); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, - amount: 500, - tokenIdStart: 0, - tokenIdEnd: 0, - tokenContract: address(burnToken), - transferRecipient: address(0), - burnFunction: bytes4(keccak256(bytes("burnFrom(address,uint256)"))) - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: address(0) - }); - - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); - vm.stopPrank(); - - vm.startPrank(tokenRecipient); - burnToken.approve(address(redeemMinter), 500); - uint256[][] memory tokenIds = new uint256[][](1); - tokenIds[0] = new uint256[](0); - uint256[][] memory amounts = new uint256[][](1); - amounts[0] = new uint256[](1); - amounts[0][0] = 500; - vm.expectRevert(abi.encodeWithSignature("WrongValueSent()")); - target.mint{value: 0.9 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - vm.expectRevert(abi.encodeWithSignature("WrongValueSent()")); - target.mint{value: 1.1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - vm.stopPrank(); - } - - function test_MintFlowFundsRecipient() external { - vm.startPrank(admin); - - address fundsRecipient = address(239); - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - - ERC20PresetMinterPauser burnToken = new ERC20PresetMinterPauser("Random Token", "RAND"); - burnToken.mint(address(tokenRecipient), 1000); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, - amount: 500, - tokenIdStart: 0, - tokenIdEnd: 0, - tokenContract: address(burnToken), - transferRecipient: address(0), - burnFunction: bytes4(keccak256(bytes("burnFrom(address,uint256)"))) - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: fundsRecipient - }); - - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); - vm.stopPrank(); - - vm.startPrank(tokenRecipient); - burnToken.approve(address(redeemMinter), 500); - uint256[][] memory tokenIds = new uint256[][](1); - tokenIds[0] = new uint256[](0); - uint256[][] memory amounts = new uint256[][](1); - amounts[0] = new uint256[](1); - amounts[0][0] = 500; - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - assertEq(fundsRecipient.balance, 1 ether); - vm.stopPrank(); - } - - function test_MintFlowAmount() external { - vm.startPrank(admin); - - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - - ERC20PresetMinterPauser burnToken = new ERC20PresetMinterPauser("Random Token", "RAND"); - burnToken.mint(address(tokenRecipient), 1000); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, - amount: 500, - tokenIdStart: 0, - tokenIdEnd: 0, - tokenContract: address(burnToken), - transferRecipient: address(0), - burnFunction: bytes4(keccak256(bytes("burnFrom(address,uint256)"))) - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: address(0) - }); - - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); - vm.stopPrank(); - - vm.startPrank(tokenRecipient); - burnToken.approve(address(redeemMinter), 500); - uint256[][] memory tokenIds = new uint256[][](1); - tokenIds[0] = new uint256[](0); - uint256[][] memory amounts = new uint256[][](1); - amounts[0] = new uint256[](1); - amounts[0][0] = 500; - vm.expectRevert(abi.encodeWithSignature("IncorrectMintAmount()")); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 11, abi.encode(redeemInstructions, tokenIds, amounts)); - vm.stopPrank(); - } - - function test_MintFlowIncorrectNumberOfTokenIds() external { - vm.startPrank(admin); - - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - - ERC1155PresetMinterPauser burnToken = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); - burnToken.mint(address(tokenRecipient), 1, 1000, ""); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155, - amount: 500, - tokenIdStart: 1, - tokenIdEnd: 1, - tokenContract: address(burnToken), - transferRecipient: address(0), - burnFunction: bytes4(keccak256(bytes("burnBatch(address,uint256[],uint256[])"))) - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: address(0) - }); - - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); - vm.stopPrank(); - - // instructions length != tokenIds length - vm.startPrank(tokenRecipient); - burnToken.setApprovalForAll(address(redeemMinter), true); - uint256[][] memory tokenIds = new uint256[][](2); - uint256[][] memory amounts = new uint256[][](1); - amounts[0] = new uint256[](1); - amounts[0][0] = 500; - vm.expectRevert(abi.encodeWithSignature("IncorrectNumberOfTokenIds()")); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - tokenIds = new uint256[][](1); - tokenIds[0] = new uint256[](1); - tokenIds[0][0] = 1; - - // ERC1155: amounts length != tokenIds length - amounts = new uint256[][](2); - vm.expectRevert(abi.encodeWithSignature("IncorrectNumberOfTokenIds()")); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - } - - function test_MintFlowIncorrectBurnOrTransferAmount() external { - vm.startPrank(admin); - - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - address redeemTokenRecipient = address(323); - - ERC1155PresetMinterPauser burnTokenERC1155 = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); - burnTokenERC1155.mint(address(tokenRecipient), 1, 500, ""); - ERC721PresetMinterPauserAutoId burnTokenERC721 = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); - burnTokenERC721.mint(address(tokenRecipient)); - burnTokenERC721.mint(address(tokenRecipient)); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](2); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155, - amount: 300, - tokenIdStart: 1, - tokenIdEnd: 1, - tokenContract: address(burnTokenERC1155), - transferRecipient: redeemTokenRecipient, - burnFunction: 0 - }); - instructions[1] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC721, - amount: 3, - tokenIdStart: 0, - tokenIdEnd: 2, - tokenContract: address(burnTokenERC721), - transferRecipient: redeemTokenRecipient, - burnFunction: 0 - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: address(0) - }); - - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); - vm.stopPrank(); - - vm.startPrank(tokenRecipient); - burnTokenERC1155.setApprovalForAll(address(redeemMinter), true); - burnTokenERC721.setApprovalForAll(address(redeemMinter), true); - - uint256[][] memory tokenIds = new uint256[][](2); - uint256[][] memory amounts = new uint256[][](2); - - // this would be correct - tokenIds[0] = new uint256[](1); - tokenIds[0][0] = 1; - amounts[0] = new uint256[](1); - amounts[0][0] = 500; - tokenIds[1] = new uint256[](2); - tokenIds[1][0] = 0; - tokenIds[1][1] = 1; - - // ERC721: tokenids length != instruction amount - tokenIds[1] = new uint256[](1); - vm.expectRevert(abi.encodeWithSignature("IncorrectBurnOrTransferAmount()")); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - tokenIds[1] = new uint256[](3); - vm.expectRevert(abi.encodeWithSignature("IncorrectBurnOrTransferAmount()")); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - tokenIds[1] = new uint256[](2); - tokenIds[1][0] = 0; - tokenIds[1][1] = 1; - - // ERC1155: sum of amounts != instruction amount - amounts[0][0] = 499; - vm.expectRevert(abi.encodeWithSignature("IncorrectBurnOrTransferAmount()")); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - amounts[0][0] = 501; - vm.expectRevert(abi.encodeWithSignature("IncorrectBurnOrTransferAmount()")); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - - vm.stopPrank(); - } - - function test_MintFlowSenderNotTokenOwnerBurn20() external { - vm.startPrank(admin); - - address actualTokenOwner = address(92834); - - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - - ERC20PresetMinterPauser burnTokenERC20 = new ERC20PresetMinterPauser("Random Token", "RAND"); - burnTokenERC20.mint(address(actualTokenOwner), 1000); - ERC1155PresetMinterPauser burnTokenERC1155 = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); - burnTokenERC1155.mint(address(actualTokenOwner), 1, 1000, ""); - ERC721PresetMinterPauserAutoId burnTokenERC721 = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); - burnTokenERC721.mint(address(actualTokenOwner)); - burnTokenERC721.mint(address(actualTokenOwner)); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, - amount: 500, - tokenIdStart: 0, - tokenIdEnd: 0, - tokenContract: address(burnTokenERC20), - transferRecipient: address(0), - burnFunction: bytes4(keccak256(bytes("burnFrom(address,uint256)"))) - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: address(0) - }); - - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); - vm.stopPrank(); - - vm.startPrank(tokenRecipient); - burnTokenERC20.approve(address(redeemMinter), 500); - - uint256[][] memory tokenIds = new uint256[][](1); - uint256[][] memory amounts = new uint256[][](1); - amounts[0] = new uint256[](1); - amounts[0][0] = 500; - - vm.expectRevert(abi.encodeWithSignature("BurnFailed()")); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - vm.stopPrank(); - } - - function test_MintFlowSenderNotTokenOwnerBurn1155() external { - vm.startPrank(admin); - - address actualTokenOwner = address(92834); - - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - - ERC20PresetMinterPauser burnTokenERC20 = new ERC20PresetMinterPauser("Random Token", "RAND"); - burnTokenERC20.mint(address(actualTokenOwner), 1000); - ERC1155PresetMinterPauser burnTokenERC1155 = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); - burnTokenERC1155.mint(address(actualTokenOwner), 1, 1000, ""); - ERC721PresetMinterPauserAutoId burnTokenERC721 = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); - burnTokenERC721.mint(address(actualTokenOwner)); - burnTokenERC721.mint(address(actualTokenOwner)); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155, - amount: 500, - tokenIdStart: 1, - tokenIdEnd: 1, - tokenContract: address(burnTokenERC1155), - transferRecipient: address(0), - burnFunction: bytes4(keccak256(bytes("burnBatch(address,uint256[],uint256[])"))) - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: address(0) - }); - - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); - vm.stopPrank(); - - vm.startPrank(tokenRecipient); - burnTokenERC1155.setApprovalForAll(address(redeemMinter), true); - - uint256[][] memory tokenIds = new uint256[][](1); - tokenIds[0] = new uint256[](1); - tokenIds[0][0] = 1; - uint256[][] memory amounts = new uint256[][](1); - amounts[0] = new uint256[](1); - amounts[0][0] = 500; - - vm.expectRevert(abi.encodeWithSignature("BurnFailed()")); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - vm.stopPrank(); - } - - function test_MintFlowSenderNotTokenOwnerBurn721() external { - vm.startPrank(admin); - - address actualTokenOwner = address(92834); - - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - - ERC20PresetMinterPauser burnTokenERC20 = new ERC20PresetMinterPauser("Random Token", "RAND"); - burnTokenERC20.mint(address(actualTokenOwner), 1000); - ERC1155PresetMinterPauser burnTokenERC1155 = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); - burnTokenERC1155.mint(address(actualTokenOwner), 1, 1000, ""); - ERC721PresetMinterPauserAutoId burnTokenERC721 = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); - burnTokenERC721.mint(address(actualTokenOwner)); - burnTokenERC721.mint(address(actualTokenOwner)); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC721, - amount: 2, - tokenIdStart: 0, - tokenIdEnd: 1, - tokenContract: address(burnTokenERC721), - transferRecipient: address(0), - burnFunction: bytes4(keccak256(bytes("burn(uint256)"))) - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: address(0) - }); - - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); - vm.stopPrank(); - - vm.prank(actualTokenOwner); - burnTokenERC721.setApprovalForAll(address(redeemMinter), true); - vm.startPrank(tokenRecipient); - burnTokenERC721.setApprovalForAll(address(redeemMinter), true); - - uint256[][] memory tokenIds = new uint256[][](1); - tokenIds[0] = new uint256[](2); - tokenIds[0][0] = 0; - tokenIds[0][1] = 1; - uint256[][] memory amounts; - - vm.expectRevert(abi.encodeWithSignature("SenderIsNotTokenOwner()")); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - vm.stopPrank(); - } - - function test_MintFlowSenderNotTokenOwnerTransfer20() external { - vm.startPrank(admin); - - address actualTokenOwner = address(92834); - - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - - ERC20PresetMinterPauser burnTokenERC20 = new ERC20PresetMinterPauser("Random Token", "RAND"); - burnTokenERC20.mint(address(actualTokenOwner), 1000); - ERC1155PresetMinterPauser burnTokenERC1155 = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); - burnTokenERC1155.mint(address(actualTokenOwner), 1, 1000, ""); - ERC721PresetMinterPauserAutoId burnTokenERC721 = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); - burnTokenERC721.mint(address(actualTokenOwner)); - burnTokenERC721.mint(address(actualTokenOwner)); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, - amount: 500, - tokenIdStart: 0, - tokenIdEnd: 0, - tokenContract: address(burnTokenERC20), - transferRecipient: address(1), - burnFunction: bytes4(0) - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: address(0) - }); - - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); - vm.stopPrank(); - - vm.startPrank(tokenRecipient); - burnTokenERC20.approve(address(redeemMinter), 500); - - uint256[][] memory tokenIds = new uint256[][](1); - uint256[][] memory amounts = new uint256[][](1); - amounts[0] = new uint256[](1); - amounts[0][0] = 500; - - vm.expectRevert("ERC20: transfer amount exceeds balance"); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - vm.stopPrank(); - } - - function test_MintFlowSenderNotTokenOwnerTransfer1155() external { - vm.startPrank(admin); - - address actualTokenOwner = address(92834); - - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - - ERC20PresetMinterPauser burnTokenERC20 = new ERC20PresetMinterPauser("Random Token", "RAND"); - burnTokenERC20.mint(address(actualTokenOwner), 1000); - ERC1155PresetMinterPauser burnTokenERC1155 = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); - burnTokenERC1155.mint(address(actualTokenOwner), 1, 1000, ""); - ERC721PresetMinterPauserAutoId burnTokenERC721 = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); - burnTokenERC721.mint(address(actualTokenOwner)); - burnTokenERC721.mint(address(actualTokenOwner)); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155, - amount: 500, - tokenIdStart: 1, - tokenIdEnd: 1, - tokenContract: address(burnTokenERC1155), - transferRecipient: address(1), - burnFunction: bytes4(0) - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: address(0) - }); - - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); - vm.stopPrank(); - - vm.startPrank(tokenRecipient); - burnTokenERC1155.setApprovalForAll(address(redeemMinter), true); - - uint256[][] memory tokenIds = new uint256[][](1); - tokenIds[0] = new uint256[](1); - tokenIds[0][0] = 1; - uint256[][] memory amounts = new uint256[][](1); - amounts[0] = new uint256[](1); - amounts[0][0] = 500; - - vm.expectRevert("ERC1155: insufficient balance for transfer"); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - vm.stopPrank(); - } - - function test_MintFlowSenderNotTokenOwnerTransfer721() external { - vm.startPrank(admin); - - address actualTokenOwner = address(92834); - - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - - ERC20PresetMinterPauser burnTokenERC20 = new ERC20PresetMinterPauser("Random Token", "RAND"); - burnTokenERC20.mint(address(actualTokenOwner), 1000); - ERC1155PresetMinterPauser burnTokenERC1155 = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); - burnTokenERC1155.mint(address(actualTokenOwner), 1, 1000, ""); - ERC721PresetMinterPauserAutoId burnTokenERC721 = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); - burnTokenERC721.mint(address(actualTokenOwner)); - burnTokenERC721.mint(address(actualTokenOwner)); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC721, - amount: 2, - tokenIdStart: 0, - tokenIdEnd: 1, - tokenContract: address(burnTokenERC721), - transferRecipient: address(1), - burnFunction: bytes4(0) - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: address(0) - }); - - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); - vm.stopPrank(); - - vm.startPrank(tokenRecipient); - burnTokenERC721.setApprovalForAll(address(redeemMinter), true); - - uint256[][] memory tokenIds = new uint256[][](1); - tokenIds[0] = new uint256[](2); - tokenIds[0][0] = 0; - tokenIds[0][1] = 1; - uint256[][] memory amounts; - - vm.expectRevert("ERC721: caller is not token owner or approved"); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - vm.stopPrank(); - } - - ///////// RESET AND CLEAR ///////// - - function test_ResetSaleAlwaysReverts() external { - vm.prank(address(target)); - vm.expectRevert(abi.encodeWithSignature("MustCallClearRedeem()")); - redeemMinter.resetSale(uint256(1)); - } - - function test_ClearRedeem() external { - vm.startPrank(admin); - - address tokenRecipient = address(322); - vm.deal(tokenRecipient, 20 ether); - - ERC721PresetMinterPauserAutoId burnToken = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); - burnToken.mint(address(tokenRecipient)); - burnToken.mint(address(tokenRecipient)); - - ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ - tokenContract: address(target), - tokenId: newTokenId, - amount: 10, - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); - instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ - tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC721, - amount: 2, - tokenIdStart: 0, - tokenIdEnd: 1, - tokenContract: address(burnToken), - transferRecipient: address(0), - burnFunction: bytes4(keccak256(bytes("burn(uint256)"))) - }); - ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ - mintToken: mintToken, - instructions: instructions, - saleStart: 0, - saleEnd: type(uint64).max, - ethAmount: 1 ether, - ethRecipient: address(0) - }); - - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); - bytes32[] memory hashes = new bytes32[](1); - hashes[0] = keccak256(abi.encode(redeemInstructions)); - vm.expectEmit(true, false, false, true); - emit RedeemsCleared(address(target), hashes); - target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.clearRedeem.selector, hashes)); - vm.stopPrank(); - - vm.startPrank(tokenRecipient); - burnToken.setApprovalForAll(address(redeemMinter), true); - uint256[][] memory tokenIds = new uint256[][](1); - tokenIds[0] = new uint256[](2); - tokenIds[0][0] = 0; - tokenIds[0][1] = 1; - uint256[][] memory amounts = new uint256[][](1); - vm.expectRevert(abi.encodeWithSignature("RedeemInstructionNotAllowed()")); - target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); - } -} +/// @notice Contract versions after v1.4.0 will not support the current burn to redeem minter +// contract ZoraCreatorRedeemMinterStrategyTest is Test { +// ProtocolRewards internal protocolRewards; +// ZoraCreator1155Impl internal target; +// ZoraCreatorRedeemMinterStrategy internal redeemMinter; +// address payable internal admin = payable(address(0x999)); +// uint256 internal newTokenId; +// address internal zora; + +// event RedeemSet(address indexed target, bytes32 indexed redeemsInstructionsHash, ZoraCreatorRedeemMinterStrategy.RedeemInstructions data); +// event RedeemProcessed(address indexed target, bytes32 indexed redeemsInstructionsHash, address sender, uint256[][] tokenIds, uint256[][] amounts); +// event RedeemsCleared(address indexed target, bytes32[] indexed redeemInstructionsHashes); + +// function setUp() external { +// zora = makeAddr("zora"); +// bytes[] memory emptyData = new bytes[](0); +// protocolRewards = new ProtocolRewards(); +// ZoraCreator1155Impl targetImpl = new ZoraCreator1155Impl(0, zora, address(0), address(protocolRewards)); +// Zora1155 proxy = new Zora1155(address(targetImpl)); +// target = ZoraCreator1155Impl(address(proxy)); +// target.initialize("test", "test", ICreatorRoyaltiesControl.RoyaltyConfiguration(0, 0, address(0)), admin, emptyData); +// redeemMinter = new ZoraCreatorRedeemMinterStrategy(); +// redeemMinter.initialize(address(target)); +// vm.startPrank(admin); +// newTokenId = target.setupNewToken("https://zora.co/testing/token.json", 10); +// target.addPermission(newTokenId, address(redeemMinter), target.PERMISSION_BIT_MINTER()); +// vm.stopPrank(); +// } + +// function test_ContractURI() external { +// assertEq(redeemMinter.contractURI(), "https://github.com/ourzora/zora-1155-contracts/"); +// } + +// function test_ContractName() external { +// assertEq(redeemMinter.contractName(), "Redeem Minter Sale Strategy"); +// } + +// function test_Version() external { +// assertEq(redeemMinter.contractVersion(), "1.0.1"); +// } + +// function test_OnlyDropContractCanCallWriteFunctions() external { +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions; +// vm.startPrank(address(admin)); + +// vm.expectRevert(abi.encodeWithSignature("CallerNotCreatorContract()")); +// redeemMinter.setRedeem(redeemInstructions); + +// bytes32[] memory hashes = new bytes32[](0); +// vm.expectRevert(abi.encodeWithSignature("CallerNotCreatorContract()")); +// redeemMinter.clearRedeem(hashes); + +// vm.expectRevert(abi.encodeWithSignature("CallerNotCreatorContract()")); +// redeemMinter.requestMint(address(0), 0, 0, 0, bytes("")); + +// vm.expectRevert(abi.encodeWithSignature("CallerNotCreatorContract()")); +// redeemMinter.resetSale(0); + +// vm.stopPrank(); +// } + +// ///////// SET REDEEM ///////// + +// function test_SetRedeem() external { +// vm.startPrank(admin); + +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); + +// ERC20PresetMinterPauser burnToken = new ERC20PresetMinterPauser("Random Token", "RAND"); +// burnToken.mint(address(tokenRecipient), 1000); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, +// amount: 500, +// tokenIdStart: 0, +// tokenIdEnd: 0, +// tokenContract: address(burnToken), +// transferRecipient: address(0), +// burnFunction: bytes4(keccak256(bytes("burnFrom(address,uint256)"))) +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); +// vm.stopPrank(); + +// vm.expectEmit(true, true, false, true); +// emit RedeemSet(address(target), keccak256(abi.encode(redeemInstructions)), redeemInstructions); +// vm.startPrank(address(target)); +// redeemMinter.setRedeem(redeemInstructions); +// vm.expectRevert(abi.encodeWithSignature("RedeemInstructionAlreadySet()")); +// redeemMinter.setRedeem(redeemInstructions); +// vm.stopPrank(); + +// assertTrue(redeemMinter.redeemInstructionsHashIsAllowed(keccak256(abi.encode(redeemInstructions)))); +// } + +// function test_SetRedeemInstructionValidation() external { +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); + +// ERC20PresetMinterPauser burnToken = new ERC20PresetMinterPauser("Random Token", "RAND"); +// burnToken.mint(address(tokenRecipient), 1000); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.NULL, +// amount: 500, +// tokenIdStart: 0, +// tokenIdEnd: 0, +// tokenContract: address(burnToken), +// transferRecipient: address(0), +// burnFunction: bytes4(keccak256(bytes("burnFrom(address,uint256)"))) +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); + +// vm.startPrank(address(target)); + +// // InvalidTokenIdsForTokenType: ERC20 w/ nonzero tokenId start or end +// redeemInstructions.instructions[0].tokenType = ZoraCreatorRedeemMinterStrategy.TokenType.ERC20; +// redeemInstructions.instructions[0].tokenIdStart = 1; +// redeemInstructions.instructions[0].tokenIdEnd = 0; +// vm.expectRevert(abi.encodeWithSignature("InvalidTokenIdsForTokenType()")); +// redeemMinter.setRedeem(redeemInstructions); +// redeemInstructions.instructions[0].tokenIdStart = 0; +// redeemInstructions.instructions[0].tokenIdEnd = 1; +// vm.expectRevert(abi.encodeWithSignature("InvalidTokenIdsForTokenType()")); +// redeemMinter.setRedeem(redeemInstructions); + +// // InvalidTokenIdsForTokenType: non ERC20 w/ tokenID start > end +// redeemInstructions.instructions[0].tokenType = ZoraCreatorRedeemMinterStrategy.TokenType.ERC721; +// redeemInstructions.instructions[0].tokenIdStart = 4; +// redeemInstructions.instructions[0].tokenIdEnd = 2; +// vm.expectRevert(abi.encodeWithSignature("InvalidTokenIdsForTokenType()")); +// redeemMinter.setRedeem(redeemInstructions); +// redeemInstructions.mintToken.tokenType = ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155; +// vm.expectRevert(abi.encodeWithSignature("InvalidTokenIdsForTokenType()")); +// redeemMinter.setRedeem(redeemInstructions); +// redeemInstructions.instructions[0].tokenIdStart = 0; +// redeemInstructions.instructions[0].tokenIdEnd = 0; + +// // InvalidTokenType: tokenType is NULL +// redeemInstructions.instructions[0].tokenType = ZoraCreatorRedeemMinterStrategy.TokenType.NULL; +// vm.expectRevert(abi.encodeWithSignature("InvalidTokenType()")); +// redeemMinter.setRedeem(redeemInstructions); +// redeemInstructions.instructions[0].tokenType = ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155; + +// // MustBurnOrTransfer: both transferRecipient and burnFunction are 0 +// redeemInstructions.instructions[0].transferRecipient = address(0); +// redeemInstructions.instructions[0].burnFunction = bytes4(0); +// vm.expectRevert(abi.encodeWithSignature("MustBurnOrTransfer()")); +// redeemMinter.setRedeem(redeemInstructions); + +// // MustBurnOrTransfer: both transferRecipient and burnFunction are non-zero +// redeemInstructions.instructions[0].transferRecipient = address(1); +// redeemInstructions.instructions[0].burnFunction = bytes4(keccak256(bytes("burnFrom(address,uint256)"))); +// vm.expectRevert(abi.encodeWithSignature("MustBurnOrTransfer()")); +// redeemMinter.setRedeem(redeemInstructions); +// redeemInstructions.instructions[0].transferRecipient = address(0); + +// // IncorrectMintAmount +// redeemInstructions.instructions[0].amount = 0; +// vm.expectRevert(abi.encodeWithSignature("IncorrectMintAmount()")); +// redeemMinter.setRedeem(redeemInstructions); +// redeemInstructions.instructions[0].amount = 500; + +// // InvalidSaleEndOrStart: start > end +// redeemInstructions.saleStart = 1; +// redeemInstructions.saleEnd = 0; +// vm.expectRevert(abi.encodeWithSignature("InvalidSaleEndOrStart()")); +// redeemMinter.setRedeem(redeemInstructions); +// redeemInstructions.saleStart = 0; +// redeemInstructions.saleEnd = type(uint64).max; + +// // InvalidSaleEndOrStart: block.timestamp > end +// redeemInstructions.saleStart = 0; +// redeemInstructions.saleEnd = 1 days; +// vm.warp(2 days); +// vm.expectRevert(abi.encodeWithSignature("InvalidSaleEndOrStart()")); +// redeemMinter.setRedeem(redeemInstructions); +// redeemInstructions.saleEnd = type(uint64).max; + +// // EmptyRedeemInstructions(); +// redeemInstructions.instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](0); +// vm.expectRevert(abi.encodeWithSignature("EmptyRedeemInstructions()")); +// redeemMinter.setRedeem(redeemInstructions); +// redeemInstructions.instructions = instructions; + +// // MintTokenContractMustBeCreatorContract +// redeemInstructions.mintToken.tokenContract = address(0); +// vm.expectRevert(abi.encodeWithSignature("MintTokenContractMustBeCreatorContract()")); +// redeemMinter.setRedeem(redeemInstructions); +// redeemInstructions.mintToken.tokenContract = address(target); + +// // MintTokenTypeMustBeERC1155: +// redeemInstructions.mintToken.tokenType = ZoraCreatorRedeemMinterStrategy.TokenType.ERC721; +// vm.expectRevert(abi.encodeWithSignature("MintTokenTypeMustBeERC1155()")); +// redeemMinter.setRedeem(redeemInstructions); +// } + +// ///////// REQUEST MINT ///////// + +// function test_MintFlowERC20() external { +// vm.startPrank(admin); + +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); + +// ERC20PresetMinterPauser burnToken = new ERC20PresetMinterPauser("Random Token", "RAND"); +// burnToken.mint(address(tokenRecipient), 1000); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, +// amount: 500, +// tokenIdStart: 0, +// tokenIdEnd: 0, +// tokenContract: address(burnToken), +// transferRecipient: address(0), +// burnFunction: bytes4(keccak256(bytes("burnFrom(address,uint256)"))) +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); + +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); +// vm.stopPrank(); + +// vm.startPrank(tokenRecipient); +// burnToken.approve(address(redeemMinter), 500); +// uint256[][] memory tokenIds = new uint256[][](1); +// tokenIds[0] = new uint256[](0); +// uint256[][] memory amounts = new uint256[][](1); +// amounts[0] = new uint256[](1); +// amounts[0][0] = 500; +// vm.expectEmit(true, true, false, false); +// emit RedeemProcessed(address(target), keccak256(abi.encode(redeemInstructions)), tokenRecipient, tokenIds, amounts); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// assertEq(address(target).balance, 1 ether); +// assertEq(target.balanceOf(tokenRecipient, newTokenId), 10); +// assertEq(burnToken.balanceOf(tokenRecipient), 500); +// vm.stopPrank(); +// } + +// function test_MintFlowERC1155() external { +// vm.startPrank(admin); + +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); + +// ERC1155PresetMinterPauser burnToken = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); +// burnToken.mint(address(tokenRecipient), 1, 1000, ""); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155, +// amount: 500, +// tokenIdStart: 1, +// tokenIdEnd: 1, +// tokenContract: address(burnToken), +// transferRecipient: address(0), +// burnFunction: bytes4(keccak256(bytes("burnBatch(address,uint256[],uint256[])"))) +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); + +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); +// vm.stopPrank(); + +// vm.startPrank(tokenRecipient); +// burnToken.setApprovalForAll(address(redeemMinter), true); +// uint256[][] memory tokenIds = new uint256[][](1); +// tokenIds[0] = new uint256[](1); +// tokenIds[0][0] = 1; +// uint256[][] memory amounts = new uint256[][](1); +// amounts[0] = new uint256[](1); +// amounts[0][0] = 500; +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// assertEq(address(target).balance, 1 ether); +// assertEq(target.balanceOf(tokenRecipient, newTokenId), 10); +// assertEq(burnToken.balanceOf(tokenRecipient, 1), 500); +// vm.stopPrank(); +// } + +// function test_MintFlowERC721() external { +// vm.startPrank(admin); + +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); + +// ERC721PresetMinterPauserAutoId burnToken = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); +// burnToken.mint(address(tokenRecipient)); +// burnToken.mint(address(tokenRecipient)); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC721, +// amount: 2, +// tokenIdStart: 0, +// tokenIdEnd: 1, +// tokenContract: address(burnToken), +// transferRecipient: address(0), +// burnFunction: bytes4(keccak256(bytes("burn(uint256)"))) +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); + +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); +// vm.stopPrank(); + +// vm.startPrank(tokenRecipient); +// burnToken.setApprovalForAll(address(redeemMinter), true); +// uint256[][] memory tokenIds = new uint256[][](1); +// tokenIds[0] = new uint256[](2); +// tokenIds[0][0] = 0; +// tokenIds[0][1] = 1; +// uint256[][] memory amounts = new uint256[][](1); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// assertEq(address(target).balance, 1 ether); +// assertEq(target.balanceOf(tokenRecipient, newTokenId), 10); +// vm.expectRevert(); +// burnToken.ownerOf(0); +// vm.expectRevert(); +// burnToken.ownerOf(1); +// vm.stopPrank(); +// } + +// function test_MintFlowMultiple() external { +// vm.startPrank(admin); + +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); + +// ERC20PresetMinterPauser burnTokenERC20 = new ERC20PresetMinterPauser("Random Token", "RAND"); +// burnTokenERC20.mint(address(tokenRecipient), 1000); +// ERC1155PresetMinterPauser burnTokenERC1155 = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); +// burnTokenERC1155.mint(address(tokenRecipient), 1, 1000, ""); +// ERC721PresetMinterPauserAutoId burnTokenERC721 = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); +// burnTokenERC721.mint(address(tokenRecipient)); +// burnTokenERC721.mint(address(tokenRecipient)); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](3); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, +// amount: 500, +// tokenIdStart: 0, +// tokenIdEnd: 0, +// tokenContract: address(burnTokenERC20), +// transferRecipient: address(0), +// burnFunction: bytes4(keccak256(bytes("burnFrom(address,uint256)"))) +// }); +// instructions[1] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155, +// amount: 500, +// tokenIdStart: 1, +// tokenIdEnd: 1, +// tokenContract: address(burnTokenERC1155), +// transferRecipient: address(0), +// burnFunction: bytes4(keccak256(bytes("burnBatch(address,uint256[],uint256[])"))) +// }); +// instructions[2] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC721, +// amount: 2, +// tokenIdStart: 0, +// tokenIdEnd: 1, +// tokenContract: address(burnTokenERC721), +// transferRecipient: address(0), +// burnFunction: bytes4(keccak256(bytes("burn(uint256)"))) +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); + +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); +// vm.stopPrank(); + +// vm.startPrank(tokenRecipient); +// burnTokenERC20.approve(address(redeemMinter), 500); +// burnTokenERC1155.setApprovalForAll(address(redeemMinter), true); +// burnTokenERC721.setApprovalForAll(address(redeemMinter), true); + +// uint256[][] memory tokenIds = new uint256[][](3); +// uint256[][] memory amounts = new uint256[][](3); + +// amounts[0] = new uint256[](1); +// amounts[0][0] = 500; + +// tokenIds[1] = new uint256[](1); +// tokenIds[1][0] = 1; +// amounts[1] = new uint256[](1); +// amounts[1][0] = 500; + +// tokenIds[2] = new uint256[](2); +// tokenIds[2][0] = 0; +// tokenIds[2][1] = 1; + +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// assertEq(address(target).balance, 1 ether); +// assertEq(target.balanceOf(tokenRecipient, newTokenId), 10); +// assertEq(burnTokenERC20.balanceOf(tokenRecipient), 500); +// assertEq(burnTokenERC1155.balanceOf(tokenRecipient, 1), 500); +// assertEq(burnTokenERC721.balanceOf(address(tokenRecipient)), 0); +// vm.stopPrank(); +// } + +// function test_MintFlowMultipleWithTransferInsteadOfBurn() external { +// vm.startPrank(admin); + +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); +// address redeemTokenRecipient = address(323); + +// ERC20PresetMinterPauser burnTokenERC20 = new ERC20PresetMinterPauser("Random Token", "RAND"); +// burnTokenERC20.mint(address(tokenRecipient), 1000); +// ERC1155PresetMinterPauser burnTokenERC1155 = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); +// burnTokenERC1155.mint(address(tokenRecipient), 1, 1000, ""); +// ERC721PresetMinterPauserAutoId burnTokenERC721 = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); +// burnTokenERC721.mint(address(tokenRecipient)); +// burnTokenERC721.mint(address(tokenRecipient)); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](3); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, +// amount: 500, +// tokenIdStart: 0, +// tokenIdEnd: 0, +// tokenContract: address(burnTokenERC20), +// transferRecipient: redeemTokenRecipient, +// burnFunction: 0 +// }); +// instructions[1] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155, +// amount: 500, +// tokenIdStart: 1, +// tokenIdEnd: 1, +// tokenContract: address(burnTokenERC1155), +// transferRecipient: redeemTokenRecipient, +// burnFunction: 0 +// }); +// instructions[2] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC721, +// amount: 2, +// tokenIdStart: 0, +// tokenIdEnd: 1, +// tokenContract: address(burnTokenERC721), +// transferRecipient: redeemTokenRecipient, +// burnFunction: 0 +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); + +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); +// vm.stopPrank(); + +// vm.startPrank(tokenRecipient); +// burnTokenERC20.approve(address(redeemMinter), 500); +// burnTokenERC1155.setApprovalForAll(address(redeemMinter), true); +// burnTokenERC721.setApprovalForAll(address(redeemMinter), true); + +// uint256[][] memory tokenIds = new uint256[][](3); +// uint256[][] memory amounts = new uint256[][](3); + +// amounts[0] = new uint256[](1); +// amounts[0][0] = 500; + +// tokenIds[1] = new uint256[](1); +// tokenIds[1][0] = 1; +// amounts[1] = new uint256[](1); +// amounts[1][0] = 500; + +// tokenIds[2] = new uint256[](2); +// tokenIds[2][0] = 0; +// tokenIds[2][1] = 1; + +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// assertEq(address(target).balance, 1 ether); +// assertEq(target.balanceOf(tokenRecipient, newTokenId), 10); +// assertEq(burnTokenERC20.balanceOf(tokenRecipient), 500); +// assertEq(burnTokenERC20.balanceOf(redeemTokenRecipient), 500); +// assertEq(burnTokenERC1155.balanceOf(tokenRecipient, 1), 500); +// assertEq(burnTokenERC1155.balanceOf(redeemTokenRecipient, 1), 500); +// assertEq(burnTokenERC721.balanceOf(address(tokenRecipient)), 0); +// assertEq(burnTokenERC721.balanceOf(redeemTokenRecipient), 2); + +// vm.stopPrank(); +// } + +// function test_MintFlowTokenIdRangesForERC1155AndERC721() external { +// vm.startPrank(admin); + +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); +// address redeemTokenRecipient = address(323); + +// ERC1155PresetMinterPauser burnTokenERC1155 = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); +// burnTokenERC1155.mint(address(tokenRecipient), 7, 100, ""); +// burnTokenERC1155.mint(address(tokenRecipient), 8, 100, ""); +// burnTokenERC1155.mint(address(tokenRecipient), 9, 100, ""); +// ERC721PresetMinterPauserAutoId burnTokenERC721 = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); +// burnTokenERC721.mint(address(tokenRecipient)); +// burnTokenERC721.mint(address(tokenRecipient)); +// burnTokenERC721.mint(address(tokenRecipient)); +// burnTokenERC721.mint(address(tokenRecipient)); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](2); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155, +// amount: 300, +// tokenIdStart: 7, +// tokenIdEnd: 9, +// tokenContract: address(burnTokenERC1155), +// transferRecipient: redeemTokenRecipient, +// burnFunction: 0 +// }); +// instructions[1] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC721, +// amount: 3, +// tokenIdStart: 1, +// tokenIdEnd: 3, +// tokenContract: address(burnTokenERC721), +// transferRecipient: redeemTokenRecipient, +// burnFunction: 0 +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); + +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); +// vm.stopPrank(); + +// vm.startPrank(tokenRecipient); +// burnTokenERC1155.setApprovalForAll(address(redeemMinter), true); +// burnTokenERC721.setApprovalForAll(address(redeemMinter), true); + +// uint256[][] memory tokenIds = new uint256[][](2); +// uint256[][] memory amounts = new uint256[][](2); + +// tokenIds[0] = new uint256[](3); +// tokenIds[0][0] = 7; +// tokenIds[0][1] = 8; +// tokenIds[0][2] = 9; +// amounts[0] = new uint256[](3); +// amounts[0][0] = 100; +// amounts[0][1] = 100; +// amounts[0][2] = 100; + +// tokenIds[1] = new uint256[](3); +// tokenIds[1][0] = 1; +// tokenIds[1][1] = 2; +// tokenIds[1][2] = 3; + +// // detour: tokenId out of range +// tokenIds[0][0] = 6; +// vm.expectRevert(abi.encodeWithSignature("TokenIdOutOfRange()")); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// tokenIds[0][0] = 10; +// vm.expectRevert(abi.encodeWithSignature("TokenIdOutOfRange()")); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// tokenIds[0][0] = 7; +// tokenIds[1][0] = 0; +// vm.expectRevert(abi.encodeWithSignature("TokenIdOutOfRange()")); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// tokenIds[1][0] = 4; +// vm.expectRevert(abi.encodeWithSignature("TokenIdOutOfRange()")); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// tokenIds[1][0] = 1; + +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// assertEq(address(target).balance, 1 ether); +// assertEq(target.balanceOf(tokenRecipient, newTokenId), 10); +// assertEq(burnTokenERC1155.balanceOf(redeemTokenRecipient, 7), 100); +// assertEq(burnTokenERC1155.balanceOf(redeemTokenRecipient, 8), 100); +// assertEq(burnTokenERC1155.balanceOf(redeemTokenRecipient, 9), 100); +// assertEq(burnTokenERC721.balanceOf(redeemTokenRecipient), 3); + +// vm.stopPrank(); +// } + +// function test_MintFlowRedeemStart() external { +// vm.startPrank(admin); + +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); + +// ERC20PresetMinterPauser burnToken = new ERC20PresetMinterPauser("Random Token", "RAND"); +// burnToken.mint(address(tokenRecipient), 1000); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, +// amount: 500, +// tokenIdStart: 0, +// tokenIdEnd: 0, +// tokenContract: address(burnToken), +// transferRecipient: address(0), +// burnFunction: bytes4(keccak256(bytes("burnFrom(address,uint256)"))) +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: uint64(block.timestamp + 1 days), +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); + +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); +// vm.stopPrank(); + +// vm.startPrank(tokenRecipient); +// burnToken.approve(address(redeemMinter), 500); +// uint256[][] memory tokenIds = new uint256[][](1); +// tokenIds[0] = new uint256[](0); +// uint256[][] memory amounts = new uint256[][](1); +// amounts[0] = new uint256[](1); +// amounts[0][0] = 500; +// vm.expectRevert(abi.encodeWithSignature("SaleHasNotStarted()")); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 1, abi.encode(redeemInstructions, tokenIds, amounts)); +// vm.stopPrank(); +// } + +// function test_MintFlowRedeemEnd() external { +// vm.startPrank(admin); + +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); + +// ERC20PresetMinterPauser burnToken = new ERC20PresetMinterPauser("Random Token", "RAND"); +// burnToken.mint(address(tokenRecipient), 1000); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, +// amount: 500, +// tokenIdStart: 0, +// tokenIdEnd: 0, +// tokenContract: address(burnToken), +// transferRecipient: address(0), +// burnFunction: bytes4(keccak256(bytes("burnFrom(address,uint256)"))) +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: uint64(1 days), +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); + +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); +// vm.stopPrank(); + +// vm.warp(2 days); + +// vm.startPrank(tokenRecipient); +// burnToken.approve(address(redeemMinter), 1000); +// uint256[] memory tokenIds = new uint256[](0); +// uint256[][] memory amounts = new uint256[][](1); +// amounts[0] = new uint256[](1); +// amounts[0][0] = 500; +// vm.expectRevert(abi.encodeWithSignature("SaleEnded()")); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 1, abi.encode(redeemInstructions, tokenIds, amounts)); +// vm.stopPrank(); +// } + +// function test_MintFlowEthValue() external { +// vm.startPrank(admin); + +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); + +// ERC20PresetMinterPauser burnToken = new ERC20PresetMinterPauser("Random Token", "RAND"); +// burnToken.mint(address(tokenRecipient), 1000); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, +// amount: 500, +// tokenIdStart: 0, +// tokenIdEnd: 0, +// tokenContract: address(burnToken), +// transferRecipient: address(0), +// burnFunction: bytes4(keccak256(bytes("burnFrom(address,uint256)"))) +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); + +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); +// vm.stopPrank(); + +// vm.startPrank(tokenRecipient); +// burnToken.approve(address(redeemMinter), 500); +// uint256[][] memory tokenIds = new uint256[][](1); +// tokenIds[0] = new uint256[](0); +// uint256[][] memory amounts = new uint256[][](1); +// amounts[0] = new uint256[](1); +// amounts[0][0] = 500; +// vm.expectRevert(abi.encodeWithSignature("INVALID_ETH_AMOUNT()")); +// target.mint{value: 0.9 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// vm.expectRevert(abi.encodeWithSignature("INVALID_ETH_AMOUNT()")); +// target.mint{value: 1.1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// vm.stopPrank(); +// } + +// function test_MintFlowFundsRecipient() external { +// vm.startPrank(admin); + +// address fundsRecipient = address(239); +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); + +// ERC20PresetMinterPauser burnToken = new ERC20PresetMinterPauser("Random Token", "RAND"); +// burnToken.mint(address(tokenRecipient), 1000); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, +// amount: 500, +// tokenIdStart: 0, +// tokenIdEnd: 0, +// tokenContract: address(burnToken), +// transferRecipient: address(0), +// burnFunction: bytes4(keccak256(bytes("burnFrom(address,uint256)"))) +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: fundsRecipient +// }); + +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); +// vm.stopPrank(); + +// vm.startPrank(tokenRecipient); +// burnToken.approve(address(redeemMinter), 500); +// uint256[][] memory tokenIds = new uint256[][](1); +// tokenIds[0] = new uint256[](0); +// uint256[][] memory amounts = new uint256[][](1); +// amounts[0] = new uint256[](1); +// amounts[0][0] = 500; +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// assertEq(fundsRecipient.balance, 1 ether); +// vm.stopPrank(); +// } + +// function test_MintFlowAmount() external { +// vm.startPrank(admin); + +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); + +// ERC20PresetMinterPauser burnToken = new ERC20PresetMinterPauser("Random Token", "RAND"); +// burnToken.mint(address(tokenRecipient), 1000); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, +// amount: 500, +// tokenIdStart: 0, +// tokenIdEnd: 0, +// tokenContract: address(burnToken), +// transferRecipient: address(0), +// burnFunction: bytes4(keccak256(bytes("burnFrom(address,uint256)"))) +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); + +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); +// vm.stopPrank(); + +// vm.startPrank(tokenRecipient); +// burnToken.approve(address(redeemMinter), 500); +// uint256[][] memory tokenIds = new uint256[][](1); +// tokenIds[0] = new uint256[](0); +// uint256[][] memory amounts = new uint256[][](1); +// amounts[0] = new uint256[](1); +// amounts[0][0] = 500; +// vm.expectRevert(abi.encodeWithSignature("IncorrectMintAmount()")); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 11, abi.encode(redeemInstructions, tokenIds, amounts)); +// vm.stopPrank(); +// } + +// function test_MintFlowIncorrectNumberOfTokenIds() external { +// vm.startPrank(admin); + +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); + +// ERC1155PresetMinterPauser burnToken = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); +// burnToken.mint(address(tokenRecipient), 1, 1000, ""); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155, +// amount: 500, +// tokenIdStart: 1, +// tokenIdEnd: 1, +// tokenContract: address(burnToken), +// transferRecipient: address(0), +// burnFunction: bytes4(keccak256(bytes("burnBatch(address,uint256[],uint256[])"))) +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); + +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); +// vm.stopPrank(); + +// // instructions length != tokenIds length +// vm.startPrank(tokenRecipient); +// burnToken.setApprovalForAll(address(redeemMinter), true); +// uint256[][] memory tokenIds = new uint256[][](2); +// uint256[][] memory amounts = new uint256[][](1); +// amounts[0] = new uint256[](1); +// amounts[0][0] = 500; +// vm.expectRevert(abi.encodeWithSignature("IncorrectNumberOfTokenIds()")); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// tokenIds = new uint256[][](1); +// tokenIds[0] = new uint256[](1); +// tokenIds[0][0] = 1; + +// // ERC1155: amounts length != tokenIds length +// amounts = new uint256[][](2); +// vm.expectRevert(abi.encodeWithSignature("IncorrectNumberOfTokenIds()")); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// } + +// function test_MintFlowIncorrectBurnOrTransferAmount() external { +// vm.startPrank(admin); + +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); +// address redeemTokenRecipient = address(323); + +// ERC1155PresetMinterPauser burnTokenERC1155 = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); +// burnTokenERC1155.mint(address(tokenRecipient), 1, 500, ""); +// ERC721PresetMinterPauserAutoId burnTokenERC721 = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); +// burnTokenERC721.mint(address(tokenRecipient)); +// burnTokenERC721.mint(address(tokenRecipient)); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](2); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155, +// amount: 300, +// tokenIdStart: 1, +// tokenIdEnd: 1, +// tokenContract: address(burnTokenERC1155), +// transferRecipient: redeemTokenRecipient, +// burnFunction: 0 +// }); +// instructions[1] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC721, +// amount: 3, +// tokenIdStart: 0, +// tokenIdEnd: 2, +// tokenContract: address(burnTokenERC721), +// transferRecipient: redeemTokenRecipient, +// burnFunction: 0 +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); + +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); +// vm.stopPrank(); + +// vm.startPrank(tokenRecipient); +// burnTokenERC1155.setApprovalForAll(address(redeemMinter), true); +// burnTokenERC721.setApprovalForAll(address(redeemMinter), true); + +// uint256[][] memory tokenIds = new uint256[][](2); +// uint256[][] memory amounts = new uint256[][](2); + +// // this would be correct +// tokenIds[0] = new uint256[](1); +// tokenIds[0][0] = 1; +// amounts[0] = new uint256[](1); +// amounts[0][0] = 500; +// tokenIds[1] = new uint256[](2); +// tokenIds[1][0] = 0; +// tokenIds[1][1] = 1; + +// // ERC721: tokenids length != instruction amount +// tokenIds[1] = new uint256[](1); +// vm.expectRevert(abi.encodeWithSignature("IncorrectBurnOrTransferAmount()")); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// tokenIds[1] = new uint256[](3); +// vm.expectRevert(abi.encodeWithSignature("IncorrectBurnOrTransferAmount()")); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// tokenIds[1] = new uint256[](2); +// tokenIds[1][0] = 0; +// tokenIds[1][1] = 1; + +// // ERC1155: sum of amounts != instruction amount +// amounts[0][0] = 499; +// vm.expectRevert(abi.encodeWithSignature("IncorrectBurnOrTransferAmount()")); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// amounts[0][0] = 501; +// vm.expectRevert(abi.encodeWithSignature("IncorrectBurnOrTransferAmount()")); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); + +// vm.stopPrank(); +// } + +// function test_MintFlowSenderNotTokenOwnerBurn20() external { +// vm.startPrank(admin); + +// address actualTokenOwner = address(92834); + +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); + +// ERC20PresetMinterPauser burnTokenERC20 = new ERC20PresetMinterPauser("Random Token", "RAND"); +// burnTokenERC20.mint(address(actualTokenOwner), 1000); +// ERC1155PresetMinterPauser burnTokenERC1155 = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); +// burnTokenERC1155.mint(address(actualTokenOwner), 1, 1000, ""); +// ERC721PresetMinterPauserAutoId burnTokenERC721 = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); +// burnTokenERC721.mint(address(actualTokenOwner)); +// burnTokenERC721.mint(address(actualTokenOwner)); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, +// amount: 500, +// tokenIdStart: 0, +// tokenIdEnd: 0, +// tokenContract: address(burnTokenERC20), +// transferRecipient: address(0), +// burnFunction: bytes4(keccak256(bytes("burnFrom(address,uint256)"))) +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); + +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); +// vm.stopPrank(); + +// vm.startPrank(tokenRecipient); +// burnTokenERC20.approve(address(redeemMinter), 500); + +// uint256[][] memory tokenIds = new uint256[][](1); +// uint256[][] memory amounts = new uint256[][](1); +// amounts[0] = new uint256[](1); +// amounts[0][0] = 500; + +// vm.expectRevert(abi.encodeWithSignature("BurnFailed()")); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// vm.stopPrank(); +// } + +// function test_MintFlowSenderNotTokenOwnerBurn1155() external { +// vm.startPrank(admin); + +// address actualTokenOwner = address(92834); + +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); + +// ERC20PresetMinterPauser burnTokenERC20 = new ERC20PresetMinterPauser("Random Token", "RAND"); +// burnTokenERC20.mint(address(actualTokenOwner), 1000); +// ERC1155PresetMinterPauser burnTokenERC1155 = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); +// burnTokenERC1155.mint(address(actualTokenOwner), 1, 1000, ""); +// ERC721PresetMinterPauserAutoId burnTokenERC721 = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); +// burnTokenERC721.mint(address(actualTokenOwner)); +// burnTokenERC721.mint(address(actualTokenOwner)); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); + +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155, +// amount: 500, +// tokenIdStart: 1, +// tokenIdEnd: 1, +// tokenContract: address(burnTokenERC1155), +// transferRecipient: address(0), +// burnFunction: bytes4(keccak256(bytes("burnBatch(address,uint256[],uint256[])"))) +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); + +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); +// vm.stopPrank(); + +// vm.startPrank(tokenRecipient); +// burnTokenERC1155.setApprovalForAll(address(redeemMinter), true); + +// uint256[][] memory tokenIds = new uint256[][](1); +// tokenIds[0] = new uint256[](1); +// tokenIds[0][0] = 1; +// uint256[][] memory amounts = new uint256[][](1); +// amounts[0] = new uint256[](1); +// amounts[0][0] = 500; + +// vm.expectRevert(abi.encodeWithSignature("BurnFailed()")); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// vm.stopPrank(); +// } + +// function test_MintFlowSenderNotTokenOwnerBurn721() external { +// vm.startPrank(admin); + +// address actualTokenOwner = address(92834); + +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); + +// ERC20PresetMinterPauser burnTokenERC20 = new ERC20PresetMinterPauser("Random Token", "RAND"); +// burnTokenERC20.mint(address(actualTokenOwner), 1000); +// ERC1155PresetMinterPauser burnTokenERC1155 = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); +// burnTokenERC1155.mint(address(actualTokenOwner), 1, 1000, ""); +// ERC721PresetMinterPauserAutoId burnTokenERC721 = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); +// burnTokenERC721.mint(address(actualTokenOwner)); +// burnTokenERC721.mint(address(actualTokenOwner)); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); + +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC721, +// amount: 2, +// tokenIdStart: 0, +// tokenIdEnd: 1, +// tokenContract: address(burnTokenERC721), +// transferRecipient: address(0), +// burnFunction: bytes4(keccak256(bytes("burn(uint256)"))) +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); + +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); +// vm.stopPrank(); + +// vm.prank(actualTokenOwner); +// burnTokenERC721.setApprovalForAll(address(redeemMinter), true); +// vm.startPrank(tokenRecipient); +// burnTokenERC721.setApprovalForAll(address(redeemMinter), true); + +// uint256[][] memory tokenIds = new uint256[][](1); +// tokenIds[0] = new uint256[](2); +// tokenIds[0][0] = 0; +// tokenIds[0][1] = 1; +// uint256[][] memory amounts; + +// vm.expectRevert(abi.encodeWithSignature("SenderIsNotTokenOwner()")); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// vm.stopPrank(); +// } + +// function test_MintFlowSenderNotTokenOwnerTransfer20() external { +// vm.startPrank(admin); + +// address actualTokenOwner = address(92834); + +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); + +// ERC20PresetMinterPauser burnTokenERC20 = new ERC20PresetMinterPauser("Random Token", "RAND"); +// burnTokenERC20.mint(address(actualTokenOwner), 1000); +// ERC1155PresetMinterPauser burnTokenERC1155 = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); +// burnTokenERC1155.mint(address(actualTokenOwner), 1, 1000, ""); +// ERC721PresetMinterPauserAutoId burnTokenERC721 = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); +// burnTokenERC721.mint(address(actualTokenOwner)); +// burnTokenERC721.mint(address(actualTokenOwner)); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); + +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC20, +// amount: 500, +// tokenIdStart: 0, +// tokenIdEnd: 0, +// tokenContract: address(burnTokenERC20), +// transferRecipient: address(1), +// burnFunction: bytes4(0) +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); + +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); +// vm.stopPrank(); + +// vm.startPrank(tokenRecipient); +// burnTokenERC20.approve(address(redeemMinter), 500); + +// uint256[][] memory tokenIds = new uint256[][](1); +// uint256[][] memory amounts = new uint256[][](1); +// amounts[0] = new uint256[](1); +// amounts[0][0] = 500; + +// vm.expectRevert("ERC20: transfer amount exceeds balance"); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// vm.stopPrank(); +// } + +// function test_MintFlowSenderNotTokenOwnerTransfer1155() external { +// vm.startPrank(admin); + +// address actualTokenOwner = address(92834); + +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); + +// ERC20PresetMinterPauser burnTokenERC20 = new ERC20PresetMinterPauser("Random Token", "RAND"); +// burnTokenERC20.mint(address(actualTokenOwner), 1000); +// ERC1155PresetMinterPauser burnTokenERC1155 = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); +// burnTokenERC1155.mint(address(actualTokenOwner), 1, 1000, ""); +// ERC721PresetMinterPauserAutoId burnTokenERC721 = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); +// burnTokenERC721.mint(address(actualTokenOwner)); +// burnTokenERC721.mint(address(actualTokenOwner)); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); + +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155, +// amount: 500, +// tokenIdStart: 1, +// tokenIdEnd: 1, +// tokenContract: address(burnTokenERC1155), +// transferRecipient: address(1), +// burnFunction: bytes4(0) +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); + +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); +// vm.stopPrank(); + +// vm.startPrank(tokenRecipient); +// burnTokenERC1155.setApprovalForAll(address(redeemMinter), true); + +// uint256[][] memory tokenIds = new uint256[][](1); +// tokenIds[0] = new uint256[](1); +// tokenIds[0][0] = 1; +// uint256[][] memory amounts = new uint256[][](1); +// amounts[0] = new uint256[](1); +// amounts[0][0] = 500; + +// vm.expectRevert("ERC1155: insufficient balance for transfer"); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// vm.stopPrank(); +// } + +// function test_MintFlowSenderNotTokenOwnerTransfer721() external { +// vm.startPrank(admin); + +// address actualTokenOwner = address(92834); + +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); + +// ERC20PresetMinterPauser burnTokenERC20 = new ERC20PresetMinterPauser("Random Token", "RAND"); +// burnTokenERC20.mint(address(actualTokenOwner), 1000); +// ERC1155PresetMinterPauser burnTokenERC1155 = new ERC1155PresetMinterPauser("https://zora.co/testing/token.json"); +// burnTokenERC1155.mint(address(actualTokenOwner), 1, 1000, ""); +// ERC721PresetMinterPauserAutoId burnTokenERC721 = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); +// burnTokenERC721.mint(address(actualTokenOwner)); +// burnTokenERC721.mint(address(actualTokenOwner)); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); + +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC721, +// amount: 2, +// tokenIdStart: 0, +// tokenIdEnd: 1, +// tokenContract: address(burnTokenERC721), +// transferRecipient: address(1), +// burnFunction: bytes4(0) +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); + +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); +// vm.stopPrank(); + +// vm.startPrank(tokenRecipient); +// burnTokenERC721.setApprovalForAll(address(redeemMinter), true); + +// uint256[][] memory tokenIds = new uint256[][](1); +// tokenIds[0] = new uint256[](2); +// tokenIds[0][0] = 0; +// tokenIds[0][1] = 1; +// uint256[][] memory amounts; + +// vm.expectRevert("ERC721: caller is not token owner or approved"); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// vm.stopPrank(); +// } + +// ///////// RESET AND CLEAR ///////// + +// function test_ResetSaleAlwaysReverts() external { +// vm.prank(address(target)); +// vm.expectRevert(abi.encodeWithSignature("MustCallClearRedeem()")); +// redeemMinter.resetSale(uint256(1)); +// } + +// function test_ClearRedeem() external { +// vm.startPrank(admin); + +// address tokenRecipient = address(322); +// vm.deal(tokenRecipient, 20 ether); + +// ERC721PresetMinterPauserAutoId burnToken = new ERC721PresetMinterPauserAutoId("Test token", "TEST", "https://zora.co/testing/token.json"); +// burnToken.mint(address(tokenRecipient)); +// burnToken.mint(address(tokenRecipient)); + +// ZoraCreatorRedeemMinterStrategy.MintToken memory mintToken = ZoraCreatorRedeemMinterStrategy.MintToken({ +// tokenContract: address(target), +// tokenId: newTokenId, +// amount: 10, +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC1155 +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstruction[] memory instructions = new ZoraCreatorRedeemMinterStrategy.RedeemInstruction[](1); +// instructions[0] = ZoraCreatorRedeemMinterStrategy.RedeemInstruction({ +// tokenType: ZoraCreatorRedeemMinterStrategy.TokenType.ERC721, +// amount: 2, +// tokenIdStart: 0, +// tokenIdEnd: 1, +// tokenContract: address(burnToken), +// transferRecipient: address(0), +// burnFunction: bytes4(keccak256(bytes("burn(uint256)"))) +// }); +// ZoraCreatorRedeemMinterStrategy.RedeemInstructions memory redeemInstructions = ZoraCreatorRedeemMinterStrategy.RedeemInstructions({ +// mintToken: mintToken, +// instructions: instructions, +// saleStart: 0, +// saleEnd: type(uint64).max, +// ethAmount: 1 ether, +// ethRecipient: address(0) +// }); + +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.setRedeem.selector, redeemInstructions)); +// bytes32[] memory hashes = new bytes32[](1); +// hashes[0] = keccak256(abi.encode(redeemInstructions)); +// vm.expectEmit(true, false, false, true); +// emit RedeemsCleared(address(target), hashes); +// target.callSale(newTokenId, redeemMinter, abi.encodeWithSelector(ZoraCreatorRedeemMinterStrategy.clearRedeem.selector, hashes)); +// vm.stopPrank(); + +// vm.startPrank(tokenRecipient); +// burnToken.setApprovalForAll(address(redeemMinter), true); +// uint256[][] memory tokenIds = new uint256[][](1); +// tokenIds[0] = new uint256[](2); +// tokenIds[0][0] = 0; +// tokenIds[0][1] = 1; +// uint256[][] memory amounts = new uint256[][](1); +// vm.expectRevert(abi.encodeWithSignature("RedeemInstructionNotAllowed()")); +// target.mint{value: 1 ether}(redeemMinter, newTokenId, 10, abi.encode(redeemInstructions, tokenIds, amounts)); +// } +// } diff --git a/test/nft/ZoraCreator1155.t.sol b/test/nft/ZoraCreator1155.t.sol index 26f2538d6..bf15761d1 100644 --- a/test/nft/ZoraCreator1155.t.sol +++ b/test/nft/ZoraCreator1155.t.sol @@ -578,18 +578,21 @@ contract ZoraCreator1155Test is Test { } function test_mint(uint256 quantity) external { + vm.assume(quantity > 0 && quantity < type(uint200).max); + init(); vm.prank(admin); uint256 tokenId = target.setupNewToken("test", quantity); vm.prank(admin); - target.addPermission(tokenId, address(simpleMinter), adminRole); + target.addPermission(tokenId, address(simpleMinter), minterRole); + + uint256 totalReward = target.computeTotalReward(quantity); + vm.deal(admin, totalReward); vm.prank(admin); - vm.expectEmit(true, true, true, true); - emit Purchased(admin, address(simpleMinter), tokenId, quantity, 0); - target.mint(simpleMinter, tokenId, quantity, abi.encode(recipient)); + target.mint{value: totalReward}(simpleMinter, tokenId, quantity, abi.encode(recipient)); IZoraCreator1155TypesV1.TokenData memory tokenData = target.getTokenInfo(tokenId); assertEq(tokenData.totalMinted, quantity); @@ -609,15 +612,19 @@ contract ZoraCreator1155Test is Test { function test_mint_revertCannotMintMoreTokens() external { init(); - vm.prank(admin); + uint256 totalReward = target.computeTotalReward(1001); + vm.deal(admin, totalReward); + + vm.startPrank(admin); + uint256 tokenId = target.setupNewToken("test", 1000); - vm.prank(admin); target.addPermission(tokenId, address(simpleMinter), adminRole); vm.expectRevert(abi.encodeWithSelector(IZoraCreator1155.CannotMintMoreTokens.selector, tokenId, 1001, 0, 1000)); - vm.prank(admin); - target.mint(simpleMinter, tokenId, 1001, abi.encode(recipient)); + target.mint{value: totalReward}(simpleMinter, tokenId, 1001, abi.encode(recipient)); + + vm.stopPrank(); } function test_FreeMintRewards(uint256 quantity) public { @@ -641,7 +648,8 @@ contract ZoraCreator1155Test is Test { (, , address fundsRecipient, , , ) = target.config(); - assertEq(protocolRewards.balanceOf(fundsRecipient), settings.creatorReward + settings.firstMinterReward); + assertEq(protocolRewards.balanceOf(recipient), settings.firstMinterReward); + assertEq(protocolRewards.balanceOf(fundsRecipient), settings.creatorReward); assertEq(protocolRewards.balanceOf(zora), settings.zoraReward + settings.mintReferralReward + settings.createReferralReward); } @@ -666,7 +674,8 @@ contract ZoraCreator1155Test is Test { (, , address fundsRecipient, , , ) = target.config(); - assertEq(protocolRewards.balanceOf(fundsRecipient), settings.creatorReward + settings.firstMinterReward); + assertEq(protocolRewards.balanceOf(recipient), settings.firstMinterReward); + assertEq(protocolRewards.balanceOf(fundsRecipient), settings.creatorReward); assertEq(protocolRewards.balanceOf(createReferral), settings.createReferralReward); assertEq(protocolRewards.balanceOf(zora), settings.zoraReward + settings.mintReferralReward); } @@ -692,7 +701,8 @@ contract ZoraCreator1155Test is Test { (, , address fundsRecipient, , , ) = target.config(); - assertEq(protocolRewards.balanceOf(fundsRecipient), settings.creatorReward + settings.firstMinterReward); + assertEq(protocolRewards.balanceOf(recipient), settings.firstMinterReward); + assertEq(protocolRewards.balanceOf(fundsRecipient), settings.creatorReward); assertEq(protocolRewards.balanceOf(mintReferral), settings.mintReferralReward); assertEq(protocolRewards.balanceOf(zora), settings.zoraReward + settings.createReferralReward); } @@ -718,7 +728,8 @@ contract ZoraCreator1155Test is Test { (, , address fundsRecipient, , , ) = target.config(); - assertEq(protocolRewards.balanceOf(fundsRecipient), settings.creatorReward + settings.firstMinterReward); + assertEq(protocolRewards.balanceOf(recipient), settings.firstMinterReward); + assertEq(protocolRewards.balanceOf(fundsRecipient), settings.creatorReward); assertEq(protocolRewards.balanceOf(createReferral), settings.createReferralReward); assertEq(protocolRewards.balanceOf(mintReferral), settings.mintReferralReward); assertEq(protocolRewards.balanceOf(zora), settings.zoraReward); @@ -779,11 +790,9 @@ contract ZoraCreator1155Test is Test { vm.prank(collector); target.mintWithRewards{value: totalValue}(fixedPriceMinter, tokenId, quantity, abi.encode(recipient), address(0)); - (, , address fundsRecipient, , , ) = target.config(); - assertEq(address(target).balance, totalSale); - assertEq(protocolRewards.balanceOf(fundsRecipient), settings.firstMinterReward); + assertEq(protocolRewards.balanceOf(recipient), settings.firstMinterReward); assertEq(protocolRewards.balanceOf(zora), settings.zoraReward + settings.mintReferralReward + settings.createReferralReward); } @@ -826,12 +835,10 @@ contract ZoraCreator1155Test is Test { vm.prank(collector); target.mintWithRewards{value: totalValue}(fixedPriceMinter, tokenId, quantity, abi.encode(recipient), mintReferral); - (, , address fundsRecipient, , , ) = target.config(); - assertEq(address(target).balance, totalSale); assertEq(protocolRewards.balanceOf(mintReferral), settings.mintReferralReward); - assertEq(protocolRewards.balanceOf(fundsRecipient), settings.firstMinterReward); + assertEq(protocolRewards.balanceOf(recipient), settings.firstMinterReward); assertEq(protocolRewards.balanceOf(zora), settings.zoraReward + settings.createReferralReward); } @@ -874,10 +881,8 @@ contract ZoraCreator1155Test is Test { vm.prank(collector); target.mintWithRewards{value: totalValue}(fixedPriceMinter, tokenId, quantity, abi.encode(recipient), address(0)); - (, , address fundsRecipient, , , ) = target.config(); - assertEq(address(target).balance, totalSale); - assertEq(protocolRewards.balanceOf(fundsRecipient), settings.firstMinterReward); + assertEq(protocolRewards.balanceOf(recipient), settings.firstMinterReward); assertEq(protocolRewards.balanceOf(createReferral), settings.createReferralReward); assertEq(protocolRewards.balanceOf(zora), settings.zoraReward + settings.mintReferralReward); } @@ -921,10 +926,8 @@ contract ZoraCreator1155Test is Test { vm.prank(collector); target.mintWithRewards{value: totalValue}(fixedPriceMinter, tokenId, quantity, abi.encode(recipient), mintReferral); - (, , address fundsRecipient, , , ) = target.config(); - assertEq(address(target).balance, totalSale); - assertEq(protocolRewards.balanceOf(fundsRecipient), settings.firstMinterReward); + assertEq(protocolRewards.balanceOf(recipient), settings.firstMinterReward); assertEq(protocolRewards.balanceOf(mintReferral), settings.mintReferralReward); assertEq(protocolRewards.balanceOf(createReferral), settings.createReferralReward); assertEq(protocolRewards.balanceOf(zora), settings.zoraReward); @@ -963,6 +966,66 @@ contract ZoraCreator1155Test is Test { target.mintWithRewards(fixedPriceMinter, tokenId, quantity, abi.encode(recipient), address(0)); } + function test_FirstMinterRewardReceivedOnConsecutiveMints(uint256 quantity) public { + vm.assume(quantity > 0 && quantity < type(uint200).max); + + init(); + + vm.prank(admin); + uint256 tokenId = target.setupNewToken("test", quantity * 2); + + vm.prank(admin); + target.addPermission(tokenId, address(simpleMinter), adminRole); + + RewardsSettings memory settings = target.computeFreeMintRewards(quantity); + + uint256 totalReward = target.computeTotalReward(quantity); + vm.deal(collector, totalReward); + + address firstMinter = makeAddr("firstMinter"); + + vm.prank(collector); + target.mintWithRewards{value: totalReward}(simpleMinter, tokenId, quantity, abi.encode(firstMinter), address(0)); + + assertEq(protocolRewards.balanceOf(firstMinter), settings.firstMinterReward); + + address collector2 = makeAddr("collector2"); + vm.deal(collector2, totalReward); + + vm.prank(collector2); + target.mintWithRewards{value: totalReward}(simpleMinter, tokenId, quantity, abi.encode(collector2), address(0)); + + assertEq(protocolRewards.balanceOf(firstMinter), settings.firstMinterReward * 2); + } + + function test_AssumeFirstMinterRecipientIsAddress(uint256 quantity) public { + vm.assume(quantity > 0 && quantity < type(uint200).max); + + init(); + + vm.prank(admin); + uint256 tokenId = target.setupNewToken("test", quantity); + + vm.prank(admin); + target.addPermission(tokenId, address(simpleMinter), adminRole); + + RewardsSettings memory settings = target.computeFreeMintRewards(quantity); + + uint256 totalReward = target.computeTotalReward(quantity); + vm.deal(collector, totalReward); + + uint256 rewardRecipient = 1234; + + vm.prank(collector); + target.mintWithRewards{value: totalReward}(simpleMinter, tokenId, quantity, abi.encode(rewardRecipient), address(0)); + + (, , address fundsRecipient, , , ) = target.config(); + + assertEq(protocolRewards.balanceOf(address(uint160(rewardRecipient))), settings.firstMinterReward); + assertEq(protocolRewards.balanceOf(fundsRecipient), settings.creatorReward); + assertEq(protocolRewards.balanceOf(zora), settings.zoraReward + settings.mintReferralReward + settings.createReferralReward); + } + function testRevert_WrongValueForSale(uint256 quantity, uint256 salePrice) public { vm.assume(quantity > 0 && quantity < 1_000_000); vm.assume(salePrice > 0 && salePrice < 10 ether); @@ -1115,8 +1178,11 @@ contract ZoraCreator1155Test is Test { vm.prank(admin); target.addPermission(tokenId, address(simpleMinter), adminRole); + uint256 totalReward = target.computeTotalReward(5); + vm.deal(admin, totalReward); + vm.prank(admin); - target.mint(simpleMinter, tokenId, 5, abi.encode(recipient)); + target.mint{value: totalReward}(simpleMinter, tokenId, 5, abi.encode(recipient)); uint256[] memory burnBatchIds = new uint256[](1); uint256[] memory burnBatchValues = new uint256[](1); @@ -1136,8 +1202,11 @@ contract ZoraCreator1155Test is Test { vm.prank(admin); target.addPermission(tokenId, address(simpleMinter), adminRole); + uint256 totalReward = target.computeTotalReward(5); + vm.deal(admin, totalReward); + vm.prank(admin); - target.mint(simpleMinter, tokenId, 5, abi.encode(recipient)); + target.mint{value: totalReward}(simpleMinter, tokenId, 5, abi.encode(recipient)); uint256[] memory burnBatchIds = new uint256[](1); uint256[] memory burnBatchValues = new uint256[](1); @@ -1159,9 +1228,14 @@ contract ZoraCreator1155Test is Test { vm.prank(admin); target.addPermission(tokenId, address(simpleMinter), minterRole); - vm.deal(admin, 1 ether); + uint256 totalReward = target.computeTotalReward(1000); + uint256 totalSale = 1 ether; + uint256 totalValue = totalReward + totalSale; + + vm.deal(admin, totalValue); + vm.prank(admin); - target.mint{value: 1 ether}(simpleMinter, tokenId, 1000, abi.encode(recipient)); + target.mint{value: totalValue}(simpleMinter, tokenId, 1000, abi.encode(recipient)); vm.prank(admin); target.withdraw(); @@ -1169,8 +1243,7 @@ contract ZoraCreator1155Test is Test { assertEq(admin.balance, 1 ether); } - function test_withdrawAll_revertETHWithdrawFailed(uint256 purchaseAmount, uint256 withdrawAmount) external { - vm.assume(withdrawAmount <= purchaseAmount); + function test_withdrawAll_revertETHWithdrawFailed() external { init(); vm.prank(admin); @@ -1187,9 +1260,13 @@ contract ZoraCreator1155Test is Test { vm.prank(admin); target.addPermission(0, address(simpleMinter), fundsManagerRole); - vm.deal(admin, 1 ether); + uint256 totalReward = target.computeTotalReward(1000); + uint256 totalSale = 1 ether; + uint256 totalValue = totalReward + totalSale; + + vm.deal(admin, totalValue); vm.prank(admin); - target.mint{value: 1 ether}(simpleMinter, tokenId, 1000, abi.encode(recipient)); + target.mint{value: totalValue}(simpleMinter, tokenId, 1000, abi.encode(recipient)); vm.expectRevert(abi.encodeWithSelector(IZoraCreator1155.ETHWithdrawFailed.selector, simpleMinter, 1 ether)); vm.prank(address(simpleMinter)); @@ -1262,7 +1339,10 @@ contract ZoraCreator1155Test is Test { ICreatorRoyaltiesControl.RoyaltyConfiguration({royaltyMintSchedule: royaltyMintSchedule, royaltyBPS: 0, royaltyRecipient: admin}) ); - target.mint(minter, tokenId, mintQuantity, abi.encode(recipient)); + uint256 totalReward = target.computeTotalReward(mintQuantity); + vm.deal(admin, totalReward); + + target.mint{value: totalReward}(minter, tokenId, mintQuantity, abi.encode(recipient)); uint256 totalRoyaltyMintsForPurchase = mintQuantity / (royaltyMintSchedule - 1); totalRoyaltyMintsForPurchase = MathUpgradeable.min(totalRoyaltyMintsForPurchase, editionSize - mintQuantity); @@ -1283,12 +1363,15 @@ contract ZoraCreator1155Test is Test { vm.prank(admin); target.addPermission(tokenId, address(minter), adminRole); + uint256 totalReward = target.computeTotalReward(80); + vm.deal(admin, totalReward); + vm.startPrank(admin); target.updateRoyaltiesForToken( tokenId, ICreatorRoyaltiesControl.RoyaltyConfiguration({royaltyMintSchedule: 5, royaltyBPS: 0, royaltyRecipient: admin}) ); - target.mint(minter, tokenId, 80, abi.encode(recipient)); + target.mint{value: totalReward}(minter, tokenId, 80, abi.encode(recipient)); assertEq(target.balanceOf(recipient, tokenId), 80); assertEq(target.balanceOf(admin, tokenId), 20); @@ -1306,13 +1389,16 @@ contract ZoraCreator1155Test is Test { vm.prank(admin); target.addPermission(tokenId, address(minter), adminRole); + uint256 totalReward = target.computeTotalReward(92); + vm.deal(admin, totalReward); + vm.startPrank(admin); target.updateRoyaltiesForToken( tokenId, ICreatorRoyaltiesControl.RoyaltyConfiguration({royaltyMintSchedule: 3, royaltyBPS: 0, royaltyRecipient: admin}) ); - target.mint(minter, tokenId, 92, abi.encode(recipient)); + target.mint{value: totalReward}(minter, tokenId, 92, abi.encode(recipient)); assertEq(target.balanceOf(recipient, tokenId), 92); assertEq(target.balanceOf(admin, tokenId), 45); @@ -1330,18 +1416,23 @@ contract ZoraCreator1155Test is Test { vm.prank(admin); target.addPermission(tokenId, address(minter), adminRole); + uint256 totalReward = target.computeTotalReward(92); + vm.deal(admin, totalReward); + vm.startPrank(admin); target.updateRoyaltiesForToken( tokenId, ICreatorRoyaltiesControl.RoyaltyConfiguration({royaltyMintSchedule: 3, royaltyBPS: 0, royaltyRecipient: admin}) ); - target.mint(minter, tokenId, 92, abi.encode(recipient)); + target.mint{value: totalReward}(minter, tokenId, 92, abi.encode(recipient)); assertEq(target.balanceOf(recipient, tokenId), 92); assertEq(target.balanceOf(admin, tokenId), 46); - target.mint(minter, tokenId, 1, abi.encode(recipient)); + vm.deal(admin, 0.000777 ether); + + target.mint{value: 0.000777 ether}(minter, tokenId, 1, abi.encode(recipient)); assertEq(target.balanceOf(recipient, tokenId), 93); assertEq(target.balanceOf(admin, tokenId), 46); diff --git a/yarn.lock b/yarn.lock index c8df57d76..814d325d9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -755,10 +755,10 @@ resolved "https://registry.yarnpkg.com/@zoralabs/openzeppelin-contracts-upgradeable/-/openzeppelin-contracts-upgradeable-4.8.4.tgz#130b69cd5ff70b1f67da11fe53fe8b2323464b84" integrity sha512-5vhL88tz00Gv2+NUhLdYBRqb9RRekfyQAodXTQxJU2LYxxy6jr1mPycTZempQ1kmw5wIwFbSIoYzpaxOx6UK6Q== -"@zoralabs/protocol-rewards@1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@zoralabs/protocol-rewards/-/protocol-rewards-1.1.1.tgz#e482c93598e92ce172f4e92584534e0521ffa8b2" - integrity sha512-lD5Jf/qWDQMG6rhnq1y2BHVEYIewDSUeAJwQD/1YIyXw1ANksLTmZZbrq8jXfFK2GbJeCzDqXKbFXSWidtyodw== +"@zoralabs/protocol-rewards@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@zoralabs/protocol-rewards/-/protocol-rewards-1.1.2.tgz#bc151601b44a74c508f5bf376a7eac355a3a468c" + integrity sha512-VLNaGth3AWNi8ehJM2eoIdWzzJIKSYqxQmlFpsjtOgBi2YnKJTJQPxrCk4Hlh/T3BBEGa1auSkGk1ynOCW0dUg== abitype@0.8.7: version "0.8.7"