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

TWAP logic #2168

merged 77 commits into from
Aug 5, 2022

Conversation

ValarDragon
Copy link
Member

@ValarDragon ValarDragon commented Jul 20, 2022

What is the purpose of the change

Core logic for TWAP implementation. Right now wanted to ask if we wanted me to split up PR'ing the types package, osmoutils, and twap/store changes first. I think the work in osmoutils is generally quite helpful for our codebase, happy to break that out sooner before finishing the remainder.

Remaining steps needed:

  • Wire into app
  • Arithmetic for TWAP
  • Add before swap hook (EDIT: Actually needs to be deleted)
  • Tests - (very load bearing todo haha)
    • Actual API tests (Mostly done)
    • CreatePool tests
    • Swap triggering update
    • EndBlock writing/reading tests
    • CreatePool + swap + end block
    • Overflow tests
    • Simulator integration for twap (blocked on Simulator: Property checks #2117 )
    • CreatePool -> Makes Twap Record
    • KeyFormat & parsing consistency
    • Unit tests for types package
    • Unit test for update and interpolate record
    • Unit test for arithmetic of twap calculation
  • Golang Docs
  • Issues for doing prune parameters in another PR
  • Issue for doing bindings in another PR
  • Add-on features relegated for another PR (ArithmeticTwap from self-stored accumulator, simulator integration, mutation testing)

Brief Changelog

  • Implement TWAPs

Testing and Verifying

This change added tests and can be verified as follows:

Tests are added in this PR, will be breaking up components to be more easily reviewable. First broken out component is #2175

Documentation and Release Note

  • Does this pull request introduce a new feature or user-facing behavior changes? yes
  • Is a relevant changelog entry added to the Unreleased section in CHANGELOG.md? yes
  • How is the feature or change documented? x/gamm/twap/README

@github-actions github-actions bot added C:app-wiring Changes to the app folder C:x/gamm Changes, features and bugs related to the gamm module. C:x/pool-incentives labels Jul 20, 2022
@github-actions github-actions bot added the C:docs Improvements or additions to documentation label Jul 20, 2022
@faddat
Copy link
Member

faddat commented Jul 21, 2022

Dev, this PR is aimed at giving users the ability to buy / sell using twap?

@ValarDragon
Copy link
Member Author

ValarDragon commented Jul 21, 2022

Nah, thats DCA'ing. This PR exposes on-chain TWAPs that people can then with cosmwasm to build that though!

Exposes an on-chain TWAP oracle for every pool

@ValarDragon ValarDragon mentioned this pull request Jul 23, 2022
2 tasks
@github-actions github-actions bot removed the C:docs Improvements or additions to documentation label Aug 2, 2022
Copy link
Member

@p0mvn p0mvn left a comment

Choose a reason for hiding this comment

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

I finished reviewing the core logic but haven't reviewed the tests in detail yet.

I would like to spend more time tomorrow trying to run the tests.

LGTM overall, great job on this! Also, it is fine with me if this PR is not split further

x/gamm/twap/api.go Outdated Show resolved Hide resolved
x/gamm/twap/logic.go Outdated Show resolved Hide resolved
x/gamm/twap/logic.go Outdated Show resolved Hide resolved
x/gamm/twap/logic.go Outdated Show resolved Hide resolved
sdk "github.com/cosmos/cosmos-sdk/types"

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

func (k Keeper) MigrateExistingPools(ctx sdk.Context, poolIds []uint64) error {
Copy link
Member

Choose a reason for hiding this comment

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

Not sure if it is desired to group this with hooks. Please consider moving this to migrations.go (like it is in the sdk) or to keeper.go.

Copy link
Member Author

@ValarDragon ValarDragon Aug 4, 2022

Choose a reason for hiding this comment

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

I wanted this file to be listeners for things that could trigger a state change. Maybe I just change the file name to listeners.go?

I'm imagining we try to to change the entire Hook system into a publisher subscriber system

Copy link
Member

Choose a reason for hiding this comment

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

Maybe I just change the file name to listeners.go?

I like listeners.go since hook and listener feel to be synonymous. Also, I think listener is frequently used when speaking of pub-sub systems.

I wanted this file to be listeners for things that could trigger a state change

But this specific function is a one-time migration that is done during the upgrade. Why would we ever use pub-sub for this logic?

Also, I was referring to existing examples such as:

func MergeLockupsForSimilarDurations(

where upgrade migrations logic exists in the keeper's migrations.go file

Copy link
Member Author

Choose a reason for hiding this comment

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

hrmm yeah your right the migraiton being here is weird.

I just realized that we can do this in InitGenesis, which is likely the correct entry point. WIll move it there.

Copy link
Member Author

Choose a reason for hiding this comment

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

ah rip we can't do it in InitGenesis without adding to the gamm keeper interface, which seems worse.

I feel like keeping it in listeners.go, as what an external module can trigger logic for, is ok personally. I'd prefer not blocking on where this function lives, as it will ultimately be deleted later.

Perhaps we can call it InitGenesisAtMigration?

Copy link
Member

Choose a reason for hiding this comment

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

We agreed to leaves as is offline - I guess we can discuss this in a separate issue later

x/gamm/twap/logic.go Show resolved Hide resolved
mergify bot pushed a commit that referenced this pull request Aug 3, 2022
Closes: #XXX

## What is the purpose of the change

Some minor pass through changes discovered while reviewing #2168 
## Documentation and Release Note

  - Does this pull request introduce a new feature or user-facing behavior changes? no
  - Is a relevant changelog entry added to the `Unreleased` section in `CHANGELOG.md`? no
  - How is the feature or change documented? not applicable
Copy link
Member

@p0mvn p0mvn left a comment

Choose a reason for hiding this comment

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

I'm part way through tests. Still have a couple of files to review

x/gamm/twap/api_test.go Outdated Show resolved Hide resolved
x/gamm/twap/api_test.go Show resolved Hide resolved
tPlus10sp5Record := newTwapRecordWithDefaults(
baseTime.Add(10*time.Second), sdk.NewDec(5), OneSec.MulInt64(10*10), OneSec)
// 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?

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

x/gamm/twap/api_test.go Outdated Show resolved Hide resolved
sdk "github.com/cosmos/cosmos-sdk/types"

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

func (k Keeper) MigrateExistingPools(ctx sdk.Context, poolIds []uint64) error {
Copy link
Member

Choose a reason for hiding this comment

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

Maybe I just change the file name to listeners.go?

I like listeners.go since hook and listener feel to be synonymous. Also, I think listener is frequently used when speaking of pub-sub systems.

I wanted this file to be listeners for things that could trigger a state change

But this specific function is a one-time migration that is done during the upgrade. Why would we ever use pub-sub for this logic?

Also, I was referring to existing examples such as:

func MergeLockupsForSimilarDurations(

where upgrade migrations logic exists in the keeper's migrations.go file

app/upgrades/v12/upgrades.go Show resolved Hide resolved
x/gamm/twap/export_test.go Outdated Show resolved Hide resolved
x/gamm/twap/export_test.go Outdated Show resolved Hide resolved
x/gamm/twap/keeper_test.go Outdated Show resolved Hide resolved
x/gamm/twap/logic.go Outdated Show resolved Hide resolved
x/gamm/twap/logic.go Outdated Show resolved Hide resolved
Copy link
Member

@p0mvn p0mvn left a comment

Choose a reason for hiding this comment

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

Tests LGTM. My first full pass on this PR is now complete.

Left some minor comments. I agree for the need for more tests outlined in TODOs. However, the test coverage in the core functions seems pretty good already, great work on that.

x/gamm/twap/hook_test.go Outdated Show resolved Hide resolved
"github.com/osmosis-labs/osmosis/v10/x/gamm/twap/types"
)

// TestCreatePoolFlow tests that upon a pool being created,
Copy link
Member

Choose a reason for hiding this comment

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

Most tests in this file seem to be more functional than unit in nature. While it is useful to have both, I don't think we have any unit tests for hooks.

Do we have an issue for unit testing hooks?

Copy link
Member Author

@ValarDragon ValarDragon Aug 5, 2022

Choose a reason for hiding this comment

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

I don't think theres any unit tests that makes sense - they should all be functionality tests, with the expected integration.

Every hook is just "capture input from elsewhere, call unit tested method"

Copy link
Member Author

Choose a reason for hiding this comment

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

I guess we could make these more table driven! Definitely very open to figuring out how to make better tests for what we want here!

Copy link
Member

Choose a reason for hiding this comment

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

I will make a separate issue for this to discuss further

)

// TestCreatePoolFlow tests that upon a pool being created,
// we have made the correct store entries.
Copy link
Member

Choose a reason for hiding this comment

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

I think we should also be more specific about what exactly we are testing in this file. At first, I was looking in the hook_listener.go due to the name of this file. However, then, I released that a lot of the functionality is actually related to endBlock which is defined in logic.go

So I suggest renaming this to hook_functional_test.go and adding a comment that all these tests are functional and testing the relationship between twap with other system components.

x/gamm/twap/hook_listener.go Show resolved Hide resolved
x/gamm/twap/logic.go Outdated Show resolved Hide resolved
x/gamm/twap/logic_test.go Outdated Show resolved Hide resolved
x/gamm/twap/logic_test.go Outdated Show resolved Hide resolved
interpolateTime: time.Unix(1, 0),
expRecord: newExpRecord(oneDec, twoDec),
},
// TODO: Overflow tests
Copy link
Member

Choose a reason for hiding this comment

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

Bump for TODO - is this being kept track of?


"accumulator = 10*OneSec, t=100s. 0 base accum (asset 1)": testCaseFromDeltasAsset1(sdk.ZeroDec(), OneSec.MulInt64(10), 100*time.Second, sdk.NewDecWithPrec(1, 1)),

// TODO: Overflow, rounding
Copy link
Member

Choose a reason for hiding this comment

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

Bump for TODO - is this being kept track of?

interpolateTime: time.Unix(55, 0),
expRecord: newExpRecord(oneDec.Add(OneSec.MulInt64(44*10)), twoDec.Add(OneSec.MulInt64(44).QuoInt64(10))),
},
"same time": {
Copy link
Member

Choose a reason for hiding this comment

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

What happens if newTime is before record time by mistake so the timeDelta is negative? How is this handled by the core logic? Is there a test covering this?

Copy link
Member Author

@ValarDragon ValarDragon Aug 5, 2022

Choose a reason for hiding this comment

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

Hrmm, there isn't a test handling it because its incorrect behavior. (Breaks the precondition on the function - thats the responsibility of the caller) But you should still get the same result. This is because TWAP is:

(accumEnd - accumStart) / (timeEnd - timeStart)

So if you reverse the arguments, you compute

(accumStart - accumEnd) / (timeStart - timeEnd)
= -(accumEnd - accumStart) / - (timeEnd - timeStart)
= (accumEnd - accumStart) / (timeEnd - timeStart)

Thus the function is argument order independent.

This is for the same reason that you can don't care about the order of points when trying to compute the slope of a line.

Copy link
Member

@p0mvn p0mvn Aug 5, 2022

Choose a reason for hiding this comment

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

That makes sense, thanks for explaining. I think it still makes to add a test even if we expect that to not happen and be incorrect. We should aim to have test cases relative to all possible inputs of a function even though some might be invalid when looking at the system holistically

@ValarDragon
Copy link
Member Author

ValarDragon commented Aug 5, 2022

TODO: overflow tests are mentally kept track of, as items that need to be addressed in a subsequent overflow handling issue & PR.

Those are not the responsibility of this PR to address imo

Copy link
Member

@p0mvn p0mvn left a comment

Choose a reason for hiding this comment

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

LGTM. Great work!

One last thing I would like to bump is discussed here:
#2168 (comment)

x/gamm/twap/logic.go Show resolved Hide resolved
sdk "github.com/cosmos/cosmos-sdk/types"

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

func (k Keeper) MigrateExistingPools(ctx sdk.Context, poolIds []uint64) error {
Copy link
Member

Choose a reason for hiding this comment

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

We agreed to leaves as is offline - I guess we can discuss this in a separate issue later

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

// TestCreatePoolFlow tests that upon a pool being created,
Copy link
Member

Choose a reason for hiding this comment

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

I will make a separate issue for this to discuss further

@ValarDragon
Copy link
Member Author

Added that test! Planning to merge upon test pass, to unblock other fronts

@ValarDragon ValarDragon merged commit 8cc17f7 into main Aug 5, 2022
@ValarDragon ValarDragon deleted the dev/twap_wip branch August 5, 2022 19:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C:app-wiring Changes to the app folder C:x/gamm Changes, features and bugs related to the gamm module.
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

5 participants