Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: creator reward recipient per token #278

Merged
merged 14 commits into from
Oct 25, 2023
19 changes: 14 additions & 5 deletions packages/1155-contracts/src/nft/ZoraCreator1155Impl.sol
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ contract ZoraCreator1155Impl is
uint256 ethValueSent = _handleRewardsAndGetValueSent(
msg.value,
quantity,
getCreatorRewardRecipient(),
getCreatorRewardRecipient(tokenId),
createReferrals[tokenId],
address(0),
firstMinters[tokenId]
Expand Down Expand Up @@ -437,7 +437,7 @@ contract ZoraCreator1155Impl is
uint256 ethValueSent = _handleRewardsAndGetValueSent(
msg.value,
quantity,
getCreatorRewardRecipient(),
getCreatorRewardRecipient(tokenId),
createReferrals[tokenId],
mintReferral,
firstMinters[tokenId]
Expand All @@ -454,9 +454,18 @@ contract ZoraCreator1155Impl is
}

/// @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));
/// @param tokenId The token id to get the creator reward recipient for
/// @dev The creator is not enforced to set a funds recipient address for a specific token or contract-wide,
/// so in the case of both the reward recipient is set to the creator's contract,
/// which can be withdrawn by the creator via the `withdrawRewards` function.
function getCreatorRewardRecipient(uint256 tokenId) public view returns (address payable) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kulkarohan can we check the front-end and subgraph to make sure there are no calls to this function?

Would it make sense to make this internal?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

confirmed - no frontend and subgraph usage of this function (yet)

i believe however frontend is planning to pin the creator reward recipient address on each token page, so i think having it public to fetch would make their lives easier, at little cost to us since we need it anyways.

but can confirm w them and if they're not can just make this internal

if (getRoyalties(tokenId).royaltyRecipient != address(0)) {
kulkarohan marked this conversation as resolved.
Show resolved Hide resolved
return payable(getRoyalties(tokenId).royaltyRecipient);
} else if (config.fundsRecipient != address(0)) {
return payable(config.fundsRecipient);
kulkarohan marked this conversation as resolved.
Show resolved Hide resolved
} else {
kulkarohan marked this conversation as resolved.
Show resolved Hide resolved
return payable(address(this));
}
}

/// @notice Set a metadata renderer for a token
Expand Down
71 changes: 71 additions & 0 deletions packages/1155-contracts/test/nft/ZoraCreator1155.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,77 @@ contract ZoraCreator1155Test is Test {
assertEq(protocolRewards.balanceOf(zora), settings.zoraReward + settings.createReferralReward);
}

function test_SetCreatorRewardRecipientForToken() public {
address collaborator = makeAddr("collaborator");
uint256 quantity = 100;

init();

vm.prank(admin);
uint256 tokenId = target.setupNewToken("test", quantity);

address payable creatorRewardRecipient;

creatorRewardRecipient = target.getCreatorRewardRecipient(tokenId);

ICreatorRoyaltiesControl.RoyaltyConfiguration memory newRoyaltyConfig = ICreatorRoyaltiesControl.RoyaltyConfiguration(0, 0, collaborator);

vm.prank(admin);
target.updateRoyaltiesForToken(tokenId, newRoyaltyConfig);

creatorRewardRecipient = target.getCreatorRewardRecipient(tokenId);

assertEq(creatorRewardRecipient, collaborator);

vm.prank(admin);
target.addPermission(tokenId, address(simpleMinter), adminRole);

RewardsSettings memory settings = target.computeFreeMintRewards(quantity);

uint256 totalReward = target.computeTotalReward(quantity);
vm.deal(collector, totalReward);

vm.prank(collector);
target.mintWithRewards{value: totalReward}(simpleMinter, tokenId, quantity, abi.encode(recipient), address(0));
kulkarohan marked this conversation as resolved.
Show resolved Hide resolved

assertEq(protocolRewards.balanceOf(collaborator), settings.creatorReward + settings.firstMinterReward);
}

function test_CreatorRewardRecipientConditionalAddress() public {
ICreatorRoyaltiesControl.RoyaltyConfiguration memory royaltyConfig;
address payable creatorRewardRecipient;

address collaborator = makeAddr("collaborator");
uint256 quantity = 100;

init();

vm.prank(admin);
uint256 tokenId = target.setupNewToken("test", quantity);

(, , address contractFundsRecipient, , , ) = target.config();

creatorRewardRecipient = target.getCreatorRewardRecipient(tokenId);
assertEq(creatorRewardRecipient, contractFundsRecipient);

royaltyConfig = ICreatorRoyaltiesControl.RoyaltyConfiguration(0, 0, collaborator);
vm.prank(admin);
target.updateRoyaltiesForToken(tokenId, royaltyConfig);

creatorRewardRecipient = target.getCreatorRewardRecipient(tokenId);
assertEq(creatorRewardRecipient, collaborator);

royaltyConfig = ICreatorRoyaltiesControl.RoyaltyConfiguration(0, 0, address(0));
vm.prank(admin);
target.updateRoyaltiesForToken(tokenId, royaltyConfig);

vm.prank(admin);
target.setFundsRecipient(payable(address(0)));

creatorRewardRecipient = target.getCreatorRewardRecipient(tokenId);
assertEq(creatorRewardRecipient, address(target));
}

function testRevert_WrongValueForSale(uint256 quantity, uint256 salePrice) public {
vm.assume(quantity > 0 && quantity < 1_000_000);
vm.assume(salePrice > 0 && salePrice < 10 ether);
Expand Down
Loading