diff --git a/app/app.go b/app/app.go index 615d6580..55e4ec07 100644 --- a/app/app.go +++ b/app/app.go @@ -1342,7 +1342,7 @@ func buildWasmMessageDecorator( srv := schedulermodulekeeper.NewMsgServerImpl(scheduler) skwSrv := skywaymodulekeeper.NewMsgServerImpl(*skyway) - return libwasm.NewMessenger( + return libwasm.NewRouterMessageDecorator( log, schedulerbindings.NewLegacyMessenger(scheduler), schedulerbindings.NewMessenger(scheduler, srv), diff --git a/util/libwasm/plugin.go b/util/libwasm/plugin.go index ec667a59..f2c289d3 100644 --- a/util/libwasm/plugin.go +++ b/util/libwasm/plugin.go @@ -10,18 +10,25 @@ import ( wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/palomachain/paloma/v2/util/liberr" "github.com/palomachain/paloma/v2/util/liblog" schedulerbindings "github.com/palomachain/paloma/v2/x/scheduler/bindings/types" skywaybindings "github.com/palomachain/paloma/v2/x/skyway/bindings/types" tfbindings "github.com/palomachain/paloma/v2/x/tokenfactory/bindings/types" ) -type Messenger struct { - legacyFallback wasmkeeper.Messenger - scheduler wasmkeeper.Messenger - skyway wasmkeeper.Messenger - tokenfactory wasmkeeper.Messenger - wrapped wasmkeeper.Messenger +const ErrUnrecognizedMessage = liberr.Error("unrecognized message type") + +type Messenger[T any] interface { + DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, t T) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) +} + +type router struct { + legacyFallback Messenger[wasmvmtypes.CosmosMsg] + scheduler Messenger[schedulerbindings.Message] + skyway Messenger[skywaybindings.Message] + tokenfactory Messenger[tfbindings.Message] + wrapped Messenger[wasmvmtypes.CosmosMsg] log log.Logger } @@ -43,15 +50,15 @@ type CustomQuery struct { TokenFactory *tfbindings.Query `json:"token_factory_query,omitempty"` } -func NewMessenger( +func NewRouterMessageDecorator( log log.Logger, - legacyFallback wasmkeeper.Messenger, - scheduler wasmkeeper.Messenger, - skyway wasmkeeper.Messenger, - tokenfactory wasmkeeper.Messenger, + legacyFallback Messenger[wasmvmtypes.CosmosMsg], + scheduler Messenger[schedulerbindings.Message], + skyway Messenger[skywaybindings.Message], + tokenfactory Messenger[tfbindings.Message], ) func(old wasmkeeper.Messenger) wasmkeeper.Messenger { return func(old wasmkeeper.Messenger) wasmkeeper.Messenger { - return &Messenger{ + return &router{ log: log, legacyFallback: legacyFallback, scheduler: scheduler, @@ -62,7 +69,7 @@ func NewMessenger( } } -func (h Messenger) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (a []sdk.Event, b [][]byte, c [][]*codectypes.Any, err error) { +func (h router) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (a []sdk.Event, b [][]byte, c [][]*codectypes.Any, err error) { logger := liblog.FromSDKLogger(h.log).WithComponent("wasm-message-decorator") logger.Debug("Dispatching message...", "contract", contractAddr, "msg", msg) @@ -86,11 +93,11 @@ func (h Messenger) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, con } switch { case contractMsg.Scheduler != nil: - return h.scheduler.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg) + return h.scheduler.DispatchMsg(ctx, contractAddr, contractIBCPortID, *contractMsg.Scheduler) case contractMsg.Skyway != nil: - return h.skyway.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg) + return h.skyway.DispatchMsg(ctx, contractAddr, contractIBCPortID, *contractMsg.Skyway) case contractMsg.TokenFactory != nil: - return h.tokenfactory.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg) + return h.tokenfactory.DispatchMsg(ctx, contractAddr, contractIBCPortID, *contractMsg.TokenFactory) } logger.Debug("Calling legacy fallback message handler...") diff --git a/util/libwasm/plugin_test.go b/util/libwasm/plugin_test.go index 2a04eb42..ebb06be4 100644 --- a/util/libwasm/plugin_test.go +++ b/util/libwasm/plugin_test.go @@ -16,29 +16,28 @@ import ( ) // MockMessenger is a mock implementation of wasmkeeper.Messenger -type MockMessenger struct { +type MockMessenger[T any] struct { mock.Mock } -func (m *MockMessenger) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) { +func (m *MockMessenger[T]) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg T) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) { args := m.Called(ctx, contractAddr, contractIBCPortID, msg) return args.Get(0).([]sdk.Event), args.Get(1).([][]byte), args.Get(2).([][]*codectypes.Any), args.Error(3) } func TestDispatchMsg(t *testing.T) { - // Setup ctx := sdk.Context{} contractAddr := sdk.AccAddress([]byte("test_address")) contractIBCPortID := "test_port" logger := log.NewNopLogger() - mockScheduler := new(MockMessenger) - mockSkyway := new(MockMessenger) - mockTokenFactory := new(MockMessenger) - mockLegacyFallback := new(MockMessenger) - mockWrapped := new(MockMessenger) + mockScheduler := new(MockMessenger[schedulerbindings.Message]) + mockSkyway := new(MockMessenger[skywaybindings.Message]) + mockTokenFactory := new(MockMessenger[tfbindings.Message]) + mockLegacyFallback := new(MockMessenger[wasmvmtypes.CosmosMsg]) + mockWrapped := new(MockMessenger[wasmvmtypes.CosmosMsg]) - h := Messenger{ + h := router{ log: logger, legacyFallback: mockLegacyFallback, scheduler: mockScheduler, diff --git a/x/scheduler/bindings/msg_plugin.go b/x/scheduler/bindings/msg_plugin.go index 4dfad5e3..16ea14c3 100644 --- a/x/scheduler/bindings/msg_plugin.go +++ b/x/scheduler/bindings/msg_plugin.go @@ -2,13 +2,12 @@ package bindings import ( "context" - "encoding/json" sdkerrors "cosmossdk.io/errors" - wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/palomachain/paloma/v2/util/libwasm" bindingstypes "github.com/palomachain/paloma/v2/x/scheduler/bindings/types" schedulertypes "github.com/palomachain/paloma/v2/x/scheduler/types" ) @@ -17,7 +16,10 @@ type SchedulerMsgServer interface { CreateJob(context.Context, *schedulertypes.MsgCreateJob) (*schedulertypes.MsgCreateJobResponse, error) } -func NewMessenger(k Schedulerkeeper, ms SchedulerMsgServer) wasmkeeper.Messenger { +func NewMessenger( + k Schedulerkeeper, + ms SchedulerMsgServer, +) libwasm.Messenger[bindingstypes.Message] { return &customMessenger{ ms: ms, k: k, @@ -29,23 +31,22 @@ type customMessenger struct { k Schedulerkeeper } -var _ wasmkeeper.Messenger = (*customMessenger)(nil) - -func (m *customMessenger) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, _ string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) { - if msg.Custom == nil { - var contractMsg bindingstypes.Message - if err := json.Unmarshal(msg.Custom, &contractMsg); err != nil { - return nil, nil, nil, sdkerrors.Wrap(err, "scheduler msg") - } - switch { - case contractMsg.CreateJob != nil: - return m.createJob(ctx, contractAddr, contractMsg.CreateJob) - case contractMsg.ExecuteJob != nil: - return m.executeJob(ctx, contractAddr, contractMsg.ExecuteJob) - } +var _ libwasm.Messenger[bindingstypes.Message] = (*customMessenger)(nil) + +func (m *customMessenger) DispatchMsg( + ctx sdk.Context, + contractAddr sdk.AccAddress, + _ string, + contractMsg bindingstypes.Message, +) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) { + switch { + case contractMsg.CreateJob != nil: + return m.createJob(ctx, contractAddr, contractMsg.CreateJob) + case contractMsg.ExecuteJob != nil: + return m.executeJob(ctx, contractAddr, contractMsg.ExecuteJob) } - return nil, nil, nil, nil + return nil, nil, nil, libwasm.ErrUnrecognizedMessage } func (m *customMessenger) createJob(ctx sdk.Context, contractAddr sdk.AccAddress, createJob *bindingstypes.CreateJob) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) { diff --git a/x/skyway/bindings/msg_plugin.go b/x/skyway/bindings/msg_plugin.go index 355f225e..b3d29149 100644 --- a/x/skyway/bindings/msg_plugin.go +++ b/x/skyway/bindings/msg_plugin.go @@ -2,13 +2,11 @@ package bindings import ( "context" - "encoding/json" sdkerrors "cosmossdk.io/errors" - wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" - wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/palomachain/paloma/v2/util/libwasm" bindingstypes "github.com/palomachain/paloma/v2/x/skyway/bindings/types" skywaytypes "github.com/palomachain/paloma/v2/x/skyway/types" "google.golang.org/protobuf/types/known/emptypb" @@ -24,84 +22,85 @@ type customMessenger struct { k SkywayMsgServer } -var _ wasmkeeper.Messenger = (*customMessenger)(nil) +var _ libwasm.Messenger[bindingstypes.Message] = (*customMessenger)(nil) -func NewMessenger(k SkywayMsgServer) wasmkeeper.Messenger { +func NewMessenger(k SkywayMsgServer) libwasm.Messenger[bindingstypes.Message] { return &customMessenger{ k: k, } } -func (m *customMessenger) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) { - if msg.Custom != nil { - var contractMsg bindingstypes.Message - if err := json.Unmarshal(msg.Custom, &contractMsg); err != nil { - return nil, nil, nil, sdkerrors.Wrap(err, "skyway msg") - } - - switch { - case contractMsg.SetErc20ToDenom != nil: - case contractMsg.SendTx != nil: - case contractMsg.CancelTx != nil: - return nil, nil, nil, nil - } +func (m *customMessenger) DispatchMsg( + ctx sdk.Context, + contractAddr sdk.AccAddress, + contractIBCPortID string, + contractMsg bindingstypes.Message, +) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) { + switch { + case contractMsg.SetErc20ToDenom != nil: + return handleSetErc20ToDenom(ctx, m.k, contractAddr, contractMsg.SetErc20ToDenom) + case contractMsg.SendTx != nil: + return sendTx(ctx, m.k, contractAddr, contractMsg.SendTx) + case contractMsg.CancelTx != nil: + return cancelTx(ctx, m.k, contractAddr, contractMsg.CancelTx) } - return nil, nil, nil, nil + + return nil, nil, nil, libwasm.ErrUnrecognizedMessage } -func sendTx(ctx sdk.Context, k SkywayMsgServer, sender sdk.AccAddress, msg bindingstypes.SendTx) error { +func sendTx(ctx sdk.Context, k SkywayMsgServer, sender sdk.AccAddress, msg *bindingstypes.SendTx) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) { if err := msg.ValidateBasic(); err != nil { - return sdkerrors.Wrap(err, "validation failed") + return nil, nil, nil, sdkerrors.Wrap(err, "validation failed") } dest, err := skywaytypes.NewEthAddress(msg.RemoteChainDestinationAddress) if err != nil { - return sdkerrors.Wrap(err, "invalid eth address") + return nil, nil, nil, sdkerrors.Wrap(err, "invalid eth address") } amount, err := sdk.ParseCoinsNormalized(msg.Amount) if err != nil { - return sdkerrors.Wrap(err, "amount") + return nil, nil, nil, sdkerrors.Wrap(err, "amount") } req := skywaytypes.NewMsgSendToRemote(sender, *dest, amount[0], msg.ChainReferenceId) _, err = k.SendToRemote(ctx, req) if err != nil { - return sdkerrors.Wrap(err, "failed to dispatch message") + return nil, nil, nil, sdkerrors.Wrap(err, "failed to dispatch message") } - return nil + return nil, nil, nil, nil } -func cancelTx(ctx sdk.Context, k SkywayMsgServer, sender sdk.AccAddress, msg bindingstypes.CancelTx) error { +func cancelTx(ctx sdk.Context, k SkywayMsgServer, sender sdk.AccAddress, msg *bindingstypes.CancelTx) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) { if err := msg.ValidateBasic(); err != nil { - return sdkerrors.Wrap(err, "validation failed") + return nil, nil, nil, sdkerrors.Wrap(err, "validation failed") } req := skywaytypes.NewMsgCancelSendToRemote(sender, msg.TransactionId) _, err := k.CancelSendToRemote(ctx, req) if err != nil { - return sdkerrors.Wrap(err, "failed to dispatch message") + return nil, nil, nil, sdkerrors.Wrap(err, "failed to dispatch message") } - return nil + return nil, nil, nil, nil } -func handleSetErc20ToDenom(ctx sdk.Context, k SkywayMsgServer, sender sdk.AccAddress, msg bindingstypes.SetErc20ToDenom) error { +func handleSetErc20ToDenom(ctx sdk.Context, k SkywayMsgServer, sender sdk.AccAddress, msg *bindingstypes.SetErc20ToDenom) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) { if err := msg.ValidateBasic(); err != nil { - return sdkerrors.Wrap(err, "validation failed") + return nil, nil, nil, sdkerrors.Wrap(err, "validation failed") } erc20, err := skywaytypes.NewEthAddress(msg.Erc20Address) if err != nil { - return sdkerrors.Wrap(err, "invalid eth address") + return nil, nil, nil, sdkerrors.Wrap(err, "invalid eth address") } req := skywaytypes.NewMsgSetERC20ToTokenDenom(sender, *erc20, msg.ChainReferenceId, msg.TokenDenom) _, err = k.SetERC20ToTokenDenom(ctx, req) if err != nil { - return sdkerrors.Wrap(err, "failed to dispatch message") + return nil, nil, nil, sdkerrors.Wrap(err, "failed to dispatch message") } - return nil + return nil, nil, nil, nil } diff --git a/x/tokenfactory/bindings/msg_plugin.go b/x/tokenfactory/bindings/msg_plugin.go index e83f0083..ba201131 100644 --- a/x/tokenfactory/bindings/msg_plugin.go +++ b/x/tokenfactory/bindings/msg_plugin.go @@ -1,21 +1,19 @@ package bindings import ( - "encoding/json" - sdkerrors "cosmossdk.io/errors" - wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/palomachain/paloma/v2/util/libwasm" bindingstypes "github.com/palomachain/paloma/v2/x/tokenfactory/bindings/types" tokenfactorykeeper "github.com/palomachain/paloma/v2/x/tokenfactory/keeper" tokenfactorytypes "github.com/palomachain/paloma/v2/x/tokenfactory/types" ) -func NewMessenger(bank *bankkeeper.BaseKeeper, tokenFactory *tokenfactorykeeper.Keeper) wasmkeeper.Messenger { +func NewMessenger(bank *bankkeeper.BaseKeeper, tokenFactory *tokenfactorykeeper.Keeper) libwasm.Messenger[bindingstypes.Message] { return &customMessenger{ bank: bank, tokenFactory: tokenFactory, @@ -27,28 +25,23 @@ type customMessenger struct { tokenFactory *tokenfactorykeeper.Keeper } -var _ wasmkeeper.Messenger = (*customMessenger)(nil) +var _ libwasm.Messenger[bindingstypes.Message] = (*customMessenger)(nil) -func (m *customMessenger) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) { - if msg.Custom != nil { - var contractMsg bindingstypes.Message - if err := json.Unmarshal(msg.Custom, &contractMsg); err != nil { - return nil, nil, nil, sdkerrors.Wrap(err, "token factory msg") - } - switch { - case contractMsg.CreateDenom != nil: - return m.createDenom(ctx, contractAddr, contractMsg.CreateDenom) - case contractMsg.MintTokens != nil: - return m.mintTokens(ctx, contractAddr, contractMsg.MintTokens) - case contractMsg.ChangeAdmin != nil: - return m.changeAdmin(ctx, contractAddr, contractMsg.ChangeAdmin) - case contractMsg.BurnTokens != nil: - return m.burnTokens(ctx, contractAddr, contractMsg.BurnTokens) - case contractMsg.SetMetadata != nil: - return m.setMetadata(ctx, contractAddr, contractMsg.SetMetadata) - } +func (m *customMessenger) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, contractMsg bindingstypes.Message) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) { + switch { + case contractMsg.CreateDenom != nil: + return m.createDenom(ctx, contractAddr, contractMsg.CreateDenom) + case contractMsg.MintTokens != nil: + return m.mintTokens(ctx, contractAddr, contractMsg.MintTokens) + case contractMsg.ChangeAdmin != nil: + return m.changeAdmin(ctx, contractAddr, contractMsg.ChangeAdmin) + case contractMsg.BurnTokens != nil: + return m.burnTokens(ctx, contractAddr, contractMsg.BurnTokens) + case contractMsg.SetMetadata != nil: + return m.setMetadata(ctx, contractAddr, contractMsg.SetMetadata) } - return nil, nil, nil, nil + + return nil, nil, nil, libwasm.ErrUnrecognizedMessage } func (m *customMessenger) createDenom(ctx sdk.Context, contractAddr sdk.AccAddress, createDenom *bindingstypes.CreateDenom) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) {