Platform: Code4rena
Start Date: 27/01/2022
Pot Size: $75,000 USDC
Total HM: 10
Participants: 26
Period: 7 days
Judge: pauliax
Total Solo HM: 5
Id: 81
League: ETH
Rank: 11/26
Findings: 4
Award: $849.08
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: cmichel
Also found by: 0x1f8b, TomFrenchBlockchain, UncleGrandpa925, WatchPug, defsec, leastwood, pauliax, sirhashalot
defsec
The contract uses Chainlink’s deprecated API latestAnswer(). Such functions might suddenly stop working if Chainlink stopped supporting deprecated APIs.
Impact: Deprecated API stops working. Prices cannot be obtained. Protocol stops and contracts have to be redeployed.
See similar Low-severity finding L11 from OpenZeppelin's Audit of Opyn Gamma Protocol: https://blog.openzeppelin.com/opyn-gamma-protocol-audit/
This was a Medium-severity finding even in the previous version of WildCredit contest as well: code-423n4/2021-07-wildcredit-findings#75 where it was reported that "latestAnswer method will return the last value, but you won’t be able to check if the data is fresh. On the other hand, calling the method latestRoundData allow you to run some extra validations”
https://github.com/code-423n4/2022-01-notional/blob/main/contracts/utils/EIP1271Wallet.sol#L176
See https://docs.chain.link/docs/deprecated-aggregatorinterface-api-reference/#latestanswer.
Code Review
Consider to add checks on the return data with proper revert messages if the price is stale or the round is incomplete, for example:
(uint80 roundID, int256 price, , uint256 timeStamp, uint80 answeredInRound) = ETH_CHAINLINK.latestRoundData(); require(price > 0, "Chainlink price <= 0"); require(answeredInRound >= roundID, "..."); require(timeStamp != 0, "...");
#0 - jeffywu
2022-02-06T15:10:25Z
Duplicate #178
#1 - pauliax
2022-02-12T12:15:48Z
A duplicate of #197
🌟 Selected for report: TomFrenchBlockchain
654.3157 USDC - $654.32
defsec
The setCoolDownTime function does not have any upper or lower bounds. Values that are too large will lead to reversions in several critical functions. User funds will be locked forever.
https://github.com/code-423n4/2022-01-notional/blob/main/contracts/sNOTE.sol#L95
function redeem(uint256 sNOTEAmount) external nonReentrant { AccountCoolDown memory coolDown = accountCoolDown[msg.sender]; require(sNOTEAmount <= balanceOf(msg.sender), "Insufficient balance"); require( coolDown.redeemWindowBegin != 0 && coolDown.redeemWindowBegin < block.timestamp && block.timestamp < coolDown.redeemWindowEnd, "Not in Redemption Window" ); uint256 bptToRedeem = getPoolTokenShare(sNOTEAmount); _burn(msg.sender, bptToRedeem); BALANCER_POOL_TOKEN.safeTransfer(msg.sender, bptToRedeem); }
Code Review
Ensure that coolDownPeriod has minimum/maximum bound.
#0 - pauliax
2022-02-14T14:45:33Z
#40
23.0433 USDC - $23.04
defsec
++i is more gas efficient than i++ in loops forwarding.
https://github.com/code-423n4/2022-01-notional/blob/main/contracts/TreasuryAction.sol#L157
Code Review
It is recommend to use unchecked{++i} and change i declaration to uint256.
#0 - jeffywu
2022-02-06T15:00:31Z
Duplicate #228
#1 - pauliax
2022-02-13T10:36:09Z
#228