Platform: Code4rena
Start Date: 03/07/2023
Pot Size: $40,000 USDC
Total HM: 14
Participants: 74
Period: 7 days
Judge: alcueca
Total Solo HM: 9
Id: 259
League: ETH
Rank: 4/74
Findings: 3
Award: $2,177.78
π Selected for report: 1
π Solo Findings: 1
π Selected for report: erebus
2152.3705 USDC - $2,152.37
Useless modifier in consructor here (even the constructor is empty, just why the modifier there, it makes no sense)
Bad assumptions to calculate the number of block passed here. BLOCK_TIME
is an immutable variable which is passed as a parameter to the constructor. However, with future updates to the Ethereum protocol (IDK, reth or other validation algorithm) which could reduce that number would mean that functions dependant on that to work incorrectly like readInstantaneousReserves or _readCumulativeReserves. Do not assume the block rate to remain constant in the future or implement some function that modifies the BLOCK_TIME
every T seconds/minutes/whatever
#0 - 141345
2023-07-13T11:35:56Z
#1 - c4-judge
2023-08-04T20:56:09Z
alcueca marked the issue as grade-a
#2 - c4-judge
2023-08-05T21:44:07Z
alcueca changed the severity to 2 (Med Risk)
#3 - c4-judge
2023-08-05T21:44:08Z
alcueca changed the severity to 2 (Med Risk)
#4 - c4-judge
2023-08-05T21:44:26Z
alcueca marked the issue as satisfactory
#5 - c4-sponsor
2023-09-28T12:15:18Z
publiuss (sponsor) acknowledged
#6 - publiuss
2023-09-28T12:18:21Z
First QA item is acknowledged. The modifier is there to initialize the ReentrancyGuard
contract. Imo, its cleaner to have an empty constructor than to have no constructor and have the user realize that it uses the ReentrancyGuard
modifier by defualt. This item is a duplicate of other QA reports.
Second QA item is a duplicate of: https://github.com/code-423n4/2023-07-basin-findings/issues/176. See comment on issue for remediation status.
π Selected for report: 0xprinc
Also found by: 0x11singh99, 0xAnah, 0xWaitress, 0xkazim, 2997ms, 33audits, 404Notfound, 8olidity, CRIMSON-RAT-REACH, CyberPunks, DanielWang888, Deekshith99, Eeyore, Eurovickk, Inspecktor, JGcarv, John, Jorgect, Kaysoft, LosPollosHermanos, MohammedRizwan, Qeew, QiuhaoLi, Rolezn, TheSavageTeddy, Topmark, Trust, Udsen, a3yip6, alexzoid, bigtone, codegpt, erebus, fatherOfBlocks, ginlee, glcanvas, hunter_w3b, josephdara, kaveyjoe, kutugu, mahdirostami, max10afternoon, oakcobalt, peanuts, pfapostol, ptsanev, qpzm, radev_sw, ravikiranweb3, sces60107, seth_lawson, te_aut, twcctop, zhaojie, ziyou-
17.5208 USDC - $17.52
Writing this
string memory name = LibContractInfo.getSymbol(address(_tokens[0])); string memory symbol = name;
does not copy the content of name in symbol, what it does is copy the POINTER to the place where the name is stored. Thus, one change in one of them leads to the other pointing to the "updated" variable, breaking the working process of the function and passing wrong arguments to the init
function (so the high severity`
From Jean Cvllr awesome tutorials about data locations we have
In reality, what happened under the hood is that we create two pointers to memory, named by the variables data and greetings. When we do data = greetings , we think we are assigning the value cafecafe to the variable data. But we are not assigning anything at all here! We are giving the following instruction to the EVM: βvariable data, I order you to point to the same location in memory that the variable greetings point to!β
(you can read the Yellow paper too but the above is more user-friendly). That means the next code does the same to the two variables because both point to the same place, so one change will affect the other the same way
for (uint256 i = 1; i < _tokens.length; ++i) { name = string.concat(name, ":", LibContractInfo.getSymbol(address(_tokens[i]))); symbol = string.concat(symbol, LibContractInfo.getSymbol(address(_tokens[i]))); } name = string.concat(name, " ", LibContractInfo.getName(_wellFunction.target), " Well"); symbol = string.concat(symbol, LibContractInfo.getSymbol(_wellFunction.target), "w");
Because of that, the initFunctionCall = abi.encodeWithSignature("init(string,string)", name, symbol);
is broken given the fact that name
and symbol
are the same.
Manual analysis
Use local variables instead of memory references/pointers
Error
#0 - c4-pre-sort
2023-07-12T04:56:07Z
141345 marked the issue as low quality report
#1 - 141345
2023-07-13T09:30:02Z
need to recheck the POC validity
maybe QA is more appropriate
#2 - c4-pre-sort
2023-07-13T09:30:11Z
141345 marked the issue as duplicate of #199
#3 - c4-judge
2023-08-04T12:43:41Z
alcueca changed the severity to QA (Quality Assurance)
#4 - c4-judge
2023-08-19T18:39:51Z
alcueca marked the issue as grade-a
π Selected for report: SM3_SS
Also found by: 0x11singh99, 0xAnah, 0xSmartContract, 0xn006e7, 0xprinc, DavidGiladi, ElCid, JCN, K42, MIQUINHO, Raihan, Rolezn, SAAJ, SY_S, Strausses, TheSavageTeddy, bigtone, erebus, hunter_w3b, josephdara, lsaudit, mahdirostami, oakcobalt, peanuts, pfapostol, seth_lawson
7.8853 USDC - $7.89
Do not use full size words for low value variables (more if they are constant). Check here
Change strings in require
to custom errors, saving gas on the way. The regex pattern is "\w*"\);
and loop through the occurrences
Use unchecked { i++; }
in loops where the end is known. The regex pattern is ; ?\w*\++
. Save gas because solidity checks integers for over/underflow after 0.8.0 by default, so we can omit that because we know the limit
#0 - c4-pre-sort
2023-07-12T10:22:09Z
141345 marked the issue as low quality report
#1 - c4-judge
2023-08-05T10:52:13Z
alcueca marked the issue as grade-b