As per docs :
Assuming
flagShort()was successful,
firstLiquidationTimeis 10hrs,secondLiquidationTimeis 12hrs,resetLiquidationTimeis 16hrs (these are modifiable)Between
updatedAtandfirstLiquidationTime,liquidate()isn't callable.
Between
firstLiquidationTimeandsecondLiquidationTime,liquidate()is only callable byshort.flagger.
The last point can be incorrectly revoked by the protocol under the normal flow of events, violating flagger's priority liquidation time-window.
Imagine the following flow of events:
#1. shortRecord_1 is flagged by flagger1 at timestamp ts. This short now has 10 hours. If cRatio is still less than primaryLiquidationCR after 10 hours, flagger1 has a 2 hour window to liquidate the short. The code sets shortRecord_1.flaggerId as 1. Read about flaggerId here:
Note: Instead of saving the flagger address, a ShortRecord saves the flaggerId instead. This is done to save space in the struct. A mapping from id to address (flagMapping) is used to lookup the address instead. There is also a corresponding AssetUser.g_flaggerId to lookup a user's flagId.
#2. 10 hours pass. shortRecord_1 is now eligible for liquidation by flagger1. Right about now, a different short record, shortRecord_2 is flagged by flagger2.
#3. Due to a logic bug in the function setFlagger(), the code sets shortRecord_2.flaggerId as 1 too, since it attempts to re-use the "inactive" flaggerId.
#4. The above point means that as per code, both shortRecord_1 and shortRecord_2 are now considered to be flagged by flagger2.
#5. Since shortRecord_1 is still in its primary liquidation window, flagger1 attempts to margin call it only to find that it reverts for him!
#6. Due to the above logic fallacy, flagger2 actually now has the power to liquidate shortRecord_1. He margin calls shortRecord_1 immediately and receives the rewards.
The current check to see if a flaggerId is "inactive" or not is incorrect. The protocol currently waits for a duration of firstLiquidationTime to pass for determining this. It should rather wait for secondLiquidationTime.
Create a file inside test/ folder by the name of TwoFlaggers.t.sol and paste the following code. Run it via forge test --mt test_TwoFlaggers -vv:
Manual review, foundry.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.