Skip to content

Commit 8fff206

Browse files
committed
Simplify root locking mechanism
1 parent b36afdb commit 8fff206

File tree

2 files changed

+20
-27
lines changed

2 files changed

+20
-27
lines changed

src/MultiRootVesting.sol

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ interface IERC721 {
1515
/// @author Rookmate (@0xRookmate)
1616
contract MultiRootVesting is Ownable {
1717
address immutable vestingToken;
18+
bool public rootsLocked;
1819

1920
enum Collection {
2021
Cat, // NFT Collection
@@ -31,11 +32,6 @@ contract MultiRootVesting is Ownable {
3132
Liquidity
3233
}
3334

34-
struct MerkleRootData {
35-
bytes32 root;
36-
bool locked;
37-
}
38-
3935
struct Vesting {
4036
uint256 totalClaim;
4137
uint256 claimed;
@@ -47,8 +43,8 @@ contract MultiRootVesting is Ownable {
4743
Collection collection;
4844
}
4945

50-
// Mapping from Collection to its merkle root data
51-
mapping(Collection => MerkleRootData) public collectionRoots;
46+
// Mapping from Collection to its merkle root
47+
mapping(Collection => bytes32) public collectionRoots;
5248
// Mapping from Collection to its NFT address
5349
mapping(Collection => address) public nftCollections;
5450
// Mapping from vesting hash to vesting data
@@ -65,7 +61,7 @@ contract MultiRootVesting is Ownable {
6561
error CollectionNotConfigured();
6662

6763
event MerkleRootUpdated(Collection indexed collection, bytes32 newRoot);
68-
event CollectionRootLocked(Collection indexed collection);
64+
event RootsLocked();
6965
event VestingClaimed(bytes32 indexed vestingId, Collection indexed collection, address recipient, uint256 amount);
7066

7167
constructor(
@@ -89,24 +85,23 @@ contract MultiRootVesting is Ownable {
8985

9086
// Set up merkle roots
9187
for (uint256 i = 0; i < collections.length; ++i) {
92-
collectionRoots[collections[i]].root = roots[i];
88+
collectionRoots[collections[i]] = roots[i];
9389
}
9490
}
9591

9692
/// @notice Update the merkle root for a specific collection (only if not locked)
9793
/// @param collection The collection to update
9894
/// @param newRoot The new merkle root
9995
function updateMerkleRoot(Collection collection, bytes32 newRoot) external onlyOwner {
100-
if (collectionRoots[collection].locked) revert RootLocked();
101-
collectionRoots[collection].root = newRoot;
96+
if (rootsLocked) revert RootLocked();
97+
collectionRoots[collection] = newRoot;
10298
emit MerkleRootUpdated(collection, newRoot);
10399
}
104100

105-
/// @notice Lock the merkle root for a specific collection permanently
106-
/// @param collection The collection to lock
107-
function lockRoot(Collection collection) external onlyOwner {
108-
collectionRoots[collection].locked = true;
109-
emit CollectionRootLocked(collection);
101+
/// @notice Lock all merkle roots permanently
102+
function lockRoots() external onlyOwner {
103+
rootsLocked = true;
104+
emit RootsLocked();
110105
}
111106

112107
/// @notice Claim vested tokens with merkle proof
@@ -133,7 +128,7 @@ contract MultiRootVesting is Ownable {
133128
bytes32 leaf = keccak256(abi.encodePacked(collection, tokenId, recipient, totalClaim, start, end));
134129

135130
// Verify merkle proof against collection root
136-
if (!MerkleProofLib.verifyCalldata(proof, collectionRoots[collection].root, leaf)) {
131+
if (!MerkleProofLib.verifyCalldata(proof, collectionRoots[collection], leaf)) {
137132
revert InvalidMerkleProof();
138133
}
139134

@@ -184,7 +179,7 @@ contract MultiRootVesting is Ownable {
184179
uint256 start = vesting.start;
185180
uint256 current = block.timestamp;
186181

187-
// Early return if vesting hasn't started
182+
// Early return if vesting hasn't started or if it hasn't passed a day since last claim
188183
if (current < start || current < (vesting.lastClaim + 1 days)) {
189184
return (vesting, 0);
190185
}

test/MultiRootVesting.t.sol

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,21 @@ contract MultiRootVestingTest is MultiRootVestingTestBase {
2020

2121
function testInitialSetup() public view {
2222
for (uint256 i = 0; i < collections.length; i++) {
23-
(bytes32 root, bool locked) = vestContract.collectionRoots(collections[i]);
23+
bytes32 root = vestContract.collectionRoots(collections[i]);
2424
assert(root == roots[i]);
25-
assert(!locked);
2625
}
2726
}
2827

29-
function testLockRoot() public {
28+
function testLockRoots() public {
3029
vm.prank(owner);
31-
vestContract.lockRoot(MultiRootVesting.Collection.Cat);
30+
vestContract.lockRoots();
3231

33-
(, bool locked) = vestContract.collectionRoots(MultiRootVesting.Collection.Cat);
34-
assertTrue(locked);
32+
assertTrue(vestContract.rootsLocked());
3533
}
3634

37-
function testCannotUpdateLockedRoot() public {
35+
function testCannotUpdateRootAfterLock() public {
3836
vm.startPrank(owner);
39-
vestContract.lockRoot(MultiRootVesting.Collection.Cat);
37+
vestContract.lockRoots();
4038

4139
vm.expectRevert(abi.encodeWithSignature("RootLocked()"));
4240
vestContract.updateMerkleRoot(MultiRootVesting.Collection.Cat, bytes32(0));
@@ -50,7 +48,7 @@ contract MultiRootVestingTest is MultiRootVestingTestBase {
5048
vm.prank(owner);
5149
vestContract.updateMerkleRoot(MultiRootVesting.Collection.Cat, newRoot);
5250

53-
(bytes32 root,) = vestContract.collectionRoots(MultiRootVesting.Collection.Cat);
51+
bytes32 root = vestContract.collectionRoots(MultiRootVesting.Collection.Cat);
5452
assertEq(root, newRoot);
5553
}
5654

0 commit comments

Comments
 (0)