@@ -6,56 +6,77 @@ import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
66import "@openzeppelin/contracts/utils/ReentrancyGuard.sol " ;
77import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol " ;
88import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol " ;
9- import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable .sol " ;
9+ import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable .sol " ;
1010
1111contract ClaimableAirdrop is
1212 ReentrancyGuard ,
1313 Initializable ,
1414 PausableUpgradeable ,
15- OwnableUpgradeable
15+ Ownable2StepUpgradeable
1616{
17- address public tokenContractAddress;
18- address public tokenOwnerAddress;
17+ /// @notice Address of the token contract to claim.
18+ address public tokenProxy;
19+
20+ /// @notice Address of the wallet that has the tokens to distribute to the claimants.
21+ address public claimSupplier;
22+
23+ /// @notice Timestamp until which the claimants can claim the tokens.
1924 uint256 public limitTimestampToClaim;
25+
26+ /// @notice Merkle root of the claimants.
2027 bytes32 public claimMerkleRoot;
2128
29+ /// @notice Mapping of the claimants that have claimed the tokens.
30+ /// @dev true if the claimant has claimed the tokens.
2231 mapping (address => bool ) public hasClaimed;
2332
33+ /// @notice Event emitted when a claimant claims the tokens.
2434 event TokenClaimed (address indexed to , uint256 indexed amount );
2535
2636 /// @custom:oz-upgrades-unsafe-allow constructor
2737 constructor () {
2838 _disableInitializers ();
2939 }
3040
41+ /// @notice Initializes the contract.
42+ /// @dev This initializer should be called only once.
43+ /// @param _owner address of the owner of the token.
44+ /// @param _tokenProxy address of the token contract.
45+ /// @param _claimSupplier address of the wallet that has the tokens to distribute to the claimants.
46+ /// @param _limitTimestampToClaim timestamp until which the claimants can claim the tokens.
47+ /// @param _claimMerkleRoot Merkle root of the claimants.
3148 function initialize (
32- address _multisig ,
33- address _tokenContractAddress ,
34- address _tokenOwnerAddress ,
49+ address _owner ,
50+ address _tokenProxy ,
51+ address _claimSupplier ,
3552 uint256 _limitTimestampToClaim ,
3653 bytes32 _claimMerkleRoot
3754 ) public initializer {
38- __Ownable_init (_multisig);
39- __Pausable_init ();
40-
41- require (_multisig != address (0 ), "Invalid multisig address " );
55+ require (_owner != address (0 ), "Invalid owner address " );
4256 require (
43- _tokenContractAddress != address (0 ),
57+ _tokenProxy != address (0 ) && _tokenProxy != address ( this ),
4458 "Invalid token contract address "
4559 );
4660 require (
47- _tokenOwnerAddress != address (0 ),
61+ _claimSupplier != address (0 ) && _claimSupplier != address ( this ),
4862 "Invalid token owner address "
4963 );
5064 require (_limitTimestampToClaim > block .timestamp , "Invalid timestamp " );
5165 require (_claimMerkleRoot != 0 , "Invalid Merkle root " );
5266
53- tokenContractAddress = _tokenContractAddress;
54- tokenOwnerAddress = _tokenOwnerAddress;
67+ __Ownable2Step_init (); // default is msg.sender
68+ _transferOwnership (_owner);
69+ __Pausable_init ();
70+
71+ tokenProxy = _tokenProxy;
72+ claimSupplier = _claimSupplier;
5573 limitTimestampToClaim = _limitTimestampToClaim;
5674 claimMerkleRoot = _claimMerkleRoot;
5775 }
5876
77+ /// @notice Claim the tokens.
78+ /// @param amount amount of tokens to claim.
79+ /// @param merkleProof Merkle proof of the claim.
5980 function claim (
6081 uint256 amount ,
6182 bytes32 [] calldata merkleProof
@@ -77,15 +98,13 @@ contract ClaimableAirdrop is
7798 require (verifies, "Invalid Merkle proof " );
7899
79100 require (
80- IERC20 (tokenContractAddress).allowance (
81- tokenOwnerAddress,
82- address (this )
83- ) >= amount,
101+ IERC20 (tokenProxy).allowance (claimSupplier, address (this )) >=
102+ amount,
84103 "Insufficient token allowance "
85104 );
86105
87- bool success = IERC20 (tokenContractAddress ).transferFrom (
88- tokenOwnerAddress ,
106+ bool success = IERC20 (tokenProxy ).transferFrom (
107+ claimSupplier ,
89108 msg .sender ,
90109 amount
91110 );
@@ -97,11 +116,33 @@ contract ClaimableAirdrop is
97116 emit TokenClaimed (msg .sender , amount);
98117 }
99118
100- function pause () public onlyOwner {
119+ /// @notice Update the Merkle root.
120+ /// @param newRoot new Merkle root.
121+ function updateMerkleRoot (bytes32 newRoot ) external whenPaused onlyOwner {
122+ require (newRoot != 0 && newRoot != claimMerkleRoot, "Invalid root " );
123+ claimMerkleRoot = newRoot;
124+ }
125+
126+ /// @notice Extend the claim period.
127+ /// @param newTimestamp new timestamp until which the claimants can claim the tokens.
128+ function extendClaimPeriod (
129+ uint256 newTimestamp
130+ ) external whenPaused onlyOwner {
131+ require (
132+ newTimestamp > limitTimestampToClaim &&
133+ newTimestamp > block .timestamp ,
134+ "Can only extend from current timestamp "
135+ );
136+ limitTimestampToClaim = newTimestamp;
137+ }
138+
139+ /// @notice Pause the contract.
140+ function pause () public whenNotPaused onlyOwner {
101141 _pause ();
102142 }
103143
104- function unpause () public onlyOwner {
144+ /// @notice Unpause the contract.
145+ function unpause () public whenPaused onlyOwner {
105146 _unpause ();
106147 }
107148}
0 commit comments