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

Alex contract vouchers spike #262

Closed
wants to merge 3 commits into from
Closed
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
1 change: 1 addition & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ var (
stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking},
govtypes.ModuleName: {authtypes.Burner},
ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner},
wasm.ModuleName: {authtypes.Minter, authtypes.Burner},
}

// module accounts that are allowed to receive tokens
Expand Down
15 changes: 14 additions & 1 deletion x/wasm/internal/keeper/cosmwasm/msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
// CosmosMsg is an rust enum and only (exactly) one of the fields should be set
// Should we do a cleaner approach in Go? (type/data?)
type CosmosMsg struct {
Bank *cosmwasmv1.BankMsg `json:"bank,omitempty"`
Bank *BankMsg `json:"bank,omitempty"`
Custom json.RawMessage `json:"custom,omitempty"`
Staking *cosmwasmv1.StakingMsg `json:"staking,omitempty"`
Wasm *cosmwasmv1.WasmMsg `json:"wasm,omitempty"`
Expand Down Expand Up @@ -56,3 +56,16 @@ type HandleResponse struct {
// log message to return over abci interface
Log []cosmwasmv1.LogAttribute `json:"log"`
}

type MintMsg struct {
Coin cosmwasmv1.Coin `json:"amount"`
}
type BurnMsg struct {
Coin cosmwasmv1.Coin `json:"amount"`
}

type BankMsg struct {
Send *cosmwasmv1.SendMsg `json:"send,omitempty"`
Mint *MintMsg `json:"mint,omitempty"`
Burn *BurnMsg `json:"burn,omitempty"`
}
72 changes: 65 additions & 7 deletions x/wasm/internal/keeper/handler_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ import (
"github.com/CosmWasm/wasmd/x/wasm/internal/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
ibctransfertypes "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types"
channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/tendermint/tendermint/crypto/tmhash"
tmbytes "github.com/tendermint/tendermint/libs/bytes"
)

type MessageHandler struct {
Expand All @@ -23,22 +26,22 @@ type MessageHandler struct {
}

func NewMessageHandler(router sdk.Router, customEncoders *MessageEncoders) MessageHandler {
encoders := DefaultEncoders(nil, nil).Merge(customEncoders)
encoders := DefaultEncoders(nil, nil, nil).Merge(customEncoders)
return MessageHandler{
router: router,
encoders: encoders,
}
}

func NewMessageHandlerV2(router sdk.Router, channelKeeper types.ChannelKeeper, capabilityKeeper types.CapabilityKeeper, customEncoders *MessageEncoders) MessageHandler {
encoders := DefaultEncoders(channelKeeper, capabilityKeeper).Merge(customEncoders)
encoders := DefaultEncoders(channelKeeper, capabilityKeeper, nil).Merge(customEncoders)
return MessageHandler{
router: router,
encoders: encoders,
}
}

type BankEncoder func(sender sdk.AccAddress, msg *cosmwasmv1.BankMsg) ([]sdk.Msg, error)
type BankEncoder func(ctx sdk.Context, sender sdk.AccAddress, msg *cosmwasmv2.BankMsg) ([]sdk.Msg, error)
type CustomEncoder func(sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error)
type StakingEncoder func(sender sdk.AccAddress, msg *cosmwasmv1.StakingMsg) ([]sdk.Msg, error)
type WasmEncoder func(sender sdk.AccAddress, msg *cosmwasmv1.WasmMsg) ([]sdk.Msg, error)
Expand All @@ -52,7 +55,12 @@ type MessageEncoders struct {
IBC IBCEncoder
}

func DefaultEncoders(channelKeeper types.ChannelKeeper, capabilityKeeper types.CapabilityKeeper) MessageEncoders {
type BankKeeper interface {
MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error
BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error
}

func DefaultEncoders(channelKeeper types.ChannelKeeper, capabilityKeeper types.CapabilityKeeper, bankKeeper bankkeeper.Keeper) MessageEncoders {
e := MessageEncoders{
Bank: EncodeBankMsg,
Custom: NoCustomMsg,
Expand All @@ -62,6 +70,9 @@ func DefaultEncoders(channelKeeper types.ChannelKeeper, capabilityKeeper types.C
if channelKeeper != nil { // todo: quick hack to keep tests happy
e.IBC = EncodeIBCMsg(channelKeeper, capabilityKeeper)
}
if bankKeeper != nil {
e.Bank = BankMsgEncoderV2(bankKeeper)
}
return e
}

Expand Down Expand Up @@ -90,7 +101,7 @@ func (e MessageEncoders) Merge(o *MessageEncoders) MessageEncoders {
func (e MessageEncoders) Encode(contractAddr sdk.AccAddress, msg cosmwasmv1.CosmosMsg) ([]sdk.Msg, error) {
switch {
case msg.Bank != nil:
return e.Bank(contractAddr, msg.Bank)
return e.Bank(sdk.Context{}, contractAddr, &cosmwasmv2.BankMsg{Send: msg.Bank.Send}) // TODO: quick hack for the spike
case msg.Custom != nil:
return e.Custom(contractAddr, msg.Custom)
case msg.Staking != nil:
Expand All @@ -105,7 +116,7 @@ func (e MessageEncoders) Encode(contractAddr sdk.AccAddress, msg cosmwasmv1.Cosm
func (e MessageEncoders) EncodeV2(ctx sdk.Context, contractAddr sdk.AccAddress, source cosmwasmv2.IBCEndpoint, msg cosmwasmv2.CosmosMsg) ([]sdk.Msg, error) {
switch {
case msg.Bank != nil:
return e.Bank(contractAddr, msg.Bank)
return e.Bank(ctx, contractAddr, msg.Bank)
case msg.Custom != nil:
return e.Custom(contractAddr, msg.Custom)
case msg.Staking != nil:
Expand All @@ -118,7 +129,54 @@ func (e MessageEncoders) EncodeV2(ctx sdk.Context, contractAddr sdk.AccAddress,
return nil, sdkerrors.Wrap(types.ErrInvalidMsg, "Unknown variant of Wasm")
}

func EncodeBankMsg(sender sdk.AccAddress, msg *cosmwasmv1.BankMsg) ([]sdk.Msg, error) {
func BankMsgEncoderV2(bank bankkeeper.Keeper) BankEncoder {
return func(ctx sdk.Context, contractAddr sdk.AccAddress, msg *cosmwasmv2.BankMsg) ([]sdk.Msg, error) {
if msg.Mint != nil {
if len(msg.Mint.Coin.Amount) == 0 {
return nil, nil
}
voucher, err := coinToVoucher(contractAddr, msg.Mint.Coin)
if err != nil {
return nil, err
}
err = bank.MintCoins(ctx, types.ModuleName, voucher)
if err != nil {
return nil, err
}
return nil, bank.SendCoinsFromModuleToAccount(
ctx, types.ModuleName, contractAddr, voucher,
)
}
if msg.Burn != nil {
if len(msg.Burn.Coin.Amount) == 0 {
return nil, nil
}
voucher, err := coinToVoucher(contractAddr, msg.Burn.Coin)
if err != nil {
return nil, err
}
err = bank.SendCoinsFromAccountToModule(ctx, contractAddr, types.ModuleName, voucher)
if err != nil {
return nil, err
}
return nil, bank.BurnCoins(ctx, types.ModuleName, voucher)
}
return EncodeBankMsg(ctx, contractAddr, msg)
}
}

func coinToVoucher(contractAddr sdk.AccAddress, coin cosmwasmv1.Coin) (sdk.Coins, error) {
sdkCoin, err := convertWasmCoinToSdkCoin(coin)
if err != nil {
return nil, err
}
denumTrace := fmt.Sprintf("%s/%s/", contractAddr.String(), sdkCoin.Denom)
var hash tmbytes.HexBytes = tmhash.Sum([]byte(denumTrace))
simpleVoucherDenum := fmt.Sprintf("wasm/%s", hash)
return sdk.NewCoins(sdk.NewCoin(simpleVoucherDenum, sdkCoin.Amount)), nil
}

func EncodeBankMsg(_ sdk.Context, sender sdk.AccAddress, msg *cosmwasmv2.BankMsg) ([]sdk.Msg, error) {
if msg.Send == nil {
return nil, sdkerrors.Wrap(types.ErrInvalidMsg, "Unknown variant of Bank")
}
Expand Down
2 changes: 1 addition & 1 deletion x/wasm/internal/keeper/handler_plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ func TestEncoding(t *testing.T) {
},
}

encoder := DefaultEncoders(nil, nil)
encoder := DefaultEncoders(nil, nil, nil)
for name, tc := range cases {
tc := tc
t.Run(name, func(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion x/wasm/internal/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func NewKeeper(
}

// todo: revisit: DefaultEncoders are used twice now
quickHack := DefaultEncoders(channelKeeper, scopedKeeper).Merge(customEncoders)
quickHack := DefaultEncoders(channelKeeper, scopedKeeper, bankKeeper).Merge(customEncoders)
keeper := Keeper{
storeKey: storeKey,
cdc: cdc,
Expand Down
102 changes: 102 additions & 0 deletions x/wasm/internal/keeper/minter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package keeper

import (
"io/ioutil"
"os"
"testing"

"github.com/CosmWasm/go-cosmwasm"
cosmwasmv1 "github.com/CosmWasm/go-cosmwasm/types"
cosmwasmv2 "github.com/CosmWasm/wasmd/x/wasm/internal/keeper/cosmwasm"
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/stretchr/testify/require"
)

func TestMinter(t *testing.T) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
ctx, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.WasmKeeper, keepers.BankKeeper
totalSupply := types.NewSupply(sdk.NewCoins(sdk.NewInt64Coin("denom", 400000000)))
bankKeeper.SetSupply(ctx, totalSupply)

deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
creator := createFakeFundedAccount(t, ctx, accKeeper, bankKeeper, deposit)

wasmCode, err := ioutil.ReadFile("./testdata/contract.wasm")
require.NoError(t, err)

// create any dummy contract to mock later
codeID, err := keeper.Create(ctx, creator, wasmCode, "", "any/builder:tag", nil)
require.NoError(t, err)
// with random addresses
initMsgBz := []byte(`{"verifier": "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5", "beneficiary":"cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5"}`)
contractAddr, err := keeper.Instantiate(ctx, codeID, creator, nil, initMsgBz, "demo contract 3", deposit)
require.NoError(t, err)
require.Equal(t, "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5", contractAddr.String())

MockContracts[contractAddr.String()] = &minterContract{t: t, contractAddr: contractAddr}
fred := createFakeFundedAccount(t, ctx, accKeeper, bankKeeper, sdk.NewCoins(sdk.NewInt64Coin("denom", 5000)))

// call execute to return a mint message
_, err = keeper.Execute(ctx, contractAddr, fred, []byte(`mint`), nil)
require.NoError(t, err)

const contractsDenom = "wasm/5EFEC84ADDE58024AEF3A7BB9CD5945F91D180D0A4AC5AA2534BEF8F6194CD79"
t.Logf("+++ Contract owns: %s", bankKeeper.GetAllBalances(ctx, contractAddr).String())
require.Equal(t, sdk.Coin{Denom: contractsDenom, Amount: sdk.NewInt(10000000)}, bankKeeper.GetBalance(ctx, contractAddr, contractsDenom))

// now call execute to return a burn message
_, err = keeper.Execute(ctx, contractAddr, fred, []byte(`burn`), nil)
require.NoError(t, err)
t.Logf("+++ Contract owns: %s", bankKeeper.GetAllBalances(ctx, contractAddr).String())
require.Equal(t, sdk.Coin{Denom: contractsDenom, Amount: sdk.NewInt(1)}, bankKeeper.GetBalance(ctx, contractAddr, contractsDenom))
}

type minterContract struct {
t *testing.T
contractAddr sdk.AccAddress
}

func (m *minterContract) Execute(hash []byte, params cosmwasmv1.Env, msg []byte, store prefix.Store, api cosmwasm.GoAPI, querier QueryHandler, meter sdk.GasMeter, gas uint64) (*cosmwasmv2.HandleResponse, uint64, error) {
msgs := map[string]*cosmwasmv2.BankMsg{
"mint": {
Mint: &cosmwasmv2.MintMsg{Coin: cosmwasmv1.Coin{Denom: "alx", Amount: "10000000"}},
},
"burn": {
Burn: &cosmwasmv2.BurnMsg{Coin: cosmwasmv1.Coin{Denom: "alx", Amount: "9999999"}},
},
}
return &cosmwasmv2.HandleResponse{
Messages: []cosmwasmv2.CosmosMsg{
{Bank: msgs[string(msg)]},
},
}, 0, nil
}

func (m minterContract) OnIBCPacketReceive(hash []byte, params cosmwasmv2.Env, packet cosmwasmv2.IBCPacket, store prefix.Store, api cosmwasm.GoAPI, querier QueryHandler, meter sdk.GasMeter, gas uint64) (*cosmwasmv2.IBCPacketReceiveResponse, uint64, error) {
panic("implement me")
}

func (m minterContract) OnIBCPacketAcknowledgement(hash []byte, params cosmwasmv2.Env, packetAck cosmwasmv2.IBCAcknowledgement, store prefix.Store, api cosmwasm.GoAPI, querier QueryHandler, meter sdk.GasMeter, gas uint64) (*cosmwasmv2.IBCPacketAcknowledgementResponse, uint64, error) {
panic("implement me")
}

func (m minterContract) OnIBCPacketTimeout(hash []byte, params cosmwasmv2.Env, packet cosmwasmv2.IBCPacket, store prefix.Store, api cosmwasm.GoAPI, querier QueryHandler, meter sdk.GasMeter, gas uint64) (*cosmwasmv2.IBCPacketTimeoutResponse, uint64, error) {
panic("implement me")
}

func (m minterContract) OnIBCChannelOpen(hash []byte, params cosmwasmv2.Env, channel cosmwasmv2.IBCChannel, store prefix.Store, api cosmwasm.GoAPI, querier QueryHandler, meter sdk.GasMeter, gas uint64) (*cosmwasmv2.IBCChannelOpenResponse, uint64, error) {
panic("implement me")
}

func (m minterContract) OnIBCChannelConnect(hash []byte, params cosmwasmv2.Env, channel cosmwasmv2.IBCChannel, store prefix.Store, api cosmwasm.GoAPI, querier QueryHandler, meter sdk.GasMeter, gas uint64) (*cosmwasmv2.IBCChannelConnectResponse, uint64, error) {
panic("implement me")
}

func (m minterContract) OnIBCChannelClose(ctx sdk.Context, hash []byte, params cosmwasmv2.Env, channel cosmwasmv2.IBCChannel, meter sdk.GasMeter, gas uint64) (*cosmwasmv2.IBCChannelCloseResponse, uint64, error) {
panic("implement me")
}
1 change: 1 addition & 0 deletions x/wasm/internal/keeper/test_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, tempDir string, supportedFeat
stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking},
govtypes.ModuleName: {authtypes.Burner},
transfertypes.ModuleName: {authtypes.Minter, authtypes.Burner},
wasmtypes.ModuleName: {authtypes.Minter, authtypes.Burner},
}
authSubsp, _ := paramsKeeper.GetSubspace(authtypes.ModuleName)
authKeeper := authkeeper.NewAccountKeeper(
Expand Down
2 changes: 1 addition & 1 deletion x/wasm/relay_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func (s *senderContract) OnIBCChannelConnect(hash []byte, params cosmwasmv2.Env,
// abusing onConnect event to send the message. can be any execute event which is not mocked though

escrowAddress := ibctransfertypes.GetEscrowAddress(channel.Endpoint.Port, channel.Endpoint.Channel)
sendToEscrowMsg := &cosmwasmv1.BankMsg{
sendToEscrowMsg := &cosmwasmv2.BankMsg{
Send: &cosmwasmv1.SendMsg{
FromAddress: s.contractAddr.String(),
ToAddress: escrowAddress.String(),
Expand Down