Skip to content

Update DEX TWAP endpoint#19

Merged
codchen merged 5 commits intomasterfrom
integrate-oracle
Jun 15, 2022
Merged

Update DEX TWAP endpoint#19
codchen merged 5 commits intomasterfrom
integrate-oracle

Conversation

@codchen
Copy link
Collaborator

@codchen codchen commented May 28, 2022

The previous twap endpoint was stateful and hardcoded to Vortex's use case.

The new twap endpoint itself is stateless, and performs calculation on the fly based on price snapshots. An exchange price snapshot is generated roughly every 60s and has a retention of one hour. Even though the snapshotting cadence is "roughly" 60s, the price snapshot itself will store the exact timestamp, which would make the twap calculation accurate.

Tested through both unit tests and local chain manual tests.

PR is large mainly due to proto-generated files.

The following steps will be performed in subsequent PRs:

  • migration handler for this change
  • parameterize the snapshotting cadence (right now it depends on epoch's cadence which is hardcoded)

@codchen codchen force-pushed the integrate-oracle branch from 5a8e59f to b4d0aec Compare May 28, 2022 23:14
@codchen codchen force-pushed the integrate-oracle branch from b4d0aec to e9cfd68 Compare June 10, 2022 20:16
@codchen codchen changed the title Integrate oracle V2 with dex module Update DEX TWAP endpoint Jun 10, 2022
@codchen codchen requested review from philipsu522 and udpatil June 10, 2022 20:22
var timeTraversed uint64 = 0
var weightedPriceSum sdk.Dec = sdk.ZeroDec()
for _, price := range prices {
newTimeTraversed := uint64(ctx.BlockTime().Unix()) - price.SnapshotTimestampInSeconds
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just double check ctx.BlockTime() is static (i.e. block start time) right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah it's set during BeginBlock based on block proposal (so consistent across all nodes)

return res, true
}

func (k Keeper) GetAllPrices(ctx sdk.Context, contractAddr string, pair types.Pair) (list []*types.Price) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when do we purge prices we no longer need?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


func calculateTwap(ctx sdk.Context, prices []*types.Price, lookback uint64) sdk.Dec {
// sort prices in descending order to start iteration from the latest
sort.Slice(prices, func(p1, p2 int) bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since the ordering won't change, we could consider using a priority queue to reduce number of sorts . If number of prices is pretty small then probably doesn't matter

} else {
newPrices = append(twap.Prices, twap.Prices[len(twap.Prices)-1])
// condition to prevent unsigned integer overflow
if currentEpoch >= priceRetention {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it always guaranteed that an epoch length is 60s? wouldnt it be good to add a check here that we only delete the epoch data if the current BlockTime - epoch BlockTime > 60 min? however one issue with that is that there is no mechanism to go back to an epoch if you skip over it on that condition :/ WDYT @codchen

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually for dex I'll extend the retention to be way longer than 60min since its price snapshots are needed for historical price queries as well. In that case we probably don't have this issue with twap I think?

var weightedPriceSum sdk.Dec = sdk.ZeroDec()
for _, price := range prices {
newTimeTraversed := uint64(ctx.BlockTime().Unix()) - price.SnapshotTimestampInSeconds
if newTimeTraversed > lookback {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in this case, wouldn't we exclude any data from the first time interval?

Lets say for example we had data at T-61 and then T-59 ... T-0, when calculating the TWAP, it would technically only represent the weighted price sum for T-59 - T-0, right? because we would break on T-61 and never include data for the first interval?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's true. We should align on the behavior in such case between dex twap and oracle twap. Still factoring in T-61 but only assign a time weight of 1 sounds reasonable to me, if that's also how oracle twap is calculated

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah that makes sense to me, currently my implementation also has the missing first interval issue, but I can modify it to keep the first out of bounds data point for calculating to the start of the TWAP window

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will approve once this change is in

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pushed the fix as well as a unit test for this case

@codchen codchen force-pushed the integrate-oracle branch from 7ae981a to a28779b Compare June 15, 2022 17:22
@codchen codchen merged commit a154021 into master Jun 15, 2022
masih pushed a commit that referenced this pull request Sep 29, 2025
masih pushed a commit that referenced this pull request Oct 1, 2025
masih pushed a commit that referenced this pull request Oct 9, 2025
@masih masih deleted the integrate-oracle branch October 31, 2025 15:49
masih pushed a commit that referenced this pull request Dec 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants