Summary
Link: https://github.com/Cyfrin/2024-09-stakelink/blob/f5824f9ad67058b24a2c08494e51ddd7efdbb90b/contracts/core/lstRewardsSplitter/LSTRewardsSplitter.sol#L141
The is no control on the addFee function that would prevent the contract owner from accidentially adding the same fee receiver several times.
Vulnerability Details
Proof of Concept:
Add the following test to lst-rewards-splitter.test.ts:
it.only('the same feeReceiver can be added several times to to a RewardsSplitter', async () => {
const { accounts, controller, token, splitter0 } = await loadFixture(deployFixture)
await token.transferAndCall(controller.target, toEther(100), '0x')
await token.transfer(splitter0.target, toEther(100))
await splitter0.addFee(accounts[6], 2000)
await splitter0.splitRewards()
console.log("Fees: ", await splitter0.getFees())
assert.equal(fromEther(await splitter0.principalDeposits()), 150)
assert.equal(fromEther(await token.balanceOf(splitter0.target)), 150)
assert.equal(fromEther(await token.balanceOf(accounts[5])), 10)
assert.equal(fromEther(await token.balanceOf(accounts[6])), 40)
})
Impact
This would cause an indirect loss of funds, because the feeReceiver address (that got added more than once to the fees array) would receive more funds that it is entitled to.
Tools Used
Manual Review
Recommendations
Modify the addFee function in the following way:
error FeeReceiverAlreadyExists();
function addFee(address _receiver, uint256 _feeBasisPoints) external onlyOwner {
for (uint256 i = 0; i < fees.length; ++i) {
if (fees[i].receiver == _receiver) revert FeeReceiverAlreadyExists();
}
fees.push(Fee(_receiver, _feeBasisPoints));
if (_totalFeesBasisPoints() > 10000) revert FeesExceedLimit();
}