mirror of https://github.com/certusone/wasmd.git
556 lines
18 KiB
Go
556 lines
18 KiB
Go
package simulation
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"math/rand"
|
|
"os"
|
|
|
|
wasmvmtypes "github.com/CosmWasm/wasmvm/v3/types"
|
|
|
|
errorsmod "cosmossdk.io/errors"
|
|
|
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
|
"github.com/cosmos/cosmos-sdk/x/auth/tx"
|
|
"github.com/cosmos/cosmos-sdk/x/simulation"
|
|
|
|
wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
|
|
"github.com/CosmWasm/wasmd/x/wasm/keeper/testdata"
|
|
"github.com/CosmWasm/wasmd/x/wasm/types"
|
|
)
|
|
|
|
// Simulation operation weights constants
|
|
const (
|
|
OpWeightMsgStoreCode = "op_weight_msg_store_code"
|
|
OpWeightMsgInstantiateContract = "op_weight_msg_instantiate_contract"
|
|
OpWeightMsgExecuteContract = "op_weight_msg_execute_contract"
|
|
OpWeightMsgUpdateAdmin = "op_weight_msg_update_admin"
|
|
OpWeightMsgClearAdmin = "op_weight_msg_clear_admin"
|
|
OpWeightMsgMigrateContract = "op_weight_msg_migrate_contract"
|
|
OpReflectContractPath = "op_reflect_contract_path"
|
|
|
|
DefaultWeightMsgStoreCode int = 50
|
|
DefaultWeightMsgInstantiateContract int = 100
|
|
DefaultWeightMsgExecuteContract int = 100
|
|
DefaultWeightMsgUpdateAdmin int = 25
|
|
DefaultWeightMsgClearAdmin int = 10
|
|
DefaultWeightMsgMigrateContract int = 50
|
|
)
|
|
|
|
// WasmKeeper is a subset of the wasm keeper used by simulations
|
|
type WasmKeeper interface {
|
|
GetAuthority() string
|
|
GetParams(ctx context.Context) types.Params
|
|
IterateCodeInfos(ctx context.Context, cb func(uint64, types.CodeInfo) bool)
|
|
IterateContractInfo(ctx context.Context, cb func(sdk.AccAddress, types.ContractInfo) bool)
|
|
QuerySmart(ctx context.Context, contractAddr sdk.AccAddress, req []byte) ([]byte, error)
|
|
PeekAutoIncrementID(ctx context.Context, lastIDKey []byte) (uint64, error)
|
|
}
|
|
type BankKeeper interface {
|
|
simulation.BankKeeper
|
|
IsSendEnabledCoin(ctx context.Context, coin sdk.Coin) bool
|
|
}
|
|
|
|
// WeightedOperations returns all the operations from the module with their respective weights
|
|
func WeightedOperations(
|
|
appParams simtypes.AppParams,
|
|
ak types.AccountKeeper,
|
|
bk BankKeeper,
|
|
wasmKeeper WasmKeeper,
|
|
) simulation.WeightedOperations {
|
|
var (
|
|
weightMsgStoreCode int
|
|
weightMsgInstantiateContract int
|
|
weightMsgExecuteContract int
|
|
weightMsgUpdateAdmin int
|
|
weightMsgClearAdmin int
|
|
weightMsgMigrateContract int
|
|
wasmContractPath string
|
|
)
|
|
appParams.GetOrGenerate(OpWeightMsgStoreCode, &weightMsgStoreCode, nil, func(_ *rand.Rand) {
|
|
weightMsgStoreCode = DefaultWeightMsgStoreCode
|
|
})
|
|
appParams.GetOrGenerate(OpWeightMsgInstantiateContract, &weightMsgInstantiateContract, nil, func(_ *rand.Rand) {
|
|
weightMsgInstantiateContract = DefaultWeightMsgInstantiateContract
|
|
})
|
|
appParams.GetOrGenerate(OpWeightMsgExecuteContract, &weightMsgInstantiateContract, nil, func(_ *rand.Rand) {
|
|
weightMsgExecuteContract = DefaultWeightMsgExecuteContract
|
|
})
|
|
appParams.GetOrGenerate(OpWeightMsgUpdateAdmin, &weightMsgUpdateAdmin, nil, func(_ *rand.Rand) {
|
|
weightMsgUpdateAdmin = DefaultWeightMsgUpdateAdmin
|
|
})
|
|
appParams.GetOrGenerate(OpWeightMsgClearAdmin, &weightMsgClearAdmin, nil, func(_ *rand.Rand) {
|
|
weightMsgClearAdmin = DefaultWeightMsgClearAdmin
|
|
})
|
|
appParams.GetOrGenerate(OpWeightMsgMigrateContract, &weightMsgMigrateContract, nil, func(_ *rand.Rand) {
|
|
weightMsgMigrateContract = DefaultWeightMsgMigrateContract
|
|
})
|
|
appParams.GetOrGenerate(OpReflectContractPath, &wasmContractPath, nil, func(_ *rand.Rand) {
|
|
wasmContractPath = ""
|
|
})
|
|
|
|
var wasmBz []byte
|
|
if wasmContractPath == "" {
|
|
wasmBz = testdata.MigrateReflectContractWasm()
|
|
} else {
|
|
var err error
|
|
wasmBz, err = os.ReadFile(wasmContractPath)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
return simulation.WeightedOperations{
|
|
simulation.NewWeightedOperation(
|
|
weightMsgStoreCode,
|
|
SimulateMsgStoreCode(ak, bk, wasmKeeper, wasmBz),
|
|
),
|
|
simulation.NewWeightedOperation(
|
|
weightMsgInstantiateContract,
|
|
SimulateMsgInstantiateContract(ak, bk, wasmKeeper, DefaultSimulationCodeIDSelector),
|
|
),
|
|
simulation.NewWeightedOperation(
|
|
weightMsgExecuteContract,
|
|
SimulateMsgExecuteContract(
|
|
ak,
|
|
bk,
|
|
wasmKeeper,
|
|
DefaultSimulationExecuteContractSelector,
|
|
DefaultSimulationExecuteSenderSelector,
|
|
DefaultSimulationExecutePayloader,
|
|
),
|
|
),
|
|
simulation.NewWeightedOperation(
|
|
weightMsgUpdateAdmin,
|
|
SimulateMsgUpdateAmin(
|
|
ak,
|
|
bk,
|
|
wasmKeeper,
|
|
DefaultSimulationUpdateAdminContractSelector,
|
|
),
|
|
),
|
|
simulation.NewWeightedOperation(
|
|
weightMsgClearAdmin,
|
|
SimulateMsgClearAdmin(
|
|
ak,
|
|
bk,
|
|
wasmKeeper,
|
|
DefaultSimulationClearAdminContractSelector,
|
|
),
|
|
),
|
|
simulation.NewWeightedOperation(
|
|
weightMsgMigrateContract,
|
|
SimulateMsgMigrateContract(
|
|
ak,
|
|
bk,
|
|
wasmKeeper,
|
|
DefaultSimulationMigrateContractSelector,
|
|
DefaultSimulationMigrateCodeIDSelector,
|
|
),
|
|
),
|
|
}
|
|
}
|
|
|
|
type (
|
|
MsgMigrateContractSelector func(sdk.Context, WasmKeeper, string) (sdk.AccAddress, types.ContractInfo)
|
|
MsgMigrateCodeIDSelector func(sdk.Context, WasmKeeper, uint64) uint64
|
|
)
|
|
|
|
func DefaultSimulationMigrateContractSelector(ctx sdk.Context, wasmKeeper WasmKeeper, adminAddress string) (sdk.AccAddress, types.ContractInfo) {
|
|
var contractAddress sdk.AccAddress
|
|
var contractInfo types.ContractInfo
|
|
wasmKeeper.IterateContractInfo(ctx, func(address sdk.AccAddress, info types.ContractInfo) bool {
|
|
if info.Admin != adminAddress {
|
|
return false
|
|
}
|
|
contractAddress = address
|
|
contractInfo = info
|
|
return true
|
|
})
|
|
return contractAddress, contractInfo
|
|
}
|
|
|
|
func DefaultSimulationMigrateCodeIDSelector(ctx sdk.Context, wasmKeeper WasmKeeper, currentCodeID uint64) uint64 {
|
|
var codeID uint64
|
|
wasmKeeper.IterateCodeInfos(ctx, func(u uint64, info types.CodeInfo) bool {
|
|
if (info.InstantiateConfig.Permission != types.AccessTypeEverybody) || (u == currentCodeID) {
|
|
return false
|
|
}
|
|
codeID = u
|
|
return true
|
|
})
|
|
return codeID
|
|
}
|
|
|
|
func SimulateMsgMigrateContract(
|
|
ak types.AccountKeeper,
|
|
bk BankKeeper,
|
|
wasmKeeper WasmKeeper,
|
|
contractSelector MsgMigrateContractSelector,
|
|
codeIDSelector MsgMigrateCodeIDSelector,
|
|
) simtypes.Operation {
|
|
return func(
|
|
r *rand.Rand,
|
|
app *baseapp.BaseApp,
|
|
ctx sdk.Context,
|
|
accs []simtypes.Account,
|
|
chainID string,
|
|
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
|
simAccount, _ := simtypes.RandomAcc(r, accs)
|
|
ctAddress, info := contractSelector(ctx, wasmKeeper, simAccount.Address.String())
|
|
if ctAddress == nil {
|
|
return simtypes.NoOpMsg(types.ModuleName, types.MsgMigrateContract{}.Type(), "no contract instance available"), nil, nil
|
|
}
|
|
|
|
codeID := codeIDSelector(ctx, wasmKeeper, info.CodeID)
|
|
if codeID == 0 {
|
|
return simtypes.NoOpMsg(types.ModuleName, types.MsgMigrateContract{}.Type(), "no target contract available"), nil, nil
|
|
}
|
|
migrateMsg := types.MsgMigrateContract{
|
|
Sender: simAccount.Address.String(),
|
|
Contract: ctAddress.String(),
|
|
CodeID: codeID,
|
|
Msg: []byte(`{}`),
|
|
}
|
|
|
|
txCtx := BuildOperationInput(r, app, ctx, &migrateMsg, simAccount, ak, bk, nil)
|
|
return simulation.GenAndDeliverTxWithRandFees(txCtx)
|
|
}
|
|
}
|
|
|
|
type MsgClearAdminContractSelector func(sdk.Context, WasmKeeper, string) sdk.AccAddress
|
|
|
|
func DefaultSimulationClearAdminContractSelector(ctx sdk.Context, wasmKeeper WasmKeeper, adminAddress string) sdk.AccAddress {
|
|
var ctAddress sdk.AccAddress
|
|
wasmKeeper.IterateContractInfo(ctx, func(addr sdk.AccAddress, info types.ContractInfo) bool {
|
|
if info.Admin != adminAddress {
|
|
return false
|
|
}
|
|
ctAddress = addr
|
|
return true
|
|
})
|
|
return ctAddress
|
|
}
|
|
|
|
func SimulateMsgClearAdmin(
|
|
ak types.AccountKeeper,
|
|
bk BankKeeper,
|
|
wasmKeeper WasmKeeper,
|
|
contractSelector MsgClearAdminContractSelector,
|
|
) simtypes.Operation {
|
|
return func(
|
|
r *rand.Rand,
|
|
app *baseapp.BaseApp,
|
|
ctx sdk.Context,
|
|
accounts []simtypes.Account,
|
|
chainID string,
|
|
) (OperationMsg simtypes.OperationMsg, futureOps []simtypes.FutureOperation, err error) {
|
|
simAccount, _ := simtypes.RandomAcc(r, accounts)
|
|
ctAddress := contractSelector(ctx, wasmKeeper, simAccount.Address.String())
|
|
if ctAddress == nil {
|
|
return simtypes.NoOpMsg(types.ModuleName, types.MsgClearAdmin{}.Type(), "no contract instance available"), nil, nil
|
|
}
|
|
|
|
msg := types.MsgClearAdmin{
|
|
Sender: simAccount.Address.String(),
|
|
Contract: ctAddress.String(),
|
|
}
|
|
txCtx := BuildOperationInput(r, app, ctx, &msg, simAccount, ak, bk, nil)
|
|
return simulation.GenAndDeliverTxWithRandFees(txCtx)
|
|
}
|
|
}
|
|
|
|
type MsgUpdateAdminContractSelector func(sdk.Context, WasmKeeper, string) (sdk.AccAddress, types.ContractInfo)
|
|
|
|
// DefaultSimulationUpdateAdminContractSelector picks the first contract which Admin != ""
|
|
func DefaultSimulationUpdateAdminContractSelector(ctx sdk.Context, wasmKeeper WasmKeeper, adminAddress string) (sdk.AccAddress, types.ContractInfo) {
|
|
var contractAddress sdk.AccAddress
|
|
var contractInfo types.ContractInfo
|
|
wasmKeeper.IterateContractInfo(ctx, func(address sdk.AccAddress, info types.ContractInfo) bool {
|
|
if info.Admin != adminAddress {
|
|
return false
|
|
}
|
|
contractAddress = address
|
|
contractInfo = info
|
|
return true
|
|
})
|
|
return contractAddress, contractInfo
|
|
}
|
|
|
|
func SimulateMsgUpdateAmin(
|
|
ak types.AccountKeeper,
|
|
bk BankKeeper,
|
|
wasmKeeper WasmKeeper,
|
|
contractSelector MsgUpdateAdminContractSelector,
|
|
) simtypes.Operation {
|
|
return func(
|
|
r *rand.Rand,
|
|
app *baseapp.BaseApp,
|
|
ctx sdk.Context,
|
|
accs []simtypes.Account,
|
|
chainID string,
|
|
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
|
simAccount, _ := simtypes.RandomAcc(r, accs)
|
|
ctAddress, _ := contractSelector(ctx, wasmKeeper, simAccount.Address.String())
|
|
if ctAddress == nil {
|
|
return simtypes.NoOpMsg(types.ModuleName, types.MsgUpdateAdmin{}.Type(), "no contract instance available"), nil, nil
|
|
}
|
|
|
|
newAdmin, _ := simtypes.RandomAcc(r, accs)
|
|
if newAdmin.Address.String() == simAccount.Address.String() {
|
|
return simtypes.NoOpMsg(types.ModuleName, types.MsgUpdateAdmin{}.Type(), "new admin cannot be the same as current admin"), nil, nil
|
|
}
|
|
|
|
msg := types.MsgUpdateAdmin{
|
|
Sender: simAccount.Address.String(),
|
|
NewAdmin: newAdmin.Address.String(),
|
|
Contract: ctAddress.String(),
|
|
}
|
|
txCtx := BuildOperationInput(r, app, ctx, &msg, simAccount, ak, bk, nil)
|
|
return simulation.GenAndDeliverTxWithRandFees(txCtx)
|
|
}
|
|
}
|
|
|
|
// SimulateMsgStoreCode generates a MsgStoreCode with random values
|
|
func SimulateMsgStoreCode(
|
|
ak types.AccountKeeper,
|
|
bk BankKeeper,
|
|
wasmKeeper WasmKeeper,
|
|
wasmBz []byte,
|
|
) simtypes.Operation {
|
|
return func(
|
|
r *rand.Rand,
|
|
app *baseapp.BaseApp,
|
|
ctx sdk.Context,
|
|
accs []simtypes.Account,
|
|
chainID string,
|
|
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
|
if wasmKeeper.GetParams(ctx).CodeUploadAccess.Permission != types.AccessTypeEverybody {
|
|
return simtypes.NoOpMsg(types.ModuleName, types.MsgStoreCode{}.Type(), "no chain permission"), nil, nil
|
|
}
|
|
|
|
simAccount, _ := simtypes.RandomAcc(r, accs)
|
|
|
|
permission := wasmKeeper.GetParams(ctx).InstantiateDefaultPermission
|
|
config := permission.With(simAccount.Address)
|
|
|
|
msg := types.MsgStoreCode{
|
|
Sender: simAccount.Address.String(),
|
|
WASMByteCode: wasmBz,
|
|
InstantiatePermission: &config,
|
|
}
|
|
txCtx := BuildOperationInput(r, app, ctx, &msg, simAccount, ak, bk, nil)
|
|
return simulation.GenAndDeliverTxWithRandFees(txCtx)
|
|
}
|
|
}
|
|
|
|
// CodeIDSelector returns code id to be used in simulations
|
|
type CodeIDSelector = func(ctx sdk.Context, wasmKeeper WasmKeeper) uint64
|
|
|
|
// DefaultSimulationCodeIDSelector picks the first code id
|
|
func DefaultSimulationCodeIDSelector(ctx sdk.Context, wasmKeeper WasmKeeper) uint64 {
|
|
var codeID uint64
|
|
wasmKeeper.IterateCodeInfos(ctx, func(u uint64, info types.CodeInfo) bool {
|
|
if info.InstantiateConfig.Permission != types.AccessTypeEverybody {
|
|
return false
|
|
}
|
|
codeID = u
|
|
return true
|
|
})
|
|
return codeID
|
|
}
|
|
|
|
// SimulateMsgInstantiateContract generates a MsgInstantiateContract with random values
|
|
func SimulateMsgInstantiateContract(
|
|
ak types.AccountKeeper,
|
|
bk BankKeeper,
|
|
wasmKeeper WasmKeeper,
|
|
codeSelector CodeIDSelector,
|
|
) simtypes.Operation {
|
|
return func(
|
|
r *rand.Rand,
|
|
app *baseapp.BaseApp,
|
|
ctx sdk.Context,
|
|
accs []simtypes.Account,
|
|
chainID string,
|
|
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
|
simAccount, _ := simtypes.RandomAcc(r, accs)
|
|
|
|
codeID := codeSelector(ctx, wasmKeeper)
|
|
if codeID == 0 {
|
|
return simtypes.NoOpMsg(types.ModuleName, types.MsgInstantiateContract{}.Type(), "no codes with permission available"), nil, nil
|
|
}
|
|
deposit := sdk.Coins{}
|
|
spendableCoins := bk.SpendableCoins(ctx, simAccount.Address)
|
|
for _, v := range spendableCoins {
|
|
if bk.IsSendEnabledCoin(ctx, v) {
|
|
deposit = deposit.Add(simtypes.RandSubsetCoins(r, sdk.NewCoins(v))...)
|
|
}
|
|
}
|
|
|
|
adminAccount, _ := simtypes.RandomAcc(r, accs)
|
|
|
|
msg := types.MsgInstantiateContract{
|
|
Sender: simAccount.Address.String(),
|
|
Admin: adminAccount.Address.String(),
|
|
CodeID: codeID,
|
|
Label: simtypes.RandStringOfLength(r, 10),
|
|
Msg: []byte(`{}`),
|
|
Funds: deposit,
|
|
}
|
|
txCtx := BuildOperationInput(r, app, ctx, &msg, simAccount, ak, bk, deposit)
|
|
return simulation.GenAndDeliverTxWithRandFees(txCtx)
|
|
}
|
|
}
|
|
|
|
// MsgExecuteContractSelector returns contract address to be used in simulations
|
|
type MsgExecuteContractSelector = func(ctx sdk.Context, wasmKeeper WasmKeeper) sdk.AccAddress
|
|
|
|
// MsgExecutePayloader extension point to modify msg with custom payload
|
|
type MsgExecutePayloader func(msg *types.MsgExecuteContract) error
|
|
|
|
// MsgExecuteSenderSelector extension point that returns the sender address
|
|
type MsgExecuteSenderSelector func(wasmKeeper WasmKeeper, ctx sdk.Context, contractAddr sdk.AccAddress, accs []simtypes.Account) (simtypes.Account, error)
|
|
|
|
// SimulateMsgExecuteContract create a execute message a reflect contract instance
|
|
func SimulateMsgExecuteContract(
|
|
ak types.AccountKeeper,
|
|
bk BankKeeper,
|
|
wasmKeeper WasmKeeper,
|
|
contractSelector MsgExecuteContractSelector,
|
|
senderSelector MsgExecuteSenderSelector,
|
|
payloader MsgExecutePayloader,
|
|
) simtypes.Operation {
|
|
return func(
|
|
r *rand.Rand,
|
|
app *baseapp.BaseApp,
|
|
ctx sdk.Context,
|
|
accs []simtypes.Account,
|
|
chainID string,
|
|
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
|
contractAddr := contractSelector(ctx, wasmKeeper)
|
|
if contractAddr == nil {
|
|
return simtypes.NoOpMsg(types.ModuleName, types.MsgExecuteContract{}.Type(), "no contract instance available"), nil, nil
|
|
}
|
|
simAccount, err := senderSelector(wasmKeeper, ctx, contractAddr, accs)
|
|
if err != nil {
|
|
return simtypes.NoOpMsg(types.ModuleName, types.MsgExecuteContract{}.Type(), "query contract owner"), nil, err
|
|
}
|
|
|
|
deposit := sdk.Coins{}
|
|
spendableCoins := bk.SpendableCoins(ctx, simAccount.Address)
|
|
for _, v := range spendableCoins {
|
|
if bk.IsSendEnabledCoin(ctx, v) {
|
|
deposit = deposit.Add(simtypes.RandSubsetCoins(r, sdk.NewCoins(v))...)
|
|
}
|
|
}
|
|
if deposit.IsZero() {
|
|
return simtypes.NoOpMsg(types.ModuleName, types.MsgExecuteContract{}.Type(), "broke account"), nil, nil
|
|
}
|
|
msg := types.MsgExecuteContract{
|
|
Sender: simAccount.Address.String(),
|
|
Contract: contractAddr.String(),
|
|
Funds: deposit,
|
|
}
|
|
if err := payloader(&msg); err != nil {
|
|
return simtypes.NoOpMsg(types.ModuleName, types.MsgExecuteContract{}.Type(), "contract execute payload"), nil, err
|
|
}
|
|
|
|
txCtx := BuildOperationInput(r, app, ctx, &msg, simAccount, ak, bk, deposit)
|
|
return simulation.GenAndDeliverTxWithRandFees(txCtx)
|
|
}
|
|
}
|
|
|
|
// BuildOperationInput helper to build object
|
|
func BuildOperationInput(
|
|
r *rand.Rand,
|
|
app *baseapp.BaseApp,
|
|
ctx sdk.Context,
|
|
msg interface {
|
|
sdk.Msg
|
|
Type() string
|
|
},
|
|
simAccount simtypes.Account,
|
|
ak types.AccountKeeper,
|
|
bk BankKeeper,
|
|
deposit sdk.Coins,
|
|
) simulation.OperationInput {
|
|
interfaceRegistry := codectypes.NewInterfaceRegistry()
|
|
txConfig := tx.NewTxConfig(codec.NewProtoCodec(interfaceRegistry), tx.DefaultSignModes)
|
|
return simulation.OperationInput{
|
|
R: r,
|
|
App: app,
|
|
TxGen: txConfig,
|
|
Cdc: nil,
|
|
Msg: msg,
|
|
Context: ctx,
|
|
SimAccount: simAccount,
|
|
AccountKeeper: ak,
|
|
Bankkeeper: bk,
|
|
ModuleName: types.ModuleName,
|
|
CoinsSpentInMsg: deposit,
|
|
}
|
|
}
|
|
|
|
// DefaultSimulationExecuteContractSelector picks the first contract address
|
|
func DefaultSimulationExecuteContractSelector(ctx sdk.Context, wasmKeeper WasmKeeper) sdk.AccAddress {
|
|
var r sdk.AccAddress
|
|
wasmKeeper.IterateContractInfo(ctx, func(address sdk.AccAddress, info types.ContractInfo) bool {
|
|
r = address
|
|
return true
|
|
})
|
|
return r
|
|
}
|
|
|
|
// DefaultSimulationExecuteSenderSelector queries reflect contract for owner address and selects accounts
|
|
func DefaultSimulationExecuteSenderSelector(wasmKeeper WasmKeeper, ctx sdk.Context, contractAddr sdk.AccAddress, accs []simtypes.Account) (simtypes.Account, error) {
|
|
var none simtypes.Account
|
|
bz, err := json.Marshal(testdata.ReflectQueryMsg{Owner: &struct{}{}})
|
|
if err != nil {
|
|
return none, errorsmod.Wrap(err, "build smart query")
|
|
}
|
|
got, err := wasmKeeper.QuerySmart(ctx, contractAddr, bz)
|
|
if err != nil {
|
|
return none, errorsmod.Wrap(err, "exec smart query")
|
|
}
|
|
var ownerRes testdata.OwnerResponse
|
|
if err := json.Unmarshal(got, &ownerRes); err != nil || ownerRes.Owner == "" {
|
|
return none, errorsmod.Wrap(err, "parse smart query response")
|
|
}
|
|
ownerAddr, err := sdk.AccAddressFromBech32(ownerRes.Owner)
|
|
if err != nil {
|
|
return none, errorsmod.Wrap(err, "parse contract owner address")
|
|
}
|
|
simAccount, ok := simtypes.FindAccount(accs, ownerAddr)
|
|
if !ok {
|
|
return none, errorsmod.Wrap(err, "unknown contract owner address")
|
|
}
|
|
return simAccount, nil
|
|
}
|
|
|
|
// DefaultSimulationExecutePayloader implements a bank msg to send the
|
|
// tokens from contract account back to original sender
|
|
func DefaultSimulationExecutePayloader(msg *types.MsgExecuteContract) error {
|
|
reflectSend := testdata.ReflectHandleMsg{
|
|
Reflect: &testdata.ReflectPayload{
|
|
Msgs: []wasmvmtypes.CosmosMsg{{
|
|
Bank: &wasmvmtypes.BankMsg{
|
|
Send: &wasmvmtypes.SendMsg{
|
|
ToAddress: msg.Sender, //
|
|
Amount: wasmkeeper.ConvertSdkCoinsToWasmCoins(msg.Funds),
|
|
},
|
|
},
|
|
}},
|
|
},
|
|
}
|
|
reflectSendBz, err := json.Marshal(reflectSend)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
msg.Msg = reflectSendBz
|
|
return nil
|
|
}
|