Platform: Code4rena
Start Date: 20/01/2022
Pot Size: $80,000 USDC
Total HM: 5
Participants: 37
Period: 7 days
Judge: Jack the Pug
Total Solo HM: 1
Id: 76
League: ETH
Rank: 8/37
Findings: 2
Award: $3,128.52
π Selected for report: 1
π Solo Findings: 0
π Selected for report: pauliax
Also found by: cccz, sirhashalot
sirhashalot
The OpenZeppelin SafeERC20 safeApprove()
function has been deprecated, as seen in the comments of the OpenZeppelin code. Using this deprecated function can lead to unintended reverts and potentially the locking of funds. A deeper discussion on the deprecation of this function is in OZ issue #2219.
The deprecated function is found in:
As suggested by the OpenZeppelin comment, replace safeApprove()
with safeIncreaseAllowance()
or safeDecreaseAllowance()
.
TOKEN.safeIncreaseAllowance(address(UMA), _amount)
TOKEN.safeDecreaseAllowance(address(UMA), 0)
want.safeIncreaseAllowance(address(lp), type(uint256).max)
#0 - CloudEllie
2022-02-21T19:25:15Z
Duplicate of #11
#1 - jack-the-pug
2022-03-26T14:15:13Z
Dup #269
π Selected for report: Afanasyevich
Also found by: sirhashalot, wuwe1, ye0lde
36.1718 USDC - $36.17
sirhashalot
The _isCleanupState()
function is only called once in SherlockClaimManager.sol. This function is short and it can save gas to embed the function's logic inline.
function _isCleanupState(State _oldState) internal pure returns (bool) { if (_oldState == State.SpccDenied) return true; if (_oldState == State.SpccPending) return true; return false; } if (_isCleanupState(_oldState) == false) revert InvalidState();
Proposed alternative removing the _isCleanupState()
function with inline logic.
if (_oldState != State.SpccDenied && _oldState != State.SpccPending) revert InvalidState();
See code above. Replace the _isCleanupState()
function call with the function's logic if gas savings is a priority.
#0 - jack-the-pug
2022-03-28T02:21:44Z
Dup #130
π Selected for report: sirhashalot
2434.9196 USDC - $2,434.92
sirhashalot
The Sherlock protocol allows agents to make a claim against previous higher coverage amounts if the coverage amount has been lowered. This feature fails to work as expected if the agent makes more than one call to protocolUpdate()
lowering the coverage amount.
The SherlockProtocolManager.sol contract has the following comments describing the previousCoverage mapping:
// Previous amount of coverage for a protocol // Previous is also tracked in case a protocol lowers their coverage amount but still needs to make a claim on the old, higher amount mapping(bytes32 => uint256) internal previousCoverage;
This shows the protocol needs to track historic coverage values because an agent can still make claims against the previous values. But the protocol is currently only able to track one previous coverage value. This means that if an agent calls the protocolUpdate()
function twice, lowering their coverage value both times, they would be unable to make a claim for their original higher coverage amount.
The previousCoverage value gets set in the protocolUpdate function. It is later returned in the coverageAmounts function which is used in the startClaim function. The startClaim function is unable to retrieve coverage amounts beyond the current and previous values, even though the protocol seeking a claim may have been covered under a higher coverage amount at the time the agent is requesting the claim for.
The most accurate solution would be to use a dynamic array to track all previous coverage values, which would require additional code to loop through the previous coverage values to find the maximum. An inelegant hack is that any time the protocolUpdate()
function is called by the owner (with onlyOwner modifier privilege) and the previousCoverage value that will be erased should remain in the previousCoverage, a temporary intermediate call to protocolUpdate()
can be done to assign the higher previousCoverage value to the currentCoverage value temporarily. Then the actual currentCoverage value is assigned and the old previousCoverage value can be pushed back to the prevousCoverage variable. This inelegant hack would not require a code change, but would rely on off-chain processes to work properly and therefore should be clearly documented if used.
#0 - Evert0x
2022-02-09T17:34:14Z
Low risk
I agree, the protocol is not guaranteed that it is able to claim for the old coverage for a significant amount of time. The way we are thinking about mitigating this is putting the protocolUpdate()
behind a timelock, even though this still allows 2 subsequent calls. At least the protocol is able to see the change coming because of the timelock.
In this timelock contract we can even program that the protocol can only be updated every x days, to mitigate it even further.