Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TWAP logic #2168

Merged
merged 77 commits into from
Aug 5, 2022
Merged
Show file tree
Hide file tree
Changes from 74 commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
34a49b1
TWAP wip
ValarDragon Jul 18, 2022
32e0406
Add proto files
ValarDragon Jul 19, 2022
6292394
more twap WIP
ValarDragon Jul 19, 2022
daf4d2d
sync
ValarDragon Jul 19, 2022
6ff72a1
Merge branch 'main' into dev/twap_wip
ValarDragon Jul 19, 2022
3f2b7a7
More TWAP stub progress
ValarDragon Jul 19, 2022
e452c24
Add update logic
ValarDragon Jul 20, 2022
c8c0339
More TWAP implementation updates
ValarDragon Jul 20, 2022
840c799
Do app integration
ValarDragon Jul 20, 2022
4a650f1
Fix simulator & bug it found
ValarDragon Jul 20, 2022
16a0ce4
More logic added / data flow reordered a bit
ValarDragon Jul 20, 2022
b9c36a0
Add to migration handler
ValarDragon Jul 20, 2022
7c96ede
Fix lint (by making prune stub)
ValarDragon Jul 20, 2022
d96b1d9
integrate BeforeSwap hook, add key format test
ValarDragon Jul 20, 2022
20f94fd
More keys tests
ValarDragon Jul 20, 2022
11d6071
Add TestGetAllUniqueDenomPairs
ValarDragon Jul 20, 2022
00e05d3
Test for the create pool flow
ValarDragon Jul 21, 2022
52ac746
Correct historical iterations
ValarDragon Jul 21, 2022
bde6f0a
Add TrackChangedPool tests
ValarDragon Jul 21, 2022
4378f9b
Add interpolate record test
ValarDragon Jul 21, 2022
4563c1d
Fix endblock flow
ValarDragon Jul 21, 2022
2cd49ae
Add UpdateRecord test
ValarDragon Jul 21, 2022
50d0891
de-dup interpolate, update record logic
ValarDragon Jul 21, 2022
ee6bf3d
After swap hook trigger test
ValarDragon Jul 21, 2022
7e94ca1
types comments
ValarDragon Jul 21, 2022
73e9970
TestGetBeginBlockAccumulatorRecord scaffolding
ValarDragon Jul 21, 2022
f381788
Complete TestGetBeginBlockAccumulatorRecord
ValarDragon Jul 21, 2022
21804e9
Improve code comment, fix lint
ValarDragon Jul 21, 2022
7936a5e
Compute Arithmetic Twap test casess
ValarDragon Jul 21, 2022
27b9392
Add Arithmetic TWAP computation method & testing methodology to doc
ValarDragon Jul 21, 2022
ab320cc
More documentation updates
ValarDragon Jul 21, 2022
65ab26a
Add migration test note
ValarDragon Jul 21, 2022
d54b266
disable some lints
ValarDragon Jul 21, 2022
9c0d6e5
Add store layout docs
ValarDragon Jul 21, 2022
6e16a81
Fix numbers in the example
ValarDragon Jul 21, 2022
e7ed1b2
Apply suggestions from code review
ValarDragon Jul 21, 2022
6bc8242
See if double line latex fixes github rendering
ValarDragon Jul 21, 2022
d2ec9ae
Merge branch 'dev/twap_wip' of github.com:osmosis-labs/osmosis into d…
ValarDragon Jul 21, 2022
f87e608
Fix remaining summation numerator
ValarDragon Jul 21, 2022
a389b08
Try to fix markdown lints
ValarDragon Jul 21, 2022
42df66a
Fix remianing markdown lint
ValarDragon Jul 21, 2022
81f478b
Fix incorrect interface in genesis proto description
ValarDragon Jul 22, 2022
30b2a11
Bring in changes from twap_types PR comments
ValarDragon Jul 22, 2022
1d23ec6
Change NewTwapRecord to return an error
ValarDragon Jul 22, 2022
0f06676
Merge branch 'main' into dev/twap_wip
ValarDragon Jul 22, 2022
f05f766
Delete beforeswap
ValarDragon Jul 22, 2022
285e356
Delete missed obsolete hook
ValarDragon Jul 22, 2022
9c1459f
Merge branch 'main' into dev/twap_wip
ValarDragon Jul 22, 2022
63fdef7
Add migration logic
ValarDragon Jul 22, 2022
6ae4d70
Add test for TestGetAllMostRecentRecordsForPool
ValarDragon Jul 22, 2022
800d341
Make multi-asset tc
ValarDragon Jul 22, 2022
7d1ada7
test TestGetRecordAtOrBeforeTime
ValarDragon Jul 22, 2022
0151b67
add wrong pool ID input case
ValarDragon Jul 22, 2022
4779ff4
Bring docs update from twap_store pr
ValarDragon Jul 22, 2022
8e4f7d5
Pull changes from twap_store from review
ValarDragon Jul 23, 2022
8c77b0b
Update Spec
ValarDragon Jul 23, 2022
483d05e
Apply suggestions from docs review
ValarDragon Jul 23, 2022
b7a4754
Add further tests
ValarDragon Jul 23, 2022
4069209
Make TestGetArithmeticTwap test, fix ordering of base and quote asset…
ValarDragon Jul 23, 2022
d481b1d
Add more test cases
ValarDragon Jul 23, 2022
4a48f4d
Add endblock flow test
ValarDragon Jul 23, 2022
3b9e72c
Merge branch 'main' into dev/twap_wip
ValarDragon Aug 2, 2022
ae4aa1a
error msg update
ValarDragon Aug 5, 2022
1d02a33
rename to listeners.go
ValarDragon Aug 5, 2022
654c82a
Add comment for record creation on pool creation
ValarDragon Aug 5, 2022
f5a6008
api_test requested updates
ValarDragon Aug 5, 2022
aa3d79f
Update x/gamm/twap/export_test.go
ValarDragon Aug 5, 2022
ccf67b8
var block & denom0 / denom1 usage
ValarDragon Aug 5, 2022
8842068
Improve ComputeArithmeticTwap comment
ValarDragon Aug 5, 2022
36db073
Review lint
ValarDragon Aug 5, 2022
203018b
Fix dangling comment
ValarDragon Aug 5, 2022
8ebcac3
Delete obsolete TODO
ValarDragon Aug 5, 2022
29bd221
Delete InterpolateRecord, just call recordWithUpdatedAccumulators
ValarDragon Aug 5, 2022
3e8fb91
Clarify accumulator setting in api test
ValarDragon Aug 5, 2022
b568faa
Delete extra line
ValarDragon Aug 5, 2022
6b60e70
Apply code review doc update
ValarDragon Aug 5, 2022
e800f9f
Add test case roman pointed out as missinsg
ValarDragon Aug 5, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/apptesting/test_suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func (s *KeeperTestHelper) Commit() {
oldHeight := s.Ctx.BlockHeight()
oldHeader := s.Ctx.BlockHeader()
s.App.Commit()
newHeader := tmtypes.Header{Height: oldHeight + 1, ChainID: oldHeader.ChainID, Time: time.Now().UTC()}
newHeader := tmtypes.Header{Height: oldHeight + 1, ChainID: oldHeader.ChainID, Time: oldHeader.Time.Add(time.Second)}
s.App.BeginBlock(abci.RequestBeginBlock{Header: newHeader})
s.Ctx = s.App.GetBaseApp().NewContext(false, newHeader)
}
Expand Down
8 changes: 8 additions & 0 deletions app/upgrades/v12/upgrades.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ func CreateUpgradeHandler(
bpm.StoreConsensusParams(ctx, cp)
}

// Initialize TWAP state
// TODO: Get allPoolIds from gamm keeper, and write test for migration.
ValarDragon marked this conversation as resolved.
Show resolved Hide resolved
allPoolIds := []uint64{}
err := keepers.TwapKeeper.MigrateExistingPools(ctx, allPoolIds)
if err != nil {
return nil, err
}

return mm.RunMigrations(ctx, configurator, fromVM)
}
}
2 changes: 2 additions & 0 deletions osmoutils/dec_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

var ThreePlusOneThird sdk.Dec = sdk.MustNewDecFromStr("3.333333333333333333")

// intended to be used with require/assert: require.True(DecEq(...))
// TODO: Replace with function in SDK types package when we update
func DecApproxEq(t *testing.T, d1 sdk.Dec, d2 sdk.Dec, tol sdk.Dec) (*testing.T, bool, string, string, string) {
Expand Down
3 changes: 2 additions & 1 deletion x/gamm/pool-models/balancer/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,8 @@ func (p *Pool) applySwap(ctx sdk.Context, tokensIn sdk.Coins, tokensOut sdk.Coin
// this is equivalent to spot_price = (Base_supply / Weight_base) / (Quote_supply / Weight_quote)
// but cancels out the common term in weight.
//
// panics if pool is misconfigured and has any weight as 0.
// panics if the pool in state is incorrect, and has any weight that is 0.
// TODO: Come back and improve docs for this.
func (p Pool) SpotPrice(ctx sdk.Context, baseAsset, quoteAsset string) (sdk.Dec, error) {
quote, base, err := p.parsePoolAssetsByDenoms(quoteAsset, baseAsset)
if err != nil {
Expand Down
91 changes: 91 additions & 0 deletions x/gamm/twap/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package twap

import (
"fmt"
"time"

sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/osmosis-labs/osmosis/v10/x/gamm/twap/types"
)

// GetArithmeticTwap returns an arithmetic time weighted average price.
// The returned twap is the time weighted average price (TWAP) of:
// * the base asset, in units of the quote asset (1 unit of base = x units of quote)
// * from (startTime, endTime),
// * as determined by prices from AMM pool `poolId`.
//
// startTime and endTime do not have to be real block times that occurred,
// the state machine will interpolate the accumulator values for those times
// from the latest Twap accumulation record prior to the provided time.
//
// startTime must be within 48 hours of ctx.BlockTime(), if you need older TWAPs,
// you will have to maintain the accumulator yourself.
//
// This function will error if:
// * startTime > endTime
// * endTime in the future
// * startTime older than 48 hours OR pool creation
// * pool with id poolId does not exist, or does not contain quoteAssetDenom, baseAssetDenom
//
// N.B. If there is a notable use case, the state machine could maintain more historical records, e.g. at one per hour.
func (k Keeper) GetArithmeticTwap(
ctx sdk.Context,
poolId uint64,
baseAssetDenom string,
quoteAssetDenom string,
startTime time.Time,
endTime time.Time) (sdk.Dec, error) {
if startTime.After(endTime) {
return sdk.Dec{}, fmt.Errorf("called GetArithmeticTwap with a start time that is after the end time."+
" (start time %s, end time %s)", startTime, endTime)
}
if endTime.Equal(ctx.BlockTime()) {
return k.GetArithmeticTwapToNow(ctx, poolId, baseAssetDenom, quoteAssetDenom, startTime)
} else if endTime.After(ctx.BlockTime()) {
return sdk.Dec{}, fmt.Errorf("called GetArithmeticTwap with an end time in the future."+
" (end time %s, current time %s)", endTime, ctx.BlockTime())
}
startRecord, err := k.getInterpolatedRecord(ctx, poolId, startTime, baseAssetDenom, quoteAssetDenom)
if err != nil {
return sdk.Dec{}, err
}
endRecord, err := k.getInterpolatedRecord(ctx, poolId, endTime, baseAssetDenom, quoteAssetDenom)
if err != nil {
return sdk.Dec{}, err
}
twap := computeArithmeticTwap(startRecord, endRecord, quoteAssetDenom)
return twap, nil
}

// GetArithmeticTwapToNow returns GetArithmeticTwap on the input, with endTime being fixed to ctx.BlockTime()
func (k Keeper) GetArithmeticTwapToNow(
ctx sdk.Context,
poolId uint64,
baseAssetDenom string,
quoteAssetDenom string,
startTime time.Time) (sdk.Dec, error) {
startRecord, err := k.getInterpolatedRecord(ctx, poolId, startTime, baseAssetDenom, quoteAssetDenom)
if err != nil {
return sdk.Dec{}, err
}
endRecord, err := k.GetBeginBlockAccumulatorRecord(ctx, poolId, baseAssetDenom, quoteAssetDenom)
if err != nil {
return sdk.Dec{}, err
}
twap := computeArithmeticTwap(startRecord, endRecord, quoteAssetDenom)
return twap, nil
}

// GetCurrentAccumulatorRecord returns a TwapRecord struct corresponding to the state of pool `poolId`
// as of the beginning of the block this is called on.
// This uses the state of the beginning of the block, as if there were swaps since the block has started,
// these swaps have had no time to be arbitraged back.
// This accumulator can be stored, to compute wider ranged twaps.
func (k Keeper) GetBeginBlockAccumulatorRecord(ctx sdk.Context, poolId uint64, asset0Denom string, asset1Denom string) (types.TwapRecord, error) {
// correct ordering of args for db
if asset1Denom > asset0Denom {
asset0Denom, asset1Denom = asset1Denom, asset0Denom
}
return k.getMostRecentRecord(ctx, poolId, asset0Denom, asset1Denom)
}
196 changes: 196 additions & 0 deletions x/gamm/twap/api_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
package twap_test

import (
"time"

sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/osmosis-labs/osmosis/v10/osmoutils"
"github.com/osmosis-labs/osmosis/v10/x/gamm/twap/types"
)

func (s *TestSuite) TestGetBeginBlockAccumulatorRecord() {
poolId, denomA, denomB := s.setupDefaultPool()
initStartRecord := newRecord(s.Ctx.BlockTime(), sdk.OneDec(), sdk.ZeroDec(), sdk.ZeroDec())
initStartRecord.PoolId, initStartRecord.Height = poolId, s.Ctx.BlockHeight()
initStartRecord.Asset0Denom, initStartRecord.Asset1Denom = denomA, denomB

zeroAccumTenPoint1Record := recordWithUpdatedSpotPrice(initStartRecord, sdk.NewDec(10), sdk.NewDecWithPrec(1, 1))

tests := map[string]struct {
// if start record is blank, don't do any sets
startRecord types.TwapRecord
// We set it to have the updated time
expRecord types.TwapRecord
time time.Time
poolId uint64
quoteDenom string
baseDenom string
expError bool
}{
"no record (wrong pool ID)": {initStartRecord, initStartRecord, baseTime, 4, denomA, denomB, true},
"default record": {initStartRecord, initStartRecord, baseTime, 1, denomA, denomB, false},
"one second later record": {initStartRecord, recordWithUpdatedAccum(initStartRecord, OneSec, OneSec), tPlusOne, 1, denomA, denomB, false},
"idempotent overwrite": {initStartRecord, initStartRecord, baseTime, 1, denomA, denomB, false},
"idempotent overwrite2": {initStartRecord, recordWithUpdatedAccum(initStartRecord, OneSec, OneSec), tPlusOne, 1, denomA, denomB, false},
"diff spot price": {zeroAccumTenPoint1Record,
recordWithUpdatedAccum(zeroAccumTenPoint1Record, OneSec.MulInt64(10), OneSec.QuoInt64(10)),
tPlusOne, 1, denomA, denomB, false},
// TODO: Overflow
}
for name, tc := range tests {
s.Run(name, func() {
// setup time
s.Ctx = s.Ctx.WithBlockTime(tc.time)
tc.expRecord.Time = tc.time

s.twapkeeper.StoreNewRecord(s.Ctx, tc.startRecord)

actualRecord, err := s.twapkeeper.GetBeginBlockAccumulatorRecord(s.Ctx, tc.poolId, tc.baseDenom, tc.quoteDenom)

if tc.expError {
s.Require().Error(err)
return
}
s.Require().NoError(err)
s.Require().Equal(tc.expRecord, actualRecord)
})
}
}

func (s *TestSuite) TestGetArithmeticTwap() {
type getTwapInput struct {
poolId uint64
quoteAssetDenom string
baseAssetDenom string
startTime time.Time
endTime time.Time
}

makeSimpleTwapInput := func(startTime time.Time, endTime time.Time, isQuoteTokenA bool) getTwapInput {
quoteAssetDenom, baseAssetDenom := denom0, denom1
if isQuoteTokenA {
baseAssetDenom, quoteAssetDenom = quoteAssetDenom, baseAssetDenom
}
return getTwapInput{1, quoteAssetDenom, baseAssetDenom, startTime, endTime}
}

quoteAssetA := true
quoteAssetB := false
// base record is a record with t=baseTime, sp0=10, sp1=.1, accumulators set to 0
baseRecord := newTwapRecordWithDefaults(baseTime, sdk.NewDec(10), sdk.ZeroDec(), sdk.ZeroDec())
ValarDragon marked this conversation as resolved.
Show resolved Hide resolved
// record with t=baseTime+10, sp0=5, sp1=.2, accumulators updated from baseRecord
// accum0 = 10 seconds * (spot price = 10), accum1 = 10 seconds * (spot price = .1)
accum0, accum1 := OneSec.MulInt64(10*10), OneSec
tPlus10sp5Record := newTwapRecordWithDefaults(
baseTime.Add(10*time.Second), sdk.NewDec(5), accum0, accum1)
// TODO: Make use of the below for test cases:
// record with t=baseTime+20, sp0=2, sp1=.5, accumulators updated from tPlus10sp5Record
// tPlus20sp2Record := newTwapRecordWithDefaults(
Copy link
Member

Choose a reason for hiding this comment

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

Can deadcode be removed?

// baseTime.Add(20*time.Second), sdk.NewDec(2), OneSec.MulInt64(10*10+5*10), OneSec.MulInt64(3))

tests := map[string]struct {
recordsToSet []types.TwapRecord
ctxTime time.Time
input getTwapInput
expTwap sdk.Dec
expErrorStr string
}{
"(1 record) start and end point to same record": {
recordsToSet: []types.TwapRecord{baseRecord},
ctxTime: baseTime.Add(time.Minute),
input: makeSimpleTwapInput(baseTime, tPlusOne, quoteAssetA),
expTwap: sdk.NewDec(10),
},
"(1 record) start and end point to same record, use sp1": {
recordsToSet: []types.TwapRecord{baseRecord},
ctxTime: baseTime.Add(time.Minute),
input: makeSimpleTwapInput(baseTime, tPlusOne, quoteAssetB),
expTwap: sdk.NewDecWithPrec(1, 1),
},
"(1 record) start and end point to same record, end time = now": {
recordsToSet: []types.TwapRecord{baseRecord},
ctxTime: baseTime.Add(time.Minute),
input: makeSimpleTwapInput(baseTime, baseTime.Add(time.Minute), quoteAssetA),
expTwap: sdk.NewDec(10),
},

"(2 record) start and end point to same record": {
recordsToSet: []types.TwapRecord{baseRecord, tPlus10sp5Record},
ctxTime: baseTime.Add(time.Minute),
input: makeSimpleTwapInput(baseTime, tPlusOne, quoteAssetA),
expTwap: sdk.NewDec(10),
},
"(2 record) start and end exact, different records": {
recordsToSet: []types.TwapRecord{baseRecord, tPlus10sp5Record},
ctxTime: baseTime.Add(time.Minute),
input: makeSimpleTwapInput(baseTime, baseTime.Add(10*time.Second), quoteAssetA),
expTwap: sdk.NewDec(10),
},
"(2 record) start exact, end after second record": {
recordsToSet: []types.TwapRecord{baseRecord, tPlus10sp5Record},
ctxTime: baseTime.Add(time.Minute),
input: makeSimpleTwapInput(baseTime, baseTime.Add(20*time.Second), quoteAssetA),
expTwap: sdk.NewDecWithPrec(75, 1), // 10 for 10s, 5 for 10s
},
"(2 record) start exact, end after second record, sp1": {
recordsToSet: []types.TwapRecord{baseRecord, tPlus10sp5Record},
ctxTime: baseTime.Add(time.Minute),
input: makeSimpleTwapInput(baseTime, baseTime.Add(20*time.Second), quoteAssetB),
expTwap: sdk.NewDecWithPrec(15, 2), // .1 for 10s, .2 for 10s
},
"(2 record) start and end interpolated": {
recordsToSet: []types.TwapRecord{baseRecord, tPlus10sp5Record},
ctxTime: baseTime.Add(time.Minute),
input: makeSimpleTwapInput(baseTime.Add(5*time.Second), baseTime.Add(20*time.Second), quoteAssetA),
// 10 for 5s, 5 for 10s = 100/15 = 6 + 2/3 = 6.66666666
expTwap: osmoutils.ThreePlusOneThird.MulInt64(2),
},

// error catching
"end time in future": {
recordsToSet: []types.TwapRecord{baseRecord},
ctxTime: baseTime,
input: makeSimpleTwapInput(baseTime, tPlusOne, quoteAssetA),
expErrorStr: "future",
},
"start time after end time": {
recordsToSet: []types.TwapRecord{baseRecord},
ctxTime: baseTime,
input: makeSimpleTwapInput(tPlusOne, baseTime, quoteAssetA),
expErrorStr: "after",
},
"start time too old (end time = now)": {
recordsToSet: []types.TwapRecord{baseRecord},
ctxTime: baseTime,
input: makeSimpleTwapInput(baseTime.Add(-time.Hour), baseTime, quoteAssetA),
expErrorStr: "too old",
},
"start time too old": {
recordsToSet: []types.TwapRecord{baseRecord},
ctxTime: baseTime.Add(time.Second),
input: makeSimpleTwapInput(baseTime.Add(-time.Hour), baseTime, quoteAssetA),
expErrorStr: "too old",
},
// TODO: overflow tests, multi-asset pool handling, make more record interpolation cases
Copy link
Member

Choose a reason for hiding this comment

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

Agree that these would be useful. Do we have an issue for adding these?

Copy link
Member Author

Choose a reason for hiding this comment

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

We do for multi-asset pool handling. Not yet for overflow, but handling overflow is one of the big remaining twap items

}
for name, test := range tests {
s.Run(name, func() {
s.SetupTest()
for _, record := range test.recordsToSet {
s.twapkeeper.StoreNewRecord(s.Ctx, record)
}
s.Ctx = s.Ctx.WithBlockTime(test.ctxTime)
twap, err := s.twapkeeper.GetArithmeticTwap(s.Ctx, test.input.poolId,
test.input.quoteAssetDenom, test.input.baseAssetDenom,
test.input.startTime, test.input.endTime)
if test.expErrorStr != "" {
s.Require().Error(err)
s.Require().Contains(err.Error(), test.expErrorStr)
return
}
s.Require().NoError(err)
s.Require().Equal(test.expTwap, twap)
})
}
}
18 changes: 9 additions & 9 deletions x/gamm/twap/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ func (k Keeper) GetChangedPools(ctx sdk.Context) []uint64 {
return k.getChangedPools(ctx)
}

// func (k Keeper) UpdateRecord(ctx sdk.Context, record types.TwapRecord) types.TwapRecord {
// return k.updateRecord(ctx, record)
// }
func (k Keeper) UpdateRecord(ctx sdk.Context, record types.TwapRecord) types.TwapRecord {
return k.updateRecord(ctx, record)
}

// func ComputeArithmeticTwap(startRecord types.TwapRecord, endRecord types.TwapRecord, quoteAsset string) sdk.Dec {
// return computeArithmeticTwap(startRecord, endRecord, quoteAsset)
// }
func ComputeArithmeticTwap(startRecord, endRecord types.TwapRecord, quoteAsset string) sdk.Dec {
return computeArithmeticTwap(startRecord, endRecord, quoteAsset)
}

// func InterpolateRecord(record types.TwapRecord, t time.Time) types.TwapRecord {
// return interpolateRecord(record, t)
// }
func RecordWithUpdatedAccumulators(record types.TwapRecord, t time.Time) types.TwapRecord {
return recordWithUpdatedAccumulators(record, t)
}
Loading