-
Notifications
You must be signed in to change notification settings - Fork 2
/
AirdropClaimMerkle.ERC1155.sol
105 lines (85 loc) · 4.74 KB
/
AirdropClaimMerkle.ERC1155.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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
// Solady
import {ERC1155} from "@solady/tokens/ERC1155.sol";
import {MerkleProofLib} from "@solady/utils/MerkleProofLib.sol";
import {Ownable} from "@solady/auth/Ownable.sol";
/// @title AirdropClaimMerkleERC1155
/// @notice ERC1155 claimable with Merkle tree
/// @dev Just an example - not audited
contract AirdropClaimMerkleERC1155 is Ownable {
ERC1155 public token;
/* -------------------------------------------------------------------------- */
/* ERRORS */
/* -------------------------------------------------------------------------- */
/// @dev The account has already claimed their tokens
error AirdropClaimMerkle_AlreadyClaimed();
/// @dev The account is not part of the merkle tree
error AirdropClaimMerkle_NotInMerkle();
/* -------------------------------------------------------------------------- */
/* EVENTS */
/* -------------------------------------------------------------------------- */
/// @dev Emitted after a successful claim
/// @param recipient of the ERC1155 tokens
/// @param tokenId of the ERC1155 token claimed
/// @param amount of tokens claimed
event Claimed(address indexed recipient, uint256 tokenId, uint256 amount);
/* -------------------------------------------------------------------------- */
/* STORAGE */
/* -------------------------------------------------------------------------- */
/* -------------------------------- IMMUTABLE ------------------------------- */
/// @dev ERC1155-claimee inclusion root
bytes32 public immutable merkleRoot;
/* ---------------------------------- STATE --------------------------------- */
/// @dev Whether account has claimed their tokens already
mapping(address account => bool claimed) public hasClaimed;
/* -------------------------------------------------------------------------- */
/* CONSTRUCTOR */
/* -------------------------------------------------------------------------- */
/// @dev Initialize contract with token and merkle root
/// @param _token to be claimed (ERC1155 compatible)
/// @param _merkleRoot inclusion root for claimees
/// Note: Sets owner to deployer
constructor(ERC1155 _token, bytes32 _merkleRoot) {
token = _token;
merkleRoot = _merkleRoot;
_initializeOwner(msg.sender);
}
/* -------------------------------------------------------------------------- */
/* FUNCTIONS */
/* -------------------------------------------------------------------------- */
/// @dev Claim tokens share as an account part of the merkle tree
/// @param _recipient address of claimee that will receive the tokens
/// @param _tokenId of the token to claim
/// @param _amount of tokens to claim
/// @param _proof merkle proof to prove the 3 above parameters are part of the merkle tree
/// Note: Uses `verifyCalldata` from `MerkleProofLib` as it is cheaper
function claimERC1155(address _recipient, uint256 _tokenId, uint256 _amount, bytes32[] calldata _proof) external {
// Throw if address has already claimed tokens
if (hasClaimed[_recipient]) revert AirdropClaimMerkle_AlreadyClaimed();
// Generate leaf
bytes32 leaf = keccak256(abi.encodePacked(_recipient, _tokenId, _amount));
// Verify leaf is part of merkle tree given proof
bool isValidLeaf = MerkleProofLib.verifyCalldata(_proof, merkleRoot, leaf);
if (!isValidLeaf) revert AirdropClaimMerkle_NotInMerkle();
// Mark account as claimed
hasClaimed[_recipient] = true;
// Transfer tokens to recipient
token.safeTransferFrom(address(this), _recipient, _tokenId, _amount, "");
// Emit claim event
emit Claimed(_recipient, _tokenId, _amount);
}
/* -------------------------------------------------------------------------- */
/* ERC1155 */
/* -------------------------------------------------------------------------- */
function onERC1155Received(address, address, uint256, uint256, bytes calldata) external pure returns (bytes4) {
return this.onERC1155Received.selector;
}
function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata)
external
pure
returns (bytes4)
{
return this.onERC1155BatchReceived.selector;
}
}