Platform: Code4rena
Start Date: 07/09/2022
Pot Size: $20,000 CANTO
Total HM: 7
Participants: 65
Period: 1 day
Judge: 0xean
Total Solo HM: 3
Id: 159
League: ETH
Rank: 55/65
Findings: 1
Award: $39.22
🌟 Selected for report: 1
🚀 Solo Findings: 0
🌟 Selected for report: lukris02
Also found by: 0x040, 0x1f8b, 0x52, 0xA5DF, 0xNazgul, 0xSky, Bnke0x0, Bronicle, CertoraInc, Chom, CodingNameKiki, Deivitto, Diraco, Dravee, EthLedger, IgnacioB, JC, JansenC, Jeiwan, R2, RaymondFam, ReyAdmirado, Rolezn, SinceJuly, TomJ, Tomo, Yiko, a12jmx, ajtra, ak1, codexploder, cryptphi, csanuragjain, erictee, fatherOfBlocks, gogo, hake, hansfriese, hickuphh3, ignacio, ontofractal, oyc_109, p_crypt0, pashov, peritoflores, rajatbeladiya, rbserver, rokinot, rvierdiiev, tnevler
242.8216 CANTO - $39.22
During the audit, 5 low and 7 non-critical issues were found.
â„– | Title | Risk Rating | Instance Count |
---|---|---|---|
L-1 | Check zero denominator | Low | 2 |
L-2 | Missing check for input variables | Low | 2 |
L-3 | Large number of observations may cause out-of-gas error | Low | 2 |
L-4 | Incorrect comment | Low | 1 |
L-5 | Misleading comment | Low | 1 |
NC-1 | Order of Functions | Non-Critical | 5 |
NC-2 | Maximum line length exceeded | Non-Critical | 2+ |
NC-3 | Constants may be used | Non-Critical | 18 |
NC-4 | Inconsistent comment spacing and location | Non-Critical | 1 |
NC-5 | Loop parameter may be changed for clarity | Non-Critical | 2 |
NC-6 | Functions without comments | Non-Critical | 4 |
NC-7 | Require statement may be placed before allocating memory for arrays | Non-Critical | 2 |
If the input parameter is equal to zero, this will cause the function call failure on division.
return (reserveAverageCumulative0 / granularity, reserveAverageCumulative1 / granularity);
return (totalSupplyCumulativeAvg / granularity);
Add the check to prevent function call failure.
If input variable points
== 0, function will return empty array.
More critical, if input variable window
== 0, function will return array with default values, which may lead to further incorrect calculations.
Add require statement or custom error - points!= 0 && window!= 0
.
Loops that do not have a fixed number of iterations, for example, loops that depend on storage values, have to be used carefully: Due to the block gas limit, transactions can only consume a certain amount of gas. Either explicitly or just due to normal operation, the number of iterations in a loop can grow beyond the block gas limit, which can cause the complete contract to be stalled at a certain point.
for(; i < lastIndex; i+=window) {
(function sampleReserves)for(; i < lastIndex; i+=window) {
(function sampleSupply)Restrict the maximum number of sample observations (points
).
// note in terms of note will always be 1
Probably the comment should be like this "price in terms of note will always be 1 ".
The comment is misleading, and there is an extra comma and an empty comment line.
for (uint i = 0; i < _reserves0.length; ++i) { reserveAverageCumulative0 += _reserves0[i]; //normalize the reserves for TWAP LP Oracle pricing, reserveAverageCumulative1 += _reserves1[i]; // }
Change or delete comment.
Some internal functions are between public, some external functions are between public, and some public functions are between external.
According to Style Guide, ordering helps readers identify which functions they can call and to find the constructor and fallback definitions easier.
Functions should be grouped according to their visibility and ordered:
Some lines of code are too long.
observations.push(Observation(blockTimestamp, reserve0CumulativeLast, reserve1CumulativeLast, totalSupplyCumulativeLast));
_totalSupply[index] = (observations[nextIndex].totalSupplyCumulative - observations[i].totalSupplyCumulative) / timeElapsed;
According to Style Guide, maximum suggested line length is 120 characters.
Make the lines shorter.
Constants may be used instead of literal values.
uint[] memory supply = pair.sampleSupply(8, 1);
prices = pair.sample(token1, decimals, 8, 1);
(unitReserves, assetReserves) = pair.sampleReserves(8, 1);
prices = pair.sample(token0, decimals, 8, 1);
(assetReserves, unitReserves) = pair.sampleReserves(8, 1);
prices = pair.sample(token1, decimals, 8, 1);
(unitReserves, assetReserves) = pair.sampleReserves(8, 1);
prices = pair.sample(token0, decimals, 8, 1);
(assetReserves, unitReserves) = pair.sampleReserves(8, 1);
for(uint i; i < 8; ++i) {
return 1e18; // Stable coins supported by the lending market are instantiated by governance and their price will always be 1 note
return 1e18 * 1e18 / (10 ** decimals); //Scale Price as a mantissa to maintain precision in comptroller
return 1e18 * 1e18 / (10 ** decimals); //Scale Price as a mantissa to maintain precision in comptroller
return getPriceCanto(underlying) * getPriceNote(address(wcanto), false) / 1e18;
LpPricesCumulative += (token0TVL + token1TVL) * 1e18 / supply[i];
return LpPrice * getPriceNote(address(wcanto), false) / 1e18; // return the price in terms of Note
return price * 1e18 / decimals; //return the scaled price
return price * 1e18 / decimals; // divide by decimals now to maintain precision
Define constant variables for repeated values (8 and 1e18).
Some comments are above the line of code and some next to it. Some comments are indented between // and the comment text, some are not.
{ //manual scope to pop symbol off of stack string memory symbol = ctoken.symbol();
underlying = address(ICErc20(address(ctoken)).underlying()); // We are getting the price for a CErc20 lending market
//set price statically to 1 when the Comptroller is retrieving Price if (compareStrings(symbol, "cNOTE")) { // note in terms of note will always be 1 return 1e18; // Stable coins supported by the lending market are instantiated by governance and their price will always be 1 note
return 1e18 * 1e18 / (10 ** decimals); //Scale Price as a mantissa to maintain precision in comptroller
Use consistent comment spacing and location.
In loop are used _reserves0.length
. It is equal to input variable granularity
. It can be clearer and more consistent if you use an input variable in the loop.
function reserves(uint granularity) external view returns(uint, uint) { (uint[] memory _reserves0, uint[] memory _reserves1)= sampleReserves(granularity, 1); uint reserveAverageCumulative0; uint reserveAverageCumulative1; for (uint i = 0; i < _reserves0.length; ++i) {
function totalSupplyAvg(uint granularity) external view returns(uint) { uint[] memory _totalSupplyAvg = sampleSupply(granularity, 1); uint totalSupplyCumulativeAvg; for (uint i = 0; i < _totalSupplyAvg.length; ++i) {
function reserves(uint granularity) external view returns(uint, uint) { (uint[] memory _reserves0, uint[] memory _reserves1)= sampleReserves(granularity, 1); uint reserveAverageCumulative0; uint reserveAverageCumulative1; //HERE for (uint i = 0; i < granularity; ++i) {
function totalSupplyAvg(uint granularity) external view returns(uint) { uint[] memory _totalSupplyAvg = sampleSupply(granularity, 1); uint totalSupplyCumulativeAvg; //HERE for (uint i = 0; i < granularity; ++i) {
Some functions do not have comments describing them.
function reserves(uint granularity)
function sampleReserves(uint points, uint window)
function totalSupplyAvg(uint granularity)
function sampleSupply(uint points, uint window)
Add comments.
uint[] memory _reserves0 = new uint[](points); uint[] memory _reserves1 = new uint[](points); uint lastIndex = observations.length-1; require(lastIndex >= points * window, "PAIR::NOT READY FOR PRICING");
uint[] memory _totalSupply = new uint[](points); uint lastIndex = observations.length-1; require(lastIndex >= points * window, "PAIR::NOT READY FOR PRICING");
uint lastIndex = observations.length-1; require(lastIndex >= points * window, "PAIR::NOT READY FOR PRICING"); uint[] memory _reserves0 = new uint[](points); uint[] memory _reserves1 = new uint[](points);
uint lastIndex = observations.length-1; require(lastIndex >= points * window, "PAIR::NOT READY FOR PRICING"); uint[] memory _totalSupply = new uint[](points);
#0 - 0xean
2022-10-13T14:35:29Z
L-1 - non critical L-2 - non critical L-3 - Low L-4 - Low L-5 - Low
Agree with all the rest of the classifications here.