Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 2 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"

appparams "github.com/sei-protocol/sei-chain/app/params"
"github.com/sei-protocol/sei-chain/wasmbinding"

"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
Expand Down Expand Up @@ -455,6 +456,7 @@ func New(
// The last arguments can contain custom message handlers, and custom query handlers,
// if we want to allow any custom callbacks
supportedFeatures := "iterator,staking,stargate"
wasmOpts = append(wasmbinding.RegisterCustomPlugins(&app.OracleKeeper), wasmOpts...)
Copy link
Collaborator

Choose a reason for hiding this comment

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

we can set wasmopts here https://github.com/sei-protocol/sei-chain/blob/master/cmd/seid/cmd/root.go#L233 just in case some future logics in New need to make use of wasmOpts but happens before this line

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think we can do that there because we need to already have an OracleKeeper for this option to be added, and the keepers are all initialized in New() not in root, 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.

@codchen wdyt?

Copy link
Collaborator

Choose a reason for hiding this comment

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

oh yeah you're right

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

This package contains CosmWasm integration points.

This package provides first class support for:

- Queries
- OracleExchangeRates
- Messages / Execution
- N/A
44 changes: 44 additions & 0 deletions wasmbinding/queries.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package wasmbinding

import (
"encoding/json"

wasmvmtypes "github.com/CosmWasm/wasmvm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
oraclewasm "github.com/sei-protocol/sei-chain/x/oracle/client/wasm"
oraclebindings "github.com/sei-protocol/sei-chain/x/oracle/client/wasm/bindings"
)

type QueryPlugin struct {
oracleHandler oraclewasm.OracleWasmQueryHandler
}

// NewQueryPlugin returns a reference to a new QueryPlugin.
func NewQueryPlugin(oh *oraclewasm.OracleWasmQueryHandler) *QueryPlugin {
return &QueryPlugin{
oracleHandler: *oh,
}
}

func (qp QueryPlugin) HandleOracleQuery(ctx sdk.Context, queryData json.RawMessage) ([]byte, error) {
var parsedQuery oraclebindings.SeiOracleQuery
if err := json.Unmarshal(queryData, &parsedQuery); err != nil {
return nil, sdkerrors.Wrap(err, "Error parsing SeiOracleQuery")
}
switch {
case parsedQuery.ExchangeRates != nil:
res, err := qp.oracleHandler.GetExchangeRates(ctx)
if err != nil {
return nil, sdkerrors.Wrap(err, "Error while Exchange Rates")
}
bz, err := json.Marshal(res)
if err != nil {
return nil, sdkerrors.Wrap(err, "Error encoding exchange rates as JSON")
}

return bz, nil
default:
return nil, wasmvmtypes.UnsupportedRequest{Kind: "Unknown Sei Oracle Query"}
}
}
55 changes: 55 additions & 0 deletions wasmbinding/query_plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package wasmbinding

import (
"encoding/json"

wasmvmtypes "github.com/CosmWasm/wasmvm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)

const (
OracleRoute = "oracle"
)

type SeiQueryWrapper struct {
// specifies which module handler should handle the query
Route string `json:"route,omitempty"`
// The query data that should be parsed into the module query
QueryData json.RawMessage `json:"query_data,omitempty"`
}

func CustomQuerier(qp *QueryPlugin) func(ctx sdk.Context, request json.RawMessage) ([]byte, error) {
return func(ctx sdk.Context, request json.RawMessage) ([]byte, error) {
var contractQuery SeiQueryWrapper
if err := json.Unmarshal(request, &contractQuery); err != nil {
return nil, sdkerrors.Wrap(err, "Error parsing request data")
}
switch contractQuery.Route {
case OracleRoute:
return qp.HandleOracleQuery(ctx, contractQuery.QueryData)
default:
return nil, wasmvmtypes.UnsupportedRequest{Kind: "Unknown Sei Query Route"}
}
}
}

// TODO: do we need this stuff from osmosis implementation? maybe remove
// ConvertSdkCoinsToWasmCoins converts sdk type coins to wasm vm type coins
func ConvertSdkCoinsToWasmCoins(coins []sdk.Coin) wasmvmtypes.Coins {
var toSend wasmvmtypes.Coins
for _, coin := range coins {
c := ConvertSdkCoinToWasmCoin(coin)
toSend = append(toSend, c)
}
return toSend
}

// ConvertSdkCoinToWasmCoin converts a sdk type coin to a wasm vm type coin
func ConvertSdkCoinToWasmCoin(coin sdk.Coin) wasmvmtypes.Coin {
return wasmvmtypes.Coin{
Denom: coin.Denom,
// Note: gamm tokens have 18 decimal places, so 10^22 is common, no longer in u64 range
Amount: coin.Amount.String(),
}
}
55 changes: 55 additions & 0 deletions wasmbinding/test/query_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package wasmbinding

import (
"encoding/json"
"testing"
"time"

"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/sei-protocol/sei-chain/app"
"github.com/sei-protocol/sei-chain/wasmbinding"
oraclewasm "github.com/sei-protocol/sei-chain/x/oracle/client/wasm"
oraclebinding "github.com/sei-protocol/sei-chain/x/oracle/client/wasm/bindings"
oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types"
oracleutils "github.com/sei-protocol/sei-chain/x/oracle/utils"
"github.com/stretchr/testify/require"
)

func TestWasmGetOracleExchangeRates(t *testing.T) {
tm := time.Now().UTC()
valPub := secp256k1.GenPrivKey().PubKey()

testWrapper := app.NewTestWrapper(t, tm, valPub)

req := oraclebinding.SeiOracleQuery{ExchangeRates: &oraclebinding.WasmQueryExchangeRatesRequest{}}
queryData, err := json.Marshal(req)
require.NoError(t, err)
query := wasmbinding.SeiQueryWrapper{Route: "oracle", QueryData: queryData}

oh := oraclewasm.NewOracleWasmQueryHandler(&testWrapper.App.OracleKeeper)
qp := wasmbinding.NewQueryPlugin(oh)
customQuerier := wasmbinding.CustomQuerier(qp)

rawQuery, err := json.Marshal(query)
require.NoError(t, err)

res, err := customQuerier(testWrapper.Ctx, rawQuery)
require.NoError(t, err)

var parsedRes oraclebinding.WasmQueryExchangeRatesResponse
err = json.Unmarshal(res, &parsedRes)
require.NoError(t, err)
require.Equal(t, oraclebinding.WasmQueryExchangeRatesResponse{DenomOracleExchangeRatePairs: oracletypes.DenomOracleExchangeRatePairs(nil)}, parsedRes)

testWrapper.Ctx = testWrapper.Ctx.WithBlockHeight(11)
testWrapper.App.OracleKeeper.SetBaseExchangeRate(testWrapper.Ctx, oracleutils.MicroAtomDenom, sdk.NewDec(12))

res, err = customQuerier(testWrapper.Ctx, rawQuery)
require.NoError(t, err)

var parsedRes2 oraclebinding.WasmQueryExchangeRatesResponse
err = json.Unmarshal(res, &parsedRes2)
require.NoError(t, err)
require.Equal(t, oraclebinding.WasmQueryExchangeRatesResponse{DenomOracleExchangeRatePairs: oracletypes.DenomOracleExchangeRatePairs{oracletypes.NewDenomOracleExchangeRatePair(oracleutils.MicroAtomDenom, sdk.NewDec(12), sdk.NewInt(11))}}, parsedRes2)
}
23 changes: 23 additions & 0 deletions wasmbinding/wasm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package wasmbinding

import (
"github.com/CosmWasm/wasmd/x/wasm"
wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
oraclewasm "github.com/sei-protocol/sei-chain/x/oracle/client/wasm"
oraclekeeper "github.com/sei-protocol/sei-chain/x/oracle/keeper"
)

func RegisterCustomPlugins(
oracle *oraclekeeper.Keeper,
) []wasmkeeper.Option {
oracleHandler := oraclewasm.NewOracleWasmQueryHandler(oracle)
wasmQueryPlugin := NewQueryPlugin(oracleHandler)

queryPluginOpt := wasmkeeper.WithQueryPlugins(&wasmkeeper.QueryPlugins{
Custom: CustomQuerier(wasmQueryPlugin),
})

return []wasm.Option{
queryPluginOpt,
}
}
15 changes: 15 additions & 0 deletions x/oracle/client/wasm/bindings/queries.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package bindings

import "github.com/sei-protocol/sei-chain/x/oracle/types"

type SeiOracleQuery struct {
// queries the oracle exchange rates
ExchangeRates *WasmQueryExchangeRatesRequest `json:"exchange_rates,omitempty"`
}

type WasmQueryExchangeRatesRequest struct{}

type WasmQueryExchangeRatesResponse struct {
DenomOracleExchangeRatePairs types.DenomOracleExchangeRatePairs `json:"denom_oracle_exchange_rate_pairs,omitempty"`
// DenomOracleExchangeRatePairs []WasmQueryDenomOracleExchangeRate `json:"denom_oracle_exchange_rate_pairs,omitempty"`
}
23 changes: 23 additions & 0 deletions x/oracle/client/wasm/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package wasm

import (
sdk "github.com/cosmos/cosmos-sdk/types"
oraclekeeper "github.com/sei-protocol/sei-chain/x/oracle/keeper"
"github.com/sei-protocol/sei-chain/x/oracle/types"
)

type OracleWasmQueryHandler struct {
oracleKeeper oraclekeeper.Keeper
}

func NewOracleWasmQueryHandler(keeper *oraclekeeper.Keeper) *OracleWasmQueryHandler {
return &OracleWasmQueryHandler{
oracleKeeper: *keeper,
}
}

func (handler OracleWasmQueryHandler) GetExchangeRates(ctx sdk.Context) (*types.QueryExchangeRatesResponse, error) {
querier := oraclekeeper.NewQuerier(handler.oracleKeeper)
c := sdk.WrapSDKContext(ctx)
return querier.ExchangeRates(c, &types.QueryExchangeRatesRequest{})
}