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

[Feature] contract info query wasm interface #520

Merged
merged 3 commits into from
Jul 28, 2021
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
37 changes: 37 additions & 0 deletions x/wasm/keeper/custom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ type bindingsTesterTaxCapQueryMsg struct {
type bindingsTesterExchangeRatesQueryMsg struct {
ExchangeRates exchangeRatesQueryMsg `json:"exchange_rates"`
}
type bindingsTesterContractInfoQuerymsg struct {
ContractInfo contractInfoQueryMsg `json:"contract_info"`
}
type swapQueryMsg struct {
OfferCoin wasmvmtypes.Coin `json:"offer_coin"`
AskDenom string `json:"ask_denom"`
Expand All @@ -100,6 +103,9 @@ type exchangeRatesQueryMsg struct {
BaseDenom string `json:"base_denom"`
QuoteDenoms []string `json:"quote_denoms"`
}
type contractInfoQueryMsg struct {
ContractAddress string `json:"contract_address"`
}

func TestInstantiateMaker(t *testing.T) {
input := CreateTestInput(t)
Expand Down Expand Up @@ -240,6 +246,37 @@ func TestExchangeRatesQuerier(t *testing.T) {
require.Equal(t, KRWExchangeRate, exchangeRateDec)
}

func TestContractInfoQuerier(t *testing.T) {
input, _, testerAddr, _ := setupBindingsTesterContract(t)

ctx, keeper := input.Ctx, input.WasmKeeper

contractInfoQueryMsg := bindingsTesterContractInfoQuerymsg{
ContractInfo: contractInfoQueryMsg{
ContractAddress: testerAddr.String(),
},
}

bz, err := json.Marshal(contractInfoQueryMsg)
require.NoError(t, err)

res, err := keeper.queryToContract(ctx, testerAddr, bz)
require.NoError(t, err)

var contractInfoResponse ContractInfoQueryResponse
err = json.Unmarshal(res, &contractInfoResponse)
require.NoError(t, err)

contractInfo, err := keeper.GetContractInfo(ctx, testerAddr)
require.NoError(t, err)
require.Equal(t, contractInfoResponse, ContractInfoQueryResponse{
CodeID: contractInfo.CodeID,
Address: contractInfo.Address,
Creator: contractInfo.Creator,
Admin: contractInfo.Admin,
})
}

func TestBuyMsg(t *testing.T) {
input, creatorAddr, makerAddr, offerCoin := setupMakerContract(t)

Expand Down
Binary file modified x/wasm/keeper/testdata/bindings_tester.wasm
Binary file not shown.
54 changes: 52 additions & 2 deletions x/wasm/keeper/wasm_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,57 @@ func (querier WasmQuerier) Query(ctx sdk.Context, request wasmvmtypes.QueryReque
return nil, wasmvmtypes.UnsupportedRequest{Kind: "unknown WasmQuery variant"}
}

// ContractInfoQueryParams query request params for contract info
type ContractInfoQueryParams struct {
ContractAddress string `json:"contract_address"`
}

// CosmosQuery custom query interface for oracle querier
type CosmosQuery struct {
ContractInfo *ContractInfoQueryParams `json:"contract_info,omitempty"`
}

// ContractInfoQueryResponse - exchange rates query response for wasm module
type ContractInfoQueryResponse struct {
Address string `json:"address"`
Creator string `json:"creator"`
Admin string `json:"admin,omitempty"`
CodeID uint64 `json:"code_id"`
}

// QueryCustom implements custom query interface
func (WasmQuerier) QueryCustom(ctx sdk.Context, data json.RawMessage) ([]byte, error) {
return nil, nil
func (querier WasmQuerier) QueryCustom(ctx sdk.Context, data json.RawMessage) ([]byte, error) {
var params CosmosQuery
err := json.Unmarshal(data, &params)

if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
}

if params.ContractInfo != nil {
contractAddress, err := sdk.AccAddressFromBech32(params.ContractInfo.ContractAddress)
if err != nil {
return nil, err
}

contractInfo, err := querier.keeper.GetContractInfo(ctx, contractAddress)
if err != nil {
return nil, err
}

bz, err := json.Marshal(ContractInfoQueryResponse{
Address: contractInfo.Address,
Creator: contractInfo.Creator,
Admin: contractInfo.Admin,
CodeID: contractInfo.CodeID,
})

if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}

return bz, nil
}

return nil, wasmvmtypes.UnsupportedRequest{Kind: "unknown Wasm variant"}
}
238 changes: 238 additions & 0 deletions x/wasm/keeper/wasm_interface_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
package keeper

import (
"encoding/json"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/secp256k1"

wasmvmtypes "github.com/CosmWasm/wasmvm/types"

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

core "github.com/terra-money/core/types"
"github.com/terra-money/core/x/wasm/types"
)

func TestEcoding(t *testing.T) {
pubKeys := []crypto.PubKey{
secp256k1.GenPrivKey().PubKey(),
secp256k1.GenPrivKey().PubKey(),
secp256k1.GenPrivKey().PubKey(),
}

addrs := []sdk.AccAddress{
sdk.AccAddress(pubKeys[0].Address()),
sdk.AccAddress(pubKeys[1].Address()),
sdk.AccAddress(pubKeys[2].Address()),
}

invalidAddr := "xrnd1d02kd90n38qvr3qb9qof83fn2d2"
cases := map[string]struct {
sender sdk.AccAddress
input wasmvmtypes.CosmosMsg
// set if valid
output sdk.Msg
// set if invalid
isError bool
}{
"simple execute": {
sender: addrs[0],
input: wasmvmtypes.CosmosMsg{
Wasm: &wasmvmtypes.WasmMsg{
Execute: &wasmvmtypes.ExecuteMsg{
ContractAddr: addrs[1].String(),
Msg: []byte("{}"),
Funds: wasmvmtypes.Coins{wasmvmtypes.NewCoin(1234, core.MicroLunaDenom)},
},
},
},
output: &types.MsgExecuteContract{
Sender: addrs[0].String(),
Contract: addrs[1].String(),
Coins: sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 1234)),
ExecuteMsg: []byte("{}"),
},
},
"simple instantiate without admin": {
sender: addrs[0],
input: wasmvmtypes.CosmosMsg{
Wasm: &wasmvmtypes.WasmMsg{
Instantiate: &wasmvmtypes.InstantiateMsg{
CodeID: 1,
Msg: []byte("{}"),
Funds: wasmvmtypes.Coins{wasmvmtypes.NewCoin(1234, core.MicroLunaDenom)},
},
},
},
output: &types.MsgInstantiateContract{
Sender: addrs[0].String(),
CodeID: 1,
InitCoins: sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 1234)),
InitMsg: []byte("{}"),
},
},
"simple instantiate with admin": {
sender: addrs[0],
input: wasmvmtypes.CosmosMsg{
Wasm: &wasmvmtypes.WasmMsg{
Instantiate: &wasmvmtypes.InstantiateMsg{
CodeID: 1,
Msg: []byte("{}"),
Funds: wasmvmtypes.Coins{wasmvmtypes.NewCoin(1234, core.MicroLunaDenom)},
Admin: addrs[0].String(),
},
},
},
output: &types.MsgInstantiateContract{
Sender: addrs[0].String(),
CodeID: 1,
InitCoins: sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 1234)),
InitMsg: []byte("{}"),
Admin: addrs[0].String(),
},
},
"simple migrate": {
sender: addrs[0],
input: wasmvmtypes.CosmosMsg{
Wasm: &wasmvmtypes.WasmMsg{
Migrate: &wasmvmtypes.MigrateMsg{
ContractAddr: addrs[1].String(),
Msg: []byte("{}"),
NewCodeID: 1,
},
},
},
output: &types.MsgMigrateContract{
Admin: addrs[0].String(),
NewCodeID: 1,
Contract: addrs[1].String(),
MigrateMsg: []byte("{}"),
},
},
"simple update admin": {
sender: addrs[0],
input: wasmvmtypes.CosmosMsg{
Wasm: &wasmvmtypes.WasmMsg{
UpdateAdmin: &wasmvmtypes.UpdateAdminMsg{
ContractAddr: addrs[1].String(),
Admin: addrs[2].String(),
},
},
},
output: &types.MsgUpdateContractAdmin{
Admin: addrs[0].String(),
Contract: addrs[1].String(),
NewAdmin: addrs[2].String(),
},
},
"simple clear admin": {
sender: addrs[0],
input: wasmvmtypes.CosmosMsg{
Wasm: &wasmvmtypes.WasmMsg{
ClearAdmin: &wasmvmtypes.ClearAdminMsg{
ContractAddr: addrs[1].String(),
},
},
},
output: &types.MsgClearContractAdmin{
Admin: addrs[0].String(),
Contract: addrs[1].String(),
},
},
"invalid address execute": {
sender: addrs[0],
input: wasmvmtypes.CosmosMsg{
Wasm: &wasmvmtypes.WasmMsg{
Execute: &wasmvmtypes.ExecuteMsg{
ContractAddr: invalidAddr,
Msg: []byte("{}"),
Funds: wasmvmtypes.Coins{wasmvmtypes.NewCoin(1234, core.MicroLunaDenom)},
},
},
},
isError: true,
},
}

parser := NewWasmMsgParser()
for name, tc := range cases {
tc := tc
t.Run(name, func(t *testing.T) {
res, err := parser.Parse(tc.sender, tc.input)
if tc.isError {
require.Error(t, err)
} else {
require.NoError(t, err)
assert.Equal(t, tc.output, res)
}
})
}
}

func TestQueryRaw(t *testing.T) {
input := CreateTestInput(t)

input.WasmKeeper.SetContractStore(input.Ctx, Addrs[0], []types.Model{
{
Key: []byte("key1"),
Value: []byte("value1"),
},
{
Key: []byte("key2"),
Value: []byte("value2"),
},
{
Key: []byte("key3"),
Value: []byte("value3"),
},
{
Key: []byte("key4"),
Value: []byte("value4"),
},
})

querier := NewWasmQuerier(input.WasmKeeper)
res, err := querier.Query(input.Ctx, wasmvmtypes.QueryRequest{
Wasm: &wasmvmtypes.WasmQuery{
Raw: &wasmvmtypes.RawQuery{
ContractAddr: Addrs[0].String(),
Key: []byte("key1"),
},
},
})

require.NoError(t, err)
require.Equal(t, res, []byte("value1"))
}

func TestQueryContractInfo(t *testing.T) {
input := CreateTestInput(t)

input.WasmKeeper.SetContractInfo(input.Ctx, Addrs[0], types.NewContractInfo(1, Addrs[0], Addrs[1], sdk.AccAddress{}, []byte{}))

bz, err := json.Marshal(CosmosQuery{
ContractInfo: &ContractInfoQueryParams{
ContractAddress: Addrs[0].String(),
},
})
require.NoError(t, err)

querier := NewWasmQuerier(input.WasmKeeper)
res, err := querier.QueryCustom(input.Ctx, bz)
require.NoError(t, err)

var contractInfoResponse ContractInfoQueryResponse
err = json.Unmarshal(res, &contractInfoResponse)
require.NoError(t, err)

require.Equal(t, contractInfoResponse, ContractInfoQueryResponse{
Address: Addrs[0].String(),
Creator: Addrs[1].String(),
Admin: "",
CodeID: 1,
})
}