Skip to content

Commit

Permalink
Custom CosmWasm Integration (#1135)
Browse files Browse the repository at this point in the history
* Rename wasmtest/ to wasm/

* Wasm queries and message types

* Use uint64 for pool id

* Use sdk.Int for Uint128

* Update / integrate README

* Rename package to wasm

* Add basic wasm types tests

* Add query response types

* Rename test packages to wasm as well

* Custom query handler (#2)

* Add custom querier for osmosis wasm queries

* Move tests to own dir to avoid cyclic deps

* Rename wasm keeper to (custom) query plugin

* Use helpers to convert from sdk to wasm coins

* Test custom queries with Osmo_reflect contract (#3)

* Add osmo_reflect contract

* Start test setup for custom queries

* Fix tests

* Complete initial query test

* Rename bindings package to bindings

* Test creating and querying 2 pools

* Rename package to wasmbindings

* Download wasm uses osmo-bindings version

* Wasm custom messages (#5)

* Add placeholder for message handler

* Implement SwapMsg encoder

* First table test for swapping message

* Cover basic ExactIn cases

* Test ExactOut swaps as well

* Update error message

Co-authored-by: Mauro Lacy <[email protected]>

* Custom queries (#4)

* Add spot price query

* Rename keeper.go to queries.go

* Add estimate price query

* Remove needless ViewKeeper interface

* GetSpotPrice refactor

* EstimatePrice refactor

* Better EstimatePrice error message

* Add TODO for multi-hop swap price estimation

* Add SpotPrice happy path integration test

* Remove FIXMEs

* Add json field names

* Custom queries #2 (#6)

* Update reflect contract to v0.3.0

* Adapt to bindings v0.3.0

* Add full denom query

* Add happy path full denom integ test

* Update to v0.3.0 proper (release)

* Add JSON unmarshalling tests / formats (#7)

* Refactor GetFullDenom

Add validation helpers

* Return string by value

* Use contract addr instead of user addr in full denom test

* Mint token message (#8)

* Convert messenge encoder to message decorator

* Implement and Test mint token message

* Add TODOs for future refactoring

* Update app/wasm/message_plugin.go

Co-authored-by: Mauro Lacy <[email protected]>

Co-authored-by: Mauro Lacy <[email protected]>

* Estimate price tests (#9)

* Fix: sender address format

* Add estimate price integration tests

* Remove FIXME

* Improve estimate swap rate integ tests

* Refactor estimate swap (#11)

* Add type conversions

* Refactor EstimatePrice to use same logic as SwapMsg

* Multi hop support (#12)

* Add exact in multi-hop tests

* Tests pass multi-hop exact in

* Add failing tests for ExactOut

* FImplement ExactOut multi-hop swaps

* Remove two outdated TODO comments

* Remove obsolete comments

* Custom queries unit tests (#10)

* Add full denom unit tests

* Add get pool state unit tests

* Add get spot price unit tests

* Add estimate price extra checks

* Add estimate price unit tests

* Add tests for zero and negative amounts

* Fix: null spot price

* Fix: Avoid panic on negative amounts

Fix rebase errors / missing null checks

* Fix rebase errors

Add negative amount checks

* Add subdenom verification (#13)

* Add subdenom verification

* Remove TODO

* Custom messages unit tests (#14)

* Fix: swap tokens error handling

* Rename messenger to CustomMessenger

* Add perform swap unit tests

* Fix: perform swap null swap check

* Add PerformMint function

* Add perform mint unit tests

* Fixes: perform mint null mint check

Mint negative amount

* Rename `EstimatePrice` to `EstimateSwap` (#15)

* Fix: swap tokens error handling

* Rename messenger to CustomMessenger

* Add perform swap unit tests

* Fix: perform swap null swap check

* Add PerformMint function

* Add perform mint unit tests

* Fixes: perform mint null mint check

Mint negative amount

* Update test contract to v0.4.0

* Rename EstimatePrice binding to EstimateSwap

* Rename EstimatePrice custom query to EstimateSwap

* Adapt test to EstimatePrice to EstimateSwap renaming

* Add multi-hop swap unit test (#16)

* Add multi-hop swap unit test

* Adjust input amount, min output

Add slippage factor

* Add more multi-hop unit tests

* Improve estimates in multi-hop tests

* Test that self-swap is disallowed

Co-authored-by: Ethan Frey <[email protected]>

* Update to new gamm apis

* go fmt

* Merge types/ into bindings/

* Fix compile errors after merge

* Fix linting issue

* Update osmo reflect to v0.5.0

* Removed all mint token messages and queries

* Rename local variable

Co-authored-by: Mauro Lacy <[email protected]>
Co-authored-by: Mauro Lacy <[email protected]>
Co-authored-by: Mauro Lacy <[email protected]>
  • Loading branch information
4 people authored Mar 31, 2022
1 parent f54dfd0 commit 12630b8
Show file tree
Hide file tree
Showing 27 changed files with 2,661 additions and 15 deletions.
2 changes: 1 addition & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ func init() {
DefaultNodeHome = filepath.Join(userHomeDir, ".osmosisd")
}

// NewOsmosis returns a reference to an initialized Osmosis.
// NewOsmosisApp returns a reference to an initialized Osmosis.
func NewOsmosisApp(
logger log.Logger,
db dbm.DB,
Expand Down
6 changes: 5 additions & 1 deletion app/keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import (
bech32ibctypes "github.com/osmosis-labs/bech32-ibc/x/bech32ibc/types"
bech32ics20keeper "github.com/osmosis-labs/bech32-ibc/x/bech32ics20/keeper"

owasm "github.com/osmosis-labs/osmosis/v7/app/wasm"
_ "github.com/osmosis-labs/osmosis/v7/client/docs/statik"
claimkeeper "github.com/osmosis-labs/osmosis/v7/x/claim/keeper"
claimtypes "github.com/osmosis-labs/osmosis/v7/x/claim/types"
Expand Down Expand Up @@ -346,7 +347,10 @@ func (app *OsmosisApp) InitNormalKeepers(

// The last arguments can contain custom message handlers, and custom query handlers,
// if we want to allow any custom callbacks
supportedFeatures := "iterator,staking,stargate"
supportedFeatures := "iterator,staking,stargate,osmosis"

wasmOpts = append(owasm.RegisterCustomPlugins(app.GAMMKeeper, app.BankKeeper), wasmOpts...)

wasmKeeper := wasm.NewKeeper(
appCodec,
keys[wasm.StoreKey],
Expand Down
34 changes: 34 additions & 0 deletions app/wasm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# CosmWasm support

This package contains CosmWasm integration points.

This package provides first class support for:

* Queries
* Denoms
* Pools
* Prices
* Messages / Execution
* Mint
* Swap

### Command line interface (CLI)

* Commands

```sh
osmosisd tx wasm -h
```

* Query

```sh
osmosisd query wasm -h
```

### Tests

This contains a few high level tests that `x/wasm` is properly integrated.

Since the code tested is not in this repo, and we are just testing the application
integration (app.go), I figured this is the most suitable location for it.
23 changes: 23 additions & 0 deletions app/wasm/bindings/msg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package wasmbindings

type OsmosisMsg struct {
// /// Contracts can mint native tokens that have an auto-generated denom
// /// namespaced under the contract's address. A contract may create any number
// /// of independent sub-denoms.
// MintTokens *MintTokens `json:"mint_tokens,omitempty"`
/// Swap over one or more pools
Swap *SwapMsg `json:"swap,omitempty"`
}

// type MintTokens struct {
// /// Must be 2-32 alphanumeric characters
// SubDenom string `json:"sub_denom"`
// Amount sdk.Int `json:"amount"`
// Recipient string `json:"recipient"`
// }

type SwapMsg struct {
First Swap `json:"first"`
Route []Step `json:"route"`
Amount SwapAmountWithLimit `json:"amount"`
}
8 changes: 8 additions & 0 deletions app/wasm/bindings/pool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package wasmbindings

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

type PoolAssets struct {
Assets []sdk.Coin
Shares sdk.Coin
}
73 changes: 73 additions & 0 deletions app/wasm/bindings/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package wasmbindings

import (
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
)

// OsmosisQuery contains osmosis custom queries.
// See https://github.com/confio/osmosis-bindings/blob/main/packages/bindings/src/query.rs
type OsmosisQuery struct {
// /// Given a subdenom minted by a contract via `OsmosisMsg::MintTokens`,
// /// returns the full denom as used by `BankMsg::Send`.
// FullDenom *FullDenom `json:"full_denom,omitempty"`
/// For a given pool ID, list all tokens traded on it with current liquidity (spot).
/// As well as the total number of LP shares and their denom.
PoolState *PoolState `json:"pool_state,omitempty"`
/// Return current spot price swapping In for Out on given pool ID.
/// Warning: this can easily be manipulated via sandwich attacks, do not use as price oracle.
/// We will add TWAP for more robust price feed.
SpotPrice *SpotPrice `json:"spot_price,omitempty"`
/// Return current spot price swapping In for Out on given pool ID.
EstimateSwap *EstimateSwap `json:"estimate_swap,omitempty"`
}

// type FullDenom struct {
// Contract string `json:"contract"`
// SubDenom string `json:"sub_denom"`
// }

type PoolState struct {
PoolId uint64 `json:"id"`
}

type SpotPrice struct {
Swap Swap `json:"swap"`
WithSwapFee bool `json:"with_swap_fee"`
}

type EstimateSwap struct {
Sender string `json:"sender"`
First Swap `json:"first"`
Route []Step `json:"route"`
Amount SwapAmount `json:"amount"`
}

func (e *EstimateSwap) ToSwapMsg() *SwapMsg {
return &SwapMsg{
First: e.First,
Route: e.Route,
Amount: e.Amount.Unlimited(),
}
}

// type FullDenomResponse struct {
// Denom string `json:"denom"`
// }

type PoolStateResponse struct {
/// The various assets that be swapped. Including current liquidity.
Assets []wasmvmtypes.Coin `json:"assets"`
/// The number of LP shares and their amount
Shares wasmvmtypes.Coin `json:"shares"`
}

type SpotPriceResponse struct {
/// How many output we would get for 1 input
Price string `json:"price"`
}

type EstimatePriceResponse struct {
// If you query with SwapAmount::Input, this is SwapAmount::Output.
// If you query with SwapAmount::Output, this is SwapAmount::Input.
Amount SwapAmount `json:"swap_amount"`
}
74 changes: 74 additions & 0 deletions app/wasm/bindings/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package wasmbindings

import (
"math"

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

type Swap struct {
PoolId uint64 `json:"pool_id"`
DenomIn string `json:"denom_in"`
DenomOut string `json:"denom_out"`
}

type Step struct {
PoolId uint64 `json:"pool_id"`
DenomOut string `json:"denom_out"`
}

type SwapAmount struct {
In *sdk.Int `json:"in,omitempty"`
Out *sdk.Int `json:"out,omitempty"`
}

// This returns SwapAmountWithLimit with the largest possible limits (that will never be hit)
func (s SwapAmount) Unlimited() SwapAmountWithLimit {
if s.In != nil {
return SwapAmountWithLimit{
ExactIn: &ExactIn{
Input: *s.In,
MinOutput: sdk.NewInt(1),
},
}
}
if s.Out != nil {
return SwapAmountWithLimit{
ExactOut: &ExactOut{
Output: *s.Out,
MaxInput: sdk.NewInt(math.MaxInt64),
},
}
}
panic("Must define In or Out")
}

type SwapAmountWithLimit struct {
ExactIn *ExactIn `json:"exact_in,omitempty"`
ExactOut *ExactOut `json:"exact_out,omitempty"`
}

// This returns the amount without min/max to use as simpler argument
func (s SwapAmountWithLimit) RemoveLimit() SwapAmount {
if s.ExactIn != nil {
return SwapAmount{
In: &s.ExactIn.Input,
}
}
if s.ExactOut != nil {
return SwapAmount{
Out: &s.ExactOut.Output,
}
}
panic("Must define ExactIn or ExactOut")
}

type ExactIn struct {
Input sdk.Int `json:"input"`
MinOutput sdk.Int `json:"min_output"`
}

type ExactOut struct {
MaxInput sdk.Int `json:"max_input"`
Output sdk.Int `json:"output"`
}
Loading

0 comments on commit 12630b8

Please sign in to comment.