generated from transmissions11/foundry-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ERC721MerkleDrop.sol
48 lines (41 loc) · 1.57 KB
/
ERC721MerkleDrop.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import {ERC721} from "solmate/tokens/ERC721.sol";
error InvalidProof();
abstract contract ERC721MerkleDrop is ERC721 {
/// @notice The merkle root, set during contract creation
bytes32 public immutable root;
constructor(string memory name, string memory symbol, bytes32 _root) ERC721(name, symbol) {
root = _root;
}
/// @notice redeem an ERC721 token
/// @param account - account thats part of the merkle tree
/// @param tokenId - the token id being redeemed
/// @param proof - generated merkle proof
/// NOTE: You'll need to use ffi to generate proofs inside a solidity environment
function redeem(address account, uint256 tokenId, bytes32[] calldata proof) external {
bytes32 proofElement;
bytes32 computedHash = keccak256(abi.encodePacked(tokenId, account));
uint256 proofLength = proof.length;
unchecked {
for (uint256 i = 0; i < proofLength; i += 1) {
proofElement = proof[i];
assembly {
let a := 0x20
let b := 0x00
if lt(proofElement, computedHash) {
a := 0x00
b := 0x20
}
mstore(a, computedHash)
mstore(b, proofElement)
computedHash := keccak256(0x00, 0x40)
}
}
}
if (computedHash != root) {
revert InvalidProof();
}
_mint(account, tokenId);
}
}