Skip to content

Commit fdab05f

Browse files
authored
feature/whitelist (#29)
* update dependencies & init merkle whitelist * updated openzeppelin version to 4.8.0 & optimized whitelist method * code-style & changed contract name * refactored * fixed code-style * refactored & added methods * refactored * added merkle whitelisted mock * updated versions & dependencies * installed merkletreejs & init test * added ZERO_BYTES32 constant & refactored mock contract & coverage 100% * rm newline * rm newline * added natspec * edited natspec * fixed version
1 parent e14b79f commit fdab05f

File tree

7 files changed

+383
-56
lines changed

7 files changed

+383
-56
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.4;
3+
4+
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
5+
6+
/**
7+
* @notice The Whitelist Access Control module
8+
*
9+
* This is a simple abstract contract that implements whitelisting logic.
10+
*
11+
* The contract is based on a Merkle tree, which allows for the huge whitelists to be cheaply validated courtesy of
12+
* O(log(n)) tree complexity. The whitelist itself is stored in the tree leaves and only the root of the tree is saved on-chain.
13+
*
14+
* To validate the whitelist belonging, the tree leaf (the whitelist element) has to be computed and passed to the
15+
* "root-construction" function together with the corresponding tree branches. The function will then check the
16+
* roots equality. If the roots match, the element belongs to the whitelist.
17+
*
18+
* Note: the branch nodes are sorted numerically.
19+
*/
20+
abstract contract MerkleWhitelisted {
21+
using MerkleProof for bytes32[];
22+
23+
bytes32 private _merkleRoot;
24+
25+
modifier onlyWhitelisted(bytes memory data_, bytes32[] calldata merkleProof_) {
26+
require(
27+
isWhitelisted(keccak256(data_), merkleProof_),
28+
"MerkleWhitelisted: not whitelisted"
29+
);
30+
_;
31+
}
32+
33+
modifier onlyWhitelistedUser(address user_, bytes32[] calldata merkleProof_) {
34+
require(isWhitelistedUser(user_, merkleProof_), "MerkleWhitelisted: not whitelisted");
35+
_;
36+
}
37+
38+
/**
39+
* @notice The function to check if the leaf belongs to the Merkle tree
40+
* @param leaf_ the leaf to be checked
41+
* @param merkleProof_ the path from the leaf to the Merkle tree root
42+
* @return true if the leaf belongs to the Merkle tree, false otherwise
43+
*/
44+
function isWhitelisted(
45+
bytes32 leaf_,
46+
bytes32[] calldata merkleProof_
47+
) public view returns (bool) {
48+
return merkleProof_.verifyCalldata(_merkleRoot, leaf_);
49+
}
50+
51+
/**
52+
* @notice The function to check if the user belongs to the Merkle tree
53+
* @param user_ the user to be checked
54+
* @param merkleProof_ the path from the user to the Merkle tree root
55+
* @return true if the user belongs to the Merkle tree, false otherwise
56+
*/
57+
function isWhitelistedUser(
58+
address user_,
59+
bytes32[] calldata merkleProof_
60+
) public view returns (bool) {
61+
return isWhitelisted(keccak256(abi.encodePacked(user_)), merkleProof_);
62+
}
63+
64+
/**
65+
* @notice The function to get the current Merkle root
66+
* @return the current Merkle root or zero bytes if it has not been set
67+
*/
68+
function getMerkleRoot() public view returns (bytes32) {
69+
return _merkleRoot;
70+
}
71+
72+
/**
73+
* @notice The function that should be called from the child contract to set the Merkle root
74+
* @param merkleRoot_ the Merkle root to be set
75+
*/
76+
function _setMerkleRoot(bytes32 merkleRoot_) internal {
77+
_merkleRoot = merkleRoot_;
78+
}
79+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.4;
3+
4+
import "../../access-control/MerkleWhitelisted.sol";
5+
6+
contract MerkleWhitelistedMock is MerkleWhitelisted {
7+
event WhitelistedUser();
8+
event WhitelistedData();
9+
10+
function onlyWhitelistedMethod(
11+
uint256 amount_,
12+
bytes32[] calldata merkleProof_
13+
) external onlyWhitelisted(_encode(amount_), merkleProof_) {
14+
emit WhitelistedData();
15+
}
16+
17+
function onlyWhitelistedUserMethod(
18+
bytes32[] calldata merkleProof_
19+
) external onlyWhitelistedUser(msg.sender, merkleProof_) {
20+
emit WhitelistedUser();
21+
}
22+
23+
function setMerkleRoot(bytes32 merkleRoot_) external {
24+
_setMerkleRoot(merkleRoot_);
25+
}
26+
27+
function _encode(uint256 amount_) private view returns (bytes memory) {
28+
return abi.encodePacked(amount_, msg.sender);
29+
}
30+
}

contracts/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@dlsl/dev-modules",
3-
"version": "2.0.3",
3+
"version": "2.1.0",
44
"license": "MIT",
55
"author": "Distributed Lab",
66
"description": "Solidity Development Modules by Distributed Lab",
@@ -19,7 +19,7 @@
1919
"!mock/**/*"
2020
],
2121
"dependencies": {
22-
"@openzeppelin/contracts": "4.5.0",
23-
"@openzeppelin/contracts-upgradeable": "4.5.0"
22+
"@openzeppelin/contracts": "4.8.0",
23+
"@openzeppelin/contracts-upgradeable": "4.8.0"
2424
}
2525
}

0 commit comments

Comments
 (0)