Skip to content

Commit

Permalink
Premint: first minter rewards (#162)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
oveddan and kulkarohan committed Sep 21, 2023
1 parent 0fc4fdb commit 875d697
Show file tree
Hide file tree
Showing 18 changed files with 1,828 additions and 1,788 deletions.
5 changes: 5 additions & 0 deletions .changeset/happy-socks-melt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@zoralabs/zora-1155-contracts": minor
---

Adds first minter rewards
5 changes: 5 additions & 0 deletions .changeset/spotty-horses-battle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@zoralabs/zora-1155-contracts": patch
---

Deprecate ZoraCreatorRedeemMinterStrategy at v1.0.1, a newer version will soon be released
2 changes: 1 addition & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
run: |
lcov --rc lcov_branch_coverage=1 \
--remove lcov.info \
--output-file lcov.info "*node_modules*" "*test*" "*script*" "*DeploymentConfig*"
--output-file lcov.info "*node_modules*" "*test*" "*script*" "*DeploymentConfig*" "*Redeem*"
- name: Report code coverage
uses: zgosalvez/github-actions-report-lcov@v2
Expand Down
3 changes: 2 additions & 1 deletion .storage-layout
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
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'
via_ir = true

[profile.optimized]
optimizer = true
optimizer_runs = 3000
optimizer_runs = 250
out = 'out'
script = 'src'
solc_version = '0.8.17'
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 0 additions & 1 deletion src/deployment/DeploymentConfig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
39 changes: 0 additions & 39 deletions src/fee/MintFeeManager.sol

This file was deleted.

61 changes: 48 additions & 13 deletions src/nft/ZoraCreator1155Impl.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -44,7 +43,6 @@ contract ZoraCreator1155Impl is
ReentrancyGuardUpgradeable,
PublicMulticall,
ERC1155Upgradeable,
MintFeeManager,
UUPSUpgradeable,
CreatorRendererControl,
LegacyNamingControl,
Expand All @@ -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);
}

Expand Down Expand Up @@ -413,22 +411,26 @@ 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);

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
Expand All @@ -444,15 +446,48 @@ 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);

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
Expand Down
3 changes: 0 additions & 3 deletions test/factory/ZoraCreator1155Factory.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
19 changes: 8 additions & 11 deletions test/factory/ZoraCreator1155Factory_Fork.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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);

Expand Down Expand Up @@ -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
Expand Down
90 changes: 0 additions & 90 deletions test/fee/MintFeeManager.t.sol

This file was deleted.

Loading

0 comments on commit 875d697

Please sign in to comment.