Platform: Code4rena
Start Date: 31/08/2023
Pot Size: $55,000 USDC
Total HM: 5
Participants: 30
Period: 6 days
Judge: hickuphh3
Total Solo HM: 2
Id: 282
League: ETH
Rank: 13/30
Findings: 1
Award: $695.61
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: ADM
Also found by: HChang26, rvierdiiev, twicek
695.6101 USDC - $695.61
https://github.com/code-423n4/2023-08-livepeer/blob/main/contracts/bonding/BondingManager.sol#L273 https://github.com/code-423n4/2023-08-livepeer/blob/main/contracts/bonding/BondingManager.sol#L130 https://github.com/code-423n4/2023-08-livepeer/blob/main/contracts/bonding/BondingManager.sol#L1667 https://github.com/code-423n4/2023-08-livepeer/blob/main/contracts/bonding/BondingManager.sol#L1500
withdrawFees()
does not properly update msg.sender
check point.
Let's take a look at withdrawFees()
. autoClaimEarnings()
modifier will claim all available earnings before making withdraw.
function withdrawFees(address payable _recipient, uint256 _amount) external whenSystemNotPaused currentRoundInitialized autoClaimEarnings(msg.sender) { require(_recipient != address(0), "invalid recipient"); uint256 fees = delegators[msg.sender].fees; require(fees >= _amount, "insufficient fees to withdraw"); delegators[msg.sender].fees = fees.sub(_amount); // Tell Minter to transfer fees (ETH) to the address minter().trustedWithdrawETH(_recipient, _amount); emit WithdrawFees(msg.sender, _recipient, _amount); }
modifier autoClaimEarnings(address _delegator) { _autoClaimEarnings(_delegator); _; }
_autoClaimEarnings()
calls updateDelegatorWithEarnings()
, where state changes are made.
function _autoClaimEarnings(address _delegator) internal { uint256 currentRound = roundsManager().currentRound(); uint256 lastClaimRound = delegators[_delegator].lastClaimRound; if (lastClaimRound < currentRound) { updateDelegatorWithEarnings(_delegator, currentRound, lastClaimRound); } }
In updateDelegatorWithEarnings()
, rewards are bonded by default which means increase in del.bondedAmount
yet no check point was created for this state change. This will result in inaccurate voting power.
del.lastClaimRound = _endRound; // Rewards are bonded by default del.bondedAmount = currentBondedAmount; del.fees = currentFees;
Manual Review
function withdrawFees(address payable _recipient, uint256 _amount) external whenSystemNotPaused currentRoundInitialized autoClaimEarnings(msg.sender) + autoCheckpoint(msg.sender) { require(_recipient != address(0), "invalid recipient"); uint256 fees = delegators[msg.sender].fees; require(fees >= _amount, "insufficient fees to withdraw"); delegators[msg.sender].fees = fees.sub(_amount); // Tell Minter to transfer fees (ETH) to the address minter().trustedWithdrawETH(_recipient, _amount); emit WithdrawFees(msg.sender, _recipient, _amount); }
Context
#0 - c4-pre-sort
2023-09-07T11:34:13Z
141345 marked the issue as duplicate of #104
#1 - c4-pre-sort
2023-09-09T10:53:54Z
141345 marked the issue as sufficient quality report
#2 - c4-judge
2023-09-18T02:17:13Z
HickupHH3 marked the issue as satisfactory
#3 - c4-judge
2023-09-18T02:17:58Z
HickupHH3 changed the severity to 2 (Med Risk)