Skip to content

Commit

Permalink
Merge pull request #123 from ourzora/purchase_with_recipient
Browse files Browse the repository at this point in the history
feat: purchase with recipient
  • Loading branch information
kulkarohan committed Jun 28, 2023
2 parents 9650357 + 5c3eee6 commit 008654a
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 7 deletions.
29 changes: 22 additions & 7 deletions src/ERC721Drop.sol
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ contract ERC721Drop is
onlyPublicSaleActive
returns (uint256)
{
return _handlePurchase(quantity, "");
return _handlePurchase(msg.sender, quantity, "");
}

/// @notice Purchase a quantity of tokens with a comment
Expand All @@ -463,10 +463,25 @@ contract ERC721Drop is
onlyPublicSaleActive
returns (uint256)
{
return _handlePurchase(quantity, comment);
return _handlePurchase(msg.sender, quantity, comment);
}

function _handlePurchase(uint256 quantity, string memory comment) internal returns (uint256) {
/// @notice Purchase a quantity of tokens to a specified recipient, with an optional comment
/// @param recipient recipient of the tokens
/// @param quantity quantity to purchase
/// @param comment optional comment to include in the IERC721Drop.Sale event (leave blank for no comment)
/// @return tokenId of the first token minted
function purchaseWithRecipient(address recipient, uint256 quantity, string calldata comment)
external
payable
nonReentrant
onlyPublicSaleActive
returns (uint256)
{
return _handlePurchase(recipient, quantity, comment);
}

function _handlePurchase(address recipient, uint256 quantity, string memory comment) internal returns (uint256) {
_mintSupplyRoyalty(quantity);
_requireCanMintQuantity(quantity);

Expand All @@ -480,21 +495,21 @@ contract ERC721Drop is
// Any other number, the per address mint limit is that.
if (
salesConfig.maxSalePurchasePerAddress != 0 &&
_numberMinted(_msgSender()) +
_numberMinted(recipient) +
quantity -
presaleMintsByAddress[_msgSender()] >
presaleMintsByAddress[recipient] >
salesConfig.maxSalePurchasePerAddress
) {
revert Purchase_TooManyForAddress();
}

_mintNFTs(_msgSender(), quantity);
_mintNFTs(recipient, quantity);
uint256 firstMintedTokenId = _lastMintedTokenId() - quantity;

_payoutZoraFee(quantity);

emit IERC721Drop.Sale({
to: _msgSender(),
to: recipient,
quantity: quantity,
pricePerToken: salePrice,
firstPurchasedTokenId: firstMintedTokenId
Expand Down
88 changes: 88 additions & 0 deletions test/ERC721Drop.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,94 @@ contract ERC721DropTest is Test {
zoraNFTBase.purchaseWithComment{value: paymentAmount}(purchaseQuantity, "test comment");
}

function test_PurchaseWithRecipient(uint64 salePrice, uint32 purchaseQuantity) public setupZoraNFTBase(purchaseQuantity) {
vm.assume(purchaseQuantity < 100 && purchaseQuantity > 0);
vm.prank(DEFAULT_OWNER_ADDRESS);
zoraNFTBase.setSaleConfiguration({
publicSaleStart: 0,
publicSaleEnd: type(uint64).max,
presaleStart: 0,
presaleEnd: 0,
publicSalePrice: salePrice,
maxSalePurchasePerAddress: purchaseQuantity + 1,
presaleMerkleRoot: bytes32(0)
});

(, uint256 zoraFee) = zoraNFTBase.zoraFeeForAmount(purchaseQuantity);
uint256 paymentAmount = uint256(salePrice) * purchaseQuantity + zoraFee;

address minter = makeAddr("minter");
address recipient = makeAddr("recipient");

vm.deal(minter, paymentAmount);
vm.prank(minter);
zoraNFTBase.purchaseWithRecipient{value: paymentAmount}(recipient, purchaseQuantity, "");

for (uint256 i; i < purchaseQuantity; ) {
assertEq(zoraNFTBase.ownerOf(++i), recipient);
}
}

function test_PurchaseWithRecipientAndComment(uint64 salePrice, uint32 purchaseQuantity) public setupZoraNFTBase(purchaseQuantity) {
vm.assume(purchaseQuantity < 100 && purchaseQuantity > 0);
vm.prank(DEFAULT_OWNER_ADDRESS);
zoraNFTBase.setSaleConfiguration({
publicSaleStart: 0,
publicSaleEnd: type(uint64).max,
presaleStart: 0,
presaleEnd: 0,
publicSalePrice: salePrice,
maxSalePurchasePerAddress: purchaseQuantity + 1,
presaleMerkleRoot: bytes32(0)
});

(, uint256 zoraFee) = zoraNFTBase.zoraFeeForAmount(purchaseQuantity);
uint256 paymentAmount = uint256(salePrice) * purchaseQuantity + zoraFee;

address minter = makeAddr("minter");
address recipient = makeAddr("recipient");

vm.deal(minter, paymentAmount);

vm.expectEmit(true, true, true, true);
emit MintComment(
minter,
address(zoraNFTBase),
0,
purchaseQuantity,
"test comment"
);
vm.prank(minter);
zoraNFTBase.purchaseWithRecipient{value: paymentAmount}(recipient, purchaseQuantity, "test comment");
}

function testRevert_PurchaseWithInvalidRecipient(uint64 salePrice, uint32 purchaseQuantity) public setupZoraNFTBase(purchaseQuantity) {
vm.assume(purchaseQuantity < 100 && purchaseQuantity > 0);
vm.prank(DEFAULT_OWNER_ADDRESS);
zoraNFTBase.setSaleConfiguration({
publicSaleStart: 0,
publicSaleEnd: type(uint64).max,
presaleStart: 0,
presaleEnd: 0,
publicSalePrice: salePrice,
maxSalePurchasePerAddress: purchaseQuantity + 1,
presaleMerkleRoot: bytes32(0)
});

(, uint256 zoraFee) = zoraNFTBase.zoraFeeForAmount(purchaseQuantity);
uint256 paymentAmount = uint256(salePrice) * purchaseQuantity + zoraFee;


address minter = makeAddr("minter");
address recipient = address(0);

vm.deal(minter, paymentAmount);

vm.expectRevert(abi.encodeWithSignature("MintToZeroAddress()"));
vm.prank(minter);
zoraNFTBase.purchaseWithRecipient{value: paymentAmount}(recipient, purchaseQuantity, "");
}

function test_UpgradeApproved() public setupZoraNFTBase(10) {
address newImpl = address(
new ERC721Drop(
Expand Down

0 comments on commit 008654a

Please sign in to comment.