Category: Coding Mistakes
Incorrect TWAP calculation
High Impact
High Severity
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↗.