Platform: Code4rena
Start Date: 06/12/2022
Pot Size: $36,500 USDC
Total HM: 16
Participants: 119
Period: 3 days
Judge: berndartmueller
Total Solo HM: 2
Id: 189
League: ETH
Rank: 93/119
Findings: 2
Award: $1.45
๐ Selected for report: 0
๐ Solo Findings: 0
๐ Selected for report: adriro
Also found by: 0x446576, 0xA5DF, 0xDave, 0xDecorativePineapple, 0xRobocop, 0xbepresent, 8olidity, Aymen0909, Ch_301, Chom, Franfran, HollaDieWaldfee, Madalad, Parth, Ruhum, Tricko, bin2chen, carrotsmuggler, chaduke, danyams, evan, gz627, hansfriese, hihen, imare, immeas, jadezti, jayphbee, jonatascm, kaliberpoziomka8552, kiki_dev, kree-dotcom, ladboy233, lukris02, lumoswiz, mahdikarimi, minhquanym, minhtrng, nameruse, neumo, obront, pauliax, poirots, reassor, rvierdiiev, slvDev, sorrynotsorry, yixxas, zapaz
0.8413 USDC - $0.84
Detailed description of the impact of this finding.
The refund()
function will call the getPrice()
to get the price. However, when sale.startPrice - sale.dropPerSecond *(sale.startTime-sale.endTime) < 0, it is possible that getPrice()
might revert due to underflow. As a result, the refund will revert. The user can not get refund even though he/she deserves a full refund.
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.
The failure of refund is caused by the lack of check of the condition
sale.startPrice - sale.dropPerSecond *(sale.startTime-sale.endTime) >=0. As a result, after some time point, the getPrice()
function will always revert at the last line due to underflow. A user will not be able to get refund even though he/she deserves to have a full refund.
One can check this condition at the factory contract to ensure getPrice() at (https://github.com/code-423n4/2022-12-escher/blob/5d8be6aa0e8634fdb2f328b99076b0d05fefab73/src/minters/LPDA.sol#L117) never underflows, otherwise, refunding will be unfair: some can get refund, some cannot.
Consider the special scenario that a seller likes to sell all NFTS within one 24 hrs otherwise, after that, the price will become zero and users can get full refund. However, such a plan will fail if we allow sale.startPrice - sale.dropPerSecond *(sale.startTime-sale.endTime) to be a negative value. In particular, a user A might get a refund when the price is still above zero, but another user cannot get a refund because when the function getPrice() is called, there is a underflow at the last line.
Remix
There are two solutions depending on what scenarios we need to support (including the one introduced above):
getPrice()
has no underflow issue.#0 - c4-judge
2022-12-13T11:54:16Z
berndartmueller marked the issue as duplicate of #392
#1 - c4-judge
2023-01-02T19:57:13Z
berndartmueller marked the issue as satisfactory
๐ Selected for report: RaymondFam
Also found by: 0xdeadbeef0x, 0xhacksmithh, AkshaySrivastav, Awesome, Bnke0x0, CRYP70, HollaDieWaldfee, JC, Parth, Rahoz, Tutturu, __141345__, ahmedov, ajtra, asgeir, aviggiano, bin2chen, btk, carrotsmuggler, cccz, chaduke, cryptonue, dic0de, fatherOfBlocks, fs0c, hansfriese, jonatascm, karanctf, ladboy233, lumoswiz, martin, obront, pashov, pauliax, rvierdiiev, shark, simon135, supernova, tourist, yellowBirdy, zapaz, zaskoh
0.6136 USDC - $0.61
Detailed description of the impact of this finding. Solidityโs transfer() and send() use a hardcoded gas amount which might change in the future. These methods should be avoided. Use .call.value(...)("") instead. See Consensys's recommendation of not using them https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept. https://github.com/code-423n4/2022-12-escher/blob/5d8be6aa0e8634fdb2f328b99076b0d05fefab73/src/minters/LPDA.sol#L105
Remix
use .call.value(...)("") instead to send eth.
#0 - c4-judge
2022-12-10T00:30:59Z
berndartmueller marked the issue as duplicate of #99
#1 - c4-judge
2023-01-03T12:48:37Z
berndartmueller marked the issue as satisfactory