The following extract from getAccountMarginRequirementUsdAndUnrealizedPnlUsd
shows how the protocol calculates a user's profit
markPrice
is proportional to the indexPrice
indexPrice
gets the price of the asset from a chainlink price feed, as follows
position.getUnrealizedPnl
uses the calculated markPrice
of the asset and compares it to the lastInteractionPrice
, If the markPrice
> lastInteractionPrice
then there will be a profit recorded. As seen in the following code.
Chainlink priceFeeds will only update if the price deviates > threshold OR the heartbeat is exceeded
The above fact gives rise to the following scenario:
If the price of the asset has increased by 0.99% and the deviation threshold = 1%, the priceFeed will NOT update till the heartbeat is exceeded OR the price increases more to surpass the threshold
Attackers can take advantage of this by the following steps:
Price of asset reported by the chainlink oracle is $1 BUT it is actually 1.0099 (0.99% higher) AND the heartbeat is about to be surpassed in the next few minutes or so
Attacker opens a long order, which will get executed by keepers before the heartbeat update (if not they can cancel the order)
Oracle updates the price to be 0.99% higher, therefore indexPrice
is 0.99% higher, therefore getUnrealizedPnl
will be positive
attacker closes the order making a profit
Repeat
This attack can also be done if the price goes down by shorting
Attackers are performing risk free trades in an unfair way
Attackers extract value from the protocol over time
Manual Review
This is not easy to mitigate without removing the use of price feeds and sticking to the low latency price streams only
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.