Platform: Code4rena
Start Date: 28/06/2022
Pot Size: $25,000 USDC
Total HM: 14
Participants: 50
Period: 4 days
Judge: GalloDaSballo
Total Solo HM: 7
Id: 141
League: ETH
Rank: 7/50
Findings: 4
Award: $1,455.65
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0x52
Also found by: Chom, __141345__, csanuragjain, ladboy233
313.1919 USDC - $313.19
Oracle periodSize = 0 which is as same as not using any oracle. It should be 1800 as expected (30 minutes).
// Capture oracle reading every 30 minutes uint constant periodSize = 0;
You comment said that capture oracle reading every 30 minutes.
But in fact, periodSize = 0 which mean you are updating your oracle every block (TWAP window 1 block) which is as same as not using any oracle.
Diff checker https://www.diffchecker.com/skDZcZJa
periodSize = 1800;
1800 seconds = 30 minutes
// Capture oracle reading every 30 minutes uint256 constant periodSize = 1800;
#0 - GalloDaSballo
2022-08-14T23:42:39Z
Dup of #124
getBorrowRate must return rate per block as defined in compound interest rate model but currently return rate per year.
Defined here: https://github.com/compound-finance/compound-protocol/blob/master/contracts/InterestRateModel.sol
This is definition
/** * @notice Calculates the current borrow interest rate per block * @param cash The total amount of cash the market has * @param borrows The total amount of borrows the market has outstanding * @param reserves The total amount of reserves the market has * @return The borrow rate per block (as a percentage, and scaled by 1e18) */ function getBorrowRate(uint cash, uint borrows, uint reserves) virtual external view returns (uint);
This is implementation
function getBorrowRate(uint cash, uint borrows, uint reserves) external override returns(uint) { updateBaseRate(); return baseRatePerYear; }
Notice that definition require borrow rate per block but implementation return baseRatePerYear
which is rate per year
Manual
return baseRatePerBlock
function getBorrowRate(uint cash, uint borrows, uint reserves) external override returns(uint) { updateBaseRate(); return baseRatePerBlock; }
#0 - nivasan1
2022-07-04T19:13:00Z
duplicate of #38
#1 - GalloDaSballo
2022-08-16T16:55:22Z
Dup of #38
🌟 Selected for report: zzzitron
Also found by: 0v3rf10w, 0x1f8b, 0x29A, AlleyCat, Bnke0x0, Chom, Funen, JC, Lambda, Limbooo, Meera, Picodes, Sm4rty, TerrierLover, TomJ, __141345__, asutorufos, aysha, c3phas, cccz, defsec, fatherOfBlocks, grGred, hake, ignacio, ladboy233, mrpathfindr, oyc_109, rfa, sach1r0, samruna, slywaters, ynnad
46.6054 USDC - $46.61
Your code is not formatted properly, you should install and enforce prettier on all your contract files.
// This is an evil token. Whenever an A -> B transfer is called, half of the amount goes to B // and half to a predefined C contract ProposalStore { ... }
ProposalStore is not an evil token!
It's not a good idea to have debugging code going to the production.
import "hardhat/console.sol";
In these files:
It's not a good idea to have debugging code going to the production.
console.log("tokenIn: ", tokenIn);
#0 - GalloDaSballo
2022-08-13T22:27:35Z
R
NC
R
Neat, would recommend using more professional language for the report
2R 1NC
🌟 Selected for report: 0x1f8b
Also found by: 0x29A, 0xArshia, 0xKitsune, Bnke0x0, Chom, Fitraldys, Funen, JC, Lambda, Meera, Noah3o6, Picodes, RedOneN, Rohan16, Sm4rty, TerrierLover, TomJ, Tomio, Waze, ajtra, c3phas, cRat1st0s, defsec, durianSausage, fatherOfBlocks, grGred, hake, ladboy233, m_Rassska, mrpathfindr, oyc_109, rfa, ynnad
21.8032 USDC - $21.80
Currently, you are using this version
function sqrt(uint y) internal pure returns (uint z) { if (y > 3) { z = y; uint x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } }
But there is a more optimized version in PRBMath library
https://github.com/paulrberg/prb-math
/// @notice Calculates the square root of x, rounding down. /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// @param x The uint256 number for which to calculate the square root. /// @return result The result as an uint256. function sqrt(uint256 x) internal pure returns (uint256 result) { if (x == 0) { return 0; } // Calculate the square root of the perfect square of a power of two that is the closest to x. uint256 xAux = uint256(x); result = 1; if (xAux >= 0x100000000000000000000000000000000) { xAux >>= 128; result <<= 64; } if (xAux >= 0x10000000000000000) { xAux >>= 64; result <<= 32; } if (xAux >= 0x100000000) { xAux >>= 32; result <<= 16; } if (xAux >= 0x10000) { xAux >>= 16; result <<= 8; } if (xAux >= 0x100) { xAux >>= 8; result <<= 4; } if (xAux >= 0x10) { xAux >>= 4; result <<= 2; } if (xAux >= 0x8) { result <<= 1; } // The operations can never overflow because the result is max 2^127 when it enters this block. unchecked { result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; // Seven iterations should be enough uint256 roundedDownResult = x / result; return result >= roundedDownResult ? roundedDownResult : result; } }
This reduce gas cost as show here https://forum.openzeppelin.com/t/a-collection-of-gas-optimisation-tricks/19966/5
Solidity 0.8.4 introduced custom errors. They are more gas efficient than revert strings, when it comes to deployment cost as well as runtime cost when the revert condition is met. Use custom errors instead of revert strings for gas savings.
Any require statement in your code can be replaced with custom error for example,
require(msg.sender == admin, "CErc20::sweepToken: only admin can sweep tokens");
Can be replaced with
// declare error before contract declaration error OnlyAdmin(); if (msg.sender != admin) revert OnlyAdmin();
#0 - GalloDaSballo
2022-08-14T20:42:46Z
Less than 100 gas saved