Platform: Code4rena
Start Date: 26/09/2022
Pot Size: $50,000 USDC
Total HM: 13
Participants: 113
Period: 5 days
Judge: 0xean
Total Solo HM: 6
Id: 166
League: ETH
Rank: 31/113
Findings: 2
Award: $87.52
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0xSmartContract
Also found by: 0xDecorativePineapple, 0xNazgul, 0xmatt, Jeiwan, Trust, berndartmueller, brgltd, catchup, ch13fd357r0y3r, cryptonue, ladboy233, minhtrng, neko_nyaa, rbserver, rvierdiiev, s3cunda
35.4829 USDC - $35.48
https://github.com/code-423n4/2022-09-quickswap/blob/main/src/core/contracts/AlgebraPool.sol#L193
initialize()
is an external function which sets the globalState.price with an initial value.
This function should only be called by the owner, once a new pool is deployed.
However, anyone can frontrun the owner and can set the initial price to an unfair value, since there is no access control.
Then once an early user deposits in the pool, malicious user can take advantage of the faulty swap ratio to make profit off the early user.
193: function initialize(uint160 initialPrice) external override { //@audit-issue there is no modifier control. Anyone can set the initialprice. 194: require(globalState.price == 0, 'AI'); 195: // getTickAtSqrtRatio checks validity of initialPrice inside 196: int24 tick = TickMath.getTickAtSqrtRatio(initialPrice); 197: 198: uint32 timestamp = _blockTimestamp(); 199: IDataStorageOperator(dataStorageOperator).initialize(timestamp, tick); 200: 201: globalState.price = initialPrice; 202: globalState.unlocked = true; 203: globalState.tick = tick; 204: 205: emit Initialize(initialPrice, tick); 206: }
https://github.com/code-423n4/2022-09-quickswap/blob/main/src/core/contracts/AlgebraPool.sol#L193
Manual review
I suggest to include an access control on the initialize() function, so that it can only be called by the owner.
#0 - 0xean
2022-10-02T22:25:46Z
dupe of #84
🌟 Selected for report: 0xNazgul
Also found by: 0x1f8b, 0x52, 0xDecorativePineapple, 0xSmartContract, 0xmatt, Aeros, Aymen0909, Bnke0x0, Chom, CodingNameKiki, Deivitto, DimitarDimitrov, IllIllI, JC, Jeiwan, Lambda, Matin, Migue, Mukund, Ocean_Sky, Olivierdem, RaymondFam, RockingMiles, Rolezn, Ruhum, Satyam_Sharma, Shinchan, Tomo, Trabajo_de_mates, V_B, Waze, __141345__, a12jmx, ajtra, asutorufos, aysha, brgltd, bulej93, carrotsmuggler, catchup, cccz, chrisdior4, cryptonue, cryptphi, d3e4, defsec, delfin454000, durianSausage, erictee, fatherOfBlocks, gogo, kaden, karanctf, ladboy233, lukris02, mahdikarimi, martin, mics, natzuu, oyc_109, p_crypt0, pedr02b2, rbserver, reassor, rotcivegaf, rvierdiiev, sikorico, slowmoses, sorrynotsorry, tnevler, trustindistrust
52.0364 USDC - $52.04
Current owner can update the owner address by calling setOwner(address _owner)
function:
77: function setOwner(address _owner) external override onlyOwner { 78: require(owner != _owner); //@audit-issue uncontrolled owner update 79: emit Owner(_owner); 80: owner = _owner; 81: }
Owner has important privileges such as setting the farming and vault addresses, setting the base feeconfiguration, updating the community fees and updating the liquidity cooldown time. If the current owner updates the new owner address by passing a faulty address, all these privileges would be lost and the owner address would not be able to be recovered again, since only the current owner can update the owner address.
While this kind of zero address checks are considered as QA among the judges, a similar submission was accepted as Medium recently (find the link below): https://github.com/code-423n4/2022-08-nounsdao-findings/issues/318
https://github.com/code-423n4/2022-08-nounsdao-findings/issues/318
Manual review
I suggest to include a 2-step process for the owner updates, where the current owner would set the pendingAdmin address and the pendingAdmin would claim the owner address.
#0 - sameepsi
2022-10-04T06:37:37Z
duplicate of #131
#1 - 0xean
2022-10-04T15:35:49Z
downgrading to QA,