Category: Coding Mistakes
Incorrect TWAP calculation
High Severity
High Impact
High Likelihood
Description
The oracle module uses the calcTwap
to compute the TWAP (time-weighted average price). Here, the maximum of snapshots[0].TimestampMs
and ctx.BlockTime().UnixMilli() - twapLookBack
is used as firstTimeStamp
.
func (k Keeper) calcTwap(ctx sdk.Context, snapshots []types.PriceSnapshot) (price sdk.Dec, err error) {
[...]
firstTimeStamp := ctx.BlockTime().UnixMilli() - twapLookBack
cumulativePrice := sdk.ZeroDec()
firstTimeStamp = math.MaxInt64(snapshots[0].TimestampMs, firstTimeStamp)
[...]
nextTimestampMs = snapshots[i+1].TimestampMs
}
price := s.Price.MulInt64(nextTimestampMs - timestampStart)
This is not sound as it is possible for the price to be negative if timestampStart
is greater than nextTimestampMs
.
Impact
If timestampStart
is greater than nextTimestampMs
, the resulting TWAP data will be incorrect. However, this is not an issue currently since the caller for calcTwap
only includes snapshots starting from ctx.BlockTime().UnixMilli() - twapLookBack
.
Recommendations
Ideally, firstTimeStamp
should always just be equal to the timestamp of the first snapshot.
Remediation
This issue has been acknowledged by Nibiru, and a fix was implemented in commit 53487734↗.