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

Restrict merkle claims to only be used once #126

Merged
merged 1 commit into from
Jan 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/minters/MerkleReserveMinter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ contract MerkleReserveMinter {
/// @param merkleRoot Merkle root for collection
error INVALID_MERKLE_PROOF(address mintTo, bytes32[] merkleProof, bytes32 merkleRoot);

/// @dev Claim has already been used
error CLAIM_ALREADY_USED();

/// ///
/// STRUCTS ///
/// ///
Expand Down Expand Up @@ -96,6 +99,9 @@ contract MerkleReserveMinter {
/// @notice Mapping of DAO token contract to merkle settings
mapping(address => MerkleMinterSettings) public allowedMerkles;

/// @notice Mapping of token contract to used claims
mapping(address => mapping(uint256 => bool)) public usedClaims;

/// ///
/// MODIFIERS ///
/// ///
Expand Down Expand Up @@ -161,6 +167,14 @@ contract MerkleReserveMinter {
revert INVALID_MERKLE_PROOF(claim.mintTo, claim.merkleProof, settings.merkleRoot);
}

// Check if claim has already been used
if (usedClaims[tokenContract][claim.tokenId]) {
revert CLAIM_ALREADY_USED();
}

// Mark claim as used
usedClaims[tokenContract][claim.tokenId] = true;

// Only allowing reserved tokens to be minted for this strategy
IToken(tokenContract).mintFromReserveTo(claim.mintTo, claim.tokenId);
}
Expand Down
41 changes: 41 additions & 0 deletions test/MerkleReserveMinter.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -360,4 +360,45 @@ contract MerkleReserveMinterTest is NounsBuilderTest {
assertEq(pricePerToken, 0);
assertEq(merkleRoot, bytes32(0));
}

function testRevert_CannotReuseClaim() public {
deployAltMock(20);

bytes32 root = bytes32(0x5e0da80989496579de029b8ad2f9c234e8de75f5487035210bfb7676e386af8b);

MerkleReserveMinter.MerkleMinterSettings memory settings = MerkleReserveMinter.MerkleMinterSettings({
mintStart: 0,
mintEnd: uint64(block.timestamp + 1000),
pricePerToken: 0 ether,
merkleRoot: root
});

vm.prank(address(founder));
minter.setMintSettings(address(token), settings);

(uint64 mintStart, uint64 mintEnd, uint64 pricePerToken, bytes32 merkleRoot) = minter.allowedMerkles(address(token));
assertEq(mintStart, settings.mintStart);
assertEq(mintEnd, settings.mintEnd);
assertEq(pricePerToken, settings.pricePerToken);
assertEq(merkleRoot, settings.merkleRoot);

TokenTypesV2.MinterParams memory params = TokenTypesV2.MinterParams({ minter: address(minter), allowed: true });
TokenTypesV2.MinterParams[] memory minters = new TokenTypesV2.MinterParams[](1);
minters[0] = params;
vm.prank(address(founder));
token.updateMinters(minters);

bytes32[] memory proof = new bytes32[](1);
proof[0] = bytes32(0xd77d6d8eeae66a03ce8ecdba82c6a0ce9cff76f7a4a6bc2bdc670680d3714273);

MerkleReserveMinter.MerkleClaim[] memory claims = new MerkleReserveMinter.MerkleClaim[](1);
claims[0] = MerkleReserveMinter.MerkleClaim({ mintTo: claimer1, tokenId: 5, merkleProof: proof });

minter.mintFromReserve(address(token), claims);

assertEq(token.ownerOf(5), claimer1);

vm.expectRevert(abi.encodeWithSignature("CLAIM_ALREADY_USED()"));
minter.mintFromReserve(address(token), claims);
}
}
Loading