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

Custom CosmWasm Integration #1135

Merged
merged 38 commits into from
Mar 31, 2022
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
e0328b2
Rename wasmtest/ to wasm/
maurolacy Mar 11, 2022
2d3bb29
Wasm queries and message types
maurolacy Mar 11, 2022
042e6de
Use uint64 for pool id
maurolacy Mar 11, 2022
91d75c5
Use sdk.Int for Uint128
maurolacy Mar 11, 2022
c6ed0f9
Update / integrate README
maurolacy Mar 11, 2022
d315407
Rename package to wasm
maurolacy Mar 13, 2022
c15dcee
Add basic wasm types tests
maurolacy Mar 13, 2022
1353907
Add query response types
Mar 14, 2022
4f6cf0d
Rename test packages to wasm as well
Mar 14, 2022
3116a19
Custom query handler (#2)
maurolacy Mar 15, 2022
56bb64b
Test custom queries with Osmo_reflect contract (#3)
ethanfrey Mar 16, 2022
904e96c
Wasm custom messages (#5)
ethanfrey Mar 17, 2022
20d4c7f
Custom queries (#4)
maurolacy Mar 17, 2022
d1a0399
Custom queries #2 (#6)
maurolacy Mar 17, 2022
ac9b93a
Add JSON unmarshalling tests / formats (#7)
maurolacy Mar 17, 2022
2a21647
Refactor GetFullDenom
Mar 17, 2022
797f559
Return string by value
Mar 17, 2022
e1ea3a6
Use contract addr instead of user addr in full denom test
Mar 17, 2022
00b5070
Mint token message (#8)
ethanfrey Mar 20, 2022
e54749c
Estimate price tests (#9)
maurolacy Mar 21, 2022
6b354dd
Refactor estimate swap (#11)
ethanfrey Mar 22, 2022
825d67b
Multi hop support (#12)
ethanfrey Mar 22, 2022
61cfb64
Custom queries unit tests (#10)
maurolacy Mar 22, 2022
37830f1
Add subdenom verification (#13)
ethanfrey Mar 22, 2022
8586062
Custom messages unit tests (#14)
maurolacy Mar 23, 2022
12627c1
Rename `EstimatePrice` to `EstimateSwap` (#15)
maurolacy Mar 23, 2022
4ed654b
Add multi-hop swap unit test (#16)
maurolacy Mar 23, 2022
ada0b18
Merge branch 'main' into wasm-integration-2
ethanfrey Mar 23, 2022
c4464e2
Update to new gamm apis
ethanfrey Mar 23, 2022
02cdd8c
go fmt
ethanfrey Mar 23, 2022
e6c6000
Merge types/ into bindings/
ethanfrey Mar 23, 2022
17a32d9
Merge branch 'main' into wasm-integration-2
ethanfrey Mar 29, 2022
3391ca9
Fix compile errors after merge
ethanfrey Mar 29, 2022
15804aa
Fix linting issue
ethanfrey Mar 29, 2022
fe90366
Update osmo reflect to v0.5.0
ethanfrey Mar 29, 2022
471b92c
Removed all mint token messages and queries
ethanfrey Mar 29, 2022
98cf636
Rename local variable
ethanfrey Mar 29, 2022
6a47da2
Merge branch 'main' into wasm-integration-2
ethanfrey Mar 31, 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
3 changes: 1 addition & 2 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,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 All @@ -188,7 +188,6 @@ func NewOsmosisApp(
wasmOpts []wasm.Option,
baseAppOptions ...func(*baseapp.BaseApp),
) *OsmosisApp {

appCodec := encodingConfig.Marshaler
cdc := encodingConfig.Amino
interfaceRegistry := encodingConfig.InterfaceRegistry
Expand Down
7 changes: 6 additions & 1 deletion app/keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ import (
bech32ibckeeper "github.com/osmosis-labs/bech32-ibc/x/bech32ibc/keeper"
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"
)

type appKeepers struct {
Expand Down Expand Up @@ -367,7 +369,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"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We add the extra feature here, so contract including osmo-bindings are supported here.


wasmOpts = append(owasm.RegisterCustomPlugins(app.GAMMKeeper, app.BankKeeper), wasmOpts...)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

And here we register the custom plugins to handle those messages


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.
25 changes: 25 additions & 0 deletions app/wasm/bindings/msg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package wasmbindings

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

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
}
Comment on lines +5 to +8
Copy link
Member

Choose a reason for hiding this comment

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

As part of the refactor, we're trying to convert a lot of instances of PoolAssets in the code / other modules, to be PoolLiquidity. We should probably revisit this wasm binding pre-release

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can gladly rename everything. Changing the type I easy and this is only used when querying the gamm, so please do suggest new names.

We use the Rust definitions as the canonical source for all types that hit the contract boundary, and this is more permanent (breaking API changes), so maybe you can double-check we use the proper names there first. Types that are only used within this package can easily be renamed by anyone

Copy link
Member

Choose a reason for hiding this comment

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

Awesome! Will review those in more depth then

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"`
Copy link
Member

Choose a reason for hiding this comment

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

Should we rename these types to have a Query suffix?

Copy link
Contributor

Choose a reason for hiding this comment

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

Is that the norm across the project? If not, I would leave it as it is.

Copy link
Member

Choose a reason for hiding this comment

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

That is the norm for all of the golang queries, I don't know whats the norm for the cosmwasm side

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We typically label them the same name as the field.

Again, as long as the json stays the same, you can gladly rename the types as you wish in another PR.
These are for use inside the osmosis Golang code, so it should be whatever idiom looks good to you.

/// 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 {
Contract string `json:"contract"`
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