Summary
Mismatch in merkle proofs lead to issues
Vulnerability Details
function getAccountData()
external
view
returns (address[] memory, uint256[] memory, uint256[] memory)
{
uint256[] memory reSDLBalances = new uint256[]();
uint256[] memory queuedBalances = new uint256[]();
for (uint256 i = 0; i < reSDLBalances.length; ++i) {
address account = accounts[i];
reSDLBalances[i] = sdlPool.effectiveBalanceOf(account);
queuedBalances[i] = accountQueuedTokens[account];
}
return (accounts, reSDLBalances, queuedBalances);
}
Merkle Tree is constructed where each leaf node is a hash of an account's address, SDL balance, and queued tokens:
Using the returned data, a Merkle Tree is constructed where each leaf node is a hash of an account's address, SDL balance, and queued tokens
leaf = keccak256(abi.encode(account, sdlBalance, queuedBalance))
The constructed Merkle Tree (including all leaves and their order) is stored on IPFS, and its hash (ipfsHash) is recorded on-chain.
Now look at the leaf construction in the function below. There is a difference in the leaf construction and hence the on-chain and off-chain merkle proof will not match.
function claimLSDTokens(
uint256 _amount,
uint256 _sharesAmount,
bytes32[] calldata _merkleProof
) external {
address account = msg.sender;
bytes32 node = keccak256(
bytes.concat(keccak256(abi.encode(account, _amount, _sharesAmount)))
);
if (!MerkleProofUpgradeable.verify(_merkleProof, merkleRoot, node)) revert InvalidProof();
uint256 amountToClaim = _amount - accountClaimed[account];
uint256 sharesAmountToClaim = _sharesAmount - accountSharesClaimed[account];
uint256 amountToClaimWithYield = stakingPool.getStakeByShares(sharesAmountToClaim);
if (amountToClaimWithYield == 0) revert NothingToClaim();
accountClaimed[account] = _amount;
accountSharesClaimed[account] = _sharesAmount;
IERC20Upgradeable(address(stakingPool)).safeTransfer(account, amountToClaimWithYield);
emit ClaimLSDTokens(account, amountToClaim, amountToClaimWithYield);
}
Impact
Users will not be able to claim their tokens
Tools Used
Manual
Recommendations
leaf = keccak256(abi.encode(account, sdlBalance, queuedBalance))