diff --git a/CHANGELOG.md b/CHANGELOG.md index 221127e66..151df8fed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,14 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features +- (genesisbridge) [#932](https://github.com/dymensionxyz/dymension/issues/932) Adds ibc module and ante handler to stop transfers to/from rollapp that has an incomplete genesis bridge (transfersEnabled) +- (genesisbridge) [#932](https://github.com/dymensionxyz/dymension/issues/932) Adds a new temporary ibc module to set the canonical channel id, since we no longer do that using a whitelisted addr +- (genesisbridge) [#932](https://github.com/dymensionxyz/dymension/issues/932) Adds a new ibc module to handle incoming 'genesis transfers'. It validates the special memo and registers a denom. It will not allow any regular transfers if transfers are not enabled +- (rollapp) [#932](https://github.com/dymensionxyz/dymension/issues/932) Renames is_genesis_event on the rollapp genesis state to 'transfers_enabled' this is backwards compatible +- (rollapp) [#932](https://github.com/dymensionxyz/dymension/issues/932) Removes concept of passing genesis accounts and denoms in the create rollapp message +- (rollapp) [#932](https://github.com/dymensionxyz/dymension/issues/932) Adds a transfersenabled flag to createRollapp (might be changed in future) +- (delayedack) [#932](https://github.com/dymensionxyz/dymension/issues/932) Adds the notion of skipctx, to skip it with a special sdk context value +- (code standards) [#932](https://github.com/dymensionxyz/dymension/issues/932) Adds a gerr (google error ) and derr (dymension error) packages for idiomatic error handling. (In future we will consolidate across dymint/rdk) - (denommetadata) [#907](https://github.com/dymensionxyz/dymension/issues/907) Add IBC middleware to migrate denom metadata to rollappp, remove `CreateDenomMetadata` and `UpdateDenomMetadata` tx handlers - (delayedack) [#849](https://github.com/dymensionxyz/dymension/issues/849) Add demand order filters: type, rollapp id and limit - (delayedack) [#850](https://github.com/dymensionxyz/dymension/issues/850) Add type filter for delayedack @@ -79,6 +87,11 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes +- (code standards) [#932](https://github.com/dymensionxyz/dymension/issues/932) Dry out existing middlewares to make use of new .GetValidTransfer* functions which take care of parsing and validating the fungible packet, and querying and validating any associated rollapp and finalizations +- (code standards) [#932](https://github.com/dymensionxyz/dymension/issues/932) Removes the obsolete ValidateRollappId func and sub routines +- (code standards) [#932](https://github.com/dymensionxyz/dymension/issues/932) Simplify GetAllBlockHeightToFinalizationQueue +- (code standards) [#932](https://github.com/dymensionxyz/dymension/issues/932) Fixes naming for our 'middlewares' to make them clearly one of ibc module / ics4 wrapper / middleware +- (code standards) [#932](https://github.com/dymensionxyz/dymension/issues/932) Moves our various utils to properly namespaced packages under utils/ - (rollapp) [#839](https://github.com/dymensionxyz/dymension/issues/839) Remove rollapp deprecated fields - (eibc) [#836](https://github.com/dymensionxyz/dymension/issues/836) Improve eibc memo error handling - (eibc) [#830](https://github.com/dymensionxyz/dymension/issues/830) Invalid tx should return ackErr diff --git a/app/ante/ante_options.go b/app/ante/ante_options.go index 2532e66da..3d288791a 100644 --- a/app/ante/ante_options.go +++ b/app/ante/ante_options.go @@ -6,6 +6,7 @@ import ( authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" ibckeeper "github.com/cosmos/ibc-go/v6/modules/core/keeper" + rollappkeeper "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper" ethante "github.com/evmos/ethermint/app/ante" errorsmod "cosmossdk.io/errors" @@ -24,6 +25,7 @@ type HandlerOptions struct { SignModeHandler authsigning.SignModeHandler MaxTxGasWanted uint64 ExtensionOptionChecker ante.ExtensionOptionChecker + RollappKeeper rollappkeeper.Keeper } func (options HandlerOptions) validate() error { diff --git a/app/ante/handlers.go b/app/ante/handlers.go index cf61d55f0..d3343b87f 100644 --- a/app/ante/handlers.go +++ b/app/ante/handlers.go @@ -4,6 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ante "github.com/cosmos/cosmos-sdk/x/auth/ante" ibcante "github.com/cosmos/ibc-go/v6/modules/core/ante" + "github.com/dymensionxyz/dymension/v3/x/rollapp/transfersenabled" ethante "github.com/evmos/ethermint/app/ante" txfeesante "github.com/osmosis-labs/osmosis/v15/x/txfees/ante" @@ -72,6 +73,8 @@ func newLegacyCosmosAnteHandlerEip712(options HandlerOptions) sdk.AnteHandler { delayedack.NewIBCProofHeightDecorator(), ibcante.NewRedundantRelayDecorator(options.IBCKeeper), ethante.NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper), + + transfersenabled.NewDecorator(options.RollappKeeper.GetRollapp, options.IBCKeeper.ChannelKeeper.GetChannelClientState), ) } @@ -80,6 +83,7 @@ func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler { deductFeeDecorator := txfeesante.NewDeductFeeDecorator(*options.TxFeesKeeper, options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper) return sdk.ChainAnteDecorators( + NewRejectMessagesDecorator(), // reject MsgEthereumTxs and vesting msgs ethante.NewAuthzLimiterDecorator([]string{ // disable the Msg types that cannot be included on an authz.MsgExec msgs field sdk.MsgTypeURL(&evmtypes.MsgEthereumTx{}), @@ -105,5 +109,7 @@ func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler { delayedack.NewIBCProofHeightDecorator(), ibcante.NewRedundantRelayDecorator(options.IBCKeeper), ethante.NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper), + + transfersenabled.NewDecorator(options.RollappKeeper.GetRollapp, options.IBCKeeper.ChannelKeeper.GetChannelClientState), ) } diff --git a/app/app.go b/app/app.go index 58aaf6c04..cd9ad0d5d 100644 --- a/app/app.go +++ b/app/app.go @@ -9,7 +9,12 @@ import ( "os" "path/filepath" - "github.com/dymensionxyz/dymension/v3/x/bridging_fee" + "github.com/dymensionxyz/dymension/v3/x/rollapp/transfersenabled" + + "github.com/dymensionxyz/dymension/v3/x/rollapp/transfergenesis" + + "github.com/dymensionxyz/dymension/v3/x/bridgingfee" + vfchooks "github.com/dymensionxyz/dymension/v3/x/vfc/hooks" "github.com/gorilla/mux" @@ -279,7 +284,7 @@ var ( govtypes.ModuleName: {authtypes.Burner}, ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, sequencermoduletypes.ModuleName: {authtypes.Minter, authtypes.Burner, authtypes.Staking}, - rollappmoduletypes.ModuleName: {authtypes.Minter}, + rollappmoduletypes.ModuleName: {}, streamermoduletypes.ModuleName: nil, evmtypes.ModuleName: {authtypes.Minter, authtypes.Burner}, // used for secure addition and subtraction of balance using module account. evmtypes.ModuleVirtualFrontierContractDeployerName: nil, // used for deploying virtual frontier bank contract. @@ -546,7 +551,7 @@ func New( app.AccountKeeper, ) - txfeeskeeper := txfeeskeeper.NewKeeper( + txFeesKeeper := txfeeskeeper.NewKeeper( app.keys[txfeestypes.StoreKey], app.GetSubspace(txfeestypes.ModuleName), app.AccountKeeper, @@ -555,7 +560,7 @@ func New( app.PoolManagerKeeper, app.GAMMKeeper, ) - app.TxFeesKeeper = &txfeeskeeper + app.TxFeesKeeper = &txFeesKeeper app.GAMMKeeper.SetPoolManager(app.PoolManagerKeeper) app.GAMMKeeper.SetTxFees(app.TxFeesKeeper) @@ -609,23 +614,14 @@ func New( ), ) - app.RollappKeeper = *rollappmodulekeeper.NewKeeper( - appCodec, - keys[rollappmoduletypes.StoreKey], - keys[rollappmoduletypes.MemStoreKey], - app.GetSubspace(rollappmoduletypes.ModuleName), - app.IBCKeeper.ClientKeeper, - app.IBCKeeper.ChannelKeeper, - app.BankKeeper, - app.DenomMetadataKeeper, - ) + app.RollappKeeper = *rollappmodulekeeper.NewKeeper(appCodec, keys[rollappmoduletypes.StoreKey], app.GetSubspace(rollappmoduletypes.ModuleName), app.IBCKeeper.ChannelKeeper) // Create Transfer Keepers app.TransferKeeper = ibctransferkeeper.NewKeeper( appCodec, keys[ibctransfertypes.StoreKey], app.GetSubspace(ibctransfertypes.ModuleName), - transferinject.NewIBCSendMiddleware(app.IBCKeeper.ChannelKeeper, app.RollappKeeper, app.BankKeeper), + transferinject.NewICS4Wrapper(app.IBCKeeper.ChannelKeeper, app.RollappKeeper, app.BankKeeper), app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, app.AccountKeeper, @@ -633,8 +629,6 @@ func New( scopedTransferKeeper, ) - app.RollappKeeper.SetTransferKeeper(app.TransferKeeper) - app.SequencerKeeper = *sequencermodulekeeper.NewKeeper( appCodec, keys[sequencermoduletypes.StoreKey], @@ -649,11 +643,8 @@ func New( keys[delayedacktypes.StoreKey], app.GetSubspace(delayedacktypes.ModuleName), app.RollappKeeper, - app.SequencerKeeper, app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper, - app.IBCKeeper.ConnectionKeeper, - app.IBCKeeper.ClientKeeper, &app.EIBCKeeper, app.BankKeeper, ) @@ -742,27 +733,18 @@ func New( ) transferModule := ibctransfer.NewAppModule(app.TransferKeeper) - transferMiddleware := ibctransfer.NewIBCModule(app.TransferKeeper) var transferStack ibcporttypes.IBCModule - transferStack = bridging_fee.NewIBCMiddleware( - transferMiddleware, - app.IBCKeeper.ChannelKeeper, - app.DelayedAckKeeper, - app.RollappKeeper, - app.TransferKeeper, - app.AccountKeeper.GetModuleAddress(txfeestypes.ModuleName), - ) + transferStack = ibctransfer.NewIBCModule(app.TransferKeeper) + transferStack = bridgingfee.NewIBCModule(transferStack.(ibctransfer.IBCModule), app.DelayedAckKeeper, app.TransferKeeper, app.AccountKeeper.GetModuleAddress(txfeestypes.ModuleName), app.RollappKeeper) + transferStack = packetforwardmiddleware.NewIBCMiddleware(transferStack, app.PacketForwardMiddlewareKeeper, 0, packetforwardkeeper.DefaultForwardTransferPacketTimeoutTimestamp, packetforwardkeeper.DefaultRefundTransferPacketTimeoutTimestamp) - transferStack = packetforwardmiddleware.NewIBCMiddleware( - transferStack, - app.PacketForwardMiddlewareKeeper, - 0, - packetforwardkeeper.DefaultForwardTransferPacketTimeoutTimestamp, - packetforwardkeeper.DefaultRefundTransferPacketTimeoutTimestamp, - ) delayedAckMiddleware := delayedackmodule.NewIBCMiddleware(transferStack, app.DelayedAckKeeper, app.RollappKeeper) - transferStack = transferinject.NewIBCAckMiddleware(delayedAckMiddleware, app.RollappKeeper) + transferStack = delayedAckMiddleware + transferStack = transferinject.NewIBCModule(transferStack, app.RollappKeeper) + transferStack = transfersenabled.NewIBCModule(transferStack, app.RollappKeeper, app.DelayedAckKeeper) + transferStack = transfergenesis.NewIBCModule(transferStack, app.DelayedAckKeeper, app.RollappKeeper, app.TransferKeeper, app.DenomMetadataKeeper) + transferStack = transfergenesis.NewIBCModuleCanonicalChannelHack(transferStack, app.RollappKeeper, app.IBCKeeper.ChannelKeeper.GetChannelClientState) // Create static IBC router, add transfer route, then set and seal it ibcRouter := ibcporttypes.NewRouter() @@ -976,6 +958,7 @@ func New( SignModeHandler: encodingConfig.TxConfig.SignModeHandler(), MaxTxGasWanted: maxGasWanted, ExtensionOptionChecker: nil, // uses default + RollappKeeper: app.RollappKeeper, }) if err != nil { panic(err) diff --git a/app/apptesting/events.go b/app/apptesting/events.go index 91f3bf577..ed7e0f1a9 100644 --- a/app/apptesting/events.go +++ b/app/apptesting/events.go @@ -51,6 +51,6 @@ func (s *KeeperTestHelper) ExtractAttributes(event sdk.Event) map[string]string func (s *KeeperTestHelper) AssertAttributes(event sdk.Event, eventAttributes []sdk.Attribute) { attrs := s.ExtractAttributes(event) for _, attr := range eventAttributes { - s.Assert().Equal(attr.Value, attrs[attr.Key]) + s.Equal(attr.Value, attrs[attr.Key]) } } diff --git a/app/apptesting/test_helpers.go b/app/apptesting/test_helpers.go index 8d133792b..0f5145383 100644 --- a/app/apptesting/test_helpers.go +++ b/app/apptesting/test_helpers.go @@ -10,6 +10,8 @@ import ( "testing" "time" + errorsmod "cosmossdk.io/errors" + "cosmossdk.io/math" "github.com/dymensionxyz/dymension/v3/app/params" @@ -453,7 +455,7 @@ func NewPubKeyFromHex(pk string) (res cryptotypes.PubKey) { panic(err) } if len(pkBytes) != ed25519.PubKeySize { - panic(errors.Wrap(errors.ErrInvalidPubKey, "invalid pubkey size")) + panic(errorsmod.Wrap(errors.ErrInvalidPubKey, "invalid pubkey size")) } return &ed25519.PubKey{Key: pkBytes} } diff --git a/app/apptesting/test_suite.go b/app/apptesting/test_suite.go index aad640575..c953bdea2 100644 --- a/app/apptesting/test_suite.go +++ b/app/apptesting/test_suite.go @@ -27,32 +27,32 @@ type KeeperTestHelper struct { Ctx sdk.Context } -func (suite *KeeperTestHelper) CreateDefaultRollapp() string { - return suite.CreateRollappWithName(rand.Str(8)) +func (s *KeeperTestHelper) CreateDefaultRollapp() string { + return s.CreateRollappWithName(rand.Str(8)) } -func (suite *KeeperTestHelper) CreateRollappWithName(name string) string { +func (s *KeeperTestHelper) CreateRollappWithName(name string) string { msgCreateRollapp := rollapptypes.MsgCreateRollapp{ Creator: alice, RollappId: name, MaxSequencers: 5, } - msgServer := rollappkeeper.NewMsgServerImpl(suite.App.RollappKeeper) - _, err := msgServer.CreateRollapp(suite.Ctx, &msgCreateRollapp) - suite.Require().NoError(err) + msgServer := rollappkeeper.NewMsgServerImpl(s.App.RollappKeeper) + _, err := msgServer.CreateRollapp(s.Ctx, &msgCreateRollapp) + s.Require().NoError(err) return name } -func (suite *KeeperTestHelper) CreateDefaultSequencer(ctx sdk.Context, rollappId string) string { +func (s *KeeperTestHelper) CreateDefaultSequencer(ctx sdk.Context, rollappId string) string { pubkey1 := secp256k1.GenPrivKey().PubKey() addr1 := sdk.AccAddress(pubkey1.Address()) pkAny1, err := codectypes.NewAnyWithValue(pubkey1) - suite.Require().Nil(err) + s.Require().Nil(err) // fund account - err = bankutil.FundAccount(suite.App.BankKeeper, ctx, addr1, sdk.NewCoins(bond)) - suite.Require().Nil(err) + err = bankutil.FundAccount(s.App.BankKeeper, ctx, addr1, sdk.NewCoins(bond)) + s.Require().Nil(err) sequencerMsg1 := sequencertypes.MsgCreateSequencer{ Creator: addr1.String(), @@ -62,13 +62,13 @@ func (suite *KeeperTestHelper) CreateDefaultSequencer(ctx sdk.Context, rollappId Description: sequencertypes.Description{}, } - msgServer := sequencerkeeper.NewMsgServerImpl(suite.App.SequencerKeeper) + msgServer := sequencerkeeper.NewMsgServerImpl(s.App.SequencerKeeper) _, err = msgServer.CreateSequencer(ctx, &sequencerMsg1) - suite.Require().Nil(err) + s.Require().Nil(err) return addr1.String() } -func (suite *KeeperTestHelper) PostStateUpdate(ctx sdk.Context, rollappId, seqAddr string, startHeight, numOfBlocks uint64) (lastHeight uint64, err error) { +func (s *KeeperTestHelper) PostStateUpdate(ctx sdk.Context, rollappId, seqAddr string, startHeight, numOfBlocks uint64) (lastHeight uint64, err error) { var bds rollapptypes.BlockDescriptors bds.BD = make([]rollapptypes.BlockDescriptor, numOfBlocks) for k := 0; k < int(numOfBlocks); k++ { @@ -84,7 +84,7 @@ func (suite *KeeperTestHelper) PostStateUpdate(ctx sdk.Context, rollappId, seqAd Version: 0, BDs: bds, } - msgServer := rollappkeeper.NewMsgServerImpl(suite.App.RollappKeeper) + msgServer := rollappkeeper.NewMsgServerImpl(s.App.RollappKeeper) _, err = msgServer.UpdateState(ctx, &updateState) return startHeight + numOfBlocks, err } diff --git a/app/params/config.go b/app/params/config.go index 9d9b71c13..a93b26fd2 100644 --- a/app/params/config.go +++ b/app/params/config.go @@ -1,6 +1,7 @@ package params import ( + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/address" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -52,15 +53,15 @@ func SetAddressPrefixes() { config.SetAddressVerifier(func(bytes []byte) error { if len(bytes) == 0 { - return sdkerrors.Wrap(sdkerrors.ErrUnknownAddress, "addresses cannot be empty") + return errorsmod.Wrap(sdkerrors.ErrUnknownAddress, "addresses cannot be empty") } if len(bytes) > address.MaxAddrLen { - return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "address max length is %d, got %d", address.MaxAddrLen, len(bytes)) + return errorsmod.Wrapf(sdkerrors.ErrUnknownAddress, "address max length is %d, got %d", address.MaxAddrLen, len(bytes)) } if len(bytes) != 20 && len(bytes) != 32 { - return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "address length must be 20 or 32 bytes, got %d", len(bytes)) + return errorsmod.Wrapf(sdkerrors.ErrUnknownAddress, "address length must be 20 or 32 bytes, got %d", len(bytes)) } return nil diff --git a/go.mod b/go.mod index 1dc0a2f8c..e7bc4b8d1 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/gorilla/mux v1.8.1 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/osmosis-labs/osmosis/v15 v15.2.0 + github.com/pkg/errors v0.9.1 github.com/spf13/cast v1.5.0 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 @@ -160,7 +161,6 @@ require ( github.com/osmosis-labs/osmosis/osmomath v0.0.4 // indirect github.com/pelletier/go-toml/v2 v2.0.7 // indirect github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.14.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect diff --git a/ibctesting/bridging_fee_test.go b/ibctesting/bridging_fee_test.go index b9b9294a2..757f01549 100644 --- a/ibctesting/bridging_fee_test.go +++ b/ibctesting/bridging_fee_test.go @@ -11,95 +11,97 @@ import ( "github.com/stretchr/testify/suite" ) -type BridgingFeeTestSuite struct { - IBCTestUtilSuite +type bridgingFeeSuite struct { + utilSuite } func TestBridgingFeeTestSuite(t *testing.T) { - suite.Run(t, new(BridgingFeeTestSuite)) + suite.Run(t, new(bridgingFeeSuite)) } -func (suite *BridgingFeeTestSuite) SetupTest() { - suite.IBCTestUtilSuite.SetupTest() -} - -func (suite *BridgingFeeTestSuite) TestNotRollappNoBridgingFee() { +func (s *bridgingFeeSuite) TestNotRollappNoBridgingFee() { // setup between cosmosChain and hubChain - path := suite.NewTransferPath(suite.hubChain, suite.cosmosChain) - suite.coordinator.Setup(path) - hubEndpoint := path.EndpointA + path := s.newTransferPath(s.hubChain(), s.cosmosChain()) + s.coordinator.Setup(path) cosmosEndpoint := path.EndpointB timeoutHeight := clienttypes.NewHeight(100, 110) amount, ok := sdk.NewIntFromString("10000000000000000000") // 10DYM - suite.Require().True(ok) + s.Require().True(ok) coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, amount) // send from cosmosChain to hubChain - msg := types.NewMsgTransfer(cosmosEndpoint.ChannelConfig.PortID, cosmosEndpoint.ChannelID, coinToSendToB, cosmosEndpoint.Chain.SenderAccount.GetAddress().String(), hubEndpoint.Chain.SenderAccount.GetAddress().String(), timeoutHeight, 0, "") - res, err := cosmosEndpoint.Chain.SendMsgs(msg) - suite.Require().NoError(err) // message committed + msg := types.NewMsgTransfer(cosmosEndpoint.ChannelConfig.PortID, cosmosEndpoint.ChannelID, coinToSendToB, s.cosmosChain().SenderAccount.GetAddress().String(), s.hubChain().SenderAccount.GetAddress().String(), timeoutHeight, 0, "") + res, err := s.cosmosChain().SendMsgs(msg) + s.Require().NoError(err) // message committed packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) - suite.Require().NoError(err) + s.Require().NoError(err) err = path.RelayPacket(packet) - suite.Require().NoError(err) // relay committed + s.NoError(err) // relay committed - denom := suite.GetRollappToHubIBCDenomFromPacket(packet) - finalBalance := ConvertToApp(suite.hubChain).BankKeeper.GetBalance(suite.hubChain.GetContext(), suite.hubChain.SenderAccount.GetAddress(), denom) - suite.Assert().Equal(sdk.NewCoin(denom, coinToSendToB.Amount), finalBalance) + denom := s.getRollappToHubIBCDenomFromPacket(packet) + finalBalance := s.hubApp().BankKeeper.GetBalance(s.hubCtx(), s.hubChain().SenderAccount.GetAddress(), denom) + s.Equal(sdk.NewCoin(denom, coinToSendToB.Amount), finalBalance) } -func (suite *BridgingFeeTestSuite) TestBridgingFee() { - path := suite.NewTransferPath(suite.hubChain, suite.rollappChain) - suite.coordinator.Setup(path) +func (s *bridgingFeeSuite) TestBridgingFee() { + path := s.newTransferPath(s.hubChain(), s.rollappChain()) + s.coordinator.Setup(path) + s.createRollappWithFinishedGenesis(path.EndpointA.ChannelID) + s.registerSequencer() rollappEndpoint := path.EndpointB - rollappIBCKeeper := suite.rollappChain.App.GetIBCKeeper() - - suite.CreateRollapp() - suite.RegisterSequencer() - suite.GenesisEvent(path.EndpointA.ChannelID) + rollappIBCKeeper := s.rollappChain().App.GetIBCKeeper() // Update rollapp state - currentRollappBlockHeight := uint64(suite.rollappChain.GetContext().BlockHeight()) - suite.UpdateRollappState(currentRollappBlockHeight) + currentRollappBlockHeight := uint64(s.rollappCtx().BlockHeight()) + s.updateRollappState(currentRollappBlockHeight) timeoutHeight := clienttypes.NewHeight(100, 110) amount, ok := sdk.NewIntFromString("10000000000000000000") // 10DYM - suite.Require().True(ok) + s.Require().True(ok) coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, amount) /* --------------------- initiating transfer on rollapp --------------------- */ - msg := types.NewMsgTransfer(rollappEndpoint.ChannelConfig.PortID, rollappEndpoint.ChannelID, coinToSendToB, suite.rollappChain.SenderAccount.GetAddress().String(), suite.hubChain.SenderAccount.GetAddress().String(), timeoutHeight, 0, "") - res, err := suite.rollappChain.SendMsgs(msg) - suite.Require().NoError(err) // message committed + msg := types.NewMsgTransfer( + rollappEndpoint.ChannelConfig.PortID, + rollappEndpoint.ChannelID, + coinToSendToB, + s.rollappChain().SenderAccount.GetAddress().String(), + s.hubChain().SenderAccount.GetAddress().String(), + timeoutHeight, + 0, + "", + ) + res, err := s.rollappChain().SendMsgs(msg) + s.Require().NoError(err) // message committed packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) - suite.Require().NoError(err) - found := rollappIBCKeeper.ChannelKeeper.HasPacketCommitment(rollappEndpoint.Chain.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - suite.Require().True(found) + s.Require().NoError(err) + found := rollappIBCKeeper.ChannelKeeper.HasPacketCommitment(s.rollappCtx(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + s.Require().True(found) err = path.RelayPacket(packet) - suite.Require().Error(err) // expecting error as no AcknowledgePacket expected to return + s.Require().Error(err) // expecting error as no AcknowledgePacket expected to return // check balance before finalization - denom := suite.GetRollappToHubIBCDenomFromPacket(packet) + denom := s.getRollappToHubIBCDenomFromPacket(packet) transferredCoins := sdk.NewCoin(denom, coinToSendToB.Amount) - recipient := suite.hubChain.SenderAccount.GetAddress() - initialBalance := ConvertToApp(suite.hubChain).BankKeeper.SpendableCoins(suite.hubChain.GetContext(), recipient) - suite.Require().Equal(initialBalance.AmountOf(denom), sdk.ZeroInt()) + recipient := s.hubChain().SenderAccount.GetAddress() + initialBalance := s.hubApp().BankKeeper.SpendableCoins(s.hubCtx(), recipient) + s.Require().Equal(initialBalance.AmountOf(denom), sdk.ZeroInt()) // Finalize the rollapp state - currentRollappBlockHeight = uint64(suite.rollappChain.GetContext().BlockHeight()) - _, err = suite.FinalizeRollappState(1, currentRollappBlockHeight) - suite.Require().NoError(err) + currentRollappBlockHeight = uint64(s.rollappCtx().BlockHeight()) + _, err = s.finalizeRollappState(1, currentRollappBlockHeight) + s.Require().NoError(err) // check balance after finalization - expectedFee := ConvertToApp(suite.hubChain).DelayedAckKeeper.BridgingFeeFromAmt(suite.hubChain.GetContext(), transferredCoins.Amount) + expectedFee := s.hubApp().DelayedAckKeeper.BridgingFeeFromAmt(s.hubCtx(), transferredCoins.Amount) expectedBalance := initialBalance.Add(transferredCoins).Sub(sdk.NewCoin(denom, expectedFee)) - finalBalance := ConvertToApp(suite.hubChain).BankKeeper.SpendableCoins(suite.hubChain.GetContext(), recipient) - suite.Assert().Equal(expectedBalance, finalBalance) + finalBalance := s.hubApp().BankKeeper.SpendableCoins(s.hubCtx(), recipient) + s.Equal(expectedBalance, finalBalance) // check fees - addr := ConvertToApp(suite.hubChain).AccountKeeper.GetModuleAccount(suite.hubChain.GetContext(), txfees.ModuleName) - txFeesBalance := ConvertToApp(suite.hubChain).BankKeeper.GetBalance(suite.hubChain.GetContext(), addr.GetAddress(), denom) - suite.Assert().Equal(expectedFee, txFeesBalance.Amount) + addr := s.hubApp().AccountKeeper.GetModuleAccount(s.hubCtx(), txfees.ModuleName) + txFeesBalance := s.hubApp().BankKeeper.GetBalance(s.hubCtx(), addr.GetAddress(), denom) + s.Equal(expectedFee, txFeesBalance.Amount) } diff --git a/ibctesting/delayed_ack_test.go b/ibctesting/delayed_ack_test.go index 28ca29fbb..d08400c5c 100644 --- a/ibctesting/delayed_ack_test.go +++ b/ibctesting/delayed_ack_test.go @@ -16,225 +16,217 @@ const ( disabledTimeoutTimestamp = uint64(0) ) -type DelayedAckTestSuite struct { - IBCTestUtilSuite +type delayedAckSuite struct { + utilSuite } func TestDelayedAckTestSuite(t *testing.T) { - suite.Run(t, new(DelayedAckTestSuite)) + suite.Run(t, new(delayedAckSuite)) } -func (suite *DelayedAckTestSuite) SetupTest() { - suite.IBCTestUtilSuite.SetupTest() - ConvertToApp(suite.hubChain).BankKeeper.SetDenomMetaData(suite.hubChain.GetContext(), banktypes.Metadata{ +func (s *delayedAckSuite) SetupTest() { + s.utilSuite.SetupTest() + s.hubApp().BankKeeper.SetDenomMetaData(s.hubCtx(), banktypes.Metadata{ Base: sdk.DefaultBondDenom, }) } // Transfer from cosmos chain to the hub. No delay expected -func (suite *DelayedAckTestSuite) TestTransferCosmosToHub() { +func (s *delayedAckSuite) TestTransferCosmosToHub() { // setup between cosmosChain and hubChain - path := suite.NewTransferPath(suite.hubChain, suite.cosmosChain) - suite.coordinator.Setup(path) + path := s.newTransferPath(s.hubChain(), s.cosmosChain()) + s.coordinator.Setup(path) - hubEndpoint := path.EndpointA cosmosEndpoint := path.EndpointB - hubIBCKeeper := suite.hubChain.App.GetIBCKeeper() + hubIBCKeeper := s.hubChain().App.GetIBCKeeper() timeoutHeight := clienttypes.NewHeight(100, 110) amount, ok := sdk.NewIntFromString("10000000000000000000") // 10DYM - suite.Require().True(ok) + s.Require().True(ok) coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, amount) // send from cosmosChain to hubChain - msg := types.NewMsgTransfer(cosmosEndpoint.ChannelConfig.PortID, cosmosEndpoint.ChannelID, coinToSendToB, cosmosEndpoint.Chain.SenderAccount.GetAddress().String(), hubEndpoint.Chain.SenderAccount.GetAddress().String(), timeoutHeight, 0, "") - res, err := cosmosEndpoint.Chain.SendMsgs(msg) - suite.Require().NoError(err) // message committed + msg := types.NewMsgTransfer(cosmosEndpoint.ChannelConfig.PortID, cosmosEndpoint.ChannelID, coinToSendToB, s.cosmosChain().SenderAccount.GetAddress().String(), s.hubChain().SenderAccount.GetAddress().String(), timeoutHeight, 0, "") + res, err := s.cosmosChain().SendMsgs(msg) + s.Require().NoError(err) // message committed packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) - suite.Require().NoError(err) + s.Require().NoError(err) // relay send err = path.RelayPacket(packet) - suite.Require().NoError(err) // relay committed + s.Require().NoError(err) // relay committed - found := hubIBCKeeper.ChannelKeeper.HasPacketAcknowledgement(hubEndpoint.Chain.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - suite.Require().True(found) + found := hubIBCKeeper.ChannelKeeper.HasPacketAcknowledgement(s.hubCtx(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) + s.Require().True(found) } -func (suite *DelayedAckTestSuite) TestTransferHubToCosmos() { +func (s *delayedAckSuite) TestTransferHubToCosmos() { // setup between cosmosChain and hubChain - path := suite.NewTransferPath(suite.hubChain, suite.cosmosChain) - suite.coordinator.Setup(path) + path := s.newTransferPath(s.hubChain(), s.cosmosChain()) + s.coordinator.Setup(path) hubEndpoint := path.EndpointA - cosmosEndpoint := path.EndpointB - cosmosIBCKeeper := suite.cosmosChain.App.GetIBCKeeper() + cosmosIBCKeeper := s.cosmosChain().App.GetIBCKeeper() timeoutHeight := clienttypes.NewHeight(100, 110) amount, ok := sdk.NewIntFromString("10000000000000000000") // 10DYM - suite.Require().True(ok) + s.Require().True(ok) coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, amount) // send from cosmosChain to hubChain - msg := types.NewMsgTransfer(hubEndpoint.ChannelConfig.PortID, hubEndpoint.ChannelID, coinToSendToB, hubEndpoint.Chain.SenderAccount.GetAddress().String(), cosmosEndpoint.Chain.SenderAccount.GetAddress().String(), timeoutHeight, 0, "") - res, err := hubEndpoint.Chain.SendMsgs(msg) - suite.Require().NoError(err) // message committed + msg := types.NewMsgTransfer(hubEndpoint.ChannelConfig.PortID, hubEndpoint.ChannelID, coinToSendToB, s.hubChain().SenderAccount.GetAddress().String(), s.cosmosChain().SenderAccount.GetAddress().String(), timeoutHeight, 0, "") + res, err := s.hubChain().SendMsgs(msg) + s.Require().NoError(err) // message committed packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) - suite.Require().NoError(err) + s.Require().NoError(err) // relay send err = path.RelayPacket(packet) - suite.Require().NoError(err) // relay committed + s.Require().NoError(err) // relay committed - found := cosmosIBCKeeper.ChannelKeeper.HasPacketAcknowledgement(cosmosEndpoint.Chain.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - suite.Require().True(found) + found := cosmosIBCKeeper.ChannelKeeper.HasPacketAcknowledgement(s.cosmosCtx(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) + s.Require().True(found) } -func (suite *DelayedAckTestSuite) TestTransferRollappToHubNotFinalized() { - path := suite.NewTransferPath(suite.hubChain, suite.rollappChain) - suite.coordinator.Setup(path) +func (s *delayedAckSuite) TestTransferRollappToHubNotFinalized() { + path := s.newTransferPath(s.hubChain(), s.rollappChain()) + s.coordinator.Setup(path) - hubEndpoint := path.EndpointA rollappEndpoint := path.EndpointB - hubIBCKeeper := suite.hubChain.App.GetIBCKeeper() + hubIBCKeeper := s.hubChain().App.GetIBCKeeper() - suite.CreateRollapp() - suite.RegisterSequencer() - suite.GenesisEvent(path.EndpointA.ChannelID) - suite.UpdateRollappState(uint64(suite.rollappChain.GetContext().BlockHeight())) + s.createRollappWithFinishedGenesis(path.EndpointA.ChannelID) + s.registerSequencer() + s.updateRollappState(uint64(s.rollappCtx().BlockHeight())) timeoutHeight := clienttypes.NewHeight(100, 110) amount, ok := sdk.NewIntFromString("10000000000000000000") // 10DYM - suite.Require().True(ok) + s.Require().True(ok) coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, amount) msg := types.NewMsgTransfer( rollappEndpoint.ChannelConfig.PortID, rollappEndpoint.ChannelID, coinToSendToB, - suite.rollappChain.SenderAccount.GetAddress().String(), - suite.hubChain.SenderAccount.GetAddress().String(), + s.rollappChain().SenderAccount.GetAddress().String(), + s.hubChain().SenderAccount.GetAddress().String(), timeoutHeight, 0, "", ) - res, err := suite.rollappChain.SendMsgs(msg) - suite.Require().NoError(err) // message committed + res, err := s.rollappChain().SendMsgs(msg) + s.Require().NoError(err) // message committed packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) - suite.Require().NoError(err) + s.Require().NoError(err) // relay send err = path.RelayPacket(packet) // expecting error as no AcknowledgePacket expected - suite.Require().Error(err) // relay committed - found := hubIBCKeeper.ChannelKeeper.HasPacketAcknowledgement(hubEndpoint.Chain.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - suite.Require().False(found) + s.Require().Error(err) // relay committed + found := hubIBCKeeper.ChannelKeeper.HasPacketAcknowledgement(s.hubCtx(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) + s.Require().False(found) } -func (suite *DelayedAckTestSuite) TestTransferRollappToHubFinalization() { - path := suite.NewTransferPath(suite.hubChain, suite.rollappChain) - suite.coordinator.Setup(path) +func (s *delayedAckSuite) TestTransferRollappToHubFinalization() { + path := s.newTransferPath(s.hubChain(), s.rollappChain()) + s.coordinator.Setup(path) - hubEndpoint := path.EndpointA - hubIBCKeeper := suite.hubChain.App.GetIBCKeeper() + hubIBCKeeper := s.hubChain().App.GetIBCKeeper() rollappEndpoint := path.EndpointB - rollappIBCKeeper := suite.rollappChain.App.GetIBCKeeper() + rollappIBCKeeper := s.rollappChain().App.GetIBCKeeper() - suite.CreateRollapp() - suite.RegisterSequencer() - suite.GenesisEvent(path.EndpointA.ChannelID) + s.createRollappWithFinishedGenesis(path.EndpointA.ChannelID) + s.registerSequencer() // Upate rollapp state - currentRollappBlockHeight := uint64(suite.rollappChain.GetContext().BlockHeight()) - suite.UpdateRollappState(currentRollappBlockHeight) + currentRollappBlockHeight := uint64(s.rollappCtx().BlockHeight()) + s.updateRollappState(currentRollappBlockHeight) timeoutHeight := clienttypes.NewHeight(100, 110) amount, ok := sdk.NewIntFromString("10000000000000000000") // 10DYM - suite.Require().True(ok) + s.Require().True(ok) coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, amount) /* --------------------- initiating transfer on rollapp --------------------- */ - msg := types.NewMsgTransfer(rollappEndpoint.ChannelConfig.PortID, rollappEndpoint.ChannelID, coinToSendToB, suite.rollappChain.SenderAccount.GetAddress().String(), suite.hubChain.SenderAccount.GetAddress().String(), timeoutHeight, 0, "") - res, err := suite.rollappChain.SendMsgs(msg) - suite.Require().NoError(err) // message committed + msg := types.NewMsgTransfer(rollappEndpoint.ChannelConfig.PortID, rollappEndpoint.ChannelID, coinToSendToB, s.rollappChain().SenderAccount.GetAddress().String(), s.hubChain().SenderAccount.GetAddress().String(), timeoutHeight, 0, "") + res, err := s.rollappChain().SendMsgs(msg) + s.Require().NoError(err) // message committed packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) - suite.Require().NoError(err) + s.Require().NoError(err) - found := rollappIBCKeeper.ChannelKeeper.HasPacketCommitment(rollappEndpoint.Chain.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - suite.Require().True(found) + found := rollappIBCKeeper.ChannelKeeper.HasPacketCommitment(s.rollappCtx(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + s.Require().True(found) // relay send err = path.RelayPacket(packet) // expecting error as no AcknowledgePacket expected to return - suite.Require().Error(err) // relay committed + s.Require().Error(err) // relay committed - found = hubIBCKeeper.ChannelKeeper.HasPacketAcknowledgement(hubEndpoint.Chain.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - suite.Require().False(found) + found = hubIBCKeeper.ChannelKeeper.HasPacketAcknowledgement(s.hubCtx(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) + s.Require().False(found) // Finalize the rollapp state - currentRollappBlockHeight = uint64(suite.rollappChain.GetContext().BlockHeight()) - _, err = suite.FinalizeRollappState(1, currentRollappBlockHeight) - suite.Require().NoError(err) + currentRollappBlockHeight = uint64(s.rollappCtx().BlockHeight()) + _, err = s.finalizeRollappState(1, currentRollappBlockHeight) + s.Require().NoError(err) // Validate ack is found - found = hubIBCKeeper.ChannelKeeper.HasPacketAcknowledgement(hubEndpoint.Chain.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - suite.Require().True(found) + found = hubIBCKeeper.ChannelKeeper.HasPacketAcknowledgement(s.hubCtx(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) + s.Require().True(found) } // TestHubToRollappTimeout tests the scenario where a packet is sent from the hub to the rollapp and the rollapp times out the packet. // The packet should actually get timed out and funds returned to the user only after the rollapp state is finalized. -func (suite *DelayedAckTestSuite) TestHubToRollappTimeout() { - path := suite.NewTransferPath(suite.hubChain, suite.rollappChain) - suite.coordinator.Setup(path) +func (s *delayedAckSuite) TestHubToRollappTimeout() { + path := s.newTransferPath(s.hubChain(), s.rollappChain()) + s.coordinator.Setup(path) // Setup endpoints hubEndpoint := path.EndpointA - rollappEndpoint := path.EndpointB - hubIBCKeeper := suite.hubChain.App.GetIBCKeeper() + hubIBCKeeper := s.hubChain().App.GetIBCKeeper() // Create rollapp and update its initial state - suite.CreateRollapp() - suite.RegisterSequencer() - suite.GenesisEvent(path.EndpointA.ChannelID) - suite.UpdateRollappState(uint64(suite.rollappChain.GetContext().BlockHeight())) + s.createRollappWithFinishedGenesis(path.EndpointA.ChannelID) + s.registerSequencer() + s.updateRollappState(uint64(s.rollappCtx().BlockHeight())) // Set the timeout height - timeoutHeight := clienttypes.GetSelfHeight(suite.rollappChain.GetContext()) + timeoutHeight := clienttypes.GetSelfHeight(s.rollappCtx()) amount, ok := sdk.NewIntFromString("1000000000000000000") // 1DYM - suite.Require().True(ok) + s.Require().True(ok) coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, amount) // Setup accounts - senderAccount := hubEndpoint.Chain.SenderAccount.GetAddress() - recieverAccount := rollappEndpoint.Chain.SenderAccount.GetAddress() + senderAccount := s.hubChain().SenderAccount.GetAddress() + receiverAccount := s.rollappChain().SenderAccount.GetAddress() // Check balances - bankKeeper := ConvertToApp(suite.hubChain).BankKeeper - preSendBalance := bankKeeper.GetBalance(suite.hubChain.GetContext(), senderAccount, sdk.DefaultBondDenom) + bankKeeper := s.hubApp().BankKeeper + preSendBalance := bankKeeper.GetBalance(s.hubCtx(), senderAccount, sdk.DefaultBondDenom) // send from hubChain to rollappChain - msg := types.NewMsgTransfer(hubEndpoint.ChannelConfig.PortID, hubEndpoint.ChannelID, coinToSendToB, senderAccount.String(), recieverAccount.String(), timeoutHeight, disabledTimeoutTimestamp, "") - res, err := hubEndpoint.Chain.SendMsgs(msg) - suite.Require().NoError(err) + msg := types.NewMsgTransfer(hubEndpoint.ChannelConfig.PortID, hubEndpoint.ChannelID, coinToSendToB, senderAccount.String(), receiverAccount.String(), timeoutHeight, disabledTimeoutTimestamp, "") + res, err := s.hubChain().SendMsgs(msg) + s.Require().NoError(err) packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) - suite.Require().NoError(err) - found := hubIBCKeeper.ChannelKeeper.HasPacketCommitment(hubEndpoint.Chain.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - suite.Require().True(found) + s.Require().NoError(err) + found := hubIBCKeeper.ChannelKeeper.HasPacketCommitment(s.hubCtx(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + s.Require().True(found) // Check balance decreased - postSendBalance := bankKeeper.GetBalance(suite.hubChain.GetContext(), senderAccount, sdk.DefaultBondDenom) - suite.Require().Equal(preSendBalance.Amount.Sub(coinToSendToB.Amount), postSendBalance.Amount) + postSendBalance := bankKeeper.GetBalance(s.hubCtx(), senderAccount, sdk.DefaultBondDenom) + s.Require().Equal(preSendBalance.Amount.Sub(coinToSendToB.Amount), postSendBalance.Amount) // Update the client to create timeout err = hubEndpoint.UpdateClient() - suite.Require().NoError(err) + s.Require().NoError(err) // Timeout the packet. Shouldn't release funds until rollapp height is finalized err = path.EndpointA.TimeoutPacket(packet) - suite.Require().NoError(err) + s.Require().NoError(err) // Validate funds are still not returned to the sender - postTimeoutBalance := bankKeeper.GetBalance(suite.hubChain.GetContext(), senderAccount, sdk.DefaultBondDenom) - suite.Require().Equal(postSendBalance.Amount, postTimeoutBalance.Amount) + postTimeoutBalance := bankKeeper.GetBalance(s.hubCtx(), senderAccount, sdk.DefaultBondDenom) + s.Require().Equal(postSendBalance.Amount, postTimeoutBalance.Amount) // Finalize the rollapp state - currentRollappBlockHeight := uint64(suite.rollappChain.GetContext().BlockHeight()) - _, err = suite.FinalizeRollappState(1, currentRollappBlockHeight) - suite.Require().NoError(err) + currentRollappBlockHeight := uint64(s.rollappCtx().BlockHeight()) + _, err = s.finalizeRollappState(1, currentRollappBlockHeight) + s.Require().NoError(err) // Validate funds are returned to the sender - postFinalizeBalance := bankKeeper.GetBalance(suite.hubChain.GetContext(), senderAccount, sdk.DefaultBondDenom) - suite.Require().Equal(preSendBalance.Amount, postFinalizeBalance.Amount) + postFinalizeBalance := bankKeeper.GetBalance(s.hubCtx(), senderAccount, sdk.DefaultBondDenom) + s.Require().Equal(preSendBalance.Amount, postFinalizeBalance.Amount) } diff --git a/ibctesting/denom_metadata_test.go b/ibctesting/denom_metadata_test.go deleted file mode 100644 index a0ec62847..000000000 --- a/ibctesting/denom_metadata_test.go +++ /dev/null @@ -1,82 +0,0 @@ -package ibctesting_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/dymensionxyz/dymension/v3/app/apptesting" - "github.com/stretchr/testify/suite" - - "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" - ibctesting "github.com/cosmos/ibc-go/v6/testing" -) - -type DenomMetaDataTestSuite struct { - IBCTestUtilSuite -} - -func TestDenomMetaDataTestSuite(t *testing.T) { - suite.Run(t, new(DenomMetaDataTestSuite)) -} - -func (suite *DenomMetaDataTestSuite) SetupTest() { - suite.IBCTestUtilSuite.SetupTest() -} - -func (suite *DenomMetaDataTestSuite) TestDenomRegistationRollappToHub() { - path := suite.NewTransferPath(suite.hubChain, suite.rollappChain) - suite.coordinator.Setup(path) - - // register rollapp with metadata for stake denom - suite.CreateRollappWithMetadata(sdk.DefaultBondDenom) - suite.RegisterSequencer() - - app := ConvertToApp(suite.hubChain) - - // invoke genesis event, in order to register denoms - suite.GenesisEvent(path.EndpointA.ChannelID) - - // Finalize the rollapp 100 blocks later so all packets are received immediately - currentRollappBlockHeight := uint64(suite.rollappChain.GetContext().BlockHeight()) - suite.UpdateRollappState(currentRollappBlockHeight) - _, err := suite.FinalizeRollappState(1, currentRollappBlockHeight+100) - suite.Require().NoError(err) - - found := app.BankKeeper.HasDenomMetaData(suite.hubChain.GetContext(), sdk.DefaultBondDenom) - suite.Require().False(found) - found = app.BankKeeper.HasDenomMetaData(suite.hubChain.GetContext(), "udym") - suite.Require().False(found) - - timeoutHeight := clienttypes.NewHeight(100, 110) - amount, ok := sdk.NewIntFromString("10000000000000000000") // 10DYM - suite.Require().True(ok) - - /* ------------------- move non-registered token from rollapp ------------------- */ - dymTokensToSend := sdk.NewCoin("udym", amount) - apptesting.FundAccount(ConvertToApp(suite.rollappChain), suite.rollappChain.GetContext(), suite.rollappChain.SenderAccount.GetAddress(), sdk.Coins{dymTokensToSend}) - msg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, dymTokensToSend, suite.rollappChain.SenderAccount.GetAddress().String(), suite.hubChain.SenderAccount.GetAddress().String(), timeoutHeight, 0, "") - res, err := suite.rollappChain.SendMsgs(msg) - suite.Require().NoError(err) // message committed - - packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) - suite.Require().NoError(err) - - // relay send - err = path.RelayPacket(packet) - suite.Require().NoError(err) - - udymVoucherDenom := types.ParseDenomTrace(types.GetPrefixedDenom(packet.GetDestPort(), packet.GetDestChannel(), "udym")) - stakeVoucherDenom := types.ParseDenomTrace(types.GetPrefixedDenom(packet.GetDestPort(), packet.GetDestChannel(), sdk.DefaultBondDenom)) - - found = app.BankKeeper.HasDenomMetaData(suite.hubChain.GetContext(), sdk.DefaultBondDenom) - suite.Require().False(found) - found = app.BankKeeper.HasDenomMetaData(suite.hubChain.GetContext(), "udym") - suite.Require().False(found) - found = app.BankKeeper.HasDenomMetaData(suite.hubChain.GetContext(), udymVoucherDenom.IBCDenom()) - suite.Require().False(found) - metadata, found := app.BankKeeper.GetDenomMetaData(suite.hubChain.GetContext(), stakeVoucherDenom.IBCDenom()) - suite.Require().True(found) - suite.Equal("bigstake", metadata.Display) - suite.Equal("BIGSTAKE", metadata.Symbol) -} diff --git a/ibctesting/eibc_test.go b/ibctesting/eibc_test.go index f40c62e1d..c4957a0ef 100644 --- a/ibctesting/eibc_test.go +++ b/ibctesting/eibc_test.go @@ -24,46 +24,46 @@ import ( eibctypes "github.com/dymensionxyz/dymension/v3/x/eibc/types" ) -type EIBCTestSuite struct { - IBCTestUtilSuite +type eibcSuite struct { + utilSuite + path *ibctesting.Path +} - msgServer eibctypes.MsgServer +func (s *eibcSuite) msgServer() eibctypes.MsgServer { + return eibckeeper.NewMsgServerImpl(s.hubApp().EIBCKeeper) } func TestEIBCTestSuite(t *testing.T) { - suite.Run(t, new(EIBCTestSuite)) + suite.Run(t, new(eibcSuite)) } -func (suite *EIBCTestSuite) SetupTest() { - suite.IBCTestUtilSuite.SetupTest() - ConvertToApp(suite.hubChain).BankKeeper.SetDenomMetaData(suite.hubChain.GetContext(), banktypes.Metadata{ +func (s *eibcSuite) SetupTest() { + s.utilSuite.SetupTest() + s.hubApp().BankKeeper.SetDenomMetaData(s.hubCtx(), banktypes.Metadata{ Base: sdk.DefaultBondDenom, }) - eibcKeeper := ConvertToApp(suite.hubChain).EIBCKeeper - suite.msgServer = eibckeeper.NewMsgServerImpl(eibcKeeper) // Change the delayedAck epoch to trigger every month to not // delete the rollapp packets and demand orders - delayedAckKeeper := ConvertToApp(suite.hubChain).DelayedAckKeeper - params := delayedAckKeeper.GetParams(suite.hubChain.GetContext()) + delayedAckKeeper := s.hubApp().DelayedAckKeeper + params := delayedAckKeeper.GetParams(s.hubCtx()) params.EpochIdentifier = "month" params.BridgingFee = sdk.ZeroDec() - delayedAckKeeper.SetParams(suite.hubChain.GetContext(), params) -} - -func (suite *EIBCTestSuite) TestEIBCDemandOrderCreation() { + delayedAckKeeper.SetParams(s.hubCtx(), params) + // Create path so we'll be using the same channel + path := s.newTransferPath(s.hubChain(), s.rollappChain()) + s.coordinator.Setup(path) // Create rollapp only once - suite.CreateRollapp() + s.createRollappWithFinishedGenesis(path.EndpointA.ChannelID) // Register sequencer - suite.RegisterSequencer() - // Create path so we'll be using the same channel - path := suite.NewTransferPath(suite.hubChain, suite.rollappChain) - suite.coordinator.Setup(path) - // Trigger the genesis event to register the denoms - suite.GenesisEvent(path.EndpointA.ChannelID) + s.registerSequencer() + s.path = path +} + +func (s *eibcSuite) TestEIBCDemandOrderCreation() { // adding state for the rollapp - suite.UpdateRollappState(uint64(suite.rollappChain.GetContext().BlockHeight())) + s.updateRollappState(uint64(s.rollappCtx().BlockHeight())) // Setup globals for the test cases - IBCSenderAccount := suite.rollappChain.SenderAccount.GetAddress().String() + IBCSenderAccount := s.rollappChain().SenderAccount.GetAddress().String() // Create cases cases := []struct { name string @@ -135,7 +135,7 @@ func (suite *EIBCTestSuite) TestEIBCDemandOrderCreation() { 0, true, map[string]map[string]string{"forward": { - "receiver": suite.hubChain.SenderAccount.GetAddress().String(), + "receiver": s.hubChain().SenderAccount.GetAddress().String(), "port": "transfer", "channel": "channel-0", }}, @@ -144,7 +144,7 @@ func (suite *EIBCTestSuite) TestEIBCDemandOrderCreation() { } totalDemandOrdersCreated := 0 for _, tc := range cases { - suite.Run(tc.name, func() { + s.Run(tc.name, func() { // Send the EIBC Packet memoObj := map[string]map[string]string{ "eibc": { @@ -164,18 +164,18 @@ func (suite *EIBCTestSuite) TestEIBCDemandOrderCreation() { } recipient := apptesting.CreateRandomAccounts(1)[0] - _ = suite.TransferRollappToHub(path, IBCSenderAccount, recipient.String(), tc.amount, memo, tc.expectAck) + _ = s.transferRollappToHub(s.path, IBCSenderAccount, recipient.String(), tc.amount, memo, tc.expectAck) // Validate demand orders results - eibcKeeper := ConvertToApp(suite.hubChain).EIBCKeeper - demandOrders, err := eibcKeeper.ListAllDemandOrders(suite.hubChain.GetContext()) - suite.Require().NoError(err) - suite.Require().Equal(tc.demandOrdersCreated, len(demandOrders)-totalDemandOrdersCreated) + eibcKeeper := s.hubApp().EIBCKeeper + demandOrders, err := eibcKeeper.ListAllDemandOrders(s.hubCtx()) + s.Require().NoError(err) + s.Require().Equal(tc.demandOrdersCreated, len(demandOrders)-totalDemandOrdersCreated) totalDemandOrdersCreated = len(demandOrders) amountInt, ok := sdk.NewIntFromString(tc.amount) - suite.Require().True(ok) + s.Require().True(ok) feeInt, ok := sdk.NewIntFromString(tc.fee) - suite.Require().True(ok) + s.Require().True(ok) if tc.demandOrdersCreated > 0 { var demandOrder *eibctypes.DemandOrder for _, order := range demandOrders { @@ -184,10 +184,10 @@ func (suite *EIBCTestSuite) TestEIBCDemandOrderCreation() { break } } - suite.Require().NotNil(demandOrder) - suite.Require().Equal(recipient.String(), demandOrder.Recipient) - suite.Require().Equal(amountInt.Sub(feeInt), demandOrder.Price[0].Amount) - suite.Require().Equal(feeInt, demandOrder.Fee.AmountOf(demandOrder.Price[0].Denom)) + s.Require().NotNil(demandOrder) + s.Require().Equal(recipient.String(), demandOrder.Recipient) + s.Require().Equal(amountInt.Sub(feeInt), demandOrder.Price[0].Amount) + s.Require().Equal(feeInt, demandOrder.Fee.AmountOf(demandOrder.Price[0].Denom)) } }) } @@ -195,24 +195,14 @@ func (suite *EIBCTestSuite) TestEIBCDemandOrderCreation() { // TestEIBCDemandOrderFulfillment tests the creation of a demand order and its fulfillment logic. // It starts by transferring the fulfiller the relevant IBC tokens which it will use to possibly fulfill the demand order. -func (suite *EIBCTestSuite) TestEIBCDemandOrderFulfillment() { - // Create rollapp only once - suite.CreateRollapp() - // Create the path once here so we'll be using the same channel all the time and hence same IBC denom - // Register sequencer - suite.RegisterSequencer() - path := suite.NewTransferPath(suite.hubChain, suite.rollappChain) - suite.coordinator.Setup(path) - // Trigger the genesis event to register the denoms - suite.GenesisEvent(path.EndpointA.ChannelID) +func (s *eibcSuite) TestEIBCDemandOrderFulfillment() { // Setup globals for the test totalDemandOrdersCreated := 0 - eibcKeeper := ConvertToApp(suite.hubChain).EIBCKeeper - bankKeeper := ConvertToApp(suite.hubChain).BankKeeper - delayedAckKeeper := ConvertToApp(suite.hubChain).DelayedAckKeeper - IBCSenderAccount := suite.rollappChain.SenderAccount.GetAddress().String() + eibcKeeper := s.hubApp().EIBCKeeper + delayedAckKeeper := s.hubApp().DelayedAckKeeper + IBCSenderAccount := s.rollappChain().SenderAccount.GetAddress().String() rollappStateIndex := uint64(0) - IBCrecipientAccountInitialIndex := 0 + IBCRecipientAccountInitialIndex := 0 fulfillerAccountInitialIndex := 1 // Create cases cases := []struct { @@ -238,17 +228,17 @@ func (suite *EIBCTestSuite) TestEIBCDemandOrderFulfillment() { }, } for idx, tc := range cases { - suite.Run(tc.name, func() { + s.Run(tc.name, func() { // Get the initial state of the accounts - IBCOriginalRecipient := suite.hubChain.SenderAccounts[IBCrecipientAccountInitialIndex+idx].SenderAccount.GetAddress() - initialIBCOriginalRecipientBalance := bankKeeper.SpendableCoins(suite.hubChain.GetContext(), IBCOriginalRecipient) - fulfiller := suite.hubChain.SenderAccounts[fulfillerAccountInitialIndex+idx].SenderAccount.GetAddress() + IBCOriginalRecipient := s.hubChain().SenderAccounts[IBCRecipientAccountInitialIndex+idx].SenderAccount.GetAddress() + initialIBCOriginalRecipientBalance := s.hubApp().BankKeeper.SpendableCoins(s.hubCtx(), IBCOriginalRecipient) + fulfiller := s.hubChain().SenderAccounts[fulfillerAccountInitialIndex+idx].SenderAccount.GetAddress() // Update the rollapp state - suite.rollappChain.NextBlock() - currentRollappBlockHeight := uint64(suite.rollappChain.GetContext().BlockHeight()) + s.rollappChain().NextBlock() + currentRollappBlockHeight := uint64(s.rollappCtx().BlockHeight()) rollappStateIndex = rollappStateIndex + 1 - suite.UpdateRollappState(currentRollappBlockHeight) + s.updateRollappState(currentRollappBlockHeight) eibc := map[string]map[string]string{ "eibc": { @@ -263,101 +253,101 @@ func (suite *EIBCTestSuite) TestEIBCDemandOrderFulfillment() { // Transfer initial IBC funds to fulfiller account with ibc memo, to give him some funds to use to fulfill stuff // // - packet := suite.TransferRollappToHub(path, IBCSenderAccount, fulfiller.String(), tc.fulfillerInitialIBCDenomBalance, memo, false) + packet := s.transferRollappToHub(s.path, IBCSenderAccount, fulfiller.String(), tc.fulfillerInitialIBCDenomBalance, memo, false) // Finalize rollapp state - at this state no demand order was fulfilled - currentRollappBlockHeight = uint64(suite.rollappChain.GetContext().BlockHeight()) - _, err := suite.FinalizeRollappState(rollappStateIndex, currentRollappBlockHeight) - suite.Require().NoError(err) + currentRollappBlockHeight = uint64(s.rollappCtx().BlockHeight()) + _, err := s.finalizeRollappState(rollappStateIndex, currentRollappBlockHeight) + s.Require().NoError(err) // Check the fulfiller balance was updated fully with the IBC amount isUpdated := false - fulfillerAccountBalanceAfterFinalization := bankKeeper.SpendableCoins(suite.hubChain.GetContext(), fulfiller) - IBCDenom = suite.GetRollappToHubIBCDenomFromPacket(packet) + fulfillerAccountBalanceAfterFinalization := s.hubApp().BankKeeper.SpendableCoins(s.hubCtx(), fulfiller) + IBCDenom = s.getRollappToHubIBCDenomFromPacket(packet) requiredFulfillerBalance, ok := sdk.NewIntFromString(tc.fulfillerInitialIBCDenomBalance) - suite.Require().True(ok) + s.Require().True(ok) for _, coin := range fulfillerAccountBalanceAfterFinalization { if coin.Denom == IBCDenom && coin.Amount.Equal(requiredFulfillerBalance) { isUpdated = true break } } - suite.Require().True(isUpdated) + s.Require().True(isUpdated) // Validate eibc demand order created - demandOrders, err := eibcKeeper.ListAllDemandOrders(suite.hubChain.GetContext()) - suite.Require().NoError(err) - suite.Require().Greater(len(demandOrders), totalDemandOrdersCreated) + demandOrders, err := eibcKeeper.ListAllDemandOrders(s.hubCtx()) + s.Require().NoError(err) + s.Require().Greater(len(demandOrders), totalDemandOrdersCreated) totalDemandOrdersCreated = len(demandOrders) // Get last demand order created by TrackingPacketKey. Last part of the key is the sequence lastDemandOrder := getLastDemandOrderByChannelAndSequence(demandOrders) // Validate demand order wasn't fulfilled but finalized - suite.Require().False(lastDemandOrder.IsFulfilled) - suite.Require().Equal(commontypes.Status_FINALIZED, lastDemandOrder.TrackingPacketStatus) + s.Require().False(lastDemandOrder.IsFulfilled) + s.Require().Equal(commontypes.Status_FINALIZED, lastDemandOrder.TrackingPacketStatus) } // Send another EIBC packet but this time fulfill it with the fulfiller balance. // Increase the block height to make sure the next ibc packet won't be considered already finalized when sent - suite.rollappChain.NextBlock() - currentRollappBlockHeight = uint64(suite.rollappChain.GetContext().BlockHeight()) + s.rollappChain().NextBlock() + currentRollappBlockHeight = uint64(s.rollappCtx().BlockHeight()) rollappStateIndex = rollappStateIndex + 1 - suite.UpdateRollappState(currentRollappBlockHeight) - packet := suite.TransferRollappToHub(path, IBCSenderAccount, IBCOriginalRecipient.String(), tc.IBCTransferAmount, memo, false) + s.updateRollappState(currentRollappBlockHeight) + packet := s.transferRollappToHub(s.path, IBCSenderAccount, IBCOriginalRecipient.String(), tc.IBCTransferAmount, memo, false) - suite.Require().True(suite.rollappHasPacketCommitment(packet)) + s.Require().True(s.rollappHasPacketCommitment(packet)) // Validate demand order created. Calling TransferRollappToHub also promotes the block time for // ibc purposes which causes the AfterEpochEnd of the rollapp packet deletion to fire (which also deletes the demand order) // hence we should only expect 1 demand order created - demandOrders, err := eibcKeeper.ListAllDemandOrders(suite.hubChain.GetContext()) - suite.Require().NoError(err) - suite.Require().Greater(len(demandOrders), totalDemandOrdersCreated) + demandOrders, err := eibcKeeper.ListAllDemandOrders(s.hubCtx()) + s.Require().NoError(err) + s.Require().Greater(len(demandOrders), totalDemandOrdersCreated) totalDemandOrdersCreated = len(demandOrders) // Get the last demand order created lastDemandOrder := getLastDemandOrderByChannelAndSequence(demandOrders) // Try and fulfill the demand order - preFulfillmentAccountBalance := bankKeeper.SpendableCoins(suite.hubChain.GetContext(), fulfiller) + preFulfillmentAccountBalance := s.hubApp().BankKeeper.SpendableCoins(s.hubCtx(), fulfiller) msgFulfillDemandOrder := &eibctypes.MsgFulfillOrder{ FulfillerAddress: fulfiller.String(), OrderId: lastDemandOrder.Id, ExpectedFee: tc.EIBCTransferFee, } // Validate demand order status based on fulfillment success - _, err = suite.msgServer.FulfillOrder(suite.hubChain.GetContext(), msgFulfillDemandOrder) + _, err = s.msgServer().FulfillOrder(s.hubCtx(), msgFulfillDemandOrder) if !tc.isFulfilledSuccess { - suite.Require().Error(err) + s.Require().Error(err) return } - suite.Require().NoError(err) + s.Require().NoError(err) // Validate eibc packet recipient has been updated - rollappPacket, err := delayedAckKeeper.GetRollappPacket(suite.hubChain.GetContext(), lastDemandOrder.TrackingPacketKey) - suite.Require().NoError(err) + rollappPacket, err := delayedAckKeeper.GetRollappPacket(s.hubCtx(), lastDemandOrder.TrackingPacketKey) + s.Require().NoError(err) var data transfertypes.FungibleTokenPacketData err = eibctypes.ModuleCdc.UnmarshalJSON(rollappPacket.Packet.GetData(), &data) - suite.Require().NoError(err) - suite.Require().Equal(msgFulfillDemandOrder.FulfillerAddress, data.Receiver) + s.Require().NoError(err) + s.Require().Equal(msgFulfillDemandOrder.FulfillerAddress, data.Receiver) // Validate balances of fulfiller and recipient - fulfillerAccountBalance := bankKeeper.SpendableCoins(suite.hubChain.GetContext(), fulfiller) - recipientAccountBalance := bankKeeper.SpendableCoins(suite.hubChain.GetContext(), IBCOriginalRecipient) + fulfillerAccountBalance := s.hubApp().BankKeeper.SpendableCoins(s.hubCtx(), fulfiller) + recipientAccountBalance := s.hubApp().BankKeeper.SpendableCoins(s.hubCtx(), IBCOriginalRecipient) ibcTransferAmountInt, _ := strconv.ParseInt(tc.IBCTransferAmount, 10, 64) eibcTransferFeeInt, _ := strconv.ParseInt(tc.EIBCTransferFee, 10, 64) demandOrderPriceInt := ibcTransferAmountInt - eibcTransferFeeInt - suite.Require().True(fulfillerAccountBalance.IsEqual(preFulfillmentAccountBalance.Sub(sdk.NewCoin(IBCDenom, sdk.NewInt(demandOrderPriceInt))))) - suite.Require().True(recipientAccountBalance.IsEqual(initialIBCOriginalRecipientBalance.Add(sdk.NewCoin(IBCDenom, sdk.NewInt(demandOrderPriceInt))))) + s.Require().True(fulfillerAccountBalance.IsEqual(preFulfillmentAccountBalance.Sub(sdk.NewCoin(IBCDenom, sdk.NewInt(demandOrderPriceInt))))) + s.Require().True(recipientAccountBalance.IsEqual(initialIBCOriginalRecipientBalance.Add(sdk.NewCoin(IBCDenom, sdk.NewInt(demandOrderPriceInt))))) // Finalize rollapp and check fulfiller balance was updated with fee - currentRollappBlockHeight = uint64(suite.rollappChain.GetContext().BlockHeight()) - evts, err := suite.FinalizeRollappState(rollappStateIndex, currentRollappBlockHeight) - suite.Require().NoError(err) + currentRollappBlockHeight = uint64(s.rollappCtx().BlockHeight()) + evts, err := s.finalizeRollappState(rollappStateIndex, currentRollappBlockHeight) + s.Require().NoError(err) ack, err := ibctesting.ParseAckFromEvents(evts) - suite.Require().NoError(err) + s.Require().NoError(err) - fulfillerAccountBalanceAfterFinalization := bankKeeper.SpendableCoins(suite.hubChain.GetContext(), fulfiller) - suite.Require().True(fulfillerAccountBalanceAfterFinalization.IsEqual(preFulfillmentAccountBalance.Add(sdk.NewCoin(IBCDenom, sdk.NewInt(eibcTransferFeeInt))))) + fulfillerAccountBalanceAfterFinalization := s.hubApp().BankKeeper.SpendableCoins(s.hubCtx(), fulfiller) + s.Require().True(fulfillerAccountBalanceAfterFinalization.IsEqual(preFulfillmentAccountBalance.Add(sdk.NewCoin(IBCDenom, sdk.NewInt(eibcTransferFeeInt))))) // Validate demand order fulfilled and packet status updated - finalizedDemandOrders, err := eibcKeeper.ListDemandOrdersByStatus(suite.hubChain.GetContext(), commontypes.Status_FINALIZED, 0) - suite.Require().NoError(err) + finalizedDemandOrders, err := eibcKeeper.ListDemandOrdersByStatus(s.hubCtx(), commontypes.Status_FINALIZED, 0) + s.Require().NoError(err) var finalizedDemandOrder *eibctypes.DemandOrder for _, order := range finalizedDemandOrders { if order.Id == lastDemandOrder.Id { @@ -365,19 +355,19 @@ func (suite *EIBCTestSuite) TestEIBCDemandOrderFulfillment() { break } } - suite.Require().NotNil(finalizedDemandOrder) - suite.Require().True(finalizedDemandOrder.IsFulfilled) - suite.Require().Equal(commontypes.Status_FINALIZED, finalizedDemandOrder.TrackingPacketStatus) - - path.EndpointA.Chain.NextBlock() - _ = path.EndpointB.UpdateClient() - err = path.EndpointB.AcknowledgePacket(packet, ack) - suite.Require().NoError(err) + s.Require().NotNil(finalizedDemandOrder) + s.Require().True(finalizedDemandOrder.IsFulfilled) + s.Require().Equal(commontypes.Status_FINALIZED, finalizedDemandOrder.TrackingPacketStatus) + + s.path.EndpointA.Chain.NextBlock() + _ = s.path.EndpointB.UpdateClient() + err = s.path.EndpointB.AcknowledgePacket(packet, ack) + s.Require().NoError(err) }) } } -func (suite *EIBCTestSuite) rollappHasPacketCommitment(packet channeltypes.Packet) bool { +func (s *eibcSuite) rollappHasPacketCommitment(packet channeltypes.Packet) bool { // TODO: this should be used to check that a commitment does (or doesn't) exist, when it should // TODO: this is important to check that things actually work as expected and dont just look ok on the outside // TODO: finish implementing, true is a temporary placeholder @@ -385,20 +375,13 @@ func (suite *EIBCTestSuite) rollappHasPacketCommitment(packet channeltypes.Packe } // TestTimeoutEIBCDemandOrderFulfillment: when a packet hub->rollapp times out, or gets an error ack, than eIBC can be used to recover quickly. -func (suite *EIBCTestSuite) TestTimeoutEIBCDemandOrderFulfillment() { - path := suite.NewTransferPath(suite.hubChain, suite.rollappChain) - suite.coordinator.Setup(path) +func (s *eibcSuite) TestTimeoutEIBCDemandOrderFulfillment() { // Setup endpoints - hubEndpoint := path.EndpointA - rollappEndpoint := path.EndpointB - hubIBCKeeper := suite.hubChain.App.GetIBCKeeper() + hubEndpoint := s.path.EndpointA + rollappEndpoint := s.path.EndpointB + hubIBCKeeper := s.hubChain().App.GetIBCKeeper() // Create rollapp and update its initial state - suite.CreateRollapp() - suite.RegisterSequencer() - // Trigger the genesis event to register the denoms - suite.GenesisEvent(path.EndpointA.ChannelID) - suite.UpdateRollappState(uint64(suite.rollappChain.GetContext().BlockHeight())) - bankKeeper := ConvertToApp(suite.hubChain).BankKeeper + s.updateRollappState(uint64(s.rollappCtx().BlockHeight())) type TC struct { name string @@ -420,7 +403,7 @@ func (suite *EIBCTestSuite) TestTimeoutEIBCDemandOrderFulfillment() { // Timeout the packet. Shouldn't release funds until rollapp height is finalized err := hubEndpoint.TimeoutPacket(packet) - suite.Require().NoError(err) + s.Require().NoError(err) }, fee: func(params eibctypes.Params) sdk.Dec { return params.TimeoutFee @@ -438,86 +421,87 @@ func (suite *EIBCTestSuite) TestTimeoutEIBCDemandOrderFulfillment() { // return an err ack ack := channeltypes.NewErrorAcknowledgement(errors.New("foobar")) err := rollappEndpoint.WriteAcknowledgement(ack, packet) - suite.Require().NoError(err) + s.Require().NoError(err) err = hubEndpoint.AcknowledgePacket(packet, ack.Acknowledgement()) - suite.Require().NoError(err) + s.Require().NoError(err) }, fee: func(params eibctypes.Params) sdk.Dec { return params.ErrackFee }, }, } { - suite.Run(tc.name, func() { + s.Run(tc.name, func() { // Set the timeout height - timeoutHeight := clienttypes.GetSelfHeight(suite.rollappChain.GetContext()) + timeoutHeight := clienttypes.GetSelfHeight(s.rollappCtx()) amount, ok := sdk.NewIntFromString("1000000000000000000") // 1DYM - suite.Require().True(ok) + s.Require().True(ok) coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, amount) // Setup accounts - senderAccount := hubEndpoint.Chain.SenderAccount.GetAddress() - receiverAccount := rollappEndpoint.Chain.SenderAccount.GetAddress() - fulfillerAccount := suite.hubChain.SenderAccounts[1].SenderAccount.GetAddress() + senderAccount := s.hubChain().SenderAccount.GetAddress() + receiverAccount := s.rollappChain().SenderAccount.GetAddress() + fulfillerAccount := s.hubChain().SenderAccounts[1].SenderAccount.GetAddress() // Get initial balances - senderInitialBalance := bankKeeper.GetBalance(suite.hubChain.GetContext(), senderAccount, sdk.DefaultBondDenom) - fulfillerInitialBalance := bankKeeper.GetBalance(suite.hubChain.GetContext(), fulfillerAccount, sdk.DefaultBondDenom) - receiverInitialBalance := bankKeeper.GetBalance(suite.hubChain.GetContext(), receiverAccount, sdk.DefaultBondDenom) + bankKeeper := s.hubApp().BankKeeper + senderInitialBalance := bankKeeper.GetBalance(s.hubCtx(), senderAccount, sdk.DefaultBondDenom) + fulfillerInitialBalance := bankKeeper.GetBalance(s.hubCtx(), fulfillerAccount, sdk.DefaultBondDenom) + receiverInitialBalance := bankKeeper.GetBalance(s.hubCtx(), receiverAccount, sdk.DefaultBondDenom) // Send from hubChain to rollappChain msg := types.NewMsgTransfer(hubEndpoint.ChannelConfig.PortID, hubEndpoint.ChannelID, coinToSendToB, senderAccount.String(), receiverAccount.String(), timeoutHeight, disabledTimeoutTimestamp, "") - res, err := hubEndpoint.Chain.SendMsgs(msg) - suite.Require().NoError(err) + res, err := s.hubChain().SendMsgs(msg) + s.Require().NoError(err) packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) - suite.Require().NoError(err) - found := hubIBCKeeper.ChannelKeeper.HasPacketCommitment(hubEndpoint.Chain.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - suite.Require().True(found) + s.Require().NoError(err) + found := hubIBCKeeper.ChannelKeeper.HasPacketCommitment(s.hubCtx(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + s.Require().True(found) // Check balance decreased - postSendBalance := bankKeeper.GetBalance(suite.hubChain.GetContext(), senderAccount, sdk.DefaultBondDenom) - suite.Require().Equal(senderInitialBalance.Amount.Sub(coinToSendToB.Amount), postSendBalance.Amount) + postSendBalance := bankKeeper.GetBalance(s.hubCtx(), senderAccount, sdk.DefaultBondDenom) + s.Require().Equal(senderInitialBalance.Amount.Sub(coinToSendToB.Amount), postSendBalance.Amount) // Validate no demand orders exist - eibcKeeper := ConvertToApp(suite.hubChain).EIBCKeeper - demandOrders, err := eibcKeeper.ListAllDemandOrders(suite.hubChain.GetContext()) - suite.Require().NoError(err) - suite.Require().Equal(nOrdersCreated, len(demandOrders)) + eibcKeeper := s.hubApp().EIBCKeeper + demandOrders, err := eibcKeeper.ListAllDemandOrders(s.hubCtx()) + s.Require().NoError(err) + s.Require().Equal(nOrdersCreated, len(demandOrders)) // Update the client to create timeout err = hubEndpoint.UpdateClient() - suite.Require().NoError(err) + s.Require().NoError(err) tc.malleate(packet) // Validate funds are still not returned to the sender - postTimeoutBalance := bankKeeper.GetBalance(suite.hubChain.GetContext(), senderAccount, sdk.DefaultBondDenom) - suite.Require().Equal(postSendBalance.Amount, postTimeoutBalance.Amount) + postTimeoutBalance := bankKeeper.GetBalance(s.hubCtx(), senderAccount, sdk.DefaultBondDenom) + s.Require().Equal(postSendBalance.Amount, postTimeoutBalance.Amount) // Validate demand order created - demandOrders, err = eibcKeeper.ListAllDemandOrders(suite.hubChain.GetContext()) - suite.Require().NoError(err) + demandOrders, err = eibcKeeper.ListAllDemandOrders(s.hubCtx()) + s.Require().NoError(err) nOrdersCreated++ - suite.Require().Equal(nOrdersCreated, len(demandOrders)) + s.Require().Equal(nOrdersCreated, len(demandOrders)) // Get the last demand order created t lastDemandOrder := getLastDemandOrderByChannelAndSequence(demandOrders) // Validate the demand order price and denom - fee := tc.fee(eibcKeeper.GetParams(suite.hubChain.GetContext())) + fee := tc.fee(eibcKeeper.GetParams(s.hubCtx())) amountDec, err := sdk.NewDecFromStr(coinToSendToB.Amount.String()) - suite.Require().NoError(err) + s.Require().NoError(err) expectedPrice := amountDec.Mul(sdk.NewDec(1).Sub(fee)).TruncateInt() - suite.Require().Equal(expectedPrice, lastDemandOrder.Price[0].Amount) - suite.Require().Equal(coinToSendToB.Denom, lastDemandOrder.Price[0].Denom) + s.Require().Equal(expectedPrice, lastDemandOrder.Price[0].Amount) + s.Require().Equal(coinToSendToB.Denom, lastDemandOrder.Price[0].Denom) // Fulfill the demand order msgFulfillDemandOrder := eibctypes.NewMsgFulfillOrder(fulfillerAccount.String(), lastDemandOrder.Id, lastDemandOrder.Fee[0].Amount.String()) - _, err = suite.msgServer.FulfillOrder(suite.hubChain.GetContext(), msgFulfillDemandOrder) - suite.Require().NoError(err) + _, err = s.msgServer().FulfillOrder(s.hubCtx(), msgFulfillDemandOrder) + s.Require().NoError(err) // Validate balances of fulfiller and sender are updated while the original recipient is not - fulfillerAccountBalance := bankKeeper.GetBalance(suite.hubChain.GetContext(), fulfillerAccount, sdk.DefaultBondDenom) - senderAccountBalance := bankKeeper.GetBalance(suite.hubChain.GetContext(), senderAccount, sdk.DefaultBondDenom) - receiverAccountBalance := bankKeeper.GetBalance(suite.hubChain.GetContext(), receiverAccount, sdk.DefaultBondDenom) - suite.Require().True(fulfillerAccountBalance.IsEqual(fulfillerInitialBalance.Sub(lastDemandOrder.Price[0]))) - suite.Require().True(senderAccountBalance.IsEqual(senderInitialBalance.Sub(lastDemandOrder.Fee[0]))) - suite.Require().True(receiverAccountBalance.IsEqual(receiverInitialBalance)) + fulfillerAccountBalance := bankKeeper.GetBalance(s.hubCtx(), fulfillerAccount, sdk.DefaultBondDenom) + senderAccountBalance := bankKeeper.GetBalance(s.hubCtx(), senderAccount, sdk.DefaultBondDenom) + receiverAccountBalance := bankKeeper.GetBalance(s.hubCtx(), receiverAccount, sdk.DefaultBondDenom) + s.Require().True(fulfillerAccountBalance.IsEqual(fulfillerInitialBalance.Sub(lastDemandOrder.Price[0]))) + s.Require().True(senderAccountBalance.IsEqual(senderInitialBalance.Sub(lastDemandOrder.Fee[0]))) + s.Require().True(receiverAccountBalance.IsEqual(receiverInitialBalance)) // Finalize the rollapp state - currentRollappBlockHeight := uint64(suite.rollappChain.GetContext().BlockHeight()) - _, err = suite.FinalizeRollappState(1, currentRollappBlockHeight) - suite.Require().NoError(err) + currentRollappBlockHeight := uint64(s.rollappCtx().BlockHeight()) + _, err = s.finalizeRollappState(1, currentRollappBlockHeight) + s.Require().NoError(err) // Funds are passed to the fulfiller - fulfillerAccountBalanceAfterTimeout := bankKeeper.GetBalance(suite.hubChain.GetContext(), fulfillerAccount, sdk.DefaultBondDenom) - suite.Require().True(fulfillerAccountBalanceAfterTimeout.IsEqual(fulfillerInitialBalance.Add(lastDemandOrder.Fee[0]))) + fulfillerAccountBalanceAfterTimeout := bankKeeper.GetBalance(s.hubCtx(), fulfillerAccount, sdk.DefaultBondDenom) + s.Require().True(fulfillerAccountBalanceAfterTimeout.IsEqual(fulfillerInitialBalance.Add(lastDemandOrder.Fee[0]))) }) } } @@ -526,8 +510,8 @@ func (suite *EIBCTestSuite) TestTimeoutEIBCDemandOrderFulfillment() { /* Utils */ /* -------------------------------------------------------------------------- */ -// TransferRollappToHub sends a transfer packet from rollapp to hub and returns the packet -func (suite *EIBCTestSuite) TransferRollappToHub( +// transferRollappToHub sends a transfer packet from rollapp to hub and returns the packet +func (s *eibcSuite) transferRollappToHub( path *ibctesting.Path, sender string, receiver string, @@ -535,36 +519,35 @@ func (suite *EIBCTestSuite) TransferRollappToHub( memo string, expectAck bool, ) channeltypes.Packet { - hubEndpoint := path.EndpointA rollappEndpoint := path.EndpointB - hubIBCKeeper := suite.hubChain.App.GetIBCKeeper() + hubIBCKeeper := s.hubChain().App.GetIBCKeeper() timeoutHeight := clienttypes.NewHeight(100, 110) amountInt, ok := sdk.NewIntFromString(amount) - suite.Require().True(ok) + s.Require().True(ok) coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, amountInt) msg := types.NewMsgTransfer(rollappEndpoint.ChannelConfig.PortID, rollappEndpoint.ChannelID, coinToSendToB, sender, receiver, timeoutHeight, 0, memo) - res, err := suite.rollappChain.SendMsgs(msg) - suite.Require().NoError(err) // message committed + res, err := s.rollappChain().SendMsgs(msg) + s.Require().NoError(err) // message committed packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) - suite.Require().NoError(err) + s.Require().NoError(err) err = path.RelayPacket(packet) // If there is an error than an ack is returned immediately. Relay will always try to extract an ack, and will // return an error if there isn't one. if expectAck { - suite.Require().NoError(err) - found := hubIBCKeeper.ChannelKeeper.HasPacketAcknowledgement(hubEndpoint.Chain.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - suite.Require().True(found) + s.Require().NoError(err) + found := hubIBCKeeper.ChannelKeeper.HasPacketAcknowledgement(s.hubCtx(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) + s.Require().True(found) } else { - suite.Require().Error(err) - found := hubIBCKeeper.ChannelKeeper.HasPacketAcknowledgement(hubEndpoint.Chain.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - suite.Require().False(found) + s.Require().Error(err) + found := hubIBCKeeper.ChannelKeeper.HasPacketAcknowledgement(s.hubCtx(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) + s.Require().False(found) } return packet } diff --git a/ibctesting/genesis_transfer_test.go b/ibctesting/genesis_transfer_test.go new file mode 100644 index 000000000..0f0a8eff4 --- /dev/null +++ b/ibctesting/genesis_transfer_test.go @@ -0,0 +1,127 @@ +package ibctesting_test + +import ( + "testing" + + "cosmossdk.io/math" + + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/dymension/v3/app/apptesting" + "github.com/stretchr/testify/suite" + + "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + ibctesting "github.com/cosmos/ibc-go/v6/testing" +) + +type transferGenesisSuite struct { + utilSuite + + path *ibctesting.Path +} + +func TestTransferGenesisTestSuite(t *testing.T) { + suite.Run(t, new(transferGenesisSuite)) +} + +func (s *transferGenesisSuite) SetupTest() { + s.utilSuite.SetupTest() + path := s.newTransferPath(s.hubChain(), s.rollappChain()) + s.coordinator.Setup(path) + s.createRollapp(false, nil) // genesis protocol is not finished yet + s.registerSequencer() + s.path = path + + // set hooks to avoid actually creating VFC contract, as this places extra requirements on the test setup + // we assume that if the denom metadata was created (checked below), then the hooks ran correctly + s.hubApp().DenomMetadataKeeper.SetHooks(nil) +} + +// In the happy path, the new rollapp will send ibc transfers with a special +// memo immediately when the channel opens. This will cause all the denoms to get registered, and tokens +// to go to the right addresses. After all transfers are sent, the bridge opens. +func (s *transferGenesisSuite) TestHappyPath() { + /* + Send a bunch of transfer packets to the hub + Check the balances are created + Check the denoms are created + Check the bridge is enabled (or not) + */ + + amt := math.NewIntFromUint64(10000000000000000000) + + denoms := []string{"foo", "bar", "baz"} + + for i, denom := range denoms { + /* ------------------- move non-registered token from rollapp ------------------- */ + + msg := s.transferMsg(amt, denom, i, len(denoms)) + apptesting.FundAccount(s.rollappApp(), s.rollappCtx(), s.rollappChain().SenderAccount.GetAddress(), sdk.Coins{msg.Token}) + res, err := s.rollappChain().SendMsgs(msg) + s.Require().NoError(err) + packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) + s.Require().NoError(err) + + err = s.path.RelayPacket(packet) + s.Require().NoError(err) + // after the last one, it should be OK + transfersEnabled := s.hubApp().RollappKeeper.MustGetRollapp(s.hubCtx(), rollappChainID()).GenesisState.TransfersEnabled + s.Require().Equal(i == len(denoms)-1, transfersEnabled, "transfers enabled check", "i", i) + } + + for _, denom := range denoms { + // has the denom? + ibcDenom := types.ParseDenomTrace(types.GetPrefixedDenom(s.path.EndpointB.ChannelConfig.PortID, s.path.EndpointB.ChannelID, denom)).IBCDenom() + metadata, found := s.hubApp().BankKeeper.GetDenomMetaData(s.hubCtx(), ibcDenom) + s.Require().True(found, "missing denom metadata for rollapps taking token") + s.Require().Equal(ibcDenom, metadata.Base) + // has the tokens? + c := s.hubApp().BankKeeper.GetBalance(s.hubCtx(), s.hubChain().SenderAccount.GetAddress(), ibcDenom) + s.Require().Equal(amt, c.Amount) + } +} + +func (s *transferGenesisSuite) transferMsg(amt math.Int, denom string, i, nDenomsTotal int) *types.MsgTransfer { + meta := banktypes.Metadata{ + Description: "", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: denom, + }, + { + Denom: "a" + denom, + Exponent: 18, + }, + }, + Base: denom, + Display: "a" + denom, // TODO: set right + Name: denom, + Symbol: denom, + URI: "", + URIHash: "", + } + s.Require().NoError(meta.Validate()) // sanity check the test is written correctly + memo := rollapptypes.GenesisTransferMemo{ + Denom: meta, + TotalNumTransfers: uint64(nDenomsTotal), + }.Namespaced().MustString() + tokens := sdk.NewCoin(meta.Base, amt) + + timeoutHeight := clienttypes.NewHeight(100, 110) + + msg := types.NewMsgTransfer( + s.path.EndpointB.ChannelConfig.PortID, + s.path.EndpointB.ChannelID, + tokens, + s.rollappChain().SenderAccount.GetAddress().String(), + s.hubChain().SenderAccount.GetAddress().String(), + timeoutHeight, + 0, + memo, + ) + + return msg +} diff --git a/ibctesting/rollapp_genesis_token_test.go b/ibctesting/rollapp_genesis_token_test.go deleted file mode 100644 index efbc913dc..000000000 --- a/ibctesting/rollapp_genesis_token_test.go +++ /dev/null @@ -1,261 +0,0 @@ -package ibctesting_test - -import ( - "fmt" - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" - "github.com/dymensionxyz/dymension/v3/app/apptesting" - "github.com/dymensionxyz/dymension/v3/utils" - rollappkeeper "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper" - "github.com/dymensionxyz/dymension/v3/x/rollapp/types" - rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" - "github.com/stretchr/testify/suite" -) - -var ( - genesisAuthorizedAccount = apptesting.CreateRandomAccounts(1)[0] - rollappDenom = "arax" - rollappIBCDenom = "ibc/9A1EACD53A6A197ADC81DF9A49F0C4A26F7FF685ACF415EE726D7D59796E71A7" -) - -type RollappGenesisTokenTestSuite struct { - IBCTestUtilSuite - - msgServer types.MsgServer - ctx sdk.Context -} - -func TestRollappGenesisTokenTestSuite(t *testing.T) { - suite.Run(t, new(RollappGenesisTokenTestSuite)) -} - -func (suite *RollappGenesisTokenTestSuite) SetupTest() { - suite.IBCTestUtilSuite.SetupTest() - rollappKeeper := ConvertToApp(suite.hubChain).RollappKeeper - suite.msgServer = rollappkeeper.NewMsgServerImpl(rollappKeeper) - suite.ctx = suite.hubChain.GetContext() -} - -func (suite *RollappGenesisTokenTestSuite) TestTriggerGenesisEvent() { - suite.CreateRollapp() - // Create a primary path - hubToRollappPath := suite.NewTransferPath(suite.hubChain, suite.rollappChain) - suite.coordinator.Setup(hubToRollappPath) - // Create a secondary path with a 3rd party chain - hubToCosmosPath := suite.NewTransferPath(suite.hubChain, suite.cosmosChain) - suite.coordinator.Setup(hubToCosmosPath) - - cases := []struct { - name string - gensisState types.RollappGenesisState - msg *types.MsgRollappGenesisEvent - deployerParams []types.DeployerParams - malleate func() - expectSavedDenom string - expErr error - }{ - { - name: "successful rollapp genesis event", - gensisState: types.RollappGenesisState{ - GenesisAccounts: []*types.GenesisAccount{ - {Address: apptesting.CreateRandomAccounts(1)[0].String(), Amount: sdk.NewCoin(rollappDenom, sdk.NewInt(350))}, - {Address: apptesting.CreateRandomAccounts(1)[0].String(), Amount: sdk.NewCoin(rollappDenom, sdk.NewInt(140))}, - }, - IsGenesisEvent: false, - }, - msg: &types.MsgRollappGenesisEvent{ - Address: genesisAuthorizedAccount.String(), - RollappId: suite.rollappChain.ChainID, - ChannelId: hubToRollappPath.EndpointA.ChannelID, - }, - deployerParams: []types.DeployerParams{{Address: genesisAuthorizedAccount.String()}}, - expectSavedDenom: rollappIBCDenom, - }, - { - name: "invalid rollapp genesis event - genesis event already triggered", - gensisState: types.RollappGenesisState{ - GenesisAccounts: []*types.GenesisAccount{ - {Address: apptesting.CreateRandomAccounts(1)[0].String(), Amount: sdk.NewCoin(rollappDenom, sdk.NewInt(350))}, - {Address: apptesting.CreateRandomAccounts(1)[0].String(), Amount: sdk.NewCoin(rollappDenom, sdk.NewInt(140))}, - }, - IsGenesisEvent: true, - }, - msg: &types.MsgRollappGenesisEvent{ - Address: genesisAuthorizedAccount.String(), - RollappId: suite.rollappChain.ChainID, - ChannelId: hubToRollappPath.EndpointA.ChannelID, - }, - deployerParams: []types.DeployerParams{{Address: genesisAuthorizedAccount.String()}}, - expErr: types.ErrGenesisEventAlreadyTriggered, - }, - { - name: "invalid rollapp genesis event - unauthorized address", - gensisState: types.RollappGenesisState{ - GenesisAccounts: []*types.GenesisAccount{ - {Address: apptesting.CreateRandomAccounts(1)[0].String(), Amount: sdk.NewCoin(rollappDenom, sdk.NewInt(350))}, - {Address: apptesting.CreateRandomAccounts(1)[0].String(), Amount: sdk.NewCoin(rollappDenom, sdk.NewInt(140))}, - }, - IsGenesisEvent: true, - }, - msg: &types.MsgRollappGenesisEvent{ - Address: apptesting.CreateRandomAccounts(1)[0].String(), - RollappId: suite.rollappChain.ChainID, - ChannelId: hubToRollappPath.EndpointA.ChannelID, - }, - deployerParams: []types.DeployerParams{{Address: genesisAuthorizedAccount.String()}}, - expErr: rollapptypes.ErrUnauthorized, - }, - { - name: "invalid rollapp genesis event - rollapp doesn't exist", - gensisState: types.RollappGenesisState{ - GenesisAccounts: []*types.GenesisAccount{ - {Address: apptesting.CreateRandomAccounts(1)[0].String(), Amount: sdk.NewCoin(rollappDenom, sdk.NewInt(350))}, - {Address: apptesting.CreateRandomAccounts(1)[0].String(), Amount: sdk.NewCoin(rollappDenom, sdk.NewInt(140))}, - }, - IsGenesisEvent: false, - }, - msg: &types.MsgRollappGenesisEvent{ - Address: genesisAuthorizedAccount.String(), - RollappId: "someRandomChainID", - ChannelId: hubToRollappPath.EndpointA.ChannelID, - }, - deployerParams: []types.DeployerParams{{Address: genesisAuthorizedAccount.String()}}, - expErr: types.ErrUnknownRollappID, - }, - { - name: "invalid rollapp genesis event - channel doesn't exist", - gensisState: types.RollappGenesisState{ - GenesisAccounts: []*types.GenesisAccount{ - {Address: apptesting.CreateRandomAccounts(1)[0].String(), Amount: sdk.NewCoin(rollappDenom, sdk.NewInt(350))}, - {Address: apptesting.CreateRandomAccounts(1)[0].String(), Amount: sdk.NewCoin(rollappDenom, sdk.NewInt(140))}, - }, - IsGenesisEvent: false, - }, - msg: &types.MsgRollappGenesisEvent{ - Address: genesisAuthorizedAccount.String(), - RollappId: suite.rollappChain.ChainID, - ChannelId: "SomeRandomChannelID", - }, - deployerParams: []types.DeployerParams{{Address: genesisAuthorizedAccount.String()}}, - expErr: channeltypes.ErrChannelNotFound, - }, - { - name: "invalid rollapp genesis event - channel id doesn't match chain id", - gensisState: types.RollappGenesisState{ - GenesisAccounts: []*types.GenesisAccount{ - {Address: apptesting.CreateRandomAccounts(1)[0].String(), Amount: sdk.NewCoin(rollappDenom, sdk.NewInt(350))}, - {Address: apptesting.CreateRandomAccounts(1)[0].String(), Amount: sdk.NewCoin(rollappDenom, sdk.NewInt(140))}, - }, - IsGenesisEvent: false, - }, - msg: &types.MsgRollappGenesisEvent{ - Address: genesisAuthorizedAccount.String(), - RollappId: suite.rollappChain.ChainID, - ChannelId: hubToCosmosPath.EndpointA.ChannelID, - }, - deployerParams: []types.DeployerParams{{Address: genesisAuthorizedAccount.String()}}, - expErr: types.ErrInvalidGenesisChannelId, - }, - { - name: "failed rollapp genesis event - error minting coins", - gensisState: types.RollappGenesisState{ - GenesisAccounts: []*types.GenesisAccount{ - {Address: ""}, - }, - IsGenesisEvent: false, - }, - msg: &types.MsgRollappGenesisEvent{ - Address: genesisAuthorizedAccount.String(), - RollappId: suite.rollappChain.ChainID, - ChannelId: hubToRollappPath.EndpointA.ChannelID, - }, - deployerParams: []types.DeployerParams{{Address: genesisAuthorizedAccount.String()}}, - expectSavedDenom: rollappIBCDenom, - expErr: types.ErrMintTokensFailed, - }, - { - name: "failed rollapp genesis event - error registering denom metadata", - gensisState: types.RollappGenesisState{ - GenesisAccounts: []*types.GenesisAccount{ - {Address: apptesting.CreateRandomAccounts(1)[0].String(), Amount: sdk.NewCoin(rollappDenom, sdk.NewInt(350))}, - {Address: apptesting.CreateRandomAccounts(1)[0].String(), Amount: sdk.NewCoin(rollappDenom, sdk.NewInt(140))}, - }, - IsGenesisEvent: false, - }, - msg: &types.MsgRollappGenesisEvent{ - Address: genesisAuthorizedAccount.String(), - RollappId: suite.rollappChain.ChainID, - ChannelId: hubToRollappPath.EndpointA.ChannelID, - }, - deployerParams: []types.DeployerParams{{Address: genesisAuthorizedAccount.String()}}, - malleate: func() { - ConvertToApp(suite.hubChain).BankKeeper.SetDenomMetaData(suite.ctx, banktypes.Metadata{Base: rollappIBCDenom}) - }, - expectSavedDenom: rollappIBCDenom, - expErr: types.ErrRegisterDenomMetadataFailed, - }, - } - for _, tc := range cases { - suite.Run(fmt.Sprintf("Case %s", tc.name), func() { - // Reset the test state - defer func() { - suite.SetupTest() - suite.CreateRollapp() - // Create a primary path - hubToRollappPath = suite.NewTransferPath(suite.hubChain, suite.rollappChain) - suite.coordinator.Setup(hubToRollappPath) - // Create a secondary path with a 3rd party chain - hubToCosmosPath = suite.NewTransferPath(suite.hubChain, suite.cosmosChain) - suite.coordinator.Setup(hubToCosmosPath) - }() - - if tc.malleate != nil { - tc.malleate() - } - - // Setup the deployer whitelist - rollappKeeper := ConvertToApp(suite.hubChain).RollappKeeper - rollappKeeper.SetParams(suite.ctx, types.NewParams(true, 2, tc.deployerParams)) - // Setup the rollapp genesis state - rollapp, found := rollappKeeper.GetRollapp(suite.ctx, suite.rollappChain.ChainID) - suite.Require().True(found) - rollapp.GenesisState = tc.gensisState - rollappKeeper.SetRollapp(suite.ctx, rollapp) - // Send the genesis event - - ctx := suite.ctx.WithProposer(suite.hubChain.NextVals.Proposer.Address.Bytes()) - _, err := suite.msgServer.TriggerGenesisEvent(ctx, tc.msg) - suite.hubChain.NextBlock() - suite.Require().ErrorIs(err, tc.expErr) - - if tc.expErr == nil { - rollapp, _ = rollappKeeper.GetRollapp(suite.ctx, suite.rollappChain.ChainID) - suite.Require().NotEmpty(rollapp.ChannelId) - } - - // Validate no tokens are in the module account - accountKeeper := ConvertToApp(suite.hubChain).AccountKeeper - bankKeeper := ConvertToApp(suite.hubChain).BankKeeper - moduleAcc := accountKeeper.GetModuleAccount(suite.ctx, types.ModuleName) - suite.Require().Equal(sdk.NewCoins(), bankKeeper.GetAllBalances(suite.ctx, moduleAcc.GetAddress())) - // Validate the genesis accounts balances - rollappIBCDenom := utils.GetForeignIBCDenom(hubToRollappPath.EndpointB.ChannelID, rollappDenom) - for _, roallppGenesisAccount := range tc.gensisState.GenesisAccounts { - if roallppGenesisAccount.Address != "" { - balance := bankKeeper.GetBalance(suite.ctx, sdk.MustAccAddressFromBech32(roallppGenesisAccount.Address), rollappIBCDenom) - if tc.expErr != nil { - suite.Require().Equal(sdk.NewCoin(rollappIBCDenom, sdk.NewInt(0)), balance) - } else { - suite.Require().Equal(roallppGenesisAccount.Amount.Amount, balance.Amount) - } - } - } - - _, found = bankKeeper.GetDenomMetaData(suite.ctx, rollappIBCDenom) - suite.Require().Equal(tc.expectSavedDenom != "", found) - }) - } -} diff --git a/ibctesting/transfers_enabled_test.go b/ibctesting/transfers_enabled_test.go new file mode 100644 index 000000000..195316927 --- /dev/null +++ b/ibctesting/transfers_enabled_test.go @@ -0,0 +1,137 @@ +package ibctesting_test + +import ( + "testing" + + errorsmod "cosmossdk.io/errors" + "github.com/dymensionxyz/dymension/v3/utils/gerr" + + "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/dymension/v3/app/apptesting" + "github.com/stretchr/testify/suite" + + "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + ibctesting "github.com/cosmos/ibc-go/v6/testing" + "github.com/cosmos/ibc-go/v6/testing/simapp" +) + +type transfersEnabledSuite struct { + utilSuite + + path *ibctesting.Path +} + +func TestTransfersEnabledTestSuite(t *testing.T) { + suite.Run(t, new(transfersEnabledSuite)) +} + +func (s *transfersEnabledSuite) SetupTest() { + s.utilSuite.SetupTest() + path := s.newTransferPath(s.hubChain(), s.rollappChain()) + s.coordinator.Setup(path) + s.createRollapp(false, nil) + s.registerSequencer() + s.path = path + s.Require().False(s.hubApp().RollappKeeper.MustGetRollapp(s.hubCtx(), rollappChainID()).GenesisState.TransfersEnabled) +} + +// Regular (non genesis) transfers RA->Hub (and Hub->RA) should both be blocked when the bridge is not open +// Note: we don't explicitly test the 'enabled' case, since this is tested in other tests in this package +func (s *transfersEnabledSuite) TestRollappToHubDisabled() { + amt := math.NewIntFromUint64(10000000000000000000) + denom := "foo" + tokens := sdk.NewCoin(denom, amt) + + timeoutHeight := clienttypes.NewHeight(100, 110) + + msg := types.NewMsgTransfer( + s.path.EndpointB.ChannelConfig.PortID, + s.path.EndpointB.ChannelID, + tokens, + s.rollappChain().SenderAccount.GetAddress().String(), + s.hubChain().SenderAccount.GetAddress().String(), + timeoutHeight, + 0, + "", + ) + + receiverBalance := s.hubApp().BankKeeper.GetBalance(s.hubCtx(), s.hubChain().SenderAccount.GetAddress(), denom) + s.Require().True(receiverBalance.Amount.IsZero()) + + apptesting.FundAccount(s.rollappApp(), s.rollappCtx(), s.rollappChain().SenderAccount.GetAddress(), sdk.Coins{msg.Token}) + res, err := s.rollappChain().SendMsgs(msg) + s.Require().NoError(err) + packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) + s.Require().NoError(err) + + // money is escrowed + senderBalance := s.rollappApp().BankKeeper.GetBalance(s.rollappCtx(), s.rollappChain().SenderAccount.GetAddress(), denom) + s.Require().True(senderBalance.Amount.IsZero()) + + // fails and returns err ack + err = s.path.RelayPacket(packet) + s.Require().NoError(err) + + // money is refunded + senderBalance = s.rollappApp().BankKeeper.GetBalance(s.rollappCtx(), s.rollappChain().SenderAccount.GetAddress(), denom) + s.Require().True(senderBalance.Amount.IsPositive()) + + // no double spend + receiverBalance = s.hubApp().BankKeeper.GetBalance(s.hubCtx(), s.hubChain().SenderAccount.GetAddress(), denom) + s.Require().True(receiverBalance.Amount.IsZero()) +} + +// Regular (non genesis) transfers (RA->Hub) and Hub->RA should both be blocked when the bridge is not open +func (s *transfersEnabledSuite) TestHubToRollappDisabled() { + amt := math.NewIntFromUint64(10000000000000000000) + denom := "foo" + tokens := sdk.NewCoin(denom, amt) + + timeoutHeight := clienttypes.NewHeight(100, 110) + + msg := types.NewMsgTransfer( + s.path.EndpointA.ChannelConfig.PortID, + s.path.EndpointA.ChannelID, + tokens, + s.hubChain().SenderAccount.GetAddress().String(), + s.rollappChain().SenderAccount.GetAddress().String(), + timeoutHeight, + 0, + "", + ) + + shouldFail := true + + for range 2 { + + apptesting.FundAccount(s.hubApp(), s.hubCtx(), s.hubChain().SenderAccount.GetAddress(), sdk.Coins{msg.Token}) + + _, _, err := simapp.SignAndDeliver( + s.hubChain().T, + s.hubChain().TxConfig, + s.hubApp().GetBaseApp(), + s.hubCtx().BlockHeader(), + []sdk.Msg{msg}, + hubChainID(), + []uint64{s.hubChain().SenderAccount.GetAccountNumber()}, + []uint64{s.hubChain().SenderAccount.GetSequence()}, + true, + !shouldFail, + s.hubChain().SenderPrivKey, + ) + + if shouldFail { + shouldFail = false + s.Require().True(errorsmod.IsOf(err, gerr.ErrFailedPrecondition)) + ra := s.hubApp().RollappKeeper.MustGetRollapp(s.hubCtx(), rollappChainID()) + ra.ChannelId = s.path.EndpointA.ChannelID + s.hubApp().RollappKeeper.SetRollapp(s.hubCtx(), ra) + s.hubApp().RollappKeeper.EnableTransfers(s.hubCtx(), ra.RollappId) + } else { + s.Require().NoError(err) + } + } +} diff --git a/ibctesting/utils_test.go b/ibctesting/utils_test.go index dd191ebb0..44007b948 100644 --- a/ibctesting/utils_test.go +++ b/ibctesting/utils_test.go @@ -3,7 +3,6 @@ package ibctesting_test import ( "bytes" "encoding/json" - "strings" "testing" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" @@ -33,151 +32,135 @@ import ( "github.com/stretchr/testify/suite" ) -// ChainIDPrefix defines the default chain ID prefix for Evmos test chains -var ChainIDPrefix = "evmos_9000-" +// chainIDPrefix defines the default chain ID prefix for Evmos test chains +var chainIDPrefix = "evmos_9000-" func init() { - ibctesting.ChainIDPrefix = ChainIDPrefix + ibctesting.ChainIDPrefix = chainIDPrefix ibctesting.DefaultTestingAppInit = func() (ibctesting.TestingApp, map[string]json.RawMessage) { return apptesting.SetupTestingApp() } } -func ConvertToApp(chain *ibctesting.TestChain) *app.App { - app, ok := chain.App.(*app.App) +func convertToApp(chain *ibctesting.TestChain) *app.App { + a, ok := chain.App.(*app.App) require.True(chain.T, ok) - return app + return a } -// IBCTestUtilSuite is a testing suite to test keeper functions. -type IBCTestUtilSuite struct { +// utilSuite is a testing suite to test keeper functions. +type utilSuite struct { suite.Suite - coordinator *ibctesting.Coordinator +} + +func hubChainID() string { + return ibctesting.GetChainID(1) +} + +func cosmosChainID() string { + return ibctesting.GetChainID(2) +} + +func rollappChainID() string { + return ibctesting.GetChainID(3) +} + +func (s *utilSuite) hubChain() *ibctesting.TestChain { + return s.coordinator.GetChain(hubChainID()) +} - // testing chains used for convenience and readability - hubChain *ibctesting.TestChain - cosmosChain *ibctesting.TestChain - rollappChain *ibctesting.TestChain +func (s *utilSuite) cosmosChain() *ibctesting.TestChain { + return s.coordinator.GetChain(cosmosChainID()) +} - // msg servers - rollappMsgServer rollapptypes.MsgServer +func (s *utilSuite) rollappChain() *ibctesting.TestChain { + return s.coordinator.GetChain(rollappChainID()) +} + +func (s *utilSuite) hubApp() *app.App { + return convertToApp(s.hubChain()) +} + +func (s *utilSuite) rollappApp() *app.App { + return convertToApp(s.rollappChain()) +} + +func (s *utilSuite) hubCtx() sdk.Context { + return s.hubChain().GetContext() +} + +func (s *utilSuite) cosmosCtx() sdk.Context { + return s.cosmosChain().GetContext() +} + +func (s *utilSuite) rollappCtx() sdk.Context { + return s.rollappChain().GetContext() +} + +func (s *utilSuite) rollappMsgServer() rollapptypes.MsgServer { + return rollappkeeper.NewMsgServerImpl(s.hubApp().RollappKeeper) } // SetupTest creates a coordinator with 2 test chains. -func (suite *IBCTestUtilSuite) SetupTest() { - suite.coordinator = ibctesting.NewCoordinator(suite.T(), 3) // initializes 3 test chains - suite.hubChain = suite.coordinator.GetChain(ibctesting.GetChainID(1)) // convenience and readability - suite.cosmosChain = suite.coordinator.GetChain(ibctesting.GetChainID(2)) // convenience and readability - suite.rollappChain = suite.newTestChainWithSingleValidator(suite.T(), suite.coordinator, ibctesting.ChainIDPrefix+"3") - suite.coordinator.Chains[suite.rollappChain.ChainID] = suite.rollappChain - // Setup msg server for the rollapp keeper - suite.rollappMsgServer = rollappkeeper.NewMsgServerImpl(ConvertToApp(suite.hubChain).RollappKeeper) +func (s *utilSuite) SetupTest() { + s.coordinator = ibctesting.NewCoordinator(s.T(), 2) // initializes test chains + s.coordinator.Chains[rollappChainID()] = s.newTestChainWithSingleValidator(s.T(), s.coordinator, rollappChainID()) } -func (suite *IBCTestUtilSuite) CreateRollapp() { +// CreateRollappWithFinishedGenesis creates a rollapp whose 'genesis' protocol is complete: +// that is, they have finished all genesis transfers and their bridge is enabled. +func (s *utilSuite) createRollappWithFinishedGenesis(canonicalChannelID string) { + s.createRollapp(true, &canonicalChannelID) +} + +func (s *utilSuite) createRollapp(transfersEnabled bool, channelID *string) { msgCreateRollapp := rollapptypes.NewMsgCreateRollapp( - suite.hubChain.SenderAccount.GetAddress().String(), - suite.rollappChain.ChainID, + s.hubChain().SenderAccount.GetAddress().String(), + rollappChainID(), 10, []string{}, - []rollapptypes.TokenMetadata{ - { - Name: "RollApp RAX", - Symbol: "rax", - Description: "The native staking token of RollApp XYZ", - DenomUnits: []*rollapptypes.DenomUnit{ - {Denom: "arax", Exponent: uint32(0), Aliases: nil}, - {Denom: "rax", Exponent: uint32(10), Aliases: []string{"RAX"}}, - }, - Base: "arax", - Display: "rax", - }, - }, - nil, - ) - _, err := suite.hubChain.SendMsgs(msgCreateRollapp) - suite.Require().NoError(err) // message committed -} -func (suite *IBCTestUtilSuite) GenesisEvent(channelID string) { - // add sender to deployer whitelist - app := ConvertToApp(suite.hubChain) - params := app.RollappKeeper.GetParams(suite.hubChain.GetContext()) - params.DeployerWhitelist = []rollapptypes.DeployerParams{{Address: suite.hubChain.SenderAccount.GetAddress().String()}} - app.RollappKeeper.SetParams(suite.hubChain.GetContext(), params) - - msgGenesisEvent := rollapptypes.NewMsgRollappGenesisEvent( - suite.hubChain.SenderAccount.GetAddress().String(), - channelID, - suite.rollappChain.ChainID, + transfersEnabled, ) - suite.hubChain.CurrentHeader.ProposerAddress = suite.hubChain.NextVals.Proposer.Address - - _, err := suite.hubChain.SendMsgs(msgGenesisEvent) - suite.Require().NoError(err) // message committed + _, err := s.hubChain().SendMsgs(msgCreateRollapp) + s.Require().NoError(err) // message committed + if channelID != nil { + a := s.hubApp() + ra := a.RollappKeeper.MustGetRollapp(s.hubCtx(), rollappChainID()) + ra.ChannelId = *channelID + a.RollappKeeper.SetRollapp(s.hubCtx(), ra) + } } -func (suite *IBCTestUtilSuite) RegisterSequencer() { +func (s *utilSuite) registerSequencer() { bond := sequencertypes.DefaultParams().MinBond // fund account - err := bankutil.FundAccount(ConvertToApp(suite.hubChain).BankKeeper, suite.hubChain.GetContext(), suite.hubChain.SenderAccount.GetAddress(), sdk.NewCoins(bond)) - suite.Require().Nil(err) + err := bankutil.FundAccount(s.hubApp().BankKeeper, s.hubCtx(), s.hubChain().SenderAccount.GetAddress(), sdk.NewCoins(bond)) + s.Require().Nil(err) // using validator pubkey as the dymint pubkey - pk, err := cryptocodec.FromTmPubKeyInterface(suite.rollappChain.Vals.Validators[0].PubKey) - suite.Require().Nil(err) + pk, err := cryptocodec.FromTmPubKeyInterface(s.rollappChain().Vals.Validators[0].PubKey) + s.Require().Nil(err) msgCreateSequencer, err := sequencertypes.NewMsgCreateSequencer( - suite.hubChain.SenderAccount.GetAddress().String(), + s.hubChain().SenderAccount.GetAddress().String(), pk, - suite.rollappChain.ChainID, + rollappChainID(), &sequencertypes.Description{}, bond, ) - suite.Require().NoError(err) // message committed - _, err = suite.hubChain.SendMsgs(msgCreateSequencer) - suite.Require().NoError(err) // message committed -} - -func (suite *IBCTestUtilSuite) CreateRollappWithMetadata(denom string) { - displayDenom := "big" + denom - msgCreateRollapp := rollapptypes.NewMsgCreateRollapp( - suite.hubChain.SenderAccount.GetAddress().String(), - suite.rollappChain.ChainID, - 10, - []string{}, - []rollapptypes.TokenMetadata{ - { - Base: denom, - DenomUnits: []*rollapptypes.DenomUnit{ - { - Denom: denom, - Exponent: 0, - }, - { - Denom: displayDenom, - Exponent: 6, - }, - }, - Description: "stake as rollapp token", - Display: displayDenom, - Name: displayDenom, - Symbol: strings.ToUpper(displayDenom), - }, - }, - nil, - ) - _, err := suite.hubChain.SendMsgs(msgCreateRollapp) - suite.Require().NoError(err) // message committed + s.Require().NoError(err) // message committed + _, err = s.hubChain().SendMsgs(msgCreateSequencer) + s.Require().NoError(err) // message committed } -func (suite *IBCTestUtilSuite) UpdateRollappState(endHeight uint64) { +func (s *utilSuite) updateRollappState(endHeight uint64) { // Get the start index and start height based on the latest state info - rollappKeeper := ConvertToApp(suite.hubChain).RollappKeeper - latestStateInfoIndex, _ := rollappKeeper.GetLatestStateInfoIndex(suite.hubChain.GetContext(), suite.rollappChain.ChainID) - stateInfo, found := rollappKeeper.GetStateInfo(suite.hubChain.GetContext(), suite.rollappChain.ChainID, latestStateInfoIndex.Index) + rollappKeeper := s.hubApp().RollappKeeper + latestStateInfoIndex, _ := rollappKeeper.GetLatestStateInfoIndex(s.hubCtx(), rollappChainID()) + stateInfo, found := rollappKeeper.GetStateInfo(s.hubCtx(), rollappChainID(), latestStateInfoIndex.Index) startHeight := uint64(1) if found { startHeight = stateInfo.StartHeight + stateInfo.NumBlocks @@ -193,8 +176,8 @@ func (suite *IBCTestUtilSuite) UpdateRollappState(endHeight uint64) { } // Update the state msgUpdateState := rollapptypes.NewMsgUpdateState( - suite.hubChain.SenderAccount.GetAddress().String(), - suite.rollappChain.ChainID, + s.hubChain().SenderAccount.GetAddress().String(), + rollappChainID(), startHeight, endHeight-startHeight+1, // numBlocks "mock-da-path", @@ -202,18 +185,18 @@ func (suite *IBCTestUtilSuite) UpdateRollappState(endHeight uint64) { blockDescriptors, ) err := msgUpdateState.ValidateBasic() - suite.Require().NoError(err) - _, err = suite.rollappMsgServer.UpdateState(suite.hubChain.GetContext(), msgUpdateState) - suite.Require().NoError(err) + s.Require().NoError(err) + _, err = s.rollappMsgServer().UpdateState(s.hubCtx(), msgUpdateState) + s.Require().NoError(err) } -func (suite *IBCTestUtilSuite) FinalizeRollappState(index uint64, endHeight uint64) (sdk.Events, error) { - rollappKeeper := ConvertToApp(suite.hubChain).RollappKeeper - ctx := suite.hubChain.GetContext() +func (s *utilSuite) finalizeRollappState(index uint64, endHeight uint64) (sdk.Events, error) { + rollappKeeper := s.hubApp().RollappKeeper + ctx := s.hubCtx() - stateInfoIdx := rollapptypes.StateInfoIndex{RollappId: suite.rollappChain.ChainID, Index: index} - stateInfo, found := rollappKeeper.GetStateInfo(ctx, suite.rollappChain.ChainID, stateInfoIdx.Index) - suite.Require().True(found) + stateInfoIdx := rollapptypes.StateInfoIndex{RollappId: rollappChainID(), Index: index} + stateInfo, found := rollappKeeper.GetStateInfo(ctx, rollappChainID(), stateInfoIdx.Index) + s.Require().True(found) stateInfo.NumBlocks = endHeight - stateInfo.StartHeight + 1 stateInfo.Status = common.Status_FINALIZED // update the status of the stateInfo @@ -222,14 +205,14 @@ func (suite *IBCTestUtilSuite) FinalizeRollappState(index uint64, endHeight uint rollappKeeper.SetLatestFinalizedStateIndex(ctx, stateInfoIdx) err := rollappKeeper.GetHooks().AfterStateFinalized( ctx, - suite.rollappChain.ChainID, + rollappChainID(), &stateInfo, ) return ctx.EventManager().Events(), err } -func (suite *IBCTestUtilSuite) NewTransferPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { +func (s *utilSuite) newTransferPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { path := ibctesting.NewPath(chainA, chainB) path.EndpointA.ChannelConfig.PortID = ibctesting.TransferPort path.EndpointB.ChannelConfig.PortID = ibctesting.TransferPort @@ -240,14 +223,14 @@ func (suite *IBCTestUtilSuite) NewTransferPath(chainA, chainB *ibctesting.TestCh return path } -func (suite *IBCTestUtilSuite) GetRollappToHubIBCDenomFromPacket(packet channeltypes.Packet) string { +func (s *utilSuite) getRollappToHubIBCDenomFromPacket(packet channeltypes.Packet) string { var data transfertypes.FungibleTokenPacketData err := eibctypes.ModuleCdc.UnmarshalJSON(packet.GetData(), &data) - suite.Require().NoError(err) - return suite.GetIBCDenomForChannel(packet.GetDestChannel(), data.Denom) + s.Require().NoError(err) + return s.getIBCDenomForChannel(packet.GetDestChannel(), data.Denom) } -func (suite *IBCTestUtilSuite) GetIBCDenomForChannel(channel string, denom string) string { +func (s *utilSuite) getIBCDenomForChannel(channel string, denom string) string { // since SendPacket did not prefix the denomination, we must prefix denomination here sourcePrefix := types.GetDenomPrefix("transfer", channel) // NOTE: sourcePrefix contains the trailing "/" @@ -257,7 +240,7 @@ func (suite *IBCTestUtilSuite) GetIBCDenomForChannel(channel string, denom strin return denomTrace.IBCDenom() } -func (suite *IBCTestUtilSuite) newTestChainWithSingleValidator(t *testing.T, coord *ibctesting.Coordinator, chainID string) *ibctesting.TestChain { +func (s *utilSuite) newTestChainWithSingleValidator(t *testing.T, coord *ibctesting.Coordinator, chainID string) *ibctesting.TestChain { genAccs := []authtypes.GenesisAccount{} genBals := []banktypes.Balance{} senderAccs := []ibctesting.SenderAccount{} @@ -266,13 +249,13 @@ func (suite *IBCTestUtilSuite) newTestChainWithSingleValidator(t *testing.T, coo valPrivKey := mock.NewPV() valPubKey, err := valPrivKey.GetPubKey() - suite.Require().NoError(err) + s.Require().NoError(err) senderPrivKey := secp256k1.GenPrivKey() acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0) amount, ok := sdk.NewIntFromString("10000000000000000000") - suite.Require().True(ok) + s.Require().True(ok) // add sender account balance := banktypes.Balance{ diff --git a/proto/dymension/rollapp/bank.proto b/proto/dymension/rollapp/bank.proto deleted file mode 100644 index 1df18cd74..000000000 --- a/proto/dymension/rollapp/bank.proto +++ /dev/null @@ -1,53 +0,0 @@ -syntax = "proto3"; -package dymensionxyz.dymension.rollapp; - -option go_package = "github.com/dymensionxyz/dymension/v3/x/rollapp/types"; - -import "gogoproto/gogo.proto"; - - -// DenomUnit represents a struct that describes a given -// denomination unit of the basic token. -message DenomUnit { - // denom represents the string name of the given denom unit (e.g uatom). - string denom = 1; - // exponent represents power of 10 exponent that one must - // raise the base_denom to in order to equal the given DenomUnit's denom - // 1 denom = 10^exponent base_denom - // (e.g. with a base_denom of uatom, one can create a DenomUnit of 'atom' with - // exponent = 6, thus: 1 atom = 10^6 uatom). - uint32 exponent = 2; - // aliases is a list of string aliases for the given denom - repeated string aliases = 3; -} - -// Metadata represents a struct that describes -// a basic token. -message TokenMetadata { - string description = 1; - // denom_units represents the list of DenomUnit's for a given coin - repeated DenomUnit denom_units = 2; - // base represents the base denom (should be the DenomUnit with exponent = 0). - string base = 3; - // display indicates the suggested denom that should be - // displayed in clients. - string display = 4; - // name defines the name of the token (eg: Cosmos Atom) - // - // Since: cosmos-sdk 0.43 - string name = 5; - // symbol is the token symbol usually shown on exchanges (eg: ATOM). This can - // be the same as the display. - // - // Since: cosmos-sdk 0.43 - string symbol = 6; - // URI to a document (on or off-chain) that contains additional information. Optional. - // - // Since: cosmos-sdk 0.46 - string uri = 7 [(gogoproto.customname) = "URI"]; - // URIHash is a sha256 hash of a document pointed by URI. It's used to verify that - // the document didn't change. Optional. - // - // Since: cosmos-sdk 0.46 - string uri_hash = 8 [(gogoproto.customname) = "URIHash"]; -} diff --git a/proto/dymension/rollapp/genesis.proto b/proto/dymension/rollapp/genesis.proto index e8b98dead..46bf3e014 100644 --- a/proto/dymension/rollapp/genesis.proto +++ b/proto/dymension/rollapp/genesis.proto @@ -5,6 +5,7 @@ import "gogoproto/gogo.proto"; import "dymension/rollapp/params.proto"; import "dymension/rollapp/rollapp.proto"; import "dymension/rollapp/state_info.proto"; +import "dymension/rollapp/genesis_transfer.proto"; // this line is used by starport scaffolding # genesis/proto/import option go_package = "github.com/dymensionxyz/dymension/v3/x/rollapp/types"; @@ -17,5 +18,6 @@ message GenesisState { repeated StateInfoIndex latestStateInfoIndexList = 4 [(gogoproto.nullable) = false]; repeated StateInfoIndex latestFinalizedStateIndexList = 5 [(gogoproto.nullable) = false]; repeated BlockHeightToFinalizationQueue blockHeightToFinalizationQueueList = 6 [(gogoproto.nullable) = false]; + repeated GenesisTransfers genesisTransfers = 7 [(gogoproto.nullable) = false]; // this line is used by starport scaffolding # genesis/proto/state } diff --git a/proto/dymension/rollapp/genesis_transfer.proto b/proto/dymension/rollapp/genesis_transfer.proto new file mode 100644 index 000000000..0f0a96117 --- /dev/null +++ b/proto/dymension/rollapp/genesis_transfer.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; +package dymensionxyz.dymension.rollapp; + +import "gogoproto/gogo.proto"; +import "dymension/rollapp/params.proto"; +import "dymension/rollapp/rollapp.proto"; +import "dymension/rollapp/state_info.proto"; +// this line is used by starport scaffolding # genesis/proto/import + +option go_package = "github.com/dymensionxyz/dymension/v3/x/rollapp/types"; + +// Not to get confused with 'genesis', genesis transfers refers to the specific protocol of bootstrapping ibc denominated tokens for the RA + +// Bookkeeping for the genesis transfer bridge protocol. +// Each rollapp will have one of these items corresponding to it. +message GenesisTransfers { + string rollappID = 1; + // The total number of incoming ibc transfers to be fast tracked in the genesis transfer period + uint64 numTotal = 2; + // The number of transfers already processed, when this number reaches numTotal the genesis transfer window closes. + uint64 numReceived = 3; +} diff --git a/proto/dymension/rollapp/params.proto b/proto/dymension/rollapp/params.proto index 7429ea323..e48d1b7cd 100644 --- a/proto/dymension/rollapp/params.proto +++ b/proto/dymension/rollapp/params.proto @@ -21,7 +21,7 @@ message Params { uint64 dispute_period_in_blocks = 1 [ (gogoproto.moretags) = "yaml:\"dispute_period_in_blocks\"" ]; - // deployer_whitelist is a list of the + // deployer_whitelist is a list of the // accounts that are allowed to create a rollapp and maximum number of rollapps. // In the case of an empty list, there are no restrictions repeated DeployerParams deployer_whitelist = 2 diff --git a/proto/dymension/rollapp/rollapp.proto b/proto/dymension/rollapp/rollapp.proto index 412512530..280bc12aa 100644 --- a/proto/dymension/rollapp/rollapp.proto +++ b/proto/dymension/rollapp/rollapp.proto @@ -4,23 +4,17 @@ package dymensionxyz.dymension.rollapp; option go_package = "github.com/dymensionxyz/dymension/v3/x/rollapp/types"; import "gogoproto/gogo.proto"; import "dymension/rollapp/state_info.proto"; -import "dymension/rollapp/bank.proto"; import "cosmos/base/v1beta1/coin.proto"; -// GenesisAccount is a struct for the genesis account for the rollapp -message GenesisAccount { - // amount of coins to be sent to the genesis address - cosmos.base.v1beta1.Coin amount = 1 [(gogoproto.nullable) = false]; - // address is a bech-32 address of the genesis account - string address = 2; -} - // RollappGenesisState is a partial repr of the state the hub can expect the rollapp to be in upon genesis message RollappGenesisState { - // genesis_accounts is a list of token allocations - repeated GenesisAccount genesis_accounts = 1; - // is_genesis_event is a boolean that indicates if the genesis event has occured - bool is_genesis_event = 2; + reserved 1; + // If true, then full usage of the canonical ibc transfer channel is enabled. + // Note: in v3.1.0 and prior this field marked the completion of the 'genesis event' + // Keeping and renaming the field enables a seamless upgrade https://www.notion.so/dymension/ADR-x-Genesis-Bridge-Phase-2-89769aa551b5440b9ed403a101775ce1?pvs=4#89698384d815435b87393dbe45bc5a74 + // to the new genesis transfer protocol + // Note: if this field is false, ibc transfers may still be allowed in one or either direction. + bool transfers_enabled = 2; } // Rollapp defines a rollapp object. First the RollApp is created and then @@ -39,8 +33,7 @@ message Rollapp { // permissionedAddresses is a bech32-encoded address list of the sequencers that are allowed to serve this rollappId. // In the case of an empty list, the rollapp is considered permissionless. repeated string permissionedAddresses = 5; - // tokenMetadata is a list of TokenMetadata that are registered on this rollapp - repeated TokenMetadata tokenMetadata = 6; + reserved 6; // genesis_state is a partial repr of the state the hub can expect the rollapp to be in upon genesis RollappGenesisState genesis_state = 7 [(gogoproto.nullable) = false]; // channel_id will be set to the canonical IBC channel of the rollapp. diff --git a/proto/dymension/rollapp/tx.proto b/proto/dymension/rollapp/tx.proto index 0f496ccc0..9e5009273 100644 --- a/proto/dymension/rollapp/tx.proto +++ b/proto/dymension/rollapp/tx.proto @@ -3,7 +3,6 @@ package dymensionxyz.dymension.rollapp; // this line is used by starport scaffolding # proto/tx/import import "dymension/rollapp/block_descriptor.proto"; -import "dymension/rollapp/bank.proto"; import "dymension/rollapp/rollapp.proto"; option go_package = "github.com/dymensionxyz/dymension/v3/x/rollapp/types"; @@ -14,7 +13,6 @@ import "gogoproto/gogo.proto"; service Msg { rpc CreateRollapp(MsgCreateRollapp) returns (MsgCreateRollappResponse); rpc UpdateState(MsgUpdateState) returns (MsgUpdateStateResponse); - rpc TriggerGenesisEvent(MsgRollappGenesisEvent) returns (MsgRollappGenesisEventResponse); } // MsgCreateRollapp creates a new rollapp chain on the hub. @@ -30,10 +28,11 @@ message MsgCreateRollapp { // sequencers that are allowed to serve this rollappId. // In the case of an empty list, the rollapp is considered permissionless repeated string permissionedAddresses = 7; - // metadata provides the client information for all the registered tokens. - repeated TokenMetadata metadatas = 8 [(gogoproto.nullable) = false]; - // genesis_accounts for the rollapp on the hub - repeated GenesisAccount genesis_accounts = 9 [(gogoproto.nullable) = false]; + reserved 8; + reserved 9; + // enable ibc transfers initially? Must be set false if intending + // to send genesis transfers. + bool transfersEnabled = 10; } message MsgCreateRollappResponse { @@ -63,19 +62,3 @@ message MsgUpdateState { message MsgUpdateStateResponse { } - - -// MsgRollappGenesisEvent is the message type for triggering the genesis event of the rollapp -message MsgRollappGenesisEvent { - // address is the bech32-encoded address of the sender - string address = 1; - // channel_id is the rollapp channel id on the hub - string channel_id = 2; - // rollapp_id is the rollapp id we want to mint tokens on the hub. - // Used for validation against channel_id to reduce error surface. - string rollapp_id = 3; -} - -message MsgRollappGenesisEventResponse { - -} \ No newline at end of file diff --git a/testutil/keeper/delayedack.go b/testutil/keeper/delayedack.go index 9d0813239..2590bec68 100644 --- a/testutil/keeper/delayedack.go +++ b/testutil/keeper/delayedack.go @@ -1,7 +1,6 @@ package keeper import ( - "context" "testing" "github.com/cosmos/cosmos-sdk/codec" @@ -11,7 +10,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" typesparams "github.com/cosmos/cosmos-sdk/x/params/types" - transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v6/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" @@ -82,29 +80,17 @@ func (ConnectionKeeperStub) GetConnection(ctx sdk.Context, connectionID string) type RollappKeeperStub struct{} -// MustGetStateInfo implements types.RollappKeeper. -func (r RollappKeeperStub) MustGetStateInfo(ctx sdk.Context, rollappId string, index uint64) rollapptypes.StateInfo { - return rollapptypes.StateInfo{} -} - func (RollappKeeperStub) GetParams(ctx sdk.Context) rollapptypes.Params { return rollapptypes.Params{} } -func (RollappKeeperStub) GetRollapp(ctx sdk.Context, chainID string) (rollapptypes.Rollapp, bool) { - return rollapptypes.Rollapp{}, false -} - -func (RollappKeeperStub) StateInfo(c context.Context, req *rollapptypes.QueryGetStateInfoRequest) (*rollapptypes.QueryGetStateInfoResponse, error) { - return nil, nil -} - func (RollappKeeperStub) GetStateInfo(ctx sdk.Context, rollappId string, index uint64) (val rollapptypes.StateInfo, found bool) { return rollapptypes.StateInfo{}, false } -func (RollappKeeperStub) GetLatestStateInfoIndex(ctx sdk.Context, rollappId string) (val rollapptypes.StateInfoIndex, found bool) { - return rollapptypes.StateInfoIndex{}, false +// MustGetStateInfo implements types.RollappKeeper. +func (r RollappKeeperStub) MustGetStateInfo(ctx sdk.Context, rollappId string, index uint64) rollapptypes.StateInfo { + return rollapptypes.StateInfo{} } func (RollappKeeperStub) GetLatestFinalizedStateIndex(ctx sdk.Context, rollappId string) (val rollapptypes.StateInfoIndex, found bool) { @@ -115,8 +101,8 @@ func (RollappKeeperStub) GetAllRollapps(ctx sdk.Context) (list []rollapptypes.Ro return []rollapptypes.Rollapp{} } -func (r RollappKeeperStub) ExtractRollappIDAndTransferPacketFromData(sdk.Context, []byte, string, string) (string, *transfertypes.FungibleTokenPacketData, error) { - return "rollappID", &transfertypes.FungibleTokenPacketData{}, nil +func (r RollappKeeperStub) GetValidTransfer(ctx sdk.Context, packetData []byte, raPortOnHub, raChanOnHub string) (data rollapptypes.TransferData, err error) { + return rollapptypes.TransferData{}, nil } type SequencerKeeperStub struct{} @@ -145,19 +131,7 @@ func DelayedackKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { "DelayedackParams", ) - k := keeper.NewKeeper( - cdc, - storeKey, - paramsSubspace, - RollappKeeperStub{}, - SequencerKeeperStub{}, - ICS4WrapperStub{}, - ChannelKeeperStub{}, - ClientKeeperStub{}, - ConnectionKeeperStub{}, - nil, - nil, - ) + k := keeper.NewKeeper(cdc, storeKey, paramsSubspace, RollappKeeperStub{}, ICS4WrapperStub{}, ChannelKeeperStub{}, nil, nil) ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) diff --git a/testutil/keeper/rollapp.go b/testutil/keeper/rollapp.go index 9cc97e9a0..2820816ad 100644 --- a/testutil/keeper/rollapp.go +++ b/testutil/keeper/rollapp.go @@ -38,16 +38,7 @@ func RollappKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { memStoreKey, "RollappParams", ) - k := keeper.NewKeeper( - cdc, - storeKey, - memStoreKey, - paramsSubspace, - nil, - nil, - nil, - nil, - ) + k := keeper.NewKeeper(cdc, storeKey, paramsSubspace, nil) ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) diff --git a/utils/derr/doc.go b/utils/derr/doc.go new file mode 100644 index 000000000..95e446b33 --- /dev/null +++ b/utils/derr/doc.go @@ -0,0 +1,8 @@ +// Package derr = dymension err is for errors besides the google ones +// +// This file should contain ubiquitous domain specific errors which warrant their own handling on top of gerr handling +// For example, if your caller code wants to differentiate between a generic failed precondition, and a failed precondition due to +// misbehavior, you would define a misbehavior error here. +// +// It is likely that there are not many of these errors, since their usage should be ubiquitous. +package derr diff --git a/utils/derr/errors.go b/utils/derr/errors.go new file mode 100644 index 000000000..578b49142 --- /dev/null +++ b/utils/derr/errors.go @@ -0,0 +1,11 @@ +package derr + +import ( + errorsmod "cosmossdk.io/errors" + "github.com/dymensionxyz/dymension/v3/utils/gerr" +) + +var ( + ErrFraud = errorsmod.Wrap(gerr.ErrFailedPrecondition, "actor is violating protocol") + ErrViolatesDymensionRollappStandard = errorsmod.Wrap(ErrFraud, "rollapp does not meet dymension rollapp standard") +) diff --git a/utils/gerr/doc.go b/utils/gerr/doc.go new file mode 100644 index 000000000..6088c8c2b --- /dev/null +++ b/utils/gerr/doc.go @@ -0,0 +1,5 @@ +// Package gerr contains fundamental error types +// See https://github.com/dymensionxyz/dymint/blob/33e78d116b5f14b91b8b3bda2b6cbfee9040e2d3/gerr/errors.go#L1 for more info +// Currently, we took a shortcut and copy the dymint code without explanation. At some point we should extract a common dymension repo. +// Note, in this repo, we leverage existing sdk errors where possible. +package gerr diff --git a/utils/gerr/errors.go b/utils/gerr/errors.go new file mode 100644 index 000000000..afe39840f --- /dev/null +++ b/utils/gerr/errors.go @@ -0,0 +1,33 @@ +package gerr + +// See doc.go for info + +import ( + errorsmod "cosmossdk.io/errors" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +const GErrors = "gerr" + +// TODO: not ideal to have the sdk errors as the 'last' place in the chain, because they dont' freely convert to grpc codes + +var ( + // uses canonical codes defined here https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto + + ErrCancelled = errorsmod.RegisterWithGRPCCode(GErrors, 1, 1, "cancelled") // no obvious sdk mapping exists + ErrUnknown = errorsmod.RegisterWithGRPCCode(GErrors, 2, 2, "unknown") // no obvious sdk mapping exists + ErrInvalidArgument = errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "invalid argument") + ErrDeadlineExceeded = errorsmod.RegisterWithGRPCCode(GErrors, 3, 4, "deadline exceeded") // no obvious sdk mapping exists + ErrNotFound = sdkerrors.ErrNotFound + ErrAlreadyExists = errorsmod.RegisterWithGRPCCode(GErrors, 4, 6, "already exists") // no obvious sdk mapping exists + ErrPermissionDenied = errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "permission denied") + ErrUnauthenticated = errorsmod.Wrapf(sdkerrors.ErrWrongPassword, "unauthenticated") + ErrResourceExhausted = errorsmod.RegisterWithGRPCCode(GErrors, 5, 8, "resource exhausted") // no obvious sdk mapping exists + ErrFailedPrecondition = errorsmod.RegisterWithGRPCCode(GErrors, 6, 9, "failed precondition") // no obvious sdk mapping exists + ErrAborted = errorsmod.RegisterWithGRPCCode(GErrors, 7, 10, "aborted") // no obvious sdk mapping exists + ErrOutOfRange = errorsmod.RegisterWithGRPCCode(GErrors, 8, 11, "out of range") // no obvious sdk mapping exists + ErrUnimplemented = errorsmod.RegisterWithGRPCCode(GErrors, 9, 12, "unimplemented") // no obvious sdk mapping exists + ErrInternal = errorsmod.RegisterWithGRPCCode(GErrors, 10, 13, "internal") // no obvious sdk mapping exists + ErrUnavailable = errorsmod.RegisterWithGRPCCode(GErrors, 11, 14, "unavailable") // no obvious sdk mapping exists + ErrDataLoss = errorsmod.RegisterWithGRPCCode(GErrors, 12, 15, "data loss") // no obvious sdk mapping exists +) diff --git a/utils/ibc.go b/utils/ibc.go deleted file mode 100644 index 8b8a3d87d..000000000 --- a/utils/ibc.go +++ /dev/null @@ -1,21 +0,0 @@ -package utils - -import ( - transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" -) - -const ( - ibcPort = "transfer" -) - -func GetForeignIBCDenom(channelId string, denom string) string { - return GetForeignDenomTrace(channelId, denom).IBCDenom() -} - -func GetForeignDenomTrace(channelId string, denom string) transfertypes.DenomTrace { - sourcePrefix := transfertypes.GetDenomPrefix(ibcPort, channelId) - // NOTE: sourcePrefix contains the trailing "/" - prefixedDenom := sourcePrefix + denom - // construct the denomination trace from the full raw denomination - return transfertypes.ParseDenomTrace(prefixedDenom) -} diff --git a/utils/ibc/doc.go b/utils/ibc/doc.go new file mode 100644 index 000000000..2020a47e6 --- /dev/null +++ b/utils/ibc/doc.go @@ -0,0 +1,2 @@ +// Package utilsibc contains ibc utils +package utilsibc diff --git a/utils/ibc/funcs.go b/utils/ibc/funcs.go new file mode 100644 index 000000000..220c2c728 --- /dev/null +++ b/utils/ibc/funcs.go @@ -0,0 +1,43 @@ +package utilsibc + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + "github.com/cosmos/ibc-go/v6/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v6/modules/light-clients/07-tendermint/types" + "github.com/dymensionxyz/dymension/v3/utils/gerr" +) + +type GetChannelClientState func(ctx sdk.Context, portID, channelID string) (string, exported.ClientState, error) + +func ChainIDFromPortChannel( + ctx sdk.Context, + getChannelClientState GetChannelClientState, + portID string, + channelID string, +) (string, error) { + _, state, err := getChannelClientState(ctx, portID, channelID) + if err != nil { + return "", errorsmod.Wrap(err, "get channel client state") + } + + tmState, ok := state.(*ibctmtypes.ClientState) + if !ok { + return "", errorsmod.Wrap(gerr.ErrInvalidArgument, "cast client state to tmtypes client state") + } + + return tmState.ChainId, nil +} + +const ( + ibcPort = "transfer" +) + +func GetForeignDenomTrace(channelId string, denom string) types.DenomTrace { + sourcePrefix := types.GetDenomPrefix(ibcPort, channelId) + // NOTE: sourcePrefix contains the trailing "/" + prefixedDenom := sourcePrefix + denom + // construct the denomination trace from the full raw denomination + return types.ParseDenomTrace(prefixedDenom) +} diff --git a/x/bridging_fee/ibc_middleware.go b/x/bridging_fee/ibc_middleware.go deleted file mode 100644 index 22d1170f7..000000000 --- a/x/bridging_fee/ibc_middleware.go +++ /dev/null @@ -1,123 +0,0 @@ -package bridging_fee - -import ( - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/ibc-go/v6/modules/apps/transfer" - transferkeeper "github.com/cosmos/ibc-go/v6/modules/apps/transfer/keeper" - transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types" - "github.com/cosmos/ibc-go/v6/modules/core/exported" - - delayedaackkeeper "github.com/dymensionxyz/dymension/v3/x/delayedack/keeper" - rollappkeeper "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper" -) - -const ( - ModuleName = "bridging_fee" -) - -var _ porttypes.Middleware = &BridgingFeeMiddleware{} - -// BridgingFeeMiddleware implements the ICS26 callbacks -// The middleware is responsible for charging a bridging fee on transfers coming from rollapps -// The actual charge happens on the packet finalization -// based on ADR: https://www.notion.so/dymension/ADR-x-Bridging-Fee-Middleware-7ba8c191373f43ce81782fc759913299?pvs=4 -type BridgingFeeMiddleware struct { - transfer.IBCModule - porttypes.ICS4Wrapper - - rollappKeeper rollappkeeper.Keeper - delayedAckKeeper delayedaackkeeper.Keeper - transferKeeper transferkeeper.Keeper - feeModuleAddr sdk.AccAddress -} - -// NewIBCMiddleware creates a new IBCMiddleware given the keeper and underlying application -func NewIBCMiddleware( - transfer transfer.IBCModule, - channelKeeper porttypes.ICS4Wrapper, - delayedAckKeeper delayedaackkeeper.Keeper, - rollappKeeper rollappkeeper.Keeper, - transferKeeper transferkeeper.Keeper, - feeModuleAddr sdk.AccAddress, -) *BridgingFeeMiddleware { - return &BridgingFeeMiddleware{ - IBCModule: transfer, - ICS4Wrapper: channelKeeper, - delayedAckKeeper: delayedAckKeeper, - rollappKeeper: rollappKeeper, - transferKeeper: transferKeeper, - feeModuleAddr: feeModuleAddr, - } -} - -// GetFeeRecipient returns the address that will receive the bridging fee -func (im BridgingFeeMiddleware) GetFeeRecipient() sdk.AccAddress { - return im.feeModuleAddr -} - -func (im *BridgingFeeMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) exported.Acknowledgement { - if !im.delayedAckKeeper.IsRollappsEnabled(ctx) { - return im.IBCModule.OnRecvPacket(ctx, packet, relayer) - } - logger := ctx.Logger().With( - "module", ModuleName, - "packet_source", packet.SourcePort, - "packet_destination", packet.DestinationPort, - "packet_sequence", packet.Sequence) - - rollappPortOnHub, rollappChannelOnHub := packet.DestinationPort, packet.DestinationChannel - rollappID, transferPacketData, err := im.rollappKeeper.ExtractRollappIDAndTransferPacketFromData(ctx, packet.Data, rollappPortOnHub, rollappChannelOnHub) - if err != nil { - logger.Error("Failed to extract rollapp id from packet", "err", err) - return channeltypes.NewErrorAcknowledgement(err) - } - - if rollappID == "" { - logger.Debug("Skipping IBC transfer OnRecvPacket for non-rollapp chain") - return im.IBCModule.OnRecvPacket(ctx, packet, relayer) - } - - // parse the transfer amount - transferAmount, ok := sdk.NewIntFromString(transferPacketData.Amount) - if !ok { - err = errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "parse transfer amount into math.Int") - return channeltypes.NewErrorAcknowledgement(err) - } - - // get fee - fee := im.delayedAckKeeper.BridgingFeeFromAmt(ctx, transferAmount) - - // update packet data for the fee charge - feePacket := *transferPacketData - feePacket.Amount = fee.String() - feePacket.Receiver = im.GetFeeRecipient().String() - - // No event emitted, as we called the transfer keeper directly (vs the transfer middleware) - err = im.transferKeeper.OnRecvPacket(ctx, packet, feePacket) - if err != nil { - logger.Error("Failed to charge bridging fee", "err", err) - // we continue as we don't want the fee charge to fail the transfer in any case - fee = sdk.ZeroInt() - } else { - logger.Debug("Charged bridging fee", "fee", fee) - ctx.EventManager().EmitEvent( - sdk.NewEvent( - EventTypeBridgingFee, - sdk.NewAttribute(AttributeKeyFee, fee.String()), - sdk.NewAttribute(sdk.AttributeKeySender, transferPacketData.Sender), - sdk.NewAttribute(transfertypes.AttributeKeyReceiver, transferPacketData.Receiver), - sdk.NewAttribute(transfertypes.AttributeKeyDenom, transferPacketData.Denom), - sdk.NewAttribute(transfertypes.AttributeKeyAmount, transferPacketData.Amount), - ), - ) - } - - // transfer the remaining amount - transferPacketData.Amount = transferAmount.Sub(fee).String() - packet.Data = transferPacketData.GetBytes() - return im.IBCModule.OnRecvPacket(ctx, packet, relayer) -} diff --git a/x/bridging_fee/events.go b/x/bridgingfee/events.go similarity index 79% rename from x/bridging_fee/events.go rename to x/bridgingfee/events.go index ea2a2231d..9c80581b6 100644 --- a/x/bridging_fee/events.go +++ b/x/bridgingfee/events.go @@ -1,4 +1,4 @@ -package bridging_fee +package bridgingfee const ( EventTypeBridgingFee = "bridging_fee" diff --git a/x/bridgingfee/ibc_module.go b/x/bridgingfee/ibc_module.go new file mode 100644 index 000000000..ff439c3f5 --- /dev/null +++ b/x/bridgingfee/ibc_module.go @@ -0,0 +1,110 @@ +package bridgingfee + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + ibctransfer "github.com/cosmos/ibc-go/v6/modules/apps/transfer" + transferkeeper "github.com/cosmos/ibc-go/v6/modules/apps/transfer/keeper" + transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v6/modules/core/exported" + commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" + delayedackkeeper "github.com/dymensionxyz/dymension/v3/x/delayedack/keeper" + rollappkeeper "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper" + "github.com/tendermint/tendermint/libs/log" +) + +const ( + ModuleName = "bridging_fee" +) + +// IBCModule is responsible for charging a bridging fee on transfers coming from rollapps +// The actual charge happens on the packet finalization +// based on ADR: https://www.notion.so/dymension/ADR-x-Bridging-Fee-Middleware-7ba8c191373f43ce81782fc759913299?pvs=4 +type IBCModule struct { + ibctransfer.IBCModule + + rollappKeeper rollappkeeper.Keeper + delayedAckKeeper delayedackkeeper.Keeper + transferKeeper transferkeeper.Keeper + feeModuleAddr sdk.AccAddress +} + +func NewIBCModule( + next ibctransfer.IBCModule, + keeper delayedackkeeper.Keeper, + transferKeeper transferkeeper.Keeper, + feeModuleAddr sdk.AccAddress, + rollappKeeper rollappkeeper.Keeper, +) *IBCModule { + return &IBCModule{ + IBCModule: next, + delayedAckKeeper: keeper, + transferKeeper: transferKeeper, + feeModuleAddr: feeModuleAddr, + rollappKeeper: rollappKeeper, + } +} + +func (w IBCModule) logger( + ctx sdk.Context, + packet channeltypes.Packet, + method string, +) log.Logger { + return ctx.Logger().With( + "module", ModuleName, + "packet_source_port", packet.SourcePort, + "packet_destination_port", packet.DestinationPort, + "packet_sequence", packet.Sequence, + "method", method, + ) +} + +func (w *IBCModule) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) exported.Acknowledgement { + l := w.logger(ctx, packet, "OnRecvPacket") + + if commontypes.SkipRollappMiddleware(ctx) || !w.delayedAckKeeper.IsRollappsEnabled(ctx) { + return w.IBCModule.OnRecvPacket(ctx, packet, relayer) + } + + transfer, err := w.rollappKeeper.GetValidTransfer(ctx, packet.GetData(), packet.GetDestPort(), packet.GetDestChannel()) + if err != nil { + l.Error("Get valid transfer.", "err", err) + err = errorsmod.Wrapf(err, "%s: get valid transfer", ModuleName) + return channeltypes.NewErrorAcknowledgement(err) + } + + if !transfer.IsRollapp() { + return w.IBCModule.OnRecvPacket(ctx, packet, relayer) + } + + // Use the packet as a basis for a fee transfer + feeData := transfer + fee := w.delayedAckKeeper.BridgingFeeFromAmt(ctx, transfer.MustAmountInt()) + feeData.Amount = fee.String() + feeData.Receiver = w.feeModuleAddr.String() + + // No event emitted, as we called the transfer keeper directly (vs the transfer middleware) + err = w.transferKeeper.OnRecvPacket(ctx, packet, feeData.FungibleTokenPacketData) + if err != nil { + l.Error("Charge bridging fee.", "err", err) + // we continue as we don't want the fee charge to fail the transfer in any case + fee = sdk.ZeroInt() + } else { + ctx.EventManager().EmitEvent( + sdk.NewEvent( + EventTypeBridgingFee, + sdk.NewAttribute(AttributeKeyFee, fee.String()), + sdk.NewAttribute(sdk.AttributeKeySender, transfer.Sender), + sdk.NewAttribute(transfertypes.AttributeKeyReceiver, transfer.Receiver), + sdk.NewAttribute(transfertypes.AttributeKeyDenom, transfer.Denom), + sdk.NewAttribute(transfertypes.AttributeKeyAmount, transfer.Amount), + ), + ) + } + + // transfer the rest to the original recipient + transfer.Amount = transfer.MustAmountInt().Sub(fee).String() + packet.Data = transfer.GetBytes() + return w.IBCModule.OnRecvPacket(ctx, packet, relayer) +} diff --git a/x/common/types/skip_middleware.go b/x/common/types/skip_middleware.go new file mode 100644 index 000000000..a793b8b77 --- /dev/null +++ b/x/common/types/skip_middleware.go @@ -0,0 +1,17 @@ +package types + +import sdk "github.com/cosmos/cosmos-sdk/types" + +type ctxKeySkipRollappMiddlewares struct{} + +// SkipRollappMiddlewareContext returns a context which can be passed +// to dymension ibc middlewares related to rollapp logic to skip the middleware. +func SkipRollappMiddlewareContext(ctx sdk.Context) sdk.Context { + return ctx.WithValue(ctxKeySkipRollappMiddlewares{}, true) +} + +// SkipRollappMiddleware returns if the context contains the SkipRollappMiddleware directive +func SkipRollappMiddleware(ctx sdk.Context) bool { + val, ok := ctx.Value(ctxKeySkipRollappMiddlewares{}).(bool) + return ok && val +} diff --git a/x/delayedack/ibc_middleware.go b/x/delayedack/ibc_middleware.go index 9ad6a329c..bdc4b2326 100644 --- a/x/delayedack/ibc_middleware.go +++ b/x/delayedack/ibc_middleware.go @@ -1,323 +1,188 @@ package delayedack import ( - "errors" + rollappkeeper "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper" errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types" "github.com/cosmos/ibc-go/v6/modules/core/exported" + "github.com/tendermint/tendermint/libs/log" + commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" "github.com/dymensionxyz/dymension/v3/x/delayedack/keeper" "github.com/dymensionxyz/dymension/v3/x/delayedack/types" - rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) var _ porttypes.Middleware = &IBCMiddleware{} -// IBCMiddleware implements the ICS26 callbacks type IBCMiddleware struct { porttypes.IBCModule - keeper.Keeper - rollappKeeper types.RollappKeeper + *keeper.Keeper // keeper is an ics4 wrapper + raKeeper rollappkeeper.Keeper } -// NewIBCMiddleware creates a new IBCMiddleware given the keeper and underlying application -func NewIBCMiddleware(app porttypes.IBCModule, k keeper.Keeper, rollappKeeper types.RollappKeeper) IBCMiddleware { +func NewIBCMiddleware(app porttypes.IBCModule, keeper keeper.Keeper, raK rollappkeeper.Keeper) IBCMiddleware { return IBCMiddleware{ - IBCModule: app, - Keeper: k, - rollappKeeper: rollappKeeper, + IBCModule: app, + Keeper: &keeper, + raKeeper: raK, } } +func (w IBCMiddleware) logger( + ctx sdk.Context, + packet channeltypes.Packet, + method string, +) log.Logger { + return ctx.Logger().With( + "module", types.ModuleName, + "packet_source_port", packet.SourcePort, + "packet_destination_port", packet.DestinationPort, + "packet_sequence", packet.Sequence, + "method", method, + ) +} + // OnRecvPacket handles the receipt of a packet and puts it into a pending queue // until its state is finalized -func (im IBCMiddleware) OnRecvPacket( +func (w IBCMiddleware) OnRecvPacket( ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, ) exported.Acknowledgement { - if !im.IsRollappsEnabled(ctx) { - return im.IBCModule.OnRecvPacket(ctx, packet, relayer) - } - logger := ctx.Logger().With( - "module", types.ModuleName, - "packet_source", packet.SourcePort, - "packet_destination", packet.DestinationPort, - "packet_sequence", packet.Sequence) - - rollappPortOnHub, rollappChannelOnHub := packet.DestinationPort, packet.DestinationChannel - - rollappID, transferPacketData, err := im.rollappKeeper.ExtractRollappIDAndTransferPacketFromData( - ctx, - packet.Data, - rollappPortOnHub, - rollappChannelOnHub, - ) - if err != nil { - logger.Error("Failed to extract rollapp id from packet", "err", err) - return channeltypes.NewErrorAcknowledgement(err) - } - - if rollappID == "" { - logger.Debug("Skipping IBC transfer OnRecvPacket for non-rollapp chain") - return im.IBCModule.OnRecvPacket(ctx, packet, relayer) - } + l := w.logger(ctx, packet, "OnRecvPacket") - err = im.ValidateRollappId(ctx, rollappID, rollappPortOnHub, rollappChannelOnHub) - if err != nil { - logger.Error("Failed to validate rollappID", "rollappID", rollappID, "err", err) - return channeltypes.NewErrorAcknowledgement(err) + if !w.Keeper.IsRollappsEnabled(ctx) { + return w.IBCModule.OnRecvPacket(ctx, packet, relayer) } - proofHeight, err := im.GetProofHeight(ctx, commontypes.RollappPacket_ON_RECV, rollappPortOnHub, rollappChannelOnHub, packet.Sequence) - if err != nil { - logger.Error("Failed to get proof height from packet", "err", err) - return channeltypes.NewErrorAcknowledgement(err) + if commontypes.SkipRollappMiddleware(ctx) { + l.Debug("Skipping because of skip delay ctx.") + return w.IBCModule.OnRecvPacket(ctx, packet, relayer) } - finalized, err := im.CheckIfFinalized(ctx, rollappID, proofHeight) + transfer, err := w.GetValidTransferWithFinalizationInfo(ctx, packet, commontypes.RollappPacket_ON_RECV) if err != nil { - logger.Error("Failed to check if packet is finalized", "err", err) - return channeltypes.NewErrorAcknowledgement(err) + l.Error("Get valid rollapp and transfer.", "err", err) + return channeltypes.NewErrorAcknowledgement(errorsmod.Wrap(err, "delayed ack: get valid transfer with finalization info")) } - if finalized { - logger.Debug("Skipping eIBC transfer OnRecvPacket as the packet proof height is already finalized") - return im.IBCModule.OnRecvPacket(ctx, packet, relayer) + if !transfer.IsRollapp() || transfer.Finalized { + return w.IBCModule.OnRecvPacket(ctx, packet, relayer) } - // Save the packet data to the store for later processing - rollappPacket := commontypes.RollappPacket{ - RollappId: rollappID, - Packet: &packet, - Status: commontypes.Status_PENDING, - Relayer: relayer, - ProofHeight: proofHeight, - Type: commontypes.RollappPacket_ON_RECV, - } - im.SetRollappPacket(ctx, rollappPacket) + rollappPacket := w.savePacket(ctx, packet, transfer, relayer, commontypes.RollappPacket_ON_RECV, nil) - logger.Debug("Set rollapp packet", - "rollappID", rollappPacket.RollappId, - "proofHeight", rollappPacket.ProofHeight, - "type", rollappPacket.Type) - - err = im.EIBCDemandOrderHandler(ctx, rollappPacket, *transferPacketData) + err = w.EIBCDemandOrderHandler(ctx, rollappPacket, transfer.FungibleTokenPacketData) if err != nil { - return channeltypes.NewErrorAcknowledgement(err) + return channeltypes.NewErrorAcknowledgement(errorsmod.Wrap(err, "delayed ack")) } return nil } // OnAcknowledgementPacket implements the IBCMiddleware interface -func (im IBCMiddleware) OnAcknowledgementPacket( +func (w IBCMiddleware) OnAcknowledgementPacket( ctx sdk.Context, packet channeltypes.Packet, acknowledgement []byte, relayer sdk.AccAddress, ) error { - if !im.IsRollappsEnabled(ctx) { - return im.IBCModule.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) - } - logger := ctx.Logger().With( - "module", types.ModuleName, - "packet_source", packet.SourcePort, - "packet_destination", packet.DestinationPort, - "packet_sequence", packet.Sequence) + l := w.logger(ctx, packet, "OnAcknowledgementPacket") - rollappPortOnHub, rollappChannelOnHub := packet.SourcePort, packet.SourceChannel + if !w.Keeper.IsRollappsEnabled(ctx) { + return w.IBCModule.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) + } var ack channeltypes.Acknowledgement if err := types.ModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { - logger.Error("Unmarshal acknowledgement", "err", err) + l.Error("Unmarshal acknowledgement.", "err", err) return errorsmod.Wrapf(types.ErrUnknownRequest, "unmarshal ICS-20 transfer packet acknowledgement: %v", err) } - rollappID, transferPacketData, err := im.rollappKeeper.ExtractRollappIDAndTransferPacketFromData(ctx, packet.Data, rollappPortOnHub, rollappChannelOnHub) + transfer, err := w.GetValidTransferWithFinalizationInfo(ctx, packet, commontypes.RollappPacket_ON_ACK) if err != nil { - logger.Error("Failed to extract rollapp id from channel", "err", err) + l.Error("Get valid rollapp and transfer.", "err", err) return err } - if rollappID == "" { - logger.Debug("Skipping IBC transfer OnAcknowledgementPacket for non-rollapp chain") - return im.IBCModule.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) - } - err = im.ValidateRollappId(ctx, rollappID, rollappPortOnHub, rollappChannelOnHub) - if err != nil { - logger.Error("Failed to validate rollappID", "rollappID", rollappID, "err", err) - return err - } - - proofHeight, err := im.GetProofHeight(ctx, commontypes.RollappPacket_ON_ACK, rollappPortOnHub, rollappChannelOnHub, packet.Sequence) - if err != nil { - logger.Error("Failed to get proof height from packet", "err", err) - return err + if !transfer.IsRollapp() || transfer.Finalized { + return w.IBCModule.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) } - finalized, err := im.CheckIfFinalized(ctx, rollappID, proofHeight) - if err != nil { - logger.Error("Failed to check if packet is finalized", "err", err) - return err - } - - if finalized { - logger.Debug("Skipping eIBC transfer OnAcknowledgementPacket as the packet proof height is already finalized") - return im.IBCModule.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) - } // Run the underlying app's OnAcknowledgementPacket callback // with cache context to avoid state changes and report the acknowledgement result. // Only save the packet if the underlying app's callback succeeds. cacheCtx, _ := ctx.CacheContext() - err = im.IBCModule.OnAcknowledgementPacket(cacheCtx, packet, acknowledgement, relayer) + err = w.IBCModule.OnAcknowledgementPacket(cacheCtx, packet, acknowledgement, relayer) if err != nil { return err } - // Save the packet data to the store for later processing - rollappPacket := commontypes.RollappPacket{ - RollappId: rollappID, - Packet: &packet, - Acknowledgement: acknowledgement, - Status: commontypes.Status_PENDING, - Relayer: relayer, - ProofHeight: proofHeight, - Type: commontypes.RollappPacket_ON_ACK, - } - im.SetRollappPacket(ctx, rollappPacket) - logger.Debug("Set rollapp packet", - "rollappID", rollappPacket.RollappId, - "proofHeight", rollappPacket.ProofHeight, - "type", rollappPacket.Type) + rollappPacket := w.savePacket(ctx, packet, transfer, relayer, commontypes.RollappPacket_ON_ACK, acknowledgement) switch ack.Response.(type) { // Only if the acknowledgement is an error, we want to create an order case *channeltypes.Acknowledgement_Error: - err = im.EIBCDemandOrderHandler(ctx, rollappPacket, *transferPacketData) - if err != nil { - return err - } + return w.EIBCDemandOrderHandler(ctx, rollappPacket, transfer.FungibleTokenPacketData) } return nil } // OnTimeoutPacket implements the IBCMiddleware interface -func (im IBCMiddleware) OnTimeoutPacket( +func (w IBCMiddleware) OnTimeoutPacket( ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, ) error { - if !im.IsRollappsEnabled(ctx) { - return im.IBCModule.OnTimeoutPacket(ctx, packet, relayer) - } - logger := ctx.Logger().With( - "module", types.ModuleName, - "packet_source", packet.SourcePort, - "packet_destination", packet.DestinationPort, - "packet_sequence", packet.Sequence) - - rollappPortOnHub, rollappChannelOnHub := packet.SourcePort, packet.SourceChannel + l := w.logger(ctx, packet, "OnTimeoutPacket") - rollappID, transferPacketData, err := im.rollappKeeper.ExtractRollappIDAndTransferPacketFromData( - ctx, - packet.Data, - rollappPortOnHub, - rollappChannelOnHub, - ) - if err != nil { - logger.Error("Failed to extract rollapp id from channel", "err", err) - return err - } - - if rollappID == "" { - logger.Debug("Skipping IBC transfer OnTimeoutPacket for non-rollapp chain") - return im.IBCModule.OnTimeoutPacket(ctx, packet, relayer) + if !w.Keeper.IsRollappsEnabled(ctx) { + return w.IBCModule.OnTimeoutPacket(ctx, packet, relayer) } - err = im.ValidateRollappId(ctx, rollappID, rollappPortOnHub, rollappChannelOnHub) + transfer, err := w.GetValidTransferWithFinalizationInfo(ctx, packet, commontypes.RollappPacket_ON_TIMEOUT) if err != nil { - logger.Error("Failed to validate rollappID", "rollappID", rollappID, "err", err) + l.Error("Get valid rollapp and transfer.", "err", err) return err } - proofHeight, err := im.GetProofHeight(ctx, commontypes.RollappPacket_ON_TIMEOUT, rollappPortOnHub, rollappChannelOnHub, packet.Sequence) - if err != nil { - logger.Error("Failed to get proof height from packet", "err", err) - return err - } - finalized, err := im.CheckIfFinalized(ctx, rollappID, proofHeight) - if err != nil { - logger.Error("Failed to check if packet is finalized", "err", err) - return err - } - - if finalized { - logger.Debug("Skipping IBC transfer OnTimeoutPacket as the packet proof height is already finalized") - return im.IBCModule.OnTimeoutPacket(ctx, packet, relayer) + if !transfer.IsRollapp() || transfer.Finalized { + return w.IBCModule.OnTimeoutPacket(ctx, packet, relayer) } // Run the underlying app's OnTimeoutPacket callback // with cache context to avoid state changes and report the timeout result. // Only save the packet if the underlying app's callback succeeds. cacheCtx, _ := ctx.CacheContext() - err = im.IBCModule.OnTimeoutPacket(cacheCtx, packet, relayer) + err = w.IBCModule.OnTimeoutPacket(cacheCtx, packet, relayer) if err != nil { return err } - // Save the packet data to the store for later processing - rollappPacket := commontypes.RollappPacket{ - RollappId: rollappID, - Packet: &packet, - Status: commontypes.Status_PENDING, - Relayer: relayer, - ProofHeight: proofHeight, - Type: commontypes.RollappPacket_ON_TIMEOUT, - } - im.SetRollappPacket(ctx, rollappPacket) - - logger.Debug("Set rollapp packet", - "rollappID", rollappPacket.RollappId, - "proofHeight", rollappPacket.ProofHeight, - "type", rollappPacket.Type) - err = im.EIBCDemandOrderHandler(ctx, rollappPacket, *transferPacketData) - if err != nil { - return err - } + rollappPacket := w.savePacket(ctx, packet, transfer, relayer, commontypes.RollappPacket_ON_TIMEOUT, nil) - return nil + return w.EIBCDemandOrderHandler(ctx, rollappPacket, transfer.FungibleTokenPacketData) } -// GetProofHeight returns the proof height of the packet -func (im IBCMiddleware) GetProofHeight(ctx sdk.Context, packetType commontypes.RollappPacket_Type, - rollappPortOnHub string, rollappChannelOnHub string, sequence uint64, -) (uint64, error) { - packetId := commontypes.NewPacketUID(packetType, rollappPortOnHub, rollappChannelOnHub, sequence) - height, ok := types.FromIBCProofContext(ctx, packetId) - if ok { - return height.RevisionHeight, nil - } else { - err := errors.New("failed to get proof height from context") - ctx.Logger().Error(err.Error(), "packetId", packetId) - return 0, err +// savePacket the packet to the store for later processing and returns it +func (w IBCMiddleware) savePacket(ctx sdk.Context, packet channeltypes.Packet, transfer types.TransferDataWithFinalization, relayer sdk.AccAddress, packetType commontypes.RollappPacket_Type, ack []byte) commontypes.RollappPacket { + p := commontypes.RollappPacket{ + RollappId: transfer.Rollapp.RollappId, + Packet: &packet, + Acknowledgement: ack, + Status: commontypes.Status_PENDING, + Relayer: relayer, + ProofHeight: transfer.ProofHeight, + Type: packetType, } -} -// CheckIfFinalized checks if the packet is finalized and if so, updates the packet status -func (im IBCMiddleware) CheckIfFinalized(ctx sdk.Context, rollappID string, proofHeight uint64) (bool, error) { - finalizedHeight, err := im.GetRollappFinalizedHeight(ctx, rollappID) - if err != nil { - if errors.Is(err, rollapptypes.ErrNoFinalizedStateYetForRollapp) { - return false, nil - } - return false, err - } + w.Keeper.SetRollappPacket(ctx, p) - return finalizedHeight >= proofHeight, nil + return p } diff --git a/x/delayedack/keeper/invariants_test.go b/x/delayedack/keeper/invariants_test.go index ec4363992..3b4ee059c 100644 --- a/x/delayedack/keeper/invariants_test.go +++ b/x/delayedack/keeper/invariants_test.go @@ -68,7 +68,7 @@ func (suite *DelayedAckTestSuite) TestInvariants() { } // progress finalization queue - err := suite.App.RollappKeeper.FinalizeQueue(suite.Ctx) + err := suite.App.RollappKeeper.FinalizeRollappStates(suite.Ctx) suite.Require().NoError(err) // test fraud diff --git a/x/delayedack/keeper/keeper.go b/x/delayedack/keeper/keeper.go index 8aadd41a6..2b0a3d444 100644 --- a/x/delayedack/keeper/keeper.go +++ b/x/delayedack/keeper/keeper.go @@ -1,25 +1,18 @@ package keeper import ( - "bytes" "fmt" - errorsmod "cosmossdk.io/errors" "github.com/cosmos/cosmos-sdk/codec" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v6/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types" - "github.com/cosmos/ibc-go/v6/modules/core/exported" - tenderminttypes "github.com/cosmos/ibc-go/v6/modules/light-clients/07-tendermint/types" + "github.com/tendermint/tendermint/libs/log" + "github.com/dymensionxyz/dymension/v3/x/delayedack/types" rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" - sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" - "github.com/tendermint/tendermint/libs/log" ) type ( @@ -29,46 +22,28 @@ type ( hooks types.MultiDelayedAckHooks paramstore paramtypes.Subspace - rollappKeeper types.RollappKeeper - sequencerKeeper types.SequencerKeeper + rollappKeeper types.RollappKeeper porttypes.ICS4Wrapper - channelKeeper types.ChannelKeeper - connectionKeeper types.ConnectionKeeper - clientKeeper types.ClientKeeper + channelKeeper types.ChannelKeeper types.EIBCKeeper bankKeeper types.BankKeeper } ) -func NewKeeper( - cdc codec.BinaryCodec, - storeKey storetypes.StoreKey, - ps paramtypes.Subspace, - rollappKeeper types.RollappKeeper, - sequencerKeeper types.SequencerKeeper, - ics4Wrapper porttypes.ICS4Wrapper, - channelKeeper types.ChannelKeeper, - connectionKeeper types.ConnectionKeeper, - clientKeeper types.ClientKeeper, - eibcKeeper types.EIBCKeeper, - bankKeeper types.BankKeeper, -) *Keeper { +func NewKeeper(cdc codec.BinaryCodec, storeKey storetypes.StoreKey, ps paramtypes.Subspace, rollappKeeper types.RollappKeeper, ics4Wrapper porttypes.ICS4Wrapper, channelKeeper types.ChannelKeeper, eibcKeeper types.EIBCKeeper, bankKeeper types.BankKeeper) *Keeper { // set KeyTable if it has not already been set if !ps.HasKeyTable() { ps = ps.WithKeyTable(types.ParamKeyTable()) } return &Keeper{ - cdc: cdc, - storeKey: storeKey, - paramstore: ps, - rollappKeeper: rollappKeeper, - sequencerKeeper: sequencerKeeper, - ICS4Wrapper: ics4Wrapper, - channelKeeper: channelKeeper, - clientKeeper: clientKeeper, - connectionKeeper: connectionKeeper, - bankKeeper: bankKeeper, - EIBCKeeper: eibcKeeper, + cdc: cdc, + storeKey: storeKey, + paramstore: ps, + rollappKeeper: rollappKeeper, + ICS4Wrapper: ics4Wrapper, + channelKeeper: channelKeeper, + bankKeeper: bankKeeper, + EIBCKeeper: eibcKeeper, } } @@ -80,11 +55,7 @@ func (k Keeper) IsRollappsEnabled(ctx sdk.Context) bool { return k.rollappKeeper.GetParams(ctx).RollappsEnabled } -func (k Keeper) GetRollapp(ctx sdk.Context, chainID string) (rollapptypes.Rollapp, bool) { - return k.rollappKeeper.GetRollapp(ctx, chainID) -} - -func (k Keeper) GetRollappFinalizedHeight(ctx sdk.Context, chainID string) (uint64, error) { +func (k Keeper) getRollappFinalizedHeight(ctx sdk.Context, chainID string) (uint64, error) { // GetLatestFinalizedStateIndex latestFinalizedStateIndex, found := k.rollappKeeper.GetLatestFinalizedStateIndex(ctx, chainID) if !found { @@ -95,20 +66,6 @@ func (k Keeper) GetRollappFinalizedHeight(ctx sdk.Context, chainID string) (uint return stateInfo.StartHeight + stateInfo.NumBlocks - 1, nil } -// GetClientState retrieves the client state for a given packet. -func (k Keeper) GetClientState(ctx sdk.Context, portID string, channelID string) (exported.ClientState, error) { - connectionEnd, err := k.GetConnectionEnd(ctx, portID, channelID) - if err != nil { - return nil, err - } - clientState, found := k.clientKeeper.GetClientState(ctx, connectionEnd.GetClientID()) - if !found { - return nil, clienttypes.ErrConsensusStateNotFound - } - - return clientState, nil -} - /* -------------------------------------------------------------------------- */ /* Hooks handling */ /* -------------------------------------------------------------------------- */ @@ -132,85 +89,3 @@ func (k *Keeper) GetHooks() types.MultiDelayedAckHooks { func (k *Keeper) LookupModuleByChannel(ctx sdk.Context, portID, channelID string) (string, *capabilitytypes.Capability, error) { return k.channelKeeper.LookupModuleByChannel(ctx, portID, channelID) } - -// ValidateRollappId checks that the rollapp id from the ibc connection matches the rollapp, checking the sequencer registered with the consensus state validator set -func (k *Keeper) ValidateRollappId(ctx sdk.Context, rollappID, rollappPortOnHub string, rollappChannelOnHub string) error { - // Get the sequencer from the latest state info update and check the validator set hash - // from the headers match with the sequencer for the rollappID - // As the assumption the sequencer is honest we don't check the packet proof height. - latestStateIndex, found := k.rollappKeeper.GetLatestStateInfoIndex(ctx, rollappID) - if !found { - return errorsmod.Wrapf(rollapptypes.ErrUnknownRollappID, "state index not found for the rollappID: %s", rollappID) - } - stateInfo, found := k.rollappKeeper.GetStateInfo(ctx, rollappID, latestStateIndex.Index) - if !found { - return errorsmod.Wrapf(rollapptypes.ErrUnknownRollappID, "state info not found for the rollappID: %s with index: %d", rollappID, latestStateIndex.Index) - } - // Compare the validators set hash of the consensus state to the sequencer hash. - // TODO (srene): We compare the validator set of the last consensus height, because it fails to get consensus for a different height, - // but we should compare the validator set at the height of the last state info, because sequencer may have changed after that. - // If the sequencer is changed, then the validation will fail till the new sequencer sends a new state info update. - tmConsensusState, err := k.getTmConsensusState(ctx, rollappPortOnHub, rollappChannelOnHub) - if err != nil { - k.Logger(ctx).Error("error consensus state", err) - return err - } - - // Gets sequencer information from the sequencer address found in the latest state info - sequencer, found := k.sequencerKeeper.GetSequencer(ctx, stateInfo.Sequencer) - if !found { - return errorsmod.Wrapf(sequencertypes.ErrUnknownSequencer, "sequencer %s not found for the rollappID %s", stateInfo.Sequencer, rollappID) - } - - // Gets the validator set hash made out of the pub key for the sequencer - seqPubKeyHash, err := sequencer.GetDymintPubKeyHash() - if err != nil { - return err - } - - // It compares the validator set hash from the consensus state with the one we recreated from the sequencer. If its true it means the chain corresponds to the rollappID chain - if !bytes.Equal(tmConsensusState.NextValidatorsHash, seqPubKeyHash) { - errMsg := fmt.Sprintf("consensus state does not match: consensus state validators %x, rollappID sequencer %x", - tmConsensusState.NextValidatorsHash, stateInfo.Sequencer) - return errorsmod.Wrap(types.ErrMismatchedSequencer, errMsg) - } - return nil -} - -func (k Keeper) GetConnectionEnd(ctx sdk.Context, portID string, channelID string) (connectiontypes.ConnectionEnd, error) { - channel, found := k.channelKeeper.GetChannel(ctx, portID, channelID) - if !found { - return connectiontypes.ConnectionEnd{}, errorsmod.Wrap(channeltypes.ErrChannelNotFound, channelID) - } - connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) - - if !found { - return connectiontypes.ConnectionEnd{}, errorsmod.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0]) - } - return connectionEnd, nil -} - -// getTmConsensusState returns the tendermint consensus state for the channel for specific height -func (k Keeper) getTmConsensusState(ctx sdk.Context, portID string, channelID string) (*tenderminttypes.ConsensusState, error) { - // Get the client state for the channel for specific height - connectionEnd, err := k.GetConnectionEnd(ctx, portID, channelID) - if err != nil { - return &tenderminttypes.ConsensusState{}, err - } - clientState, err := k.GetClientState(ctx, portID, channelID) - if err != nil { - return &tenderminttypes.ConsensusState{}, err - } - - // TODO(srene) : consensus state is only obtained when getting it for latestheight. this can be an issue when sequencer changes. i have to figure out why is only returned for latest height - - consensusState, found := k.clientKeeper.GetClientConsensusState(ctx, connectionEnd.GetClientID(), clientState.GetLatestHeight()) - if !found { - return nil, clienttypes.ErrConsensusStateNotFound - } - tmConsensusState, ok := consensusState.(*tenderminttypes.ConsensusState) - if !ok { - return nil, errorsmod.Wrapf(types.ErrInvalidType, "expected tendermint consensus state, got %T", consensusState) - } - return tmConsensusState, nil -} diff --git a/x/delayedack/keeper/rollapp_packet.go b/x/delayedack/keeper/rollapp_packet.go index 16a657e59..9ef389132 100644 --- a/x/delayedack/keeper/rollapp_packet.go +++ b/x/delayedack/keeper/rollapp_packet.go @@ -3,7 +3,6 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" - commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" "github.com/dymensionxyz/dymension/v3/x/delayedack/types" ) diff --git a/x/delayedack/keeper/rollapp_packet_test.go b/x/delayedack/keeper/rollapp_packet_test.go index be6bdcbc6..145949cba 100644 --- a/x/delayedack/keeper/rollapp_packet_test.go +++ b/x/delayedack/keeper/rollapp_packet_test.go @@ -152,15 +152,15 @@ func (suite *DelayedAckTestSuite) TestListRollappPackets() { expectOnRecvLength := 3 onRecvPackets := keeper.ListRollappPackets(ctx, types.ByTypeByStatus(commontypes.RollappPacket_ON_RECV, commontypes.Status_PENDING)) - suite.Assert().Equal(expectOnRecvLength, len(onRecvPackets)) + suite.Equal(expectOnRecvLength, len(onRecvPackets)) expectOnAckLength := 6 onAckPackets := keeper.ListRollappPackets(ctx, types.ByTypeByStatus(commontypes.RollappPacket_ON_ACK, commontypes.Status_FINALIZED)) - suite.Assert().Equal(expectOnAckLength, len(onAckPackets)) + suite.Equal(expectOnAckLength, len(onAckPackets)) expectOnTimeoutLength := 6 onTimeoutPackets := keeper.ListRollappPackets(ctx, types.ByTypeByStatus(commontypes.RollappPacket_ON_TIMEOUT, commontypes.Status_REVERTED)) - suite.Assert().Equal(expectOnTimeoutLength, len(onTimeoutPackets)) + suite.Equal(expectOnTimeoutLength, len(onTimeoutPackets)) suite.Require().Equal(totalLength, len(onRecvPackets)+len(onAckPackets)+len(onTimeoutPackets)) } diff --git a/x/delayedack/keeper/transfer.go b/x/delayedack/keeper/transfer.go new file mode 100644 index 000000000..ce16ef9bd --- /dev/null +++ b/x/delayedack/keeper/transfer.go @@ -0,0 +1,54 @@ +package keeper + +import ( + "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + "github.com/dymensionxyz/dymension/v3/utils/gerr" + commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" + "github.com/dymensionxyz/dymension/v3/x/delayedack/types" + rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" +) + +// GetValidTransferWithFinalizationInfo does GetValidTransferFromReceivedPacket, but additionally it gets the finalization status and proof height +// of the packet. +func (k Keeper) GetValidTransferWithFinalizationInfo( + ctx sdk.Context, + packet channeltypes.Packet, + packetType commontypes.RollappPacket_Type, +) (data types.TransferDataWithFinalization, err error) { + switch packetType { + case commontypes.RollappPacket_ON_RECV: + data.TransferData, err = k.rollappKeeper.GetValidTransfer(ctx, packet.GetData(), packet.GetDestPort(), packet.GetDestChannel()) + case commontypes.RollappPacket_ON_TIMEOUT, commontypes.RollappPacket_ON_ACK: + data.TransferData, err = k.rollappKeeper.GetValidTransfer(ctx, packet.GetData(), packet.GetSourcePort(), packet.GetSourceChannel()) + } + if err != nil { + err = errors.Wrap(err, "get valid transfer data") + return + } + + packetId := commontypes.NewPacketUID(packetType, packet.DestinationPort, packet.DestinationChannel, packet.Sequence) + height, ok := types.PacketProofHeightFromCtx(ctx, packetId) + if !ok { + // TODO: should probably be a panic + err = errors.Wrapf(gerr.ErrNotFound, "get proof height from context: packetID: %s", packetId) + return + } + data.ProofHeight = height.RevisionHeight + + if !data.IsRollapp() { + return + } + + finalizedHeight, err := k.getRollappFinalizedHeight(ctx, data.Rollapp.RollappId) + if errors.IsOf(err, rollapptypes.ErrNoFinalizedStateYetForRollapp) { + err = nil + } else if err != nil { + err = errors.Wrap(err, "get rollapp finalized height") + } else { + data.Finalized = data.ProofHeight <= finalizedHeight + } + + return +} diff --git a/x/delayedack/proof_height_ante.go b/x/delayedack/proof_height_ante.go index 05d8dba81..60b462131 100644 --- a/x/delayedack/proof_height_ante.go +++ b/x/delayedack/proof_height_ante.go @@ -53,7 +53,7 @@ func (rrd IBCProofHeightDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula continue } - ctx = delayedacktypes.NewIBCProofContext(ctx, packetId, height) + ctx = delayedacktypes.CtxWithPacketProofHeight(ctx, packetId, height) } return next(ctx, tx, simulate) } diff --git a/x/delayedack/rollapp_hooks.go b/x/delayedack/rollapp_hooks.go index a36f01344..9042bcc58 100644 --- a/x/delayedack/rollapp_hooks.go +++ b/x/delayedack/rollapp_hooks.go @@ -8,17 +8,17 @@ import ( var _ rollapptypes.RollappHooks = &IBCMiddleware{} -func (im IBCMiddleware) BeforeUpdateState(ctx sdk.Context, seqAddr string, rollappId string) error { +func (w IBCMiddleware) BeforeUpdateState(ctx sdk.Context, seqAddr string, rollappId string) error { return nil } // AfterStateFinalized implements the RollappHooks interface -func (im IBCMiddleware) AfterStateFinalized(ctx sdk.Context, rollappID string, stateInfo *rollapptypes.StateInfo) error { +func (w IBCMiddleware) AfterStateFinalized(ctx sdk.Context, rollappID string, stateInfo *rollapptypes.StateInfo) error { // Finalize the packets for the rollapp at the given height stateEndHeight := stateInfo.StartHeight + stateInfo.NumBlocks - 1 - return im.FinalizeRollappPackets(ctx, im.IBCModule, rollappID, stateEndHeight) + return w.FinalizeRollappPackets(ctx, w.IBCModule, rollappID, stateEndHeight) } -func (im IBCMiddleware) FraudSubmitted(ctx sdk.Context, rollappID string, height uint64, seqAddr string) error { - return im.HandleFraud(ctx, rollappID, im.IBCModule) +func (w IBCMiddleware) FraudSubmitted(ctx sdk.Context, rollappID string, height uint64, seqAddr string) error { + return w.HandleFraud(ctx, rollappID, w.IBCModule) } diff --git a/x/delayedack/types/errors.go b/x/delayedack/types/errors.go index c9670a80d..c616df552 100644 --- a/x/delayedack/types/errors.go +++ b/x/delayedack/types/errors.go @@ -7,9 +7,6 @@ import ( var ( ErrCanOnlyUpdatePendingPacket = errorsmod.Register(ModuleName, 1, "can only update pending packet") ErrRollappPacketDoesNotExist = errorsmod.Register(ModuleName, 2, "rollapp packet does not exist") - ErrMismatchedStateRoots = errorsmod.Register(ModuleName, 5, "mismatched state roots") - ErrMismatchedSequencer = errorsmod.Register(ModuleName, 6, "mismatched sequencer") ErrUnknownRequest = errorsmod.Register(ModuleName, 8, "unknown request") - ErrInvalidType = errorsmod.Register(ModuleName, 9, "invalid type") ErrBadEIBCFee = errorsmod.Register(ModuleName, 10, "provided eibc fee is invalid") ) diff --git a/x/delayedack/types/expected_keepers.go b/x/delayedack/types/expected_keepers.go index 95c9fbd52..16d7c131f 100644 --- a/x/delayedack/types/expected_keepers.go +++ b/x/delayedack/types/expected_keepers.go @@ -4,51 +4,30 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" - connectiontypes "github.com/cosmos/ibc-go/v6/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v6/modules/core/exported" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" eibctypes "github.com/dymensionxyz/dymension/v3/x/eibc/types" "github.com/dymensionxyz/dymension/v3/x/rollapp/types" rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" - sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" ) // ChannelKeeper defines the expected IBC channel keeper type ChannelKeeper interface { LookupModuleByChannel(ctx sdk.Context, portID, channelID string) (string, *capabilitytypes.Capability, error) - GetChannel(ctx sdk.Context, portID, channelID string) (channeltypes.Channel, bool) - GetChannelClientState(ctx sdk.Context, portID, channelID string) (string, exported.ClientState, error) -} - -type ClientKeeper interface { - GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) - GetClientConsensusState(ctx sdk.Context, clientID string, height exported.Height) (exported.ConsensusState, bool) -} - -type ConnectionKeeper interface { - GetConnection(ctx sdk.Context, connectionID string) (connectiontypes.ConnectionEnd, bool) } type RollappKeeper interface { GetParams(ctx sdk.Context) rollapptypes.Params - GetRollapp(ctx sdk.Context, chainID string) (rollapp rollapptypes.Rollapp, found bool) GetStateInfo(ctx sdk.Context, rollappId string, index uint64) (val rollapptypes.StateInfo, found bool) MustGetStateInfo(ctx sdk.Context, rollappId string, index uint64) rollapptypes.StateInfo - GetLatestStateInfoIndex(ctx sdk.Context, rollappId string) (val rollapptypes.StateInfoIndex, found bool) GetLatestFinalizedStateIndex(ctx sdk.Context, rollappId string) (val types.StateInfoIndex, found bool) GetAllRollapps(ctx sdk.Context) (list []types.Rollapp) - ExtractRollappIDAndTransferPacketFromData( + GetValidTransfer( ctx sdk.Context, - data []byte, - rollappPortOnHub string, - rollappChannelOnHub string, - ) (string, *transfertypes.FungibleTokenPacketData, error) + packetData []byte, + raPortOnHub, raChanOnHub string, + ) (data types.TransferData, err error) } -type SequencerKeeper interface { - GetSequencer(ctx sdk.Context, sequencerAddress string) (val sequencertypes.Sequencer, found bool) -} type EIBCKeeper interface { SetDemandOrder(ctx sdk.Context, order *eibctypes.DemandOrder) error TimeoutFee(ctx sdk.Context) sdk.Dec diff --git a/x/delayedack/types/fungible_packet.go b/x/delayedack/types/fungible_packet.go new file mode 100644 index 000000000..7132f0a0b --- /dev/null +++ b/x/delayedack/types/fungible_packet.go @@ -0,0 +1,13 @@ +package types + +import ( + rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" +) + +type TransferDataWithFinalization struct { + rollapptypes.TransferData + // Proof height is only be populated if and only if the rollappID is not empty + ProofHeight uint64 + // Finalized is only be populated if and only if the rollappID is not empty + Finalized bool +} diff --git a/x/delayedack/types/proof_height_context.go b/x/delayedack/types/proof_height_context.go index 387881ee5..3b234427e 100644 --- a/x/delayedack/types/proof_height_context.go +++ b/x/delayedack/types/proof_height_context.go @@ -14,12 +14,12 @@ const ( proofHeightCtxKey = "ibc_proof_height" ) -func NewIBCProofContext(ctx sdk.Context, packetId commontypes.PacketUID, height clienttypes.Height) sdk.Context { +func CtxWithPacketProofHeight(ctx sdk.Context, packetId commontypes.PacketUID, height clienttypes.Height) sdk.Context { key := fmt.Sprintf("%s_%s", proofHeightCtxKey, packetId.String()) return ctx.WithValue(key, height) } -func FromIBCProofContext(ctx sdk.Context, packetId commontypes.PacketUID) (clienttypes.Height, bool) { +func PacketProofHeightFromCtx(ctx sdk.Context, packetId commontypes.PacketUID) (clienttypes.Height, bool) { key := fmt.Sprintf("%s_%s", proofHeightCtxKey, packetId.String()) u, ok := ctx.Value(key).(clienttypes.Height) return u, ok diff --git a/x/denommetadata/keeper/keeper.go b/x/denommetadata/keeper/keeper.go index 7bd6b5b31..b9edf13c7 100644 --- a/x/denommetadata/keeper/keeper.go +++ b/x/denommetadata/keeper/keeper.go @@ -3,6 +3,8 @@ package keeper import ( "fmt" + "github.com/dymensionxyz/dymension/v3/utils/gerr" + "github.com/dymensionxyz/dymension/v3/x/denommetadata/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -25,11 +27,15 @@ func NewKeeper(bankKeeper types.BankKeeper) *Keeper { } } +func (k *Keeper) HasDenomMetadata(ctx sdk.Context, base string) bool { + return k.bankKeeper.HasDenomMetaData(ctx, base) +} + // CreateDenomMetadata creates a new denommetadata func (k *Keeper) CreateDenomMetadata(ctx sdk.Context, metadata banktypes.Metadata) error { - found := k.bankKeeper.HasDenomMetaData(ctx, metadata.Base) + found := k.HasDenomMetadata(ctx, metadata.Base) if found { - return types.ErrDenomAlreadyExists + return gerr.ErrAlreadyExists } k.bankKeeper.SetDenomMetaData(ctx, metadata) err := k.hooks.AfterDenomMetadataCreation(ctx, metadata) @@ -41,9 +47,9 @@ func (k *Keeper) CreateDenomMetadata(ctx sdk.Context, metadata banktypes.Metadat // UpdateDenomMetadata returns the denommetadata of the specified denom func (k *Keeper) UpdateDenomMetadata(ctx sdk.Context, metadata banktypes.Metadata) error { - found := k.bankKeeper.HasDenomMetaData(ctx, metadata.Base) + found := k.HasDenomMetadata(ctx, metadata.Base) if !found { - return types.ErrDenomDoesNotExist + return gerr.ErrNotFound } k.bankKeeper.SetDenomMetaData(ctx, metadata) err := k.hooks.AfterDenomMetadataUpdate(ctx, metadata) @@ -63,9 +69,6 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { // SetHooks sets the hooks for the denommetadata keeper func (k *Keeper) SetHooks(sh types.MultiDenomMetadataHooks) { - if k.hooks != nil { - panic("cannot set rollapp hooks twice") - } k.hooks = sh } diff --git a/x/denommetadata/keeper/keeper_test.go b/x/denommetadata/keeper/keeper_test.go index 0287268a2..4c535d14b 100644 --- a/x/denommetadata/keeper/keeper_test.go +++ b/x/denommetadata/keeper/keeper_test.go @@ -3,11 +3,12 @@ package keeper_test import ( "testing" + errorsmod "cosmossdk.io/errors" + "github.com/dymensionxyz/dymension/v3/utils/gerr" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/dymensionxyz/dymension/v3/app/apptesting" - "github.com/dymensionxyz/dymension/v3/x/denommetadata/types" - "github.com/stretchr/testify/suite" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" ) @@ -64,14 +65,14 @@ func (suite *KeeperTestSuite) TestCreateExistingDenom() { suite.Require().NoError(err) err = keeper.CreateDenomMetadata(suite.Ctx, suite.getDymMetadata()) - suite.Require().EqualError(err, types.ErrDenomAlreadyExists.Error()) + suite.Require().True(errorsmod.IsOf(err, gerr.ErrAlreadyExists)) } func (suite *KeeperTestSuite) TestUpdateMissingDenom() { keeper := suite.App.DenomMetadataKeeper err := keeper.UpdateDenomMetadata(suite.Ctx, suite.getDymUpdateMetadata()) - suite.Require().EqualError(err, types.ErrDenomDoesNotExist.Error()) + suite.Require().True(errorsmod.IsOf(err, gerr.ErrNotFound)) } func (suite *KeeperTestSuite) getDymMetadata() banktypes.Metadata { diff --git a/x/denommetadata/types/errors.go b/x/denommetadata/types/errors.go index 9d5762ead..d96c7738b 100644 --- a/x/denommetadata/types/errors.go +++ b/x/denommetadata/types/errors.go @@ -8,7 +8,5 @@ import ( // x/denommetadata module sentinel errors var ( - ErrDenomAlreadyExists = errorsmod.Register(ModuleName, 1000, "denom metadata is already registered") - ErrDenomDoesNotExist = errorsmod.Register(ModuleName, 1001, "unable to find denom metadata registered") - ErrUnknownRequest = errorsmod.Register(ModuleName, 1002, "unknown request") + ErrUnknownRequest = errorsmod.Register(ModuleName, 1002, "unknown request") ) diff --git a/x/denommetadata/types/expected_keepers.go b/x/denommetadata/types/expected_keepers.go index 562d9cdcb..0881e1d77 100644 --- a/x/denommetadata/types/expected_keepers.go +++ b/x/denommetadata/types/expected_keepers.go @@ -3,29 +3,9 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/cosmos/ibc-go/v6/modules/core/exported" - rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" - tmbytes "github.com/tendermint/tendermint/libs/bytes" ) -// TransferKeeper defines the expected transfer keeper -type TransferKeeper interface { - HasDenomTrace(ctx sdk.Context, denomTraceHash tmbytes.HexBytes) bool -} - -// ChannelKeeper defines the expected IBC channel keeper -type ChannelKeeper interface { - GetChannelClientState(ctx sdk.Context, portID, channelID string) (string, exported.ClientState, error) -} - -// BankKeeper defines the expected interface needed type BankKeeper interface { HasDenomMetaData(ctx sdk.Context, denom string) bool SetDenomMetaData(ctx sdk.Context, denomMetaData types.Metadata) } - -type RollappKeeper interface { - GetParams(ctx sdk.Context) rollapptypes.Params - GetRollapp(ctx sdk.Context, chainID string) (rollapp rollapptypes.Rollapp, found bool) - RegisterDenomMetadata(ctx sdk.Context, rollapp rollapptypes.Rollapp, ibcBaseDenom, baseDenom string) -} diff --git a/x/denommetadata/types/hooks.go b/x/denommetadata/types/hooks.go index ef0f86d2b..19eb12895 100644 --- a/x/denommetadata/types/hooks.go +++ b/x/denommetadata/types/hooks.go @@ -16,7 +16,7 @@ var _ DenomMetadataHooks = MultiDenomMetadataHooks{} // combine multiple DenomMetadata hooks, all hook functions are run in array sequence type MultiDenomMetadataHooks []DenomMetadataHooks -// Creates hooks for the DenomMetadata Module. +// NewMultiDenomMetadataHooks creates hooks for the DenomMetadata Module. func NewMultiDenomMetadataHooks(hooks ...DenomMetadataHooks) MultiDenomMetadataHooks { return hooks } diff --git a/x/eibc/keeper/handler.go b/x/eibc/keeper/handler.go index a342360b1..6f161a7b6 100644 --- a/x/eibc/keeper/handler.go +++ b/x/eibc/keeper/handler.go @@ -6,9 +6,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + uibc "github.com/dymensionxyz/dymension/v3/utils/ibc" "github.com/pkg/errors" - "github.com/dymensionxyz/dymension/v3/utils" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" dacktypes "github.com/dymensionxyz/dymension/v3/x/delayedack/types" "github.com/dymensionxyz/dymension/v3/x/eibc/types" @@ -140,7 +140,7 @@ func (k *Keeper) getEIBCTransferDenom(packet channeltypes.Packet, fungibleTokenP denom = denomTrace.IBCDenom() } } else { - denom = utils.GetForeignIBCDenom(packet.GetDestChannel(), fungibleTokenPacketData.Denom) + denom = uibc.GetForeignDenomTrace(packet.GetDestChannel(), fungibleTokenPacketData.Denom).IBCDenom() } return denom } diff --git a/x/rollapp/client/cli/flags.go b/x/rollapp/client/cli/flags.go index 402d32b4c..1a0e01f42 100644 --- a/x/rollapp/client/cli/flags.go +++ b/x/rollapp/client/cli/flags.go @@ -6,13 +6,14 @@ import ( const ( // Create rollapp flags - FlagGenesisAccountsPath = "genesis-accounts-path" + + FlagGenesisTransfersEnabled = "transfers-enabled" ) // FlagSetCreateRollapp returns flags for creating gauges. func FlagSetCreateRollapp() *flag.FlagSet { fs := flag.NewFlagSet("", flag.ContinueOnError) - fs.String(FlagGenesisAccountsPath, "", "path to a json file containing genesis accounts") + fs.Bool(FlagGenesisTransfersEnabled, false, "Enable ibc transfers immediately. Must be false if using genesis transfers (genesis accounts).") return fs } diff --git a/x/rollapp/client/cli/tx.go b/x/rollapp/client/cli/tx.go index 11eae2b80..10ba341cf 100644 --- a/x/rollapp/client/cli/tx.go +++ b/x/rollapp/client/cli/tx.go @@ -2,18 +2,13 @@ package cli import ( "fmt" - "time" "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/tx" "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) -var DefaultRelativePacketTimeoutTimestamp = uint64((time.Duration(10) * time.Minute).Nanoseconds()) - // GetTxCmd returns the transaction commands for this module func GetTxCmd() *cobra.Command { cmd := &cobra.Command{ @@ -26,38 +21,6 @@ func GetTxCmd() *cobra.Command { cmd.AddCommand(CmdCreateRollapp()) cmd.AddCommand(CmdUpdateState()) - cmd.AddCommand(CmdGenesisEvent()) - - return cmd -} - -func CmdGenesisEvent() *cobra.Command { - cmd := &cobra.Command{ - Use: "genesis-event [rollapp-id] [channel-id] [flags]", - Short: "Trigger a genesis event from this rollapp and channel", - Example: "dymd tx rollapp genesis-event [rollapp-id] [channel-id] ", - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) (err error) { - // Get arguments - rollappId := args[0] - channelId := args[1] - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - msg := types.NewMsgRollappGenesisEvent( - clientCtx.GetFromAddress().String(), - channelId, - rollappId, - ) - - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - flags.AddTxFlagsToCmd(cmd) return cmd } diff --git a/x/rollapp/client/cli/tx_create_rollapp.go b/x/rollapp/client/cli/tx_create_rollapp.go index 681a353db..ee4620045 100644 --- a/x/rollapp/client/cli/tx_create_rollapp.go +++ b/x/rollapp/client/cli/tx_create_rollapp.go @@ -7,7 +7,6 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/dymensionxyz/dymension/v3/utils" "github.com/dymensionxyz/dymension/v3/x/rollapp/types" "github.com/spf13/cast" "github.com/spf13/cobra" @@ -15,7 +14,7 @@ import ( var _ = strconv.Itoa(0) -// TODO: refactor to be flag of []string +// PermissionedAddresses .. TODO: refactor to be flag of []string type PermissionedAddresses struct { Addresses []string `json:"addresses"` } @@ -25,7 +24,7 @@ func CmdCreateRollapp() *cobra.Command { Use: "create-rollapp [rollapp-id] [max-sequencers] [permissioned-addresses] [metadata.json]", Short: "Create a new rollapp", Example: "dymd tx rollapp create-rollapp ROLLAPP_CHAIN_ID 10 '{\"Addresses\":[]}' metadata.json", - Args: cobra.RangeArgs(3, 4), + Args: cobra.ExactArgs(3), RunE: func(cmd *cobra.Command, args []string) (err error) { argRollappId := args[0] @@ -43,29 +42,13 @@ func CmdCreateRollapp() *cobra.Command { if err != nil { return err } - // Parse metadata - var metadatas []types.TokenMetadata - if len(args) == 4 { - metadatas, err = utils.ParseJsonFromFile[types.TokenMetadata](args[3]) - if err != nil { - return err - } - } - // Parse genesis accounts - genesisAccountsPath, _ := cmd.Flags().GetString(FlagGenesisAccountsPath) - genesisAccounts, err := utils.ParseJsonFromFile[types.GenesisAccount](genesisAccountsPath) - if err != nil && genesisAccountsPath != "" { + + transfersEnabled, err := cmd.Flags().GetBool(FlagGenesisTransfersEnabled) + if err != nil { return err } - msg := types.NewMsgCreateRollapp( - clientCtx.GetFromAddress().String(), - argRollappId, - argMaxSequencers, - argPermissionedAddresses.Addresses, - metadatas, - genesisAccounts, - ) + msg := types.NewMsgCreateRollapp(clientCtx.GetFromAddress().String(), argRollappId, argMaxSequencers, argPermissionedAddresses.Addresses, transfersEnabled) return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, diff --git a/x/rollapp/genesis.go b/x/rollapp/genesis.go index 483ae7e35..67dbf8876 100644 --- a/x/rollapp/genesis.go +++ b/x/rollapp/genesis.go @@ -29,8 +29,9 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) for _, elem := range genState.BlockHeightToFinalizationQueueList { k.SetBlockHeightToFinalizationQueue(ctx, elem) } - // this line is used by starport scaffolding # genesis/module/init k.SetParams(ctx, genState.Params) + k.SetGenesisTransfers(ctx, genState.GenesisTransfers) + // this line is used by starport scaffolding # genesis/module/init } // ExportGenesis returns the capability module's exported genesis. @@ -43,6 +44,7 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { genesis.LatestStateInfoIndexList = k.GetAllLatestStateInfoIndex(ctx) genesis.LatestFinalizedStateIndexList = k.GetAllLatestFinalizedStateIndex(ctx) genesis.BlockHeightToFinalizationQueueList = k.GetAllBlockHeightToFinalizationQueue(ctx) + genesis.GenesisTransfers = k.GetAllGenesisTransfers(ctx) return genesis } diff --git a/x/rollapp/genesis_test.go b/x/rollapp/genesis_test.go index f28c5a6af..49376a002 100644 --- a/x/rollapp/genesis_test.go +++ b/x/rollapp/genesis_test.go @@ -1,8 +1,11 @@ package rollapp_test import ( + "strings" "testing" + "golang.org/x/exp/slices" + keepertest "github.com/dymensionxyz/dymension/v3/testutil/keeper" "github.com/dymensionxyz/dymension/v3/testutil/nullify" "github.com/dymensionxyz/dymension/v3/x/rollapp" @@ -10,7 +13,7 @@ import ( "github.com/stretchr/testify/require" ) -func TestInitGenesis(t *testing.T) { +func TestInitExportGenesis(t *testing.T) { genesisState := types.GenesisState{ Params: types.DefaultParams(), @@ -52,6 +55,18 @@ func TestInitGenesis(t *testing.T) { CreationHeight: 1, }, }, + GenesisTransfers: []types.GenesisTransfers{ + { + RollappID: "0", + NumTotal: 3, + NumReceived: 3, + }, + { + RollappID: "1", + NumTotal: 3, + NumReceived: 3, + }, + }, // this line is used by starport scaffolding # genesis/test/state } @@ -60,9 +75,11 @@ func TestInitGenesis(t *testing.T) { got := rollapp.ExportGenesis(ctx, *k) require.NotNil(t, got) - nullify.Fill(&genesisState) - nullify.Fill(got) + nullify.Fill(genesisState) + nullify.Fill(*got) + require.True(t, GenesisTransfersAreEquivalent(genesisState.GetGenesisTransfers(), got.GetGenesisTransfers())) + require.ElementsMatch(t, genesisState.GenesisTransfers, got.GenesisTransfers) require.ElementsMatch(t, genesisState.RollappList, got.RollappList) require.ElementsMatch(t, genesisState.StateInfoList, got.StateInfoList) require.ElementsMatch(t, genesisState.LatestStateInfoIndexList, got.LatestStateInfoIndexList) @@ -70,41 +87,34 @@ func TestInitGenesis(t *testing.T) { // this line is used by starport scaffolding # genesis/test/assert } -func TestExportGenesis(t *testing.T) { - params := types.Params{ - DisputePeriodInBlocks: 11, - DeployerWhitelist: []types.DeployerParams{{Address: "dym1wg8p6j0pxpnsvhkwfu54ql62cnrumf0v634mft"}}, - RollappsEnabled: false, +// GenesisTransfersAreEquivalent returns if a,b are the same, in terms of containing +// the same semantic content. Intended for use in tests. +func GenesisTransfersAreEquivalent(x, y []types.GenesisTransfers) bool { + if len(x) != len(y) { + return false } - rollappList := []types.Rollapp{{RollappId: "0"}, {RollappId: "1"}} - stateInfoList := []types.StateInfo{ - {StateInfoIndex: types.StateInfoIndex{RollappId: "0", Index: 0}}, - {StateInfoIndex: types.StateInfoIndex{RollappId: "1", Index: 1}}, - } - latestStateInfoIndexList := []types.StateInfoIndex{{RollappId: "0"}, {RollappId: "1"}} - blockHeightToFinalizationQueueList := []types.BlockHeightToFinalizationQueue{{CreationHeight: 0}, {CreationHeight: 1}} - // Set the items in the keeper - k, ctx := keepertest.RollappKeeper(t) - for _, rollapp := range rollappList { - k.SetRollapp(ctx, rollapp) + sort := func(l []types.GenesisTransfers) { + slices.SortStableFunc(l, func(a, b types.GenesisTransfers) bool { + return strings.Compare(a.GetRollappID(), b.GetRollappID()) <= 0 + }) } - for _, stateInfo := range stateInfoList { - k.SetStateInfo(ctx, stateInfo) - } - for _, latestStateInfoIndex := range latestStateInfoIndexList { - k.SetLatestStateInfoIndex(ctx, latestStateInfoIndex) - } - for _, blockHeightToFinalizationQueue := range blockHeightToFinalizationQueueList { - k.SetBlockHeightToFinalizationQueue(ctx, blockHeightToFinalizationQueue) + + sort(x) + sort(y) + for i := range len(x) { + a := x[i] + b := y[i] + if a.NumTotal != b.NumTotal { + return false + } + if a.NumReceived != b.NumReceived { + return false + } + if a.RollappID != b.RollappID { + return false + } + } - k.SetParams(ctx, params) - // Verify the exported genesis state - got := rollapp.ExportGenesis(ctx, *k) - require.NotNil(t, got) - // Validate the exported genesis state - require.Equal(t, params, got.Params) - require.ElementsMatch(t, rollappList, got.RollappList) - require.ElementsMatch(t, stateInfoList, got.StateInfoList) - require.ElementsMatch(t, latestStateInfoIndexList, got.LatestStateInfoIndexList) - require.ElementsMatch(t, blockHeightToFinalizationQueueList, got.BlockHeightToFinalizationQueueList) + + return true } diff --git a/x/rollapp/keeper/authenticate_packet.go b/x/rollapp/keeper/authenticate_packet.go new file mode 100644 index 000000000..91b5a5ed8 --- /dev/null +++ b/x/rollapp/keeper/authenticate_packet.go @@ -0,0 +1,91 @@ +package keeper + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + "github.com/dymensionxyz/dymension/v3/utils/gerr" + uibc "github.com/dymensionxyz/dymension/v3/utils/ibc" + "github.com/dymensionxyz/dymension/v3/x/rollapp/types" +) + +/* +TODO: : instead of calling these all the time in every middleware, we could do it once and use + context https://github.com/dymensionxyz/dymension/issues/914 +*/ + +// GetValidTransfer takes a packet, ensures it is a (basic) validated fungible token packet, and gets the chain id. +// If the channel chain id is also a rollapp id, we check that the canonical channel id we have saved for that rollapp +// agrees is indeed the channel we are receiving from. In this way, we stop anyone from pretending to be the RA. (Assuming +// that the mechanism for setting the canonical channel in the first place is correct). +func (k Keeper) GetValidTransfer( + ctx sdk.Context, + packetData []byte, + raPortOnHub, raChanOnHub string, +) (data types.TransferData, err error) { + if err = transfertypes.ModuleCdc.UnmarshalJSON(packetData, &data.FungibleTokenPacketData); err != nil { + err = errorsmod.Wrap(err, "unmarshal transfer data") + return + } + + if err = data.ValidateBasic(); err != nil { + err = errorsmod.Wrap(err, "validate basic") + return + } + + ra, err := k.getRollappByPortChan(ctx, raPortOnHub, raChanOnHub) + if errorsmod.IsOf(err, errRollappNotFound) { + // no problem, it corresponds to a regular non-rollapp chain + err = nil + return + } + if err != nil { + err = errorsmod.Wrap(err, "get rollapp id") + return + } + + data.Rollapp = ra + + return +} + +var errRollappNotFound = errorsmod.Wrap(gerr.ErrNotFound, "rollapp") + +// getRollappByPortChan returns the rollapp id that a packet came from, if we are certain +// that the packet came from that rollapp. That means that the canonical channel +// has already been set. +func (k Keeper) getRollappByPortChan(ctx sdk.Context, + raPortOnHub, raChanOnHub string, +) (*types.Rollapp, error) { + /* + TODO: + There is an open issue of how we go about making sure that the packet really came from the rollapp, and once we know that it came + from the rollapp, also how we deal with fraud from the sequencer + See https://github.com/dymensionxyz/research/issues/242 for info + See + https://github.com/dymensionxyz/dymension/blob/8734e239483bb6290de6d01c196da35fa033e160/x/delayedack/keeper/authenticate_packet.go#L100-L204 + https://github.com/dymensionxyz/dymension/blob/8734e239483bb6290de6d01c196da35fa033e160/x/delayedack/keeper/authenticate_packet.go#L100-L204 + https://github.com/dymensionxyz/dymension/blob/a74ffb0cec00768bbb8dbe3fd6413e66388010d3/x/delayedack/keeper/keeper.go#L98-L107 + https://github.com/dymensionxyz/dymension/blob/986d51ccd4807d514c91b3a147ac1b8ce5b590a1/x/delayedack/keeper/authenticate_packet.go#L47-L59 + for the old implementations of checks + */ + chainID, err := uibc.ChainIDFromPortChannel(ctx, k.channelKeeper.GetChannelClientState, raPortOnHub, raChanOnHub) + if err != nil { + return nil, errorsmod.Wrap(err, "chain id from port and channel") + } + rollapp, ok := k.GetRollapp(ctx, chainID) + if !ok { + return nil, errorsmod.Wrapf(errRollappNotFound, "chain id: %s: port: %s: channel: %s", chainID, raPortOnHub, raChanOnHub) + } + if rollapp.ChannelId == "" { + return nil, errorsmod.Wrapf(gerr.ErrFailedPrecondition, "rollapp canonical channel mapping has not been set: %s", chainID) + } + + if rollapp.ChannelId != raChanOnHub { + return nil, errorsmod.Wrapf( + gerr.ErrInvalidArgument, + "packet destination channel id mismatch: expect: %s: got: %s", rollapp.ChannelId, raChanOnHub, + ) + } + return &rollapp, nil +} diff --git a/x/rollapp/keeper/block_height_to_finalization_queue.go b/x/rollapp/keeper/block_height_to_finalization_queue.go index cfae60c2e..ab87acca9 100644 --- a/x/rollapp/keeper/block_height_to_finalization_queue.go +++ b/x/rollapp/keeper/block_height_to_finalization_queue.go @@ -10,14 +10,14 @@ import ( "github.com/osmosis-labs/osmosis/v15/osmoutils" ) -// FinalizeQueue is called every block to finalize states when their dispute period over. -func (k Keeper) FinalizeQueue(ctx sdk.Context) error { +// FinalizeRollappStates is called every block to finalize states when their dispute period over. +func (k Keeper) FinalizeRollappStates(ctx sdk.Context) error { if uint64(ctx.BlockHeight()) < k.DisputePeriodInBlocks(ctx) { return nil } // check to see if there are pending states to be finalized finalizationHeight := uint64(ctx.BlockHeight() - int64(k.DisputePeriodInBlocks(ctx))) - pendingFinalizationQueue := k.GetAllFinalizationQueueUntilHeight(ctx, finalizationHeight) + pendingFinalizationQueue := k.GetAllFinalizationQueueUntilHeightInclusive(ctx, finalizationHeight) return osmoutils.ApplyFuncIfNoError(ctx, // we trap at this granularity because we want to avoid iterating inside the @@ -99,34 +99,28 @@ func (k Keeper) RemoveBlockHeightToFinalizationQueue( )) } -// GetAllFinalizationQueueUntilHeight returns all the blockHeightToFinalizationQueues with creation height equal or less to the input height -func (k Keeper) GetAllFinalizationQueueUntilHeight(ctx sdk.Context, height uint64) (list []types.BlockHeightToFinalizationQueue) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.BlockHeightToFinalizationQueueKeyPrefix)) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - defer iterator.Close() // nolint: errcheck - - for ; iterator.Valid(); iterator.Next() { - var val types.BlockHeightToFinalizationQueue - k.cdc.MustUnmarshal(iterator.Value(), &val) - if height < val.CreationHeight { - break - } - list = append(list, val) - } - - return +// GetAllFinalizationQueueUntilHeightInclusive returns all the blockHeightToFinalizationQueues with creation height equal or less to the input height +func (k Keeper) GetAllFinalizationQueueUntilHeightInclusive(ctx sdk.Context, height uint64) (list []types.BlockHeightToFinalizationQueue) { + height++ + return k.getFinalizationQueue(ctx, &height) } // GetAllBlockHeightToFinalizationQueue returns all blockHeightToFinalizationQueue func (k Keeper) GetAllBlockHeightToFinalizationQueue(ctx sdk.Context) (list []types.BlockHeightToFinalizationQueue) { + return k.getFinalizationQueue(ctx, nil) +} + +func (k Keeper) getFinalizationQueue(ctx sdk.Context, endHeightNonInclusive *uint64) (list []types.BlockHeightToFinalizationQueue) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.BlockHeightToFinalizationQueueKeyPrefix)) iterator := sdk.KVStorePrefixIterator(store, []byte{}) - defer iterator.Close() // nolint: errcheck for ; iterator.Valid(); iterator.Next() { var val types.BlockHeightToFinalizationQueue k.cdc.MustUnmarshal(iterator.Value(), &val) + if endHeightNonInclusive != nil && *endHeightNonInclusive <= val.CreationHeight { + break + } list = append(list, val) } diff --git a/x/rollapp/keeper/block_height_to_finalization_queue_test.go b/x/rollapp/keeper/block_height_to_finalization_queue_test.go index e3a1b31d5..c76b3260b 100644 --- a/x/rollapp/keeper/block_height_to_finalization_queue_test.go +++ b/x/rollapp/keeper/block_height_to_finalization_queue_test.go @@ -19,8 +19,8 @@ var _ = strconv.IntSize func (suite *RollappTestSuite) TestGetAllFinalizationQueueUntilHeight() { suite.SetupTest() - initialheight := uint64(10) - suite.Ctx = suite.Ctx.WithBlockHeight(int64(initialheight)) + initialHeight := uint64(10) + suite.Ctx = suite.Ctx.WithBlockHeight(int64(initialHeight)) ctx := &suite.Ctx keeper := suite.App.RollappKeeper @@ -29,15 +29,15 @@ func (suite *RollappTestSuite) TestGetAllFinalizationQueueUntilHeight() { // Create 2 state updates _, err := suite.PostStateUpdate(*ctx, rollapp, proposer, 1, uint64(10)) suite.Require().Nil(err) - suite.Ctx = suite.Ctx.WithBlockHeight(int64(initialheight + 1)) + suite.Ctx = suite.Ctx.WithBlockHeight(int64(initialHeight + 1)) _, err = suite.PostStateUpdate(*ctx, rollapp, proposer, 11, uint64(10)) suite.Require().Nil(err) // Get the pending finalization queue - suite.Assert().Len(keeper.GetAllFinalizationQueueUntilHeight(*ctx, initialheight-1), 0) - suite.Assert().Len(keeper.GetAllFinalizationQueueUntilHeight(*ctx, initialheight), 1) - suite.Assert().Len(keeper.GetAllFinalizationQueueUntilHeight(*ctx, initialheight+1), 2) - suite.Assert().Len(keeper.GetAllFinalizationQueueUntilHeight(*ctx, initialheight+100), 2) + suite.Len(keeper.GetAllFinalizationQueueUntilHeightInclusive(*ctx, initialHeight-1), 0) + suite.Len(keeper.GetAllFinalizationQueueUntilHeightInclusive(*ctx, initialHeight), 1) + suite.Len(keeper.GetAllFinalizationQueueUntilHeightInclusive(*ctx, initialHeight+1), 2) + suite.Len(keeper.GetAllFinalizationQueueUntilHeightInclusive(*ctx, initialHeight+100), 2) } func TestBlockHeightToFinalizationQueueGet(t *testing.T) { diff --git a/x/rollapp/keeper/fraud_handler.go b/x/rollapp/keeper/fraud_handler.go index f3fa13af1..b623fa28b 100644 --- a/x/rollapp/keeper/fraud_handler.go +++ b/x/rollapp/keeper/fraud_handler.go @@ -87,7 +87,7 @@ func (k Keeper) HandleFraud(ctx sdk.Context, rollappID, clientId string, fraudHe // freeze IBC client state func (k Keeper) freezeClientState(ctx sdk.Context, clientId string) error { - clientState, ok := k.ibcclientKeeper.GetClientState(ctx, clientId) + clientState, ok := k.ibcClientKeeper.GetClientState(ctx, clientId) if !ok { return errorsmod.Wrapf(types.ErrInvalidClientState, "client state for clientID %s not found", clientId) } @@ -98,7 +98,7 @@ func (k Keeper) freezeClientState(ctx sdk.Context, clientId string) error { } tmClientState.FrozenHeight = clienttypes.NewHeight(tmClientState.GetLatestHeight().GetRevisionHeight(), tmClientState.GetLatestHeight().GetRevisionNumber()) - k.ibcclientKeeper.SetClientState(ctx, clientId, tmClientState) + k.ibcClientKeeper.SetClientState(ctx, clientId, tmClientState) return nil } diff --git a/x/rollapp/keeper/fraud_handler_test.go b/x/rollapp/keeper/fraud_handler_test.go index da440860a..1793236be 100644 --- a/x/rollapp/keeper/fraud_handler_test.go +++ b/x/rollapp/keeper/fraud_handler_test.go @@ -49,7 +49,7 @@ func (suite *RollappTestSuite) TestHandleFraud() { } // finalize some of the states - err = suite.App.RollappKeeper.FinalizeQueue(suite.Ctx.WithBlockHeight(20)) + err = suite.App.RollappKeeper.FinalizeRollappStates(suite.Ctx.WithBlockHeight(20)) suite.Require().Nil(err) // assert before fraud submission @@ -165,7 +165,7 @@ func (suite *RollappTestSuite) TestHandleFraud_AlreadyFinalized() { // finalize state suite.Ctx = suite.Ctx.WithBlockHeight(ctx.BlockHeight() + int64(keeper.DisputePeriodInBlocks(*ctx))) - err = suite.App.RollappKeeper.FinalizeQueue(suite.Ctx) + err = suite.App.RollappKeeper.FinalizeRollappStates(suite.Ctx) suite.Require().Nil(err) stateInfo, err := suite.App.RollappKeeper.FindStateInfoByHeight(suite.Ctx, rollapp, 1) suite.Require().Nil(err) @@ -238,7 +238,7 @@ func (suite *RollappTestSuite) assertFraudHandled(rollappId string) { // check queue queue := suite.App.RollappKeeper.GetAllBlockHeightToFinalizationQueue(suite.Ctx) - suite.Assert().Greater(len(queue), 0) + suite.Greater(len(queue), 0) for _, q := range queue { for _, stateInfoIndex := range q.FinalizationQueue { suite.Require().NotEqual(rollappId, stateInfoIndex.RollappId) diff --git a/x/rollapp/keeper/genesis_transfer.go b/x/rollapp/keeper/genesis_transfer.go new file mode 100644 index 000000000..b49154de4 --- /dev/null +++ b/x/rollapp/keeper/genesis_transfer.go @@ -0,0 +1,93 @@ +package keeper + +import ( + errorsmod "cosmossdk.io/errors" + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/dymension/v3/utils/derr" + "github.com/dymensionxyz/dymension/v3/x/rollapp/types" +) + +// VerifyAndRecordGenesisTransfer takes a transfer 'index' from the rollapp sequencer and book keeps it +// If we have previously seen a different n, we reject it, the sequencer is not following protocol. +// If we have previously seen the same IX already, we reject it, as IBC guarantees exactly once delivery, then the sequencer must not be following protocol +// Once we have recorded n indexes, this rollapp can proceed to the next step of the genesis transfer protocol +// Returns the number of transfers recorded so far (including this one) +func (k Keeper) VerifyAndRecordGenesisTransfer(ctx sdk.Context, rollappID string, nTotal uint64) (uint64, error) { + ra := k.MustGetRollapp(ctx, rollappID) + if ra.GenesisState.TransfersEnabled { + // Could plausibly occur if a chain sends too many genesis transfers (not matching their memo) + // or if a chain which registered with the bridge enabled tries to send some genesis transfers + return 0, errorsmod.Wrap(derr.ErrViolatesDymensionRollappStandard, "received genesis transfer but all bridge transfers are already enabled") + } + + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.TransferGenesisMapKeyPrefix)) + + nKey := types.TransferGenesisNumKey(rollappID) + nTotalKey := types.TransferGenesisNumTotalKey(rollappID) + + n := uint64(0) + + if store.Has(nTotalKey) { + nTotalExistingBz := store.Get(nTotalKey) + nTotalExisting := sdk.BigEndianToUint64(nTotalExistingBz) + if nTotal != nTotalExisting { + return 0, errorsmod.Wrapf(derr.ErrViolatesDymensionRollappStandard, "different num total transfers: got: %d: got previously: %d", nTotal, nTotalExisting) + } + nBz := store.Get(nKey) + n = sdk.BigEndianToUint64(nBz) + } + + n++ + store.Set(nTotalKey, sdk.Uint64ToBigEndian(nTotal)) + store.Set(nKey, sdk.Uint64ToBigEndian(n)) + return n, nil +} + +func (k Keeper) EnableTransfers(ctx sdk.Context, rollappID string) { + ra := k.MustGetRollapp(ctx, rollappID) + ra.GenesisState.TransfersEnabled = true + k.SetRollapp(ctx, ra) + ctx.EventManager().EmitEvent(sdk.NewEvent(types.EventTypeTransferGenesisTransfersEnabled, + sdk.NewAttribute(types.AttributeKeyRollappId, rollappID), + )) +} + +func (k Keeper) SetGenesisTransfers(ctx sdk.Context, transfers []types.GenesisTransfers) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.TransferGenesisMapKeyPrefix)) + + for _, transfer := range transfers { + + nKey := types.TransferGenesisNumKey(transfer.RollappID) + nTotalKey := types.TransferGenesisNumTotalKey(transfer.RollappID) + store.Set(nTotalKey, sdk.Uint64ToBigEndian(transfer.NumTotal)) + store.Set(nKey, sdk.Uint64ToBigEndian(transfer.NumReceived)) + } +} + +func (k Keeper) GetAllGenesisTransfers(ctx sdk.Context) []types.GenesisTransfers { + var ret []types.GenesisTransfers + + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.TransferGenesisMapKeyPrefix)) + + rollapps := k.GetAllRollapps(ctx) + + for _, ra := range rollapps { + + raID := ra.RollappId + nTotalKey := types.TransferGenesisNumTotalKey(raID) + nTotalBz := store.Get(nTotalKey) + nTotal := sdk.BigEndianToUint64(nTotalBz) + nKey := types.TransferGenesisNumKey(raID) + nBz := store.Get(nKey) + n := sdk.BigEndianToUint64(nBz) + x := types.GenesisTransfers{ + RollappID: raID, + NumTotal: nTotal, + NumReceived: n, + } + ret = append(ret, x) + } + + return ret +} diff --git a/x/rollapp/keeper/invariants_test.go b/x/rollapp/keeper/invariants_test.go index 85bbc3615..73514ac71 100644 --- a/x/rollapp/keeper/invariants_test.go +++ b/x/rollapp/keeper/invariants_test.go @@ -51,7 +51,7 @@ func (suite *RollappTestSuite) TestInvariants() { // progress finalization queue suite.Ctx = suite.Ctx.WithBlockHeight(initialheight + 2) - err := suite.App.RollappKeeper.FinalizeQueue(suite.Ctx) + err := suite.App.RollappKeeper.FinalizeRollappStates(suite.Ctx) suite.Require().Nil(err) // check invariant diff --git a/x/rollapp/keeper/keeper.go b/x/rollapp/keeper/keeper.go index a4fe2c194..d502767b7 100644 --- a/x/rollapp/keeper/keeper.go +++ b/x/rollapp/keeper/keeper.go @@ -3,8 +3,6 @@ package keeper import ( "fmt" - errorsmod "cosmossdk.io/errors" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/codec" @@ -12,7 +10,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - "github.com/dymensionxyz/dymension/v3/utils" "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) @@ -20,43 +17,26 @@ type ( Keeper struct { cdc codec.BinaryCodec storeKey storetypes.StoreKey - memKey storetypes.StoreKey hooks types.MultiRollappHooks paramstore paramtypes.Subspace - ibcclientKeeper types.IBCClientKeeper - transferKeeper types.TransferKeeper - channelKeeper types.ChannelKeeper - bankKeeper types.BankKeeper - denommetadataKeeper types.DenomMetadataKeeper + ibcClientKeeper types.IBCClientKeeper + channelKeeper types.ChannelKeeper } ) -func NewKeeper( - cdc codec.BinaryCodec, - storeKey, - memKey storetypes.StoreKey, - ps paramtypes.Subspace, - ibcclientKeeper types.IBCClientKeeper, - channelKeeper types.ChannelKeeper, - bankKeeper types.BankKeeper, - denommetadataKeeper types.DenomMetadataKeeper, -) *Keeper { +func NewKeeper(cdc codec.BinaryCodec, storeKey storetypes.StoreKey, ps paramtypes.Subspace, channelKeeper types.ChannelKeeper) *Keeper { // set KeyTable if it has not already been set if !ps.HasKeyTable() { ps = ps.WithKeyTable(types.ParamKeyTable()) } return &Keeper{ - cdc: cdc, - storeKey: storeKey, - memKey: memKey, - paramstore: ps, - hooks: nil, - ibcclientKeeper: ibcclientKeeper, - channelKeeper: channelKeeper, - bankKeeper: bankKeeper, - denommetadataKeeper: denommetadataKeeper, + cdc: cdc, + storeKey: storeKey, + paramstore: ps, + hooks: nil, + channelKeeper: channelKeeper, } } @@ -64,114 +44,10 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } -// TriggerRollappGenesisEvent triggers the genesis event for the rollapp. -func (k Keeper) TriggerRollappGenesisEvent(ctx sdk.Context, rollapp types.Rollapp) error { - // Validate it hasn't been triggered yet - if rollapp.GenesisState.IsGenesisEvent { - return types.ErrGenesisEventAlreadyTriggered - } - - if err := k.registerDenomMetadata(ctx, rollapp); err != nil { - return errorsmod.Wrapf(types.ErrRegisterDenomMetadataFailed, "register denom metadata: %s", err) - } - - if err := k.mintRollappGenesisTokens(ctx, rollapp); err != nil { - return errorsmod.Wrapf(types.ErrMintTokensFailed, "mint rollapp genesis tokens: %s", err) - } - - rollapp.GenesisState.IsGenesisEvent = true - k.SetRollapp(ctx, rollapp) - return nil -} - -// registerDenomMetadata registers the denom metadata for the IBC token -func (k Keeper) registerDenomMetadata(ctx sdk.Context, rollapp types.Rollapp) error { - for i := range rollapp.TokenMetadata { - denomTrace := utils.GetForeignDenomTrace(rollapp.ChannelId, rollapp.TokenMetadata[i].Base) - traceHash := denomTrace.Hash() - // if the denom trace does not exist, add it - if !k.transferKeeper.HasDenomTrace(ctx, traceHash) { - k.transferKeeper.SetDenomTrace(ctx, denomTrace) - } - - ibcBaseDenom := denomTrace.IBCDenom() - - // create a new token denom metadata where it's base = ibcDenom, - // and the rest of the fields are taken from rollapp.metadata - metadata := banktypes.Metadata{ - Description: "auto-generated metadata for " + ibcBaseDenom + " from rollapp " + rollapp.RollappId, - Base: ibcBaseDenom, - DenomUnits: make([]*banktypes.DenomUnit, len(rollapp.TokenMetadata[i].DenomUnits)), - Display: rollapp.TokenMetadata[i].Display, - Name: rollapp.TokenMetadata[i].Name, - Symbol: rollapp.TokenMetadata[i].Symbol, - URI: rollapp.TokenMetadata[i].URI, - URIHash: rollapp.TokenMetadata[i].URIHash, - } - // Copy DenomUnits slice - for j, du := range rollapp.TokenMetadata[i].DenomUnits { - newDu := banktypes.DenomUnit{ - Aliases: du.Aliases, - Denom: du.Denom, - Exponent: du.Exponent, - } - // base denom_unit should be the same as baseDenom - if newDu.Exponent == 0 { - newDu.Denom = ibcBaseDenom - newDu.Aliases = append(newDu.Aliases, du.Denom) - } - metadata.DenomUnits[j] = &newDu - } - - // validate metadata - if validity := metadata.Validate(); validity != nil { - return fmt.Errorf("invalid denom metadata on genesis event: %w", validity) - } - - // save the new token denom metadata - if err := k.denommetadataKeeper.CreateDenomMetadata(ctx, metadata); err != nil { - return fmt.Errorf("create denom metadata: %w", err) - } - - k.Logger(ctx).Info("registered denom metadata for IBC token", "rollappID", rollapp.RollappId, "denom", ibcBaseDenom) - } - return nil -} - -func (k Keeper) mintRollappGenesisTokens(ctx sdk.Context, rollapp types.Rollapp) error { - for _, acc := range rollapp.GenesisState.GenesisAccounts { - ibcBaseDenom := utils.GetForeignDenomTrace(rollapp.ChannelId, acc.Amount.Denom).IBCDenom() - coinsToMint := sdk.NewCoins(sdk.NewCoin(ibcBaseDenom, acc.Amount.Amount)) - - if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, coinsToMint); err != nil { - return fmt.Errorf("mint coins: %w", err) - } - - accAddress, err := sdk.AccAddressFromBech32(acc.Address) - if err != nil { - return fmt.Errorf("convert account address: %w", err) - } - - if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, accAddress, coinsToMint); err != nil { - return fmt.Errorf("send coins to account: %w", err) - } - } - return nil -} - -// SetTransferKeeper MUST be called to set the IBC client keeper. -func (k *Keeper) SetTransferKeeper(tk types.TransferKeeper) { - if k.transferKeeper != nil { - panic("cannot set transfer keeper twice") - } - k.transferKeeper = tk -} - /* -------------------------------------------------------------------------- */ /* Hooks */ /* -------------------------------------------------------------------------- */ -// SetHooks sets the rollapp hooks func (k *Keeper) SetHooks(sh types.MultiRollappHooks) { if k.hooks != nil { panic("cannot set rollapp hooks twice") diff --git a/x/rollapp/keeper/msg_server.go b/x/rollapp/keeper/msg_server.go index 3515c3da0..77d78ce33 100644 --- a/x/rollapp/keeper/msg_server.go +++ b/x/rollapp/keeper/msg_server.go @@ -1,11 +1,6 @@ package keeper import ( - "context" - - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - tenderminttypes "github.com/cosmos/ibc-go/v6/modules/light-clients/07-tendermint/types" "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) @@ -20,42 +15,3 @@ func NewMsgServerImpl(keeper Keeper) types.MsgServer { } var _ types.MsgServer = msgServer{} - -func (k msgServer) TriggerGenesisEvent(goCtx context.Context, msg *types.MsgRollappGenesisEvent) (*types.MsgRollappGenesisEventResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - - // Get the sender and validate they are in the whitelist - if whitelist := k.DeployerWhitelist(ctx); len(whitelist) > 0 { - if !k.IsAddressInDeployerWhiteList(ctx, msg.Address) { - return nil, types.ErrUnauthorized - } - } - - // Get the rollapp - rollapp, found := k.GetRollapp(ctx, msg.RollappId) - if !found { - return nil, types.ErrUnknownRollappID - } - - // Get the channel and validate it's connected client chain is the same as the rollapp's - _, clientState, err := k.channelKeeper.GetChannelClientState(ctx, "transfer", msg.ChannelId) - if err != nil { - return nil, err - } - tmClientState, ok := clientState.(*tenderminttypes.ClientState) - if !ok { - return nil, errorsmod.Wrapf(types.ErrInvalidGenesisChannelId, "expected tendermint client state, got %T", clientState) - } - if tmClientState.GetChainID() != msg.RollappId { - return nil, errorsmod.Wrapf(types.ErrInvalidGenesisChannelId, "channel %s is connected to chain ID %s, expected %s", - msg.ChannelId, tmClientState.GetChainID(), msg.RollappId) - } - - // Update the rollapp with the channelID and trigger the genesis event - rollapp.ChannelId = msg.ChannelId - if err = k.TriggerRollappGenesisEvent(ctx, rollapp); err != nil { - return nil, err - } - - return &types.MsgRollappGenesisEventResponse{}, nil -} diff --git a/x/rollapp/keeper/msg_server_create_rollapp_test.go b/x/rollapp/keeper/msg_server_create_rollapp_test.go index a488ea814..4169f5f01 100644 --- a/x/rollapp/keeper/msg_server_create_rollapp_test.go +++ b/x/rollapp/keeper/msg_server_create_rollapp_test.go @@ -43,10 +43,10 @@ func (suite *RollappTestSuite) createRollappAndVerify(numOfAddresses int, expect queryResponse, err := suite.queryClient.Rollapp(goCtx, &types.QueryGetRollappRequest{ RollappId: rollapp.GetRollappId(), }) + suite.Require().Nil(err) if queryResponse.Rollapp.PermissionedAddresses == nil { queryResponse.Rollapp.PermissionedAddresses = []string{} } - suite.Require().Nil(err) suite.Require().EqualValues(&rollappExpect, &queryResponse.Rollapp) rollappSummaryExpect := types.RollappSummary{ diff --git a/x/rollapp/keeper/msg_server_update_state_test.go b/x/rollapp/keeper/msg_server_update_state_test.go index 930b3785d..7ceafad35 100644 --- a/x/rollapp/keeper/msg_server_update_state_test.go +++ b/x/rollapp/keeper/msg_server_update_state_test.go @@ -109,6 +109,7 @@ func (suite *RollappTestSuite) TestUpdateState() { if i == 6 { disputePeriodInBlocks -= 3 } + suite.Ctx = suite.Ctx.WithBlockHeight(suite.Ctx.BlockHeader().Height + 1) goCtx = sdk.WrapSDKContext(suite.Ctx) @@ -126,7 +127,7 @@ func (suite *RollappTestSuite) TestUpdateState() { suite.Require().EqualValues(expectedFinalizationQueue, types.BlockHeightToFinalizationQueue{ CreationHeight: expectedStateInfo.CreationHeight, FinalizationQueue: []types.StateInfoIndex{latestStateInfoIndex}, - }) + }, "finalization queue", "i", i) // create new update updateState := types.MsgUpdateState{ @@ -156,7 +157,7 @@ func (suite *RollappTestSuite) TestUpdateState() { } // check finalization status change - pendingQueues := suite.App.RollappKeeper.GetAllFinalizationQueueUntilHeight(suite.Ctx, uint64(suite.Ctx.BlockHeader().Height)) + pendingQueues := suite.App.RollappKeeper.GetAllFinalizationQueueUntilHeightInclusive(suite.Ctx, uint64(suite.Ctx.BlockHeader().Height)) for _, finalizationQueue := range pendingQueues { diff --git a/x/rollapp/keeper/rollapp.go b/x/rollapp/keeper/rollapp.go index a398a14d7..a8a022226 100644 --- a/x/rollapp/keeper/rollapp.go +++ b/x/rollapp/keeper/rollapp.go @@ -1,6 +1,8 @@ package keeper import ( + "fmt" + "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/dymensionxyz/dymension/v3/x/rollapp/types" @@ -63,6 +65,14 @@ func (k Keeper) GetRollapp( return val, true } +func (k Keeper) MustGetRollapp(ctx sdk.Context, rollappId string) types.Rollapp { + ret, found := k.GetRollapp(ctx, rollappId) + if !found { + panic(fmt.Sprintf("rollapp not found: id: %s", rollappId)) + } + return ret +} + // RemoveRollapp removes a rollapp from the store using rollapp name func (k Keeper) RemoveRollapp( ctx sdk.Context, @@ -74,7 +84,7 @@ func (k Keeper) RemoveRollapp( )) } -// GetAllRollapp returns all rollapp +// GetAllRollapps returns all rollapp func (k Keeper) GetAllRollapps(ctx sdk.Context) (list []types.Rollapp) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.RollappKeyPrefix)) iterator := sdk.KVStorePrefixIterator(store, []byte{}) diff --git a/x/rollapp/keeper/state_info.go b/x/rollapp/keeper/state_info.go index 37ac72f30..c2abda15a 100644 --- a/x/rollapp/keeper/state_info.go +++ b/x/rollapp/keeper/state_info.go @@ -36,6 +36,17 @@ func (k Keeper) GetStateInfo( return val, true } +// GetLatestStateInfo is utility +func (k Keeper) GetLatestStateInfo(ctx sdk.Context, + rollappId string, +) (types.StateInfo, bool) { + ix, ok := k.GetLatestStateInfoIndex(ctx, rollappId) + if !ok { + return types.StateInfo{}, false + } + return k.GetStateInfo(ctx, rollappId, ix.GetIndex()) +} + func (k Keeper) MustGetStateInfo(ctx sdk.Context, rollappId string, index uint64, diff --git a/x/rollapp/keeper/util.go b/x/rollapp/keeper/util.go deleted file mode 100644 index b0ac4918b..000000000 --- a/x/rollapp/keeper/util.go +++ /dev/null @@ -1,85 +0,0 @@ -package keeper - -import ( - "fmt" - - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" - ibctypes "github.com/cosmos/ibc-go/v6/modules/light-clients/07-tendermint/types" - - "github.com/dymensionxyz/dymension/v3/x/rollapp/types" -) - -// ExtractRollappIDAndTransferPacketFromData extracts the rollapp ID and fungible token from the packet data -// Returns an empty string if the rollapp is not found -func (k Keeper) ExtractRollappIDAndTransferPacketFromData( - ctx sdk.Context, - data []byte, - rollappPortOnHub string, - rollappChannelOnHub string, -) (string, *transfertypes.FungibleTokenPacketData, error) { - // no-op if the packet is not a fungible token packet - packet := new(transfertypes.FungibleTokenPacketData) - if err := types.ModuleCdc.UnmarshalJSON(data, packet); err != nil { - return "", packet, errorsmod.Wrapf(err, "unmarshal packet data") - } - - rollapp, err := k.ExtractRollappFromChannel(ctx, rollappPortOnHub, rollappChannelOnHub) - if err != nil { - return "", packet, err - } - - if rollapp == nil { - return "", packet, nil - } - - return rollapp.RollappId, packet, nil -} - -// ExtractRollappFromChannel extracts the rollapp from the IBC port and channel. -// Returns nil if the rollapp is not found. -func (k Keeper) ExtractRollappFromChannel( - ctx sdk.Context, - rollappPortOnHub string, - rollappChannelOnHub string, -) (*types.Rollapp, error) { - // Check if the packet is destined for a rollapp - chainID, err := k.ExtractChainIDFromChannel(ctx, rollappPortOnHub, rollappChannelOnHub) - if err != nil { - return nil, err - } - - rollapp, found := k.GetRollapp(ctx, chainID) - if !found { - return nil, nil - } - - if rollapp.ChannelId == "" { - return nil, errorsmod.Wrapf(types.ErrGenesisEventNotTriggered, "empty channel id: rollap id: %s", chainID) - } - // check if the channelID matches the rollappID's channelID - if rollapp.ChannelId != rollappChannelOnHub { - return nil, errorsmod.Wrapf( - types.ErrMismatchedChannelID, - "channel id mismatch: expect: %s: got: %s", rollapp.ChannelId, rollappChannelOnHub, - ) - } - - return &rollapp, nil -} - -// ExtractChainIDFromChannel extracts the chain ID from the channel -func (k Keeper) ExtractChainIDFromChannel(ctx sdk.Context, portID string, channelID string) (string, error) { - _, clientState, err := k.channelKeeper.GetChannelClientState(ctx, portID, channelID) - if err != nil { - return "", fmt.Errorf("extract clientID from channel: %w", err) - } - - tmClientState, ok := clientState.(*ibctypes.ClientState) - if !ok { - return "", nil - } - - return tmClientState.ChainId, nil -} diff --git a/x/rollapp/module.go b/x/rollapp/module.go index 36af6ade6..3cbca044d 100644 --- a/x/rollapp/module.go +++ b/x/rollapp/module.go @@ -5,6 +5,8 @@ import ( "encoding/json" "fmt" + simulationtypes "github.com/dymensionxyz/dymension/v3/simulation/types" + "github.com/gorilla/mux" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" @@ -100,15 +102,15 @@ type AppModule struct { AppModuleBasic keeper *keeper.Keeper - accountKeeper types.AccountKeeper - bankKeeper types.BankKeeper + accountKeeper simulationtypes.AccountKeeper + bankKeeper simulationtypes.BankKeeper } func NewAppModule( cdc codec.Codec, keeper *keeper.Keeper, - accountKeeper types.AccountKeeper, - bankKeeper types.BankKeeper, + accountKeeper simulationtypes.AccountKeeper, + bankKeeper simulationtypes.BankKeeper, ) AppModule { return AppModule{ AppModuleBasic: NewAppModuleBasic(cdc), @@ -177,7 +179,7 @@ func (am AppModule) GetHooks() []types.RollappHooks { // EndBlock executes all ABCI EndBlock logic respective to the capability module. It // returns no validator updates. func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { - err := am.keeper.FinalizeQueue(ctx) + err := am.keeper.FinalizeRollappStates(ctx) if err != nil { // we failed finalizing the queue for one or more rollapps. // we choose not to panic as it's not invariant breaking and the consequences are diff --git a/x/rollapp/module_simulation.go b/x/rollapp/module_simulation.go index b892e3503..df863e76b 100644 --- a/x/rollapp/module_simulation.go +++ b/x/rollapp/module_simulation.go @@ -88,7 +88,7 @@ func (am AppModule) WeightedOperations(simState module.SimulationState) []simtyp ) operations = append(operations, simulation.NewWeightedOperation( weightMsgCreateRollapp, - rollappsimulation.SimulateMsgCreateRollapp(am.accountKeeper, am.bankKeeper, *am.keeper), + rollappsimulation.SimulateMsgCreateRollapp(am.accountKeeper, am.bankKeeper), )) var weightMsgUpdateState int @@ -99,7 +99,7 @@ func (am AppModule) WeightedOperations(simState module.SimulationState) []simtyp ) operations = append(operations, simulation.NewWeightedOperation( weightMsgUpdateState, - rollappsimulation.SimulateMsgUpdateState(am.accountKeeper, am.bankKeeper, *am.keeper), + rollappsimulation.SimulateMsgUpdateState(am.accountKeeper, am.bankKeeper), )) // this line is used by starport scaffolding # simapp/module/operation diff --git a/x/rollapp/simulation/create_rollapp.go b/x/rollapp/simulation/create_rollapp.go index c5c4450b6..f6fd37db7 100644 --- a/x/rollapp/simulation/create_rollapp.go +++ b/x/rollapp/simulation/create_rollapp.go @@ -9,15 +9,10 @@ import ( simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/dymensionxyz/dymension/v3/simulation" simulationtypes "github.com/dymensionxyz/dymension/v3/simulation/types" - "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper" "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) -func SimulateMsgCreateRollapp( - ak types.AccountKeeper, - bk types.BankKeeper, - k keeper.Keeper, -) simtypes.Operation { +func SimulateMsgCreateRollapp(ak simulationtypes.AccountKeeper, bk simulationtypes.BankKeeper) simtypes.Operation { return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { // choose creator and rollappId @@ -61,8 +56,6 @@ func SimulateMsgCreateRollapp( PermissionedAddresses: permissionedAddresses, } - // fmt.Printf("SimulateMsgCreateRollapp: RollappId(%s) bFailMaxSequencers(%t) bFailMaxWithholdingBlocks(%t) bFailDuplicateSequencer(%t)\n", - // msg.RollappId, bFailMaxSequencers, bFailMaxWithholdingBlocks, bFailDuplicateSequencer) bExpectedError := bFailMaxSequencers || bFailDuplicateSequencer || bAlreadyExists if !bExpectedError { diff --git a/x/rollapp/simulation/update_state.go b/x/rollapp/simulation/update_state.go index 0b7b9b91e..0f4eba52d 100644 --- a/x/rollapp/simulation/update_state.go +++ b/x/rollapp/simulation/update_state.go @@ -7,14 +7,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/dymensionxyz/dymension/v3/simulation" - "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper" + simulationtypes "github.com/dymensionxyz/dymension/v3/simulation/types" "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) func SimulateMsgUpdateState( - ak types.AccountKeeper, - bk types.BankKeeper, - k keeper.Keeper, + ak simulationtypes.AccountKeeper, + bk simulationtypes.BankKeeper, ) simtypes.Operation { return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { @@ -84,19 +83,6 @@ func SimulateMsgUpdateState( simulation.GlobalRollappList[rollappIndex].LastCreationHeight = uint64(ctx.BlockHeight()) } - // println("LastCreationHeight: ", simulation.GlobalRollappList[rollappIndex].LastCreationHeight) - // println("BlockHeight: ", uint64(ctx.BlockHeight())) - // println(" bExpectedError: ", bExpectedError) - // println(" bNotActive: ", bNotActive) - // println(" bWrongRollapp: ", bWrongRollapp) - // println(" bNoBds: ", bNoBds) - // println(" bWrongStartHeight: ", bWrongStartHeight) - // println(" startHeight: ", startHeight) - // println(" bStateWasUpdatedInThisHeight: ", bStateWasUpdatedInThisHeight) - // for _, item := range k.GetAllStateInfo(ctx) { - // println("CreationHeight: ", item.CreationHeight) - // } - return simulation.GenAndDeliverMsgWithRandFees(msg, msg.Type(), types.ModuleName, r, app, &ctx, &sequencer.Account, bk, ak, nil, bExpectedError) } } diff --git a/x/rollapp/transfergenesis/doc.go b/x/rollapp/transfergenesis/doc.go new file mode 100644 index 000000000..a76576823 --- /dev/null +++ b/x/rollapp/transfergenesis/doc.go @@ -0,0 +1,12 @@ +// Package transfergenesis is the most important piece of the transfer genesis ('genesis bridge') protocol. +// +// The protocol is as follows: +// +// Rollapps may specify some transfers in THEIR genesis file +// The transfers will be sent in OnChanOpenConfirm +// The hub will receive the transfers in any order +// Before all transfers have arrived, the Hub will reject any OTHER (user submitted) transfers to/from the Rollapp +// After all transfers have arrived, the Hub will accept any transfers, as usual. +// Imporant: it is now WRONG to open an ibc connection in the Rollapp->Hub direction. +// Connections should be opened in the Hub->Rollapp direction only +package transfergenesis diff --git a/x/rollapp/transfergenesis/ibc_module.go b/x/rollapp/transfergenesis/ibc_module.go new file mode 100644 index 000000000..c1c97e3ec --- /dev/null +++ b/x/rollapp/transfergenesis/ibc_module.go @@ -0,0 +1,248 @@ +package transfergenesis + +import ( + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/dymensionxyz/dymension/v3/utils/derr" + commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + uibc "github.com/dymensionxyz/dymension/v3/utils/ibc" + + "github.com/dymensionxyz/dymension/v3/x/rollapp/types" + + "github.com/dymensionxyz/dymension/v3/utils/gerr" + + "github.com/tendermint/tendermint/libs/log" + + transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types" + "github.com/cosmos/ibc-go/v6/modules/core/exported" + delayedackkeeper "github.com/dymensionxyz/dymension/v3/x/delayedack/keeper" + rollappkeeper "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper" + rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" +) + +const ( + memoNamespaceKey = "genesis_transfer" +) + +type DenomMetadataKeeper interface { + CreateDenomMetadata(ctx sdk.Context, metadata banktypes.Metadata) error + HasDenomMetadata(ctx sdk.Context, base string) bool +} + +type TransferKeeper interface { + SetDenomTrace(ctx sdk.Context, denomTrace transfertypes.DenomTrace) +} + +type IBCModule struct { + porttypes.IBCModule // next one + delayedackKeeper delayedackkeeper.Keeper + rollappKeeper rollappkeeper.Keeper + transferKeeper TransferKeeper + denomKeeper DenomMetadataKeeper +} + +func NewIBCModule( + next porttypes.IBCModule, + delayedAckKeeper delayedackkeeper.Keeper, + rollappKeeper rollappkeeper.Keeper, + transferKeeper TransferKeeper, + denomKeeper DenomMetadataKeeper, +) IBCModule { + return IBCModule{ + IBCModule: next, + delayedackKeeper: delayedAckKeeper, + rollappKeeper: rollappKeeper, + transferKeeper: transferKeeper, + denomKeeper: denomKeeper, + } +} + +func (w IBCModule) logger( + ctx sdk.Context, + packet channeltypes.Packet, +) log.Logger { + return ctx.Logger().With( + "module", "transferGenesis", + "packet_source_port", packet.SourcePort, + "packet_destination_port", packet.DestinationPort, + "packet_sequence", packet.Sequence, + "method", "OnRecvPacket", + ) +} + +// OnRecvPacket will, if the packet is a transfer packet: +// if it's not a genesis transfer: pass on the packet only if transfers are enabled +// else: check it's a valid genesis transfer. If it is, then register the denom, if +// it's the last one, open the bridge. +// NOTE: we assume that by this point the canonical channel ID has already been set +// for the rollapp, in a secure way. +func (w IBCModule) OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, + relayer sdk.AccAddress, +) exported.Acknowledgement { + l := w.logger(ctx, packet) + + if commontypes.SkipRollappMiddleware(ctx) || !w.delayedackKeeper.IsRollappsEnabled(ctx) { + return w.IBCModule.OnRecvPacket(ctx, packet, relayer) + } + + transfer, err := w.rollappKeeper.GetValidTransfer(ctx, packet.GetData(), packet.GetDestPort(), packet.GetDestChannel()) + if err != nil { + l.Error("Get valid transfer from received packet", "err", err) + return channeltypes.NewErrorAcknowledgement(errorsmod.Wrap(err, "transfer genesis: get valid transfer")) + } + + if !transfer.IsRollapp() { + l.Debug("Transfer is not from a rollapp.") + return w.IBCModule.OnRecvPacket(ctx, packet, relayer) + } + + memo, err := getMemo(transfer.GetMemo()) + if errorsmod.IsOf(err, gerr.ErrNotFound) { + // If someone tries to send a transfer without the memo before the bridge is open, they will + // be blocked at the transfersenabled middleware + return w.IBCModule.OnRecvPacket(ctx, packet, relayer) + } + if err != nil { + l.Error("Get memo.", "err", err) + return channeltypes.NewErrorAcknowledgement(errorsmod.Wrap(err, "get memo")) + } + + ra := transfer.Rollapp + + nTransfersDone, err := w.rollappKeeper.VerifyAndRecordGenesisTransfer(ctx, ra.RollappId, memo.TotalNumTransfers) + if errorsmod.IsOf(err, derr.ErrViolatesDymensionRollappStandard) { + // The rollapp has deviated from the protocol! + handleFraudErr := w.handleFraud(ra.RollappId) + if err != nil { + l.Error("Handling fraud.", "err", handleFraudErr) + } else { + l.Info("Handled fraud: verify and record genesis transfer.", "err", err) + } + return channeltypes.NewErrorAcknowledgement(errorsmod.Wrap(err, "transfer genesis")) + } + if err != nil { + l.Error("Verify and record transfer.", "err", err) + return channeltypes.NewErrorAcknowledgement(errorsmod.Wrap(err, "transfer genesis: verify and record")) + } + + // it's a valid genesis transfer! + + err = w.registerDenomMetadata(ctx, ra.RollappId, ra.ChannelId, memo.Denom) + if err != nil { + l.Error("Register denom metadata.", "err", err) + return channeltypes.NewErrorAcknowledgement(errorsmod.Wrap(err, "transfer genesis: register denom metadata")) + } + + l.Debug("Received valid genesis transfer. Registered denom data.", + "num total", memo.TotalNumTransfers, + "num received so far", nTransfersDone, + ) + + if nTransfersDone == memo.TotalNumTransfers { + // The transfer window is finished! + ctx.EventManager().EmitEvent(allTransfersReceivedEvent(ra.RollappId, nTransfersDone)) + w.rollappKeeper.EnableTransfers(ctx, ra.RollappId) + l.Info("All genesis transfers received, bridge opened.", + "rollapp", ra.RollappId, + "n transfers", nTransfersDone) + } + + l.Debug("Passing on the transfer down the stack, but skipping delayedack, the transferEnabled blocker and bridging fee.") + + return w.IBCModule.OnRecvPacket(commontypes.SkipRollappMiddlewareContext(ctx), packet, relayer) +} + +// handleFraud : the rollapp has violated the DRS! +func (w IBCModule) handleFraud(raID string) error { + // TODO: see https://github.com/dymensionxyz/dymension/issues/930 + return nil +} + +func allTransfersReceivedEvent(raID string, nReceived uint64) sdk.Event { + return sdk.NewEvent(types.EventTypeTransferGenesisAllReceived, + sdk.NewAttribute(types.AttributeKeyRollappId, raID), + sdk.NewAttribute(types.AttributeKeyTransferGenesisNReceived, strconv.FormatUint(nReceived, 10)), + ) +} + +func getMemo(rawMemo string) (rollapptypes.GenesisTransferMemo, error) { + if len(rawMemo) == 0 { + return rollapptypes.GenesisTransferMemo{}, gerr.ErrNotFound + } + + // check if the key is there, because we want to differentiate between people not sending us the data, vs + // them sending it but it being malformed + + keyMap := make(map[string]any) + + err := json.Unmarshal([]byte(rawMemo), &keyMap) + if err != nil { + return rollapptypes.GenesisTransferMemo{}, errorsmod.Wrap(errors.Join(gerr.ErrInvalidArgument, sdkerrors.ErrJSONUnmarshal), "rawMemo") + } + + if _, ok := keyMap[memoNamespaceKey]; !ok { + return rollapptypes.GenesisTransferMemo{}, gerr.ErrNotFound + } + + var m rollapptypes.GenesisTransferMemoNamespaced + err = json.Unmarshal([]byte(rawMemo), &m) + if err != nil { + return rollapptypes.GenesisTransferMemo{}, errorsmod.Wrap(errors.Join(gerr.ErrInvalidArgument, sdkerrors.ErrJSONUnmarshal), "rawMemo") + } + + if err := m.Data.Valid(); err != nil { + return rollapptypes.GenesisTransferMemo{}, errorsmod.Wrap(errors.Join(gerr.ErrInvalidArgument, err), "validate data") + } + return m.Data, nil +} + +func (w IBCModule) registerDenomMetadata(ctx sdk.Context, rollappID, channelID string, m banktypes.Metadata) error { + trace := uibc.GetForeignDenomTrace(channelID, m.Base) + m.Base = trace.IBCDenom() + + if w.denomKeeper.HasDenomMetadata(ctx, m.GetBase()) { + // Not strictly necessary but an easy optimisation, as, in general, we dont place restrictions on the number + // of genesis transfers that a rollapp might do. + return nil + } + + w.transferKeeper.SetDenomTrace(ctx, trace) + + /* + Change the base to the ibc denom, and add an alias to the original + */ + m.Description = fmt.Sprintf("auto-generated ibc denom for rollapp: base: %s: rollapp: %s", m.GetBase(), rollappID) + for i, u := range m.DenomUnits { + if u.Exponent == 0 { + m.DenomUnits[i].Aliases = append(m.DenomUnits[i].Aliases, u.Denom) + m.DenomUnits[i].Denom = m.GetBase() + } + } + + if err := m.Validate(); err != nil { + return errorsmod.Wrap(errors.Join(gerr.ErrInvalidArgument, err), "metadata validate") + } + + // We go by the denom keeper instead of calling bank directly, as something might happen in-between + err := w.denomKeeper.CreateDenomMetadata(ctx, m) + if err != nil { + return errorsmod.Wrap(err, "create denom metadata") + } + + return nil +} diff --git a/x/rollapp/transfergenesis/ibc_module_canonical_channel_hack.go b/x/rollapp/transfergenesis/ibc_module_canonical_channel_hack.go new file mode 100644 index 000000000..e9ede4812 --- /dev/null +++ b/x/rollapp/transfergenesis/ibc_module_canonical_channel_hack.go @@ -0,0 +1,52 @@ +package transfergenesis + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types" + "github.com/cosmos/ibc-go/v6/modules/core/exported" + uibc "github.com/dymensionxyz/dymension/v3/utils/ibc" + rollappkeeper "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper" +) + +/* +TODO: this whole file is temporary + Prior to this we relied on the whitelist addr to set the canonical channel, but that is no longer possible + This currently file is a hack (not secure) + The real solution will come in a followup PR + See https://github.com/dymensionxyz/research/issues/242 +*/ + +type IBCModuleCanonicalChannelHack struct { + porttypes.IBCModule // next one + rollappKeeper rollappkeeper.Keeper + channelKeeper uibc.GetChannelClientState +} + +func NewIBCModuleCanonicalChannelHack( + next porttypes.IBCModule, + rollappKeeper rollappkeeper.Keeper, + channelKeeper uibc.GetChannelClientState, +) *IBCModuleCanonicalChannelHack { + return &IBCModuleCanonicalChannelHack{IBCModule: next, rollappKeeper: rollappKeeper, channelKeeper: channelKeeper} +} + +func (w IBCModuleCanonicalChannelHack) OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, + relayer sdk.AccAddress, +) exported.Acknowledgement { + l := ctx.Logger().With("module", "hack set canonical channel") + + chainID, err := uibc.ChainIDFromPortChannel(ctx, w.channelKeeper, packet.GetDestPort(), packet.GetDestChannel()) + if err != nil { + return channeltypes.NewErrorAcknowledgement(err) + } + ra, ok := w.rollappKeeper.GetRollapp(ctx, chainID) + if ok && ra.ChannelId == "" { + ra.ChannelId = packet.GetDestChannel() + w.rollappKeeper.SetRollapp(ctx, ra) + l.Info("Set the canonical channel.", "channel id", packet.GetDestChannel()) + } + return w.IBCModule.OnRecvPacket(ctx, packet, relayer) +} diff --git a/x/rollapp/transfergenesis/memo_test.go b/x/rollapp/transfergenesis/memo_test.go new file mode 100644 index 000000000..a53da5119 --- /dev/null +++ b/x/rollapp/transfergenesis/memo_test.go @@ -0,0 +1,83 @@ +package transfergenesis + +import ( + "testing" + + rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" + + errorsmod "cosmossdk.io/errors" + + "github.com/dymensionxyz/dymension/v3/utils/gerr" + + _ "embed" + + "github.com/stretchr/testify/require" + + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +func Test_getExample(t *testing.T) { + t.Skip("Not a real test. You can use this during development to quickly generate example json") + + m := rollapptypes.GenesisTransferMemo{ + Denom: banktypes.Metadata{ + Description: "The native staking and governance token of the rollappevm_1234-1", + DenomUnits: make([]*banktypes.DenomUnit, 2), + Base: "arax", + Display: "rax", + Name: "rax", + Symbol: "rax", + }, + TotalNumTransfers: 42, + } + m.Denom.DenomUnits[0] = &banktypes.DenomUnit{ + Denom: "arax", + } + m.Denom.DenomUnits[1] = &banktypes.DenomUnit{ + Denom: "rax", + Exponent: 18, + } + m.TotalNumTransfers = 42 + + t.Log(m.Namespaced().MustString()) +} + +var ( + //go:embed testdata/memo_malformed.json + memoMalformedBz string + //go:embed testdata/memo_happy_path.json + memoHappyPath string + //go:embed testdata/memo_happy_path_with_other_namespace.json + memoHappyPathWithOtherNamespace string + //go:embed testdata/memo_namespace_empty.json + memoNamespaceEmpty string +) + +func TestGetMemo(t *testing.T) { + t.Run("empty str: returns not found", func(t *testing.T) { + _, err := getMemo("") + require.True(t, errorsmod.IsOf(err, gerr.ErrNotFound)) + }) + t.Run("empty json: returns not found", func(t *testing.T) { + _, err := getMemo("{}") + require.True(t, errorsmod.IsOf(err, gerr.ErrNotFound)) + }) + t.Run("does not have namespace key: returns not found", func(t *testing.T) { + _, err := getMemo(memoNamespaceEmpty) + require.True(t, errorsmod.IsOf(err, gerr.ErrNotFound)) + }) + t.Run("malformed: returns malformed", func(t *testing.T) { + _, err := getMemo(memoMalformedBz) + require.True(t, errorsmod.IsOf(err, gerr.ErrInvalidArgument)) + }) + t.Run("happy path: returns data", func(t *testing.T) { + m, err := getMemo(memoHappyPath) + require.NoError(t, err) + require.Equal(t, "arax", m.Denom.GetBase()) + }) + t.Run("happy path, with other namespace: returns data", func(t *testing.T) { + m, err := getMemo(memoHappyPathWithOtherNamespace) + require.NoError(t, err) + require.Equal(t, "arax", m.Denom.GetBase()) + }) +} diff --git a/x/rollapp/transfergenesis/testdata/memo_happy_path.json b/x/rollapp/transfergenesis/testdata/memo_happy_path.json new file mode 100644 index 000000000..026598a4d --- /dev/null +++ b/x/rollapp/transfergenesis/testdata/memo_happy_path.json @@ -0,0 +1,21 @@ +{ + "genesis_transfer": { + "denom": { + "description": "The native staking and governance token of the rollappevm_1234-1", + "denom_units": [ + { + "denom": "arax" + }, + { + "denom": "rax", + "exponent": 18 + } + ], + "base": "arax", + "display": "rax", + "name": "rax", + "symbol": "rax" + }, + "total_num_transfers": 42 + } +} \ No newline at end of file diff --git a/x/rollapp/transfergenesis/testdata/memo_happy_path_with_other_namespace.json b/x/rollapp/transfergenesis/testdata/memo_happy_path_with_other_namespace.json new file mode 100644 index 000000000..f23083b7d --- /dev/null +++ b/x/rollapp/transfergenesis/testdata/memo_happy_path_with_other_namespace.json @@ -0,0 +1,23 @@ +{ + "genesis_transfer": { + "denom": { + "description": "The native staking and governance token of the rollappevm_1234-1", + "denom_units": [ + { + "denom": "arax" + }, + { + "denom": "rax", + "exponent": 18 + } + ], + "base": "arax", + "display": "rax", + "name": "rax", + "symbol": "rax" + }, + "total_num_transfers": 42 + }, + "foobar" : "some stuff", + "foobar2" : "some stuff" +} \ No newline at end of file diff --git a/x/rollapp/transfergenesis/testdata/memo_malformed.json b/x/rollapp/transfergenesis/testdata/memo_malformed.json new file mode 100644 index 000000000..8f8b02223 --- /dev/null +++ b/x/rollapp/transfergenesis/testdata/memo_malformed.json @@ -0,0 +1,15 @@ +{ + "genesis_transfer": { + "denom": { + "description": "The native staking and governance token of the rollappevm_1234-1", + "denom_units": { + "foobar": "xyz" + }, + "base": "arax", + "display": "rax", + "name": "rax", + "symbol": 42 + }, + "total_num_transfers": 0 + } +} \ No newline at end of file diff --git a/x/rollapp/transfergenesis/testdata/memo_namespace_empty.json b/x/rollapp/transfergenesis/testdata/memo_namespace_empty.json new file mode 100644 index 000000000..bb132676c --- /dev/null +++ b/x/rollapp/transfergenesis/testdata/memo_namespace_empty.json @@ -0,0 +1,4 @@ +{ + "foobar" : "some stuff", + "foobar2" : "some stuff" +} \ No newline at end of file diff --git a/x/rollapp/transfersenabled/ante_decorator.go b/x/rollapp/transfersenabled/ante_decorator.go new file mode 100644 index 000000000..4d67a4580 --- /dev/null +++ b/x/rollapp/transfersenabled/ante_decorator.go @@ -0,0 +1,59 @@ +package transfersenabled + +import ( + uibc "github.com/dymensionxyz/dymension/v3/utils/ibc" + + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + transferTypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + "github.com/dymensionxyz/dymension/v3/utils/gerr" + "github.com/dymensionxyz/dymension/v3/x/rollapp/types" +) + +type GetRollapp func(ctx sdk.Context, rollappId string) (val types.Rollapp, found bool) + +type Decorator struct { + getRollapp GetRollapp + getChannelClientState uibc.GetChannelClientState +} + +func NewDecorator(getRollapp GetRollapp, getChannelClientState uibc.GetChannelClientState) *Decorator { + return &Decorator{ + getRollapp: getRollapp, + getChannelClientState: getChannelClientState, + } +} + +func (h Decorator) transfersEnabled(ctx sdk.Context, transfer *transferTypes.MsgTransfer) (bool, error) { + chainID, err := uibc.ChainIDFromPortChannel(ctx, h.getChannelClientState, transfer.SourcePort, transfer.SourceChannel) + if err != nil { + return false, errorsmod.Wrap(err, "chain id from port channel") + } + ra, ok := h.getRollapp(ctx, chainID) + if !ok { + return true, nil + } + return ra.GenesisState.TransfersEnabled, nil +} + +func (h Decorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { + for _, msg := range tx.GetMsgs() { + typeURL := sdk.MsgTypeURL(msg) + if typeURL == sdk.MsgTypeURL(&transferTypes.MsgTransfer{}) { + m, ok := msg.(*transferTypes.MsgTransfer) + if !ok { + return ctx, errorsmod.Wrap(gerr.ErrUnknown, "type url matched transfer type url but could not type cast") + } + ok, err := h.transfersEnabled(ctx, m) + if err != nil { + return ctx, errorsmod.Wrap(err, "transfer genesis: transfers enabled") + } + if !ok { + return ctx, errorsmod.Wrap(gerr.ErrFailedPrecondition, "transfers to/from rollapp are disabled") + } + } + } + + return next(ctx, tx, simulate) +} diff --git a/x/rollapp/transfersenabled/ibc_module.go b/x/rollapp/transfersenabled/ibc_module.go new file mode 100644 index 000000000..111c5a7b6 --- /dev/null +++ b/x/rollapp/transfersenabled/ibc_module.go @@ -0,0 +1,77 @@ +package transfersenabled + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types" + "github.com/cosmos/ibc-go/v6/modules/core/exported" + "github.com/dymensionxyz/dymension/v3/utils/gerr" + commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" + delayedackkeeper "github.com/dymensionxyz/dymension/v3/x/delayedack/keeper" + rollappkeeper "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper" + "github.com/tendermint/tendermint/libs/log" +) + +type IBCModule struct { + porttypes.IBCModule // next one + rollappKeeper rollappkeeper.Keeper + delayedackKeeper delayedackkeeper.Keeper +} + +func NewIBCModule( + next porttypes.IBCModule, + rollappKeeper rollappkeeper.Keeper, + delayedAckKeeper delayedackkeeper.Keeper, +) IBCModule { + return IBCModule{ + IBCModule: next, + rollappKeeper: rollappKeeper, + delayedackKeeper: delayedAckKeeper, + } +} + +func (w IBCModule) logger( + ctx sdk.Context, + packet channeltypes.Packet, +) log.Logger { + return ctx.Logger().With( + "module", "transferEnabled", + "packet_source_port", packet.SourcePort, + "packet_destination_port", packet.DestinationPort, + "packet_sequence", packet.Sequence, + "method", "OnRecvPacket", + ) +} + +// OnRecvPacket will block any packet from a rollapp for which transfers are not enabled +// for that rollapp. Pass a skip context to skip the check. +func (w IBCModule) OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, + relayer sdk.AccAddress, +) exported.Acknowledgement { + l := w.logger(ctx, packet) + + if commontypes.SkipRollappMiddleware(ctx) || !w.delayedackKeeper.IsRollappsEnabled(ctx) { + return w.IBCModule.OnRecvPacket(ctx, packet, relayer) + } + + transfer, err := w.rollappKeeper.GetValidTransfer(ctx, packet.GetData(), packet.GetDestPort(), packet.GetDestChannel()) + if err != nil { + return channeltypes.NewErrorAcknowledgement(errorsmod.Wrap(err, "transfer enabled?: get valid transfer")) + } + + if !transfer.IsRollapp() { + return w.IBCModule.OnRecvPacket(ctx, packet, relayer) + } + + if !transfer.Rollapp.GenesisState.TransfersEnabled { + // Someone on the RA tried to send a transfer before the bridge is open! Return an err ack and they will get refunded + err = errorsmod.Wrapf(gerr.ErrFailedPrecondition, "transfers are disabled: rollapp id: %s", transfer.Rollapp.RollappId) + l.Debug("Returning error ack.", "err", err) + return channeltypes.NewErrorAcknowledgement(err) + } + + return w.IBCModule.OnRecvPacket(ctx, packet, relayer) +} diff --git a/x/rollapp/types/bank.pb.go b/x/rollapp/types/bank.pb.go deleted file mode 100644 index 4d31c12af..000000000 --- a/x/rollapp/types/bank.pb.go +++ /dev/null @@ -1,986 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dymension/rollapp/bank.proto - -package types - -import ( - fmt "fmt" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -// DenomUnit represents a struct that describes a given -// denomination unit of the basic token. -type DenomUnit struct { - // denom represents the string name of the given denom unit (e.g uatom). - Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` - // exponent represents power of 10 exponent that one must - // raise the base_denom to in order to equal the given DenomUnit's denom - // 1 denom = 10^exponent base_denom - // (e.g. with a base_denom of uatom, one can create a DenomUnit of 'atom' with - // exponent = 6, thus: 1 atom = 10^6 uatom). - Exponent uint32 `protobuf:"varint,2,opt,name=exponent,proto3" json:"exponent,omitempty"` - // aliases is a list of string aliases for the given denom - Aliases []string `protobuf:"bytes,3,rep,name=aliases,proto3" json:"aliases,omitempty"` -} - -func (m *DenomUnit) Reset() { *m = DenomUnit{} } -func (m *DenomUnit) String() string { return proto.CompactTextString(m) } -func (*DenomUnit) ProtoMessage() {} -func (*DenomUnit) Descriptor() ([]byte, []int) { - return fileDescriptor_e7bcc95cdae840f1, []int{0} -} -func (m *DenomUnit) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *DenomUnit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_DenomUnit.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *DenomUnit) XXX_Merge(src proto.Message) { - xxx_messageInfo_DenomUnit.Merge(m, src) -} -func (m *DenomUnit) XXX_Size() int { - return m.Size() -} -func (m *DenomUnit) XXX_DiscardUnknown() { - xxx_messageInfo_DenomUnit.DiscardUnknown(m) -} - -var xxx_messageInfo_DenomUnit proto.InternalMessageInfo - -func (m *DenomUnit) GetDenom() string { - if m != nil { - return m.Denom - } - return "" -} - -func (m *DenomUnit) GetExponent() uint32 { - if m != nil { - return m.Exponent - } - return 0 -} - -func (m *DenomUnit) GetAliases() []string { - if m != nil { - return m.Aliases - } - return nil -} - -// Metadata represents a struct that describes -// a basic token. -type TokenMetadata struct { - Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` - // denom_units represents the list of DenomUnit's for a given coin - DenomUnits []*DenomUnit `protobuf:"bytes,2,rep,name=denom_units,json=denomUnits,proto3" json:"denom_units,omitempty"` - // base represents the base denom (should be the DenomUnit with exponent = 0). - Base string `protobuf:"bytes,3,opt,name=base,proto3" json:"base,omitempty"` - // display indicates the suggested denom that should be - // displayed in clients. - Display string `protobuf:"bytes,4,opt,name=display,proto3" json:"display,omitempty"` - // name defines the name of the token (eg: Cosmos Atom) - // - // Since: cosmos-sdk 0.43 - Name string `protobuf:"bytes,5,opt,name=name,proto3" json:"name,omitempty"` - // symbol is the token symbol usually shown on exchanges (eg: ATOM). This can - // be the same as the display. - // - // Since: cosmos-sdk 0.43 - Symbol string `protobuf:"bytes,6,opt,name=symbol,proto3" json:"symbol,omitempty"` - // URI to a document (on or off-chain) that contains additional information. Optional. - // - // Since: cosmos-sdk 0.46 - URI string `protobuf:"bytes,7,opt,name=uri,proto3" json:"uri,omitempty"` - // URIHash is a sha256 hash of a document pointed by URI. It's used to verify that - // the document didn't change. Optional. - // - // Since: cosmos-sdk 0.46 - URIHash string `protobuf:"bytes,8,opt,name=uri_hash,json=uriHash,proto3" json:"uri_hash,omitempty"` -} - -func (m *TokenMetadata) Reset() { *m = TokenMetadata{} } -func (m *TokenMetadata) String() string { return proto.CompactTextString(m) } -func (*TokenMetadata) ProtoMessage() {} -func (*TokenMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_e7bcc95cdae840f1, []int{1} -} -func (m *TokenMetadata) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *TokenMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_TokenMetadata.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *TokenMetadata) XXX_Merge(src proto.Message) { - xxx_messageInfo_TokenMetadata.Merge(m, src) -} -func (m *TokenMetadata) XXX_Size() int { - return m.Size() -} -func (m *TokenMetadata) XXX_DiscardUnknown() { - xxx_messageInfo_TokenMetadata.DiscardUnknown(m) -} - -var xxx_messageInfo_TokenMetadata proto.InternalMessageInfo - -func (m *TokenMetadata) GetDescription() string { - if m != nil { - return m.Description - } - return "" -} - -func (m *TokenMetadata) GetDenomUnits() []*DenomUnit { - if m != nil { - return m.DenomUnits - } - return nil -} - -func (m *TokenMetadata) GetBase() string { - if m != nil { - return m.Base - } - return "" -} - -func (m *TokenMetadata) GetDisplay() string { - if m != nil { - return m.Display - } - return "" -} - -func (m *TokenMetadata) GetName() string { - if m != nil { - return m.Name - } - return "" -} - -func (m *TokenMetadata) GetSymbol() string { - if m != nil { - return m.Symbol - } - return "" -} - -func (m *TokenMetadata) GetURI() string { - if m != nil { - return m.URI - } - return "" -} - -func (m *TokenMetadata) GetURIHash() string { - if m != nil { - return m.URIHash - } - return "" -} - -func init() { - proto.RegisterType((*DenomUnit)(nil), "dymensionxyz.dymension.rollapp.DenomUnit") - proto.RegisterType((*TokenMetadata)(nil), "dymensionxyz.dymension.rollapp.TokenMetadata") -} - -func init() { proto.RegisterFile("dymension/rollapp/bank.proto", fileDescriptor_e7bcc95cdae840f1) } - -var fileDescriptor_e7bcc95cdae840f1 = []byte{ - // 375 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x92, 0xc1, 0x6a, 0xea, 0x40, - 0x14, 0x86, 0x8d, 0x51, 0xa3, 0x23, 0x6e, 0x06, 0xb9, 0xcc, 0x95, 0x4b, 0x0c, 0x2e, 0x2e, 0xb9, - 0x9b, 0x04, 0xae, 0x7d, 0x02, 0xe9, 0xa2, 0x16, 0xda, 0xc5, 0x50, 0x29, 0x74, 0x23, 0x13, 0x33, - 0x98, 0xc1, 0x64, 0x26, 0x64, 0x26, 0xc5, 0xf4, 0x29, 0xba, 0xee, 0x13, 0x75, 0xe9, 0xb2, 0x2b, - 0x29, 0xf1, 0x45, 0xca, 0x44, 0x4d, 0x5d, 0x75, 0xf7, 0x7f, 0xff, 0xf9, 0x87, 0x73, 0x0e, 0x73, - 0xc0, 0x9f, 0xb0, 0x48, 0x28, 0x97, 0x4c, 0x70, 0x3f, 0x13, 0x71, 0x4c, 0xd2, 0xd4, 0x0f, 0x08, - 0xdf, 0x78, 0x69, 0x26, 0x94, 0x80, 0x76, 0x5d, 0xdd, 0x16, 0x2f, 0x5e, 0x0d, 0xde, 0x29, 0x3a, - 0x1a, 0xae, 0xc5, 0x5a, 0x54, 0x51, 0x5f, 0xab, 0xe3, 0xab, 0xc9, 0x23, 0xe8, 0x5d, 0x53, 0x2e, - 0x92, 0x05, 0x67, 0x0a, 0x0e, 0x41, 0x3b, 0xd4, 0x80, 0x0c, 0xc7, 0x70, 0x7b, 0xf8, 0x08, 0x70, - 0x04, 0xba, 0x74, 0x9b, 0x0a, 0x4e, 0xb9, 0x42, 0x4d, 0xc7, 0x70, 0x07, 0xb8, 0x66, 0x88, 0x80, - 0x45, 0x62, 0x46, 0x24, 0x95, 0xc8, 0x74, 0x4c, 0xb7, 0x87, 0xcf, 0x38, 0x79, 0x6b, 0x82, 0xc1, - 0x83, 0xd8, 0x50, 0x7e, 0x47, 0x15, 0x09, 0x89, 0x22, 0xd0, 0x01, 0xfd, 0x90, 0xca, 0x55, 0xc6, - 0x52, 0xc5, 0x04, 0x3f, 0xf5, 0xb8, 0xb4, 0xe0, 0xad, 0x4e, 0x70, 0x91, 0x2c, 0x73, 0xce, 0x94, - 0x44, 0x4d, 0xc7, 0x74, 0xfb, 0xff, 0xff, 0x79, 0x3f, 0x2f, 0xe6, 0xd5, 0xf3, 0x63, 0x10, 0x9e, - 0xa5, 0x84, 0x10, 0xb4, 0x02, 0x22, 0x29, 0x32, 0xab, 0x36, 0x95, 0xd6, 0xd3, 0x86, 0x4c, 0xa6, - 0x31, 0x29, 0x50, 0xab, 0xb2, 0xcf, 0xa8, 0xd3, 0x9c, 0x24, 0x14, 0xb5, 0x8f, 0x69, 0xad, 0xe1, - 0x2f, 0xd0, 0x91, 0x45, 0x12, 0x88, 0x18, 0x75, 0x2a, 0xf7, 0x44, 0xf0, 0x37, 0x30, 0xf3, 0x8c, - 0x21, 0x4b, 0x9b, 0x33, 0xab, 0xdc, 0x8f, 0xcd, 0x05, 0x9e, 0x63, 0xed, 0xc1, 0xbf, 0xa0, 0x9b, - 0x67, 0x6c, 0x19, 0x11, 0x19, 0xa1, 0x6e, 0x55, 0xef, 0x97, 0xfb, 0xb1, 0xb5, 0xc0, 0xf3, 0x1b, - 0x22, 0x23, 0x6c, 0xe5, 0x19, 0xd3, 0x62, 0x76, 0xff, 0x5e, 0xda, 0xc6, 0xae, 0xb4, 0x8d, 0xcf, - 0xd2, 0x36, 0x5e, 0x0f, 0x76, 0x63, 0x77, 0xb0, 0x1b, 0x1f, 0x07, 0xbb, 0xf1, 0x74, 0xb5, 0x66, - 0x2a, 0xca, 0x03, 0x6f, 0x25, 0x12, 0xff, 0x72, 0xef, 0x6f, 0xf0, 0x9f, 0xa7, 0xfe, 0xb6, 0x3e, - 0x00, 0x55, 0xa4, 0x54, 0x06, 0x9d, 0xea, 0x33, 0xa7, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x3f, - 0x70, 0x1f, 0xd7, 0x22, 0x02, 0x00, 0x00, -} - -func (m *DenomUnit) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *DenomUnit) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *DenomUnit) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Aliases) > 0 { - for iNdEx := len(m.Aliases) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Aliases[iNdEx]) - copy(dAtA[i:], m.Aliases[iNdEx]) - i = encodeVarintBank(dAtA, i, uint64(len(m.Aliases[iNdEx]))) - i-- - dAtA[i] = 0x1a - } - } - if m.Exponent != 0 { - i = encodeVarintBank(dAtA, i, uint64(m.Exponent)) - i-- - dAtA[i] = 0x10 - } - if len(m.Denom) > 0 { - i -= len(m.Denom) - copy(dAtA[i:], m.Denom) - i = encodeVarintBank(dAtA, i, uint64(len(m.Denom))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *TokenMetadata) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *TokenMetadata) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *TokenMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.URIHash) > 0 { - i -= len(m.URIHash) - copy(dAtA[i:], m.URIHash) - i = encodeVarintBank(dAtA, i, uint64(len(m.URIHash))) - i-- - dAtA[i] = 0x42 - } - if len(m.URI) > 0 { - i -= len(m.URI) - copy(dAtA[i:], m.URI) - i = encodeVarintBank(dAtA, i, uint64(len(m.URI))) - i-- - dAtA[i] = 0x3a - } - if len(m.Symbol) > 0 { - i -= len(m.Symbol) - copy(dAtA[i:], m.Symbol) - i = encodeVarintBank(dAtA, i, uint64(len(m.Symbol))) - i-- - dAtA[i] = 0x32 - } - if len(m.Name) > 0 { - i -= len(m.Name) - copy(dAtA[i:], m.Name) - i = encodeVarintBank(dAtA, i, uint64(len(m.Name))) - i-- - dAtA[i] = 0x2a - } - if len(m.Display) > 0 { - i -= len(m.Display) - copy(dAtA[i:], m.Display) - i = encodeVarintBank(dAtA, i, uint64(len(m.Display))) - i-- - dAtA[i] = 0x22 - } - if len(m.Base) > 0 { - i -= len(m.Base) - copy(dAtA[i:], m.Base) - i = encodeVarintBank(dAtA, i, uint64(len(m.Base))) - i-- - dAtA[i] = 0x1a - } - if len(m.DenomUnits) > 0 { - for iNdEx := len(m.DenomUnits) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.DenomUnits[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintBank(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - } - if len(m.Description) > 0 { - i -= len(m.Description) - copy(dAtA[i:], m.Description) - i = encodeVarintBank(dAtA, i, uint64(len(m.Description))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func encodeVarintBank(dAtA []byte, offset int, v uint64) int { - offset -= sovBank(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *DenomUnit) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Denom) - if l > 0 { - n += 1 + l + sovBank(uint64(l)) - } - if m.Exponent != 0 { - n += 1 + sovBank(uint64(m.Exponent)) - } - if len(m.Aliases) > 0 { - for _, s := range m.Aliases { - l = len(s) - n += 1 + l + sovBank(uint64(l)) - } - } - return n -} - -func (m *TokenMetadata) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Description) - if l > 0 { - n += 1 + l + sovBank(uint64(l)) - } - if len(m.DenomUnits) > 0 { - for _, e := range m.DenomUnits { - l = e.Size() - n += 1 + l + sovBank(uint64(l)) - } - } - l = len(m.Base) - if l > 0 { - n += 1 + l + sovBank(uint64(l)) - } - l = len(m.Display) - if l > 0 { - n += 1 + l + sovBank(uint64(l)) - } - l = len(m.Name) - if l > 0 { - n += 1 + l + sovBank(uint64(l)) - } - l = len(m.Symbol) - if l > 0 { - n += 1 + l + sovBank(uint64(l)) - } - l = len(m.URI) - if l > 0 { - n += 1 + l + sovBank(uint64(l)) - } - l = len(m.URIHash) - if l > 0 { - n += 1 + l + sovBank(uint64(l)) - } - return n -} - -func sovBank(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozBank(x uint64) (n int) { - return sovBank(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *DenomUnit) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowBank - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: DenomUnit: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: DenomUnit: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowBank - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthBank - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthBank - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Denom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Exponent", wireType) - } - m.Exponent = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowBank - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Exponent |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Aliases", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowBank - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthBank - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthBank - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Aliases = append(m.Aliases, string(dAtA[iNdEx:postIndex])) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipBank(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthBank - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *TokenMetadata) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowBank - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: TokenMetadata: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: TokenMetadata: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowBank - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthBank - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthBank - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Description = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DenomUnits", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowBank - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthBank - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthBank - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.DenomUnits = append(m.DenomUnits, &DenomUnit{}) - if err := m.DenomUnits[len(m.DenomUnits)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Base", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowBank - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthBank - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthBank - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Base = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Display", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowBank - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthBank - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthBank - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Display = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowBank - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthBank - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthBank - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Name = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Symbol", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowBank - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthBank - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthBank - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Symbol = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 7: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field URI", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowBank - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthBank - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthBank - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.URI = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 8: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field URIHash", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowBank - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthBank - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthBank - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.URIHash = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipBank(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthBank - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipBank(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowBank - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowBank - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowBank - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthBank - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupBank - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthBank - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthBank = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowBank = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupBank = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/rollapp/types/codec.go b/x/rollapp/types/codec.go index 6e4725786..3c2307b21 100644 --- a/x/rollapp/types/codec.go +++ b/x/rollapp/types/codec.go @@ -12,11 +12,10 @@ import ( func RegisterCodec(cdc *codec.LegacyAmino) { cdc.RegisterConcrete(&MsgCreateRollapp{}, "rollapp/CreateRollapp", nil) cdc.RegisterConcrete(&MsgUpdateState{}, "rollapp/UpdateState", nil) - cdc.RegisterConcrete(&MsgRollappGenesisEvent{}, "rollapp/RollappGenesisEvent", nil) } func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { - registry.RegisterImplementations((*sdk.Msg)(nil), &MsgCreateRollapp{}, &MsgUpdateState{}, &MsgRollappGenesisEvent{}) + registry.RegisterImplementations((*sdk.Msg)(nil), &MsgCreateRollapp{}, &MsgUpdateState{}) registry.RegisterImplementations((*govtypes.Content)(nil), &SubmitFraudProposal{}) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } diff --git a/x/rollapp/types/errors.go b/x/rollapp/types/errors.go index 2f7eb4bb2..d115021c3 100644 --- a/x/rollapp/types/errors.go +++ b/x/rollapp/types/errors.go @@ -8,46 +8,30 @@ import ( // x/rollapp module sentinel errors var ( - ErrRollappExists = errorsmod.Register(ModuleName, 1000, "rollapp already exists for this rollapp-id; must use new rollapp-id") - ErrInvalidMaxSequencers = errorsmod.Register(ModuleName, 1001, "invalid max sequencers") - ErrInvalidCreatorAddress = errorsmod.Register(ModuleName, 1002, "invalid creator address") - ErrInvalidPermissionedAddress = errorsmod.Register(ModuleName, 1003, "invalid permissioned address") - ErrPermissionedAddressesDuplicate = errorsmod.Register(ModuleName, 1004, "permissioned-address has duplicates") - ErrInvalidNumBlocks = errorsmod.Register(ModuleName, 1005, "invalid number of blocks") - ErrInvalidBlockSequence = errorsmod.Register(ModuleName, 1006, "invalid block sequence") - ErrUnknownRollappID = errorsmod.Register(ModuleName, 1007, "rollapp does not exist") - ErrVersionMismatch = errorsmod.Register(ModuleName, 1008, "rollapp version mismatch") - ErrWrongBlockHeight = errorsmod.Register(ModuleName, 1009, "start-height does not match rollapps state") - ErrMultiUpdateStateInBlock = errorsmod.Register(ModuleName, 1010, "only one state update can take place per block") - ErrInvalidStateRoot = errorsmod.Register(ModuleName, 1011, "invalid blocks state root") - ErrUnauthorizedRollappCreator = errorsmod.Register(ModuleName, 1013, "rollapp creator not registered in the whitelist") - ErrInvalidClientType = errorsmod.Register(ModuleName, 1014, "client type of the rollapp isn't dymint") - ErrHeightStateNotFinalized = errorsmod.Register(ModuleName, 1015, "rollapp block on this height was not finalized yet") - ErrInvalidAppHash = errorsmod.Register(ModuleName, 1016, "the app hash is different from the finalized state root") - ErrStateNotExists = errorsmod.Register(ModuleName, 1017, "state of this height doesn't exist") - ErrInvalidHeight = errorsmod.Register(ModuleName, 1018, "invalid rollapp height") - ErrRollappCreatorExceedMaximumRollapps = errorsmod.Register(ModuleName, 1019, "rollapp creator exceeds maximum allowed rollapps as registered in the whitelist") - ErrInvalidRollappID = errorsmod.Register(ModuleName, 1020, "invalid rollapp-id") - ErrEIP155Exists = errorsmod.Register(ModuleName, 1021, "EIP155 already exists; must use unique EIP155 identifier") - ErrRollappsDisabled = errorsmod.Register(ModuleName, 1022, "rollapps are disabled") - ErrInvalidTokenMetadata = errorsmod.Register(ModuleName, 1023, "invalid token metadata") - ErrNoFinalizedStateYetForRollapp = errorsmod.Register(ModuleName, 1024, "no finalized state yet for rollapp") - ErrInvalidClientState = errorsmod.Register(ModuleName, 1025, "invalid client state") - ErrInvalidSequencer = errorsmod.Register(ModuleName, 1026, "invalid sequencer") - ErrInvalidGenesisChannelId = errorsmod.Register(ModuleName, 1027, "invalid genesis channel id") - ErrGenesisEventNotTriggered = errorsmod.Register(ModuleName, 1028, "genesis event not triggered yet") - ErrGenesisEventAlreadyTriggered = errorsmod.Register(ModuleName, 1029, "genesis event already triggered") - ErrTooManyPermissionedAddresses = errorsmod.Register(ModuleName, 1030, "invalid number of permissioned addresses") - ErrInvalidGenesisAccount = errorsmod.Register(ModuleName, 1031, "invalid genesis account") - ErrMintTokensFailed = errorsmod.Register(ModuleName, 1032, "failed to mint tokens") - ErrRegisterDenomMetadataFailed = errorsmod.Register(ModuleName, 1033, "failed to register denom metadata") - ErrMismatchedChannelID = errorsmod.Register(ModuleName, 1034, "mismatched channel id") - ErrRollappNotRegistered = errorsmod.Register(ModuleName, 1035, "rollapp not registered") - ErrUnknownRequest = errorsmod.Register(ModuleName, 1036, "unknown request") - ErrNotFound = errorsmod.Register(ModuleName, 1037, "not found") - ErrLogic = errorsmod.Register(ModuleName, 1038, "internal logic error") - ErrUnauthorized = errorsmod.Register(ModuleName, 1039, "unauthorized") - ErrInvalidAddress = errorsmod.Register(ModuleName, 1040, "invalid address") + ErrRollappExists = errorsmod.Register(ModuleName, 1000, "rollapp already exists for this rollapp-id; must use new rollapp-id") + ErrInvalidMaxSequencers = errorsmod.Register(ModuleName, 1001, "invalid max sequencers") + ErrInvalidCreatorAddress = errorsmod.Register(ModuleName, 1002, "invalid creator address") + ErrInvalidPermissionedAddress = errorsmod.Register(ModuleName, 1003, "invalid permissioned address") + ErrPermissionedAddressesDuplicate = errorsmod.Register(ModuleName, 1004, "permissioned-address has duplicates") + ErrInvalidNumBlocks = errorsmod.Register(ModuleName, 1005, "invalid number of blocks") + ErrInvalidBlockSequence = errorsmod.Register(ModuleName, 1006, "invalid block sequence") + ErrUnknownRollappID = errorsmod.Register(ModuleName, 1007, "rollapp does not exist") + ErrVersionMismatch = errorsmod.Register(ModuleName, 1008, "rollapp version mismatch") + ErrWrongBlockHeight = errorsmod.Register(ModuleName, 1009, "start-height does not match rollapps state") + ErrInvalidStateRoot = errorsmod.Register(ModuleName, 1011, "invalid blocks state root") + ErrUnauthorizedRollappCreator = errorsmod.Register(ModuleName, 1013, "rollapp creator not registered in the whitelist") + ErrStateNotExists = errorsmod.Register(ModuleName, 1017, "state of this height doesn't exist") + ErrInvalidHeight = errorsmod.Register(ModuleName, 1018, "invalid rollapp height") + ErrInvalidRollappID = errorsmod.Register(ModuleName, 1020, "invalid rollapp-id") + ErrRollappsDisabled = errorsmod.Register(ModuleName, 1022, "rollapps are disabled") + ErrNoFinalizedStateYetForRollapp = errorsmod.Register(ModuleName, 1024, "no finalized state yet for rollapp") + ErrInvalidClientState = errorsmod.Register(ModuleName, 1025, "invalid client state") + ErrTooManyPermissionedAddresses = errorsmod.Register(ModuleName, 1030, "invalid number of permissioned addresses") + ErrRollappNotRegistered = errorsmod.Register(ModuleName, 1035, "rollapp not registered") + ErrUnknownRequest = errorsmod.Register(ModuleName, 1036, "unknown request") + ErrNotFound = errorsmod.Register(ModuleName, 1037, "not found") + ErrLogic = errorsmod.Register(ModuleName, 1038, "internal logic error") + ErrInvalidAddress = errorsmod.Register(ModuleName, 1040, "invalid address") /* ------------------------------ fraud related ----------------------------- */ ErrDisputeAlreadyFinalized = errorsmod.Register(ModuleName, 2000, "disputed height already finalized") diff --git a/x/rollapp/types/events.go b/x/rollapp/types/events.go index fe4837e87..41a69f75e 100644 --- a/x/rollapp/types/events.go +++ b/x/rollapp/types/events.go @@ -16,4 +16,10 @@ const ( AttributeKeyFraudHeight = "fraud_height" AttributeKeyFraudSequencer = "fraud_sequencer" AttributeKeyClientID = "client_id" + + // EventTypeTransferGenesisAllReceived is when all genesis transfers from the rollapp have been received + EventTypeTransferGenesisAllReceived = "transfer_genesis_all_received" + // EventTypeTransferGenesisTransfersEnabled is when the bridge is enabled + EventTypeTransferGenesisTransfersEnabled = "transfer_genesis_transfers_enabled" + AttributeKeyTransferGenesisNReceived = "num_transfers_received" ) diff --git a/x/rollapp/types/expected_keepers.go b/x/rollapp/types/expected_keepers.go index 545a71942..53bd0ad7f 100644 --- a/x/rollapp/types/expected_keepers.go +++ b/x/rollapp/types/expected_keepers.go @@ -2,40 +2,14 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" "github.com/cosmos/ibc-go/v6/modules/core/exported" - tmbytes "github.com/tendermint/tendermint/libs/bytes" ) -// AccountKeeper defines the expected account keeper used for simulations (noalias) -type AccountKeeper interface { - GetAccount(ctx sdk.Context, addr sdk.AccAddress) types.AccountI - // Methods imported from account should be defined here -} - -// BankKeeper defines the expected interface needed to retrieve account balances. -type BankKeeper interface { - SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins - MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error - SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error -} - type IBCClientKeeper interface { GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) SetClientState(ctx sdk.Context, clientID string, clientState exported.ClientState) } -type TransferKeeper interface { - HasDenomTrace(ctx sdk.Context, denomTraceHash tmbytes.HexBytes) bool - SetDenomTrace(ctx sdk.Context, denomTrace transfertypes.DenomTrace) -} - type ChannelKeeper interface { GetChannelClientState(ctx sdk.Context, portID, channelID string) (string, exported.ClientState, error) } - -type DenomMetadataKeeper interface { - CreateDenomMetadata(ctx sdk.Context, metadata banktypes.Metadata) error -} diff --git a/x/rollapp/types/genesis.go b/x/rollapp/types/genesis.go index fc92a78f3..a1592af0c 100644 --- a/x/rollapp/types/genesis.go +++ b/x/rollapp/types/genesis.go @@ -15,6 +15,7 @@ func DefaultGenesis() *GenesisState { LatestStateInfoIndexList: []StateInfoIndex{}, LatestFinalizedStateIndexList: []StateInfoIndex{}, BlockHeightToFinalizationQueueList: []BlockHeightToFinalizationQueue{}, + GenesisTransfers: []GenesisTransfers{}, // this line is used by starport scaffolding # genesis/types/default Params: DefaultParams(), } @@ -75,5 +76,7 @@ func (gs GenesisState) Validate() error { } // this line is used by starport scaffolding # genesis/types/validate + // TODO: + return gs.Params.Validate() } diff --git a/x/rollapp/types/genesis.pb.go b/x/rollapp/types/genesis.pb.go index 671f63031..b163f237b 100644 --- a/x/rollapp/types/genesis.pb.go +++ b/x/rollapp/types/genesis.pb.go @@ -31,6 +31,7 @@ type GenesisState struct { LatestStateInfoIndexList []StateInfoIndex `protobuf:"bytes,4,rep,name=latestStateInfoIndexList,proto3" json:"latestStateInfoIndexList"` LatestFinalizedStateIndexList []StateInfoIndex `protobuf:"bytes,5,rep,name=latestFinalizedStateIndexList,proto3" json:"latestFinalizedStateIndexList"` BlockHeightToFinalizationQueueList []BlockHeightToFinalizationQueue `protobuf:"bytes,6,rep,name=blockHeightToFinalizationQueueList,proto3" json:"blockHeightToFinalizationQueueList"` + GenesisTransfers []GenesisTransfers `protobuf:"bytes,7,rep,name=genesisTransfers,proto3" json:"genesisTransfers"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -108,6 +109,13 @@ func (m *GenesisState) GetBlockHeightToFinalizationQueueList() []BlockHeightToFi return nil } +func (m *GenesisState) GetGenesisTransfers() []GenesisTransfers { + if m != nil { + return m.GenesisTransfers + } + return nil +} + func init() { proto.RegisterType((*GenesisState)(nil), "dymensionxyz.dymension.rollapp.GenesisState") } @@ -115,31 +123,33 @@ func init() { func init() { proto.RegisterFile("dymension/rollapp/genesis.proto", fileDescriptor_f4bf6d3c28914609) } var fileDescriptor_f4bf6d3c28914609 = []byte{ - // 374 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x92, 0x3d, 0x4f, 0x6a, 0x31, - 0x18, 0xc7, 0xcf, 0xb9, 0xbc, 0x0c, 0xe5, 0xde, 0xa5, 0xb9, 0x03, 0x21, 0xb9, 0x85, 0x30, 0x5c, - 0x71, 0xe9, 0x49, 0xc0, 0xd9, 0x81, 0x18, 0x95, 0xc4, 0xf8, 0x02, 0xba, 0xb8, 0x98, 0x02, 0xe5, - 0xd0, 0x78, 0x68, 0x4f, 0x68, 0x31, 0xc0, 0xe6, 0x37, 0x70, 0xf0, 0x43, 0x31, 0x32, 0x3a, 0x19, - 0x03, 0x5f, 0xc4, 0xd0, 0xf3, 0x70, 0xc4, 0xa0, 0x40, 0xe2, 0xd4, 0x36, 0xcf, 0xff, 0xf9, 0xfd, - 0xfe, 0x43, 0x51, 0xbe, 0x3d, 0xea, 0x71, 0xa9, 0x85, 0x92, 0x5e, 0x5f, 0x05, 0x01, 0x0b, 0x43, - 0xcf, 0xe7, 0x92, 0x6b, 0xa1, 0x69, 0xd8, 0x57, 0x46, 0x61, 0x12, 0x07, 0x86, 0xa3, 0x31, 0x8d, - 0x1f, 0x14, 0xd2, 0xb9, 0xbf, 0xbe, 0xf2, 0x95, 0x8d, 0x7a, 0x8b, 0x5b, 0xb4, 0x95, 0x23, 0xeb, - 0xd8, 0x90, 0xf5, 0x59, 0x0f, 0xa8, 0xb9, 0x2f, 0xb4, 0x70, 0x42, 0xa0, 0xb8, 0x1e, 0xd0, 0x86, - 0x19, 0x7e, 0x27, 0x64, 0x07, 0x24, 0xc5, 0xc7, 0x14, 0xfa, 0x7d, 0x12, 0x95, 0x6d, 0x2c, 0x66, - 0xf8, 0x08, 0xa5, 0x23, 0x4b, 0xd6, 0x2d, 0xb8, 0xa5, 0x4c, 0xf9, 0x3f, 0xdd, 0x5c, 0x9e, 0x5e, - 0xda, 0x74, 0x35, 0x39, 0x79, 0xcd, 0x3b, 0x75, 0xd8, 0xc5, 0x17, 0x28, 0x03, 0xf3, 0x33, 0xa1, - 0x4d, 0xf6, 0x57, 0x21, 0x51, 0xca, 0x94, 0xf7, 0xb6, 0xa1, 0xea, 0xd1, 0x09, 0xac, 0x55, 0x02, - 0xbe, 0x41, 0x7f, 0x6c, 0xf7, 0x9a, 0xec, 0x28, 0x8b, 0x4c, 0x58, 0xe4, 0xfe, 0x36, 0x64, 0x63, - 0xb9, 0x04, 0xd0, 0xcf, 0x14, 0x1c, 0xa2, 0x6c, 0xc0, 0x0c, 0xd7, 0x26, 0xce, 0xd5, 0x64, 0x9b, - 0x0f, 0xad, 0x21, 0x69, 0x0d, 0x74, 0x67, 0x83, 0xdd, 0x04, 0xcd, 0xb7, 0x54, 0x3c, 0x46, 0xff, - 0xa2, 0xd9, 0xb1, 0x90, 0x2c, 0x10, 0x63, 0xde, 0x86, 0xd0, 0x52, 0x9b, 0xfa, 0x81, 0x76, 0x33, - 0x1a, 0x3f, 0xbb, 0xa8, 0xd8, 0x0c, 0x54, 0xeb, 0xfe, 0x94, 0x0b, 0xbf, 0x6b, 0xae, 0x15, 0x04, - 0x99, 0x11, 0x4a, 0x5e, 0x0d, 0xf8, 0x80, 0xdb, 0x06, 0x69, 0xdb, 0xe0, 0x70, 0x5b, 0x83, 0xea, - 0x46, 0x12, 0x34, 0xda, 0xc1, 0x57, 0x3d, 0x9f, 0xcc, 0x88, 0x3b, 0x9d, 0x11, 0xf7, 0x6d, 0x46, - 0xdc, 0xa7, 0x39, 0x71, 0xa6, 0x73, 0xe2, 0xbc, 0xcc, 0x89, 0x73, 0x7b, 0xe0, 0x0b, 0xd3, 0x1d, - 0x34, 0x69, 0x4b, 0xf5, 0xbc, 0xd5, 0x36, 0x1f, 0x0f, 0xef, 0xa1, 0xe2, 0x0d, 0xe3, 0xef, 0x6d, - 0x46, 0x21, 0xd7, 0xcd, 0xb4, 0xfd, 0xda, 0x95, 0xf7, 0x00, 0x00, 0x00, 0xff, 0xff, 0x49, 0x15, - 0xad, 0xd6, 0x98, 0x03, 0x00, 0x00, + // 412 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x93, 0x4d, 0x6b, 0x22, 0x31, + 0x1c, 0xc6, 0x67, 0xd6, 0x97, 0x85, 0xb8, 0x0b, 0x4b, 0xd8, 0xc3, 0x20, 0x6c, 0x14, 0x0f, 0xbb, + 0xee, 0x65, 0x66, 0xd1, 0x3d, 0xef, 0x41, 0x96, 0x5a, 0xa1, 0xf4, 0x45, 0xed, 0xa5, 0x17, 0xc9, + 0x68, 0x1c, 0x43, 0xc7, 0x64, 0x98, 0xc4, 0xa2, 0x7e, 0x8a, 0x1e, 0xfa, 0xa1, 0x3c, 0x7a, 0xec, + 0xa9, 0x14, 0xa5, 0xdf, 0xa3, 0x98, 0x89, 0x53, 0x5b, 0xab, 0x23, 0xf4, 0x34, 0x13, 0xf2, 0xfc, + 0x7f, 0xbf, 0x27, 0x90, 0x80, 0x42, 0x6f, 0x32, 0x24, 0x4c, 0x50, 0xce, 0x9c, 0x90, 0xfb, 0x3e, + 0x0e, 0x02, 0xc7, 0x23, 0x8c, 0x08, 0x2a, 0xec, 0x20, 0xe4, 0x92, 0x43, 0x14, 0x07, 0xc6, 0x93, + 0xa9, 0x1d, 0x2f, 0x6c, 0x9d, 0xce, 0x7f, 0xf7, 0xb8, 0xc7, 0x55, 0xd4, 0x59, 0xfd, 0x45, 0x53, + 0x79, 0xb4, 0x8d, 0x0d, 0x70, 0x88, 0x87, 0x9a, 0x9a, 0x7f, 0x47, 0xab, 0xbf, 0x3a, 0x50, 0xda, + 0x0e, 0x08, 0x89, 0x25, 0xe9, 0x50, 0xd6, 0x5f, 0x4b, 0xca, 0x3b, 0xbb, 0x77, 0x64, 0x88, 0x99, + 0xe8, 0x93, 0x30, 0x4a, 0x96, 0x9e, 0x32, 0xe0, 0x4b, 0x3d, 0xda, 0x6a, 0xad, 0x28, 0xf0, 0x3f, + 0xc8, 0x46, 0x7d, 0x2c, 0xb3, 0x68, 0x96, 0x73, 0x95, 0x9f, 0xf6, 0xfe, 0x63, 0xda, 0xe7, 0x2a, + 0x5d, 0x4b, 0xcf, 0x1e, 0x0a, 0x46, 0x53, 0xcf, 0xc2, 0x33, 0x90, 0xd3, 0xfb, 0x27, 0x54, 0x48, + 0xeb, 0x53, 0x31, 0x55, 0xce, 0x55, 0x7e, 0x25, 0xa1, 0x9a, 0xd1, 0x57, 0xb3, 0x36, 0x09, 0xf0, + 0x12, 0x7c, 0x55, 0xa7, 0x6c, 0xb0, 0x3e, 0x57, 0xc8, 0x94, 0x42, 0xfe, 0x4e, 0x42, 0xb6, 0xd6, + 0x43, 0x1a, 0xfa, 0x9a, 0x02, 0x03, 0x60, 0xf9, 0x58, 0x12, 0x21, 0xe3, 0x5c, 0x83, 0xf5, 0xc8, + 0x58, 0x19, 0xd2, 0xca, 0x60, 0x1f, 0x6c, 0x50, 0x93, 0x5a, 0xb3, 0x93, 0x0a, 0xa7, 0xe0, 0x47, + 0xb4, 0x77, 0x44, 0x19, 0xf6, 0xe9, 0x94, 0xf4, 0x74, 0x68, 0xad, 0xcd, 0x7c, 0x40, 0xbb, 0x1f, + 0x0d, 0xef, 0x4c, 0x50, 0x72, 0x7d, 0xde, 0xbd, 0x3e, 0x26, 0xd4, 0x1b, 0xc8, 0x36, 0xd7, 0x41, + 0x2c, 0x29, 0x67, 0x17, 0x23, 0x32, 0x22, 0xaa, 0x41, 0x56, 0x35, 0xf8, 0x97, 0xd4, 0xa0, 0xb6, + 0x97, 0xa4, 0x1b, 0x1d, 0xe0, 0x83, 0x2e, 0xf8, 0xa6, 0x6f, 0x67, 0x5b, 0x5f, 0x4e, 0x61, 0x7d, + 0x56, 0x1d, 0xfe, 0x24, 0x75, 0xa8, 0xbf, 0x99, 0xd3, 0xd6, 0x2d, 0x5e, 0xed, 0x74, 0xb6, 0x40, + 0xe6, 0x7c, 0x81, 0xcc, 0xc7, 0x05, 0x32, 0x6f, 0x97, 0xc8, 0x98, 0x2f, 0x91, 0x71, 0xbf, 0x44, + 0xc6, 0xd5, 0x5f, 0x8f, 0xca, 0xc1, 0xc8, 0xb5, 0xbb, 0x7c, 0xe8, 0x6c, 0xda, 0x5e, 0x16, 0xce, + 0x4d, 0xd5, 0x19, 0xc7, 0x0f, 0x49, 0x4e, 0x02, 0x22, 0xdc, 0xac, 0x7a, 0x3e, 0xd5, 0xe7, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x6a, 0x9b, 0x0a, 0x23, 0x26, 0x04, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -162,6 +172,20 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.GenesisTransfers) > 0 { + for iNdEx := len(m.GenesisTransfers) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.GenesisTransfers[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } + } if len(m.BlockHeightToFinalizationQueueList) > 0 { for iNdEx := len(m.BlockHeightToFinalizationQueueList) - 1; iNdEx >= 0; iNdEx-- { { @@ -294,6 +318,12 @@ func (m *GenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) } } + if len(m.GenesisTransfers) > 0 { + for _, e := range m.GenesisTransfers { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } return n } @@ -535,6 +565,40 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GenesisTransfers", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.GenesisTransfers = append(m.GenesisTransfers, GenesisTransfers{}) + if err := m.GenesisTransfers[len(m.GenesisTransfers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/rollapp/types/genesis_transfer.go b/x/rollapp/types/genesis_transfer.go new file mode 100644 index 000000000..e2ec73a79 --- /dev/null +++ b/x/rollapp/types/genesis_transfer.go @@ -0,0 +1,35 @@ +package types + +import ( + "encoding/json" + + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +type GenesisTransferMemo struct { + Denom banktypes.Metadata `json:"denom"` + // How many transfers in total will be sent in the transfer genesis period + TotalNumTransfers uint64 `json:"total_num_transfers"` +} + +func (g GenesisTransferMemo) Valid() error { + return g.Denom.Validate() +} + +func (g GenesisTransferMemo) Namespaced() GenesisTransferMemoNamespaced { + return GenesisTransferMemoNamespaced{g} +} + +// GenesisTransferMemoNamespaced is a namespaced wrapper +type GenesisTransferMemoNamespaced struct { + Data GenesisTransferMemo `json:"genesis_transfer"` +} + +// MustString returns a human-readable json string - intended for tests. +func (g GenesisTransferMemoNamespaced) MustString() string { + bz, err := json.MarshalIndent(g, "", "\t") + if err != nil { + panic(err) + } + return string(bz) +} diff --git a/x/rollapp/types/genesis_transfer.pb.go b/x/rollapp/types/genesis_transfer.pb.go new file mode 100644 index 000000000..687d3c360 --- /dev/null +++ b/x/rollapp/types/genesis_transfer.pb.go @@ -0,0 +1,398 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: dymension/rollapp/genesis_transfer.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Bookkeeping for the genesis transfer bridge protocol. +// Each rollapp will have one of these items corresponding to it. +type GenesisTransfers struct { + RollappID string `protobuf:"bytes,1,opt,name=rollappID,proto3" json:"rollappID,omitempty"` + // The total number of incoming ibc transfers to be fast tracked in the genesis transfer period + NumTotal uint64 `protobuf:"varint,2,opt,name=numTotal,proto3" json:"numTotal,omitempty"` + // The number of transfers already processed, when this number reaches numTotal the genesis transfer window closes. + NumReceived uint64 `protobuf:"varint,3,opt,name=numReceived,proto3" json:"numReceived,omitempty"` +} + +func (m *GenesisTransfers) Reset() { *m = GenesisTransfers{} } +func (m *GenesisTransfers) String() string { return proto.CompactTextString(m) } +func (*GenesisTransfers) ProtoMessage() {} +func (*GenesisTransfers) Descriptor() ([]byte, []int) { + return fileDescriptor_abbd5969075b03fa, []int{0} +} +func (m *GenesisTransfers) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisTransfers) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisTransfers.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisTransfers) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisTransfers.Merge(m, src) +} +func (m *GenesisTransfers) XXX_Size() int { + return m.Size() +} +func (m *GenesisTransfers) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisTransfers.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisTransfers proto.InternalMessageInfo + +func (m *GenesisTransfers) GetRollappID() string { + if m != nil { + return m.RollappID + } + return "" +} + +func (m *GenesisTransfers) GetNumTotal() uint64 { + if m != nil { + return m.NumTotal + } + return 0 +} + +func (m *GenesisTransfers) GetNumReceived() uint64 { + if m != nil { + return m.NumReceived + } + return 0 +} + +func init() { + proto.RegisterType((*GenesisTransfers)(nil), "dymensionxyz.dymension.rollapp.GenesisTransfers") +} + +func init() { + proto.RegisterFile("dymension/rollapp/genesis_transfer.proto", fileDescriptor_abbd5969075b03fa) +} + +var fileDescriptor_abbd5969075b03fa = []byte{ + // 257 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x48, 0xa9, 0xcc, 0x4d, + 0xcd, 0x2b, 0xce, 0xcc, 0xcf, 0xd3, 0x2f, 0xca, 0xcf, 0xc9, 0x49, 0x2c, 0x28, 0xd0, 0x4f, 0x4f, + 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0x8e, 0x2f, 0x29, 0x4a, 0xcc, 0x2b, 0x4e, 0x4b, 0x2d, 0xd2, 0x2b, + 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x83, 0xab, 0xac, 0xa8, 0xac, 0xd2, 0x83, 0x73, 0xf4, 0xa0, + 0xda, 0xa4, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x4a, 0xf5, 0x41, 0x2c, 0x88, 0x2e, 0x29, 0x39, + 0x4c, 0xf3, 0x0b, 0x12, 0x8b, 0x12, 0x73, 0x8b, 0xa1, 0xf2, 0xf2, 0x98, 0xf2, 0x50, 0x1a, 0xaa, + 0x40, 0x09, 0x53, 0x41, 0x71, 0x49, 0x62, 0x49, 0x6a, 0x7c, 0x66, 0x5e, 0x1a, 0xd4, 0x12, 0xa5, + 0x3c, 0x2e, 0x01, 0x77, 0x88, 0xa3, 0x43, 0xa0, 0x6e, 0x2e, 0x16, 0x92, 0xe1, 0xe2, 0x84, 0xaa, + 0xf7, 0x74, 0x91, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0c, 0x42, 0x08, 0x08, 0x49, 0x71, 0x71, 0xe4, + 0x95, 0xe6, 0x86, 0xe4, 0x97, 0x24, 0xe6, 0x48, 0x30, 0x29, 0x30, 0x6a, 0xb0, 0x04, 0xc1, 0xf9, + 0x42, 0x0a, 0x5c, 0xdc, 0x79, 0xa5, 0xb9, 0x41, 0xa9, 0xc9, 0xa9, 0x99, 0x65, 0xa9, 0x29, 0x12, + 0xcc, 0x60, 0x69, 0x64, 0x21, 0x27, 0xbf, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, + 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, + 0x88, 0x32, 0x49, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x47, 0x0e, 0x2f, + 0x04, 0x47, 0xbf, 0xcc, 0x58, 0xbf, 0x02, 0xee, 0x95, 0x92, 0xca, 0x82, 0xd4, 0xe2, 0x24, 0x36, + 0xb0, 0x37, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x28, 0x1c, 0x26, 0x98, 0x8d, 0x01, 0x00, + 0x00, +} + +func (m *GenesisTransfers) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisTransfers) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisTransfers) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.NumReceived != 0 { + i = encodeVarintGenesisTransfer(dAtA, i, uint64(m.NumReceived)) + i-- + dAtA[i] = 0x18 + } + if m.NumTotal != 0 { + i = encodeVarintGenesisTransfer(dAtA, i, uint64(m.NumTotal)) + i-- + dAtA[i] = 0x10 + } + if len(m.RollappID) > 0 { + i -= len(m.RollappID) + copy(dAtA[i:], m.RollappID) + i = encodeVarintGenesisTransfer(dAtA, i, uint64(len(m.RollappID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesisTransfer(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesisTransfer(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisTransfers) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.RollappID) + if l > 0 { + n += 1 + l + sovGenesisTransfer(uint64(l)) + } + if m.NumTotal != 0 { + n += 1 + sovGenesisTransfer(uint64(m.NumTotal)) + } + if m.NumReceived != 0 { + n += 1 + sovGenesisTransfer(uint64(m.NumReceived)) + } + return n +} + +func sovGenesisTransfer(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesisTransfer(x uint64) (n int) { + return sovGenesisTransfer(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisTransfers) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesisTransfer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisTransfers: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisTransfers: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RollappID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesisTransfer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesisTransfer + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesisTransfer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RollappID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NumTotal", wireType) + } + m.NumTotal = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesisTransfer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NumTotal |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NumReceived", wireType) + } + m.NumReceived = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesisTransfer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NumReceived |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipGenesisTransfer(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesisTransfer + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesisTransfer(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesisTransfer + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesisTransfer + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesisTransfer + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesisTransfer + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesisTransfer + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesisTransfer + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesisTransfer = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesisTransfer = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesisTransfer = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/rollapp/types/hooks.go b/x/rollapp/types/hooks.go index 8ec01b7fd..4784409e3 100644 --- a/x/rollapp/types/hooks.go +++ b/x/rollapp/types/hooks.go @@ -19,9 +19,9 @@ type RollappHooks interface { var _ RollappHooks = MultiRollappHooks{} // combine multiple rollapp hooks, all hook functions are run in array sequence + type MultiRollappHooks []RollappHooks -// Creates hooks for the Rollapp Module. func NewMultiRollappHooks(hooks ...RollappHooks) MultiRollappHooks { return hooks } diff --git a/x/rollapp/types/key_transfer_genesis.go b/x/rollapp/types/key_transfer_genesis.go new file mode 100644 index 000000000..44575c67f --- /dev/null +++ b/x/rollapp/types/key_transfer_genesis.go @@ -0,0 +1,46 @@ +package types + +import ( + "encoding/binary" +) + +var _ binary.ByteOrder + +const ( + TransferGenesisMapKeyPrefix = "TransferGenesis/map/value/" +) + +var ( + transferGenesisNumTotalSubkey = []byte{1} + transferGenesisNumSubkey = []byte{2} +) + +// TransferGenesisNumTotalKey returns the store key to check the total number of genesis transfers that the rollapp has decided to do +func TransferGenesisNumTotalKey( + rollappID string, +) []byte { + var key []byte + // build the key bytes + rollappIdBytes := []byte(rollappID) + // concatenate the byte slices directly + key = append(key, transferGenesisNumTotalSubkey...) + key = append(key, []byte("/")...) + key = append(key, rollappIdBytes...) + + return key +} + +// TransferGenesisNumKey returns the store key to check the number of genesis transfers that the rollapp has done +func TransferGenesisNumKey( + rollappID string, +) []byte { + var key []byte + // build the key bytes + rollappIdBytes := []byte(rollappID) + // concatenate the byte slices directly + key = append(key, transferGenesisNumSubkey...) + key = append(key, []byte("/")...) + key = append(key, rollappIdBytes...) + + return key +} diff --git a/x/rollapp/types/message_create_rollapp.go b/x/rollapp/types/message_create_rollapp.go index ad9a455f4..a08ae09ad 100644 --- a/x/rollapp/types/message_create_rollapp.go +++ b/x/rollapp/types/message_create_rollapp.go @@ -10,16 +10,19 @@ var _ sdk.Msg = &MsgCreateRollapp{} const MaxAllowedSequencers = 100 -func NewMsgCreateRollapp(creator string, rollappId string, maxSequencers uint64, permissionedAddresses []string, - metadatas []TokenMetadata, genesisAccounts []GenesisAccount, +func NewMsgCreateRollapp( + creator string, + rollappId string, + maxSequencers uint64, + permissionedAddresses []string, + transfersEnabled bool, ) *MsgCreateRollapp { return &MsgCreateRollapp{ Creator: creator, RollappId: rollappId, MaxSequencers: maxSequencers, PermissionedAddresses: permissionedAddresses, - Metadatas: metadatas, - GenesisAccounts: genesisAccounts, + TransfersEnabled: transfersEnabled, } } @@ -45,20 +48,7 @@ func (msg *MsgCreateRollapp) GetSignBytes() []byte { } func (msg *MsgCreateRollapp) GetRollapp() Rollapp { - // Build the genesis state from the genesis accounts - rollappGenesisState := RollappGenesisState{ - IsGenesisEvent: false, - } - rollappGenesisState.GenesisAccounts = make([]*GenesisAccount, len(msg.GenesisAccounts)) - for i := range msg.GenesisAccounts { - rollappGenesisState.GenesisAccounts[i] = &msg.GenesisAccounts[i] - } - metadata := make([]*TokenMetadata, len(msg.Metadatas)) - for i := range msg.Metadatas { - metadata[i] = &msg.Metadatas[i] - } - - return NewRollapp(msg.Creator, msg.RollappId, msg.MaxSequencers, msg.PermissionedAddresses, metadata, rollappGenesisState) + return NewRollapp(msg.Creator, msg.RollappId, msg.MaxSequencers, msg.PermissionedAddresses, msg.TransfersEnabled) } func (msg *MsgCreateRollapp) ValidateBasic() error { diff --git a/x/rollapp/types/message_create_rollapp_test.go b/x/rollapp/types/message_create_rollapp_test.go index 98076a603..eaf1f235e 100644 --- a/x/rollapp/types/message_create_rollapp_test.go +++ b/x/rollapp/types/message_create_rollapp_test.go @@ -3,24 +3,11 @@ package types import ( "testing" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/dymensionxyz/dymension/v3/testutil/sample" "github.com/stretchr/testify/require" ) func TestMsgCreateRollapp_ValidateBasic(t *testing.T) { - defaultMetadata := TokenMetadata{ - Description: "valid", - DenomUnits: []*DenomUnit{ - {Denom: "uvalid", Exponent: 0}, - {Denom: "valid", Exponent: 18}, - }, - Base: "uvalid", - Display: "valid", - Name: "valid", - Symbol: "VALID", - } - seqDupAddr := sample.AccAddress() var tooManyAddresses []string @@ -43,13 +30,6 @@ func TestMsgCreateRollapp_ValidateBasic(t *testing.T) { MaxSequencers: 2, RollappId: "dym_100-1", PermissionedAddresses: []string{sample.AccAddress(), sample.AccAddress()}, - Metadatas: []TokenMetadata{defaultMetadata}, - GenesisAccounts: []GenesisAccount{ - { - Address: sample.AccAddress(), - Amount: sdk.NewCoin("valid", sdk.NewInt(1000)), - }, - }, }, }, { @@ -114,51 +94,7 @@ func TestMsgCreateRollapp_ValidateBasic(t *testing.T) { }, err: ErrInvalidPermissionedAddress, }, - { - name: "valid token metadata", - msg: MsgCreateRollapp{ - Creator: sample.AccAddress(), - MaxSequencers: 1, - RollappId: "dym_100-1", - Metadatas: []TokenMetadata{defaultMetadata}, - }, - err: nil, - }, - { - name: "invalid token metadata", // just trigger one case to see if validation is done or not - msg: MsgCreateRollapp{ - Creator: sample.AccAddress(), - MaxSequencers: 1, - RollappId: "dym_100-1", - Metadatas: []TokenMetadata{{ - Description: "valid", - DenomUnits: []*DenomUnit{ - {Denom: "uvalid", Exponent: 0}, - {Denom: "valid", Exponent: 18}, - }, - Base: "uvalid", - Display: "valid", - Name: "", // empty - Symbol: "VALID", - }}, - }, - err: ErrInvalidTokenMetadata, - }, - { - name: "invalid genesis account address", - msg: MsgCreateRollapp{ - Creator: sample.AccAddress(), - MaxSequencers: 1, - RollappId: "dym_100-1", - GenesisAccounts: []GenesisAccount{ - { - Address: "invalid_address", - Amount: sdk.NewCoin("valid", sdk.NewInt(1000)), - }, - }, - }, - err: ErrInvalidGenesisAccount, - }, + { name: "more addresses than sequencers", // just trigger one case to see if validation is done or not msg: MsgCreateRollapp{ diff --git a/x/rollapp/types/message_rollapp_genesis_event.go b/x/rollapp/types/message_rollapp_genesis_event.go deleted file mode 100644 index da96518d1..000000000 --- a/x/rollapp/types/message_rollapp_genesis_event.go +++ /dev/null @@ -1,62 +0,0 @@ -package types - -import ( - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -const TypeMsgRollappGenesisEvent = "rollapp_genesis_event" - -var _ sdk.Msg = &MsgRollappGenesisEvent{} - -const ( - maxChannelIDLength = 100 - maxRollappIDLength = 100 -) - -func NewMsgRollappGenesisEvent(address string, channel_id string, rollapp_id string) *MsgRollappGenesisEvent { - return &MsgRollappGenesisEvent{ - Address: address, - ChannelId: channel_id, - RollappId: rollapp_id, - } -} - -func (msg *MsgRollappGenesisEvent) Route() string { - return RouterKey -} - -func (msg *MsgRollappGenesisEvent) Type() string { - return TypeMsgRollappGenesisEvent -} - -func (msg *MsgRollappGenesisEvent) GetSigners() []sdk.AccAddress { - creator, err := sdk.AccAddressFromBech32(msg.Address) - if err != nil { - panic(err) - } - return []sdk.AccAddress{creator} -} - -func (msg *MsgRollappGenesisEvent) GetSignBytes() []byte { - bz := ModuleCdc.MustMarshalJSON(msg) - return sdk.MustSortJSON(bz) -} - -func (msg *MsgRollappGenesisEvent) ValidateBasic() error { - _, err := sdk.AccAddressFromBech32(msg.Address) - if err != nil { - return errorsmod.Wrapf(ErrInvalidAddress, "invalid address (%s)", err) - } - if msg.ChannelId == "" { - return errorsmod.Wrap(ErrInvalidGenesisChannelId, "channel id cannot be empty") - } else if len(msg.ChannelId) > maxChannelIDLength { - return errorsmod.Wrapf(ErrInvalidGenesisChannelId, "channel id cannot exceed %d characters", maxChannelIDLength) - } - if msg.RollappId == "" { - return errorsmod.Wrap(ErrInvalidRollappID, "rollapp id cannot be empty") - } else if len(msg.RollappId) > maxRollappIDLength { - return errorsmod.Wrapf(ErrInvalidRollappID, "rollapp id cannot exceed %d characters", maxRollappIDLength) - } - return nil -} diff --git a/x/rollapp/types/params.go b/x/rollapp/types/params.go index 79f49a49a..17b722d50 100644 --- a/x/rollapp/types/params.go +++ b/x/rollapp/types/params.go @@ -14,11 +14,10 @@ var _ paramtypes.ParamSet = (*Params)(nil) var ( // KeyRollappsEnabled is store's key for RollappsEnabled Params KeyRollappsEnabled = []byte("RollappsEnabled") - // DeployerWhitelist is store's key for DeployerWhitelist Params + // KeyDeployerWhitelist is store's key for DeployerWhitelist Params KeyDeployerWhitelist = []byte("DeployerWhitelist") // KeyDisputePeriodInBlocks is store's key for DisputePeriodInBlocks Params - KeyDisputePeriodInBlocks = []byte("DisputePeriodInBlocks") - // default value + KeyDisputePeriodInBlocks = []byte("DisputePeriodInBlocks") DefaultDisputePeriodInBlocks uint64 = 3 // MinDisputePeriodInBlocks is the minimum number of blocks for dispute period MinDisputePeriodInBlocks uint64 = 1 diff --git a/x/rollapp/types/rollapp.go b/x/rollapp/types/rollapp.go index 3e711f097..e4aff78dc 100644 --- a/x/rollapp/types/rollapp.go +++ b/x/rollapp/types/rollapp.go @@ -5,17 +5,15 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -func NewRollapp(creator string, rollappId string, maxSequencers uint64, permissionedAddresses []string, - metadatas []*TokenMetadata, genesisAccounts RollappGenesisState, -) Rollapp { - return Rollapp{ +func NewRollapp(creator string, rollappId string, maxSequencers uint64, permissionedAddresses []string, transfersEnabled bool) Rollapp { + ret := Rollapp{ RollappId: rollappId, Creator: creator, MaxSequencers: maxSequencers, PermissionedAddresses: permissionedAddresses, - GenesisState: genesisAccounts, - TokenMetadata: metadatas, } + ret.GenesisState.TransfersEnabled = transfersEnabled + return ret } func (r Rollapp) ValidateBasic() error { @@ -57,22 +55,5 @@ func (r Rollapp) ValidateBasic() error { } } - // verifies that token metadata, if any, must be valid - if len(r.TokenMetadata) > 0 { - for _, metadata := range r.TokenMetadata { - if err := metadata.Validate(); err != nil { - return errorsmod.Wrapf(ErrInvalidTokenMetadata, "%s: %v", metadata.Base, err) - } - } - } - - // genesisAccounts address validation - for _, acc := range r.GenesisState.GenesisAccounts { - _, err := sdk.AccAddressFromBech32(acc.Address) - if err != nil { - return errorsmod.Wrapf(err, "invalid genesis account address (%s)", acc.Address) - } - } - return nil } diff --git a/x/rollapp/types/rollapp.pb.go b/x/rollapp/types/rollapp.pb.go index 32f82873e..0b35b648b 100644 --- a/x/rollapp/types/rollapp.pb.go +++ b/x/rollapp/types/rollapp.pb.go @@ -5,7 +5,7 @@ package types import ( fmt "fmt" - types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/cosmos-sdk/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" io "io" @@ -24,74 +24,21 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// GenesisAccount is a struct for the genesis account for the rollapp -type GenesisAccount struct { - // amount of coins to be sent to the genesis address - Amount types.Coin `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount"` - // address is a bech-32 address of the genesis account - Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` -} - -func (m *GenesisAccount) Reset() { *m = GenesisAccount{} } -func (m *GenesisAccount) String() string { return proto.CompactTextString(m) } -func (*GenesisAccount) ProtoMessage() {} -func (*GenesisAccount) Descriptor() ([]byte, []int) { - return fileDescriptor_2c072320fdc0abd9, []int{0} -} -func (m *GenesisAccount) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *GenesisAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_GenesisAccount.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *GenesisAccount) XXX_Merge(src proto.Message) { - xxx_messageInfo_GenesisAccount.Merge(m, src) -} -func (m *GenesisAccount) XXX_Size() int { - return m.Size() -} -func (m *GenesisAccount) XXX_DiscardUnknown() { - xxx_messageInfo_GenesisAccount.DiscardUnknown(m) -} - -var xxx_messageInfo_GenesisAccount proto.InternalMessageInfo - -func (m *GenesisAccount) GetAmount() types.Coin { - if m != nil { - return m.Amount - } - return types.Coin{} -} - -func (m *GenesisAccount) GetAddress() string { - if m != nil { - return m.Address - } - return "" -} - // RollappGenesisState is a partial repr of the state the hub can expect the rollapp to be in upon genesis type RollappGenesisState struct { - // genesis_accounts is a list of token allocations - GenesisAccounts []*GenesisAccount `protobuf:"bytes,1,rep,name=genesis_accounts,json=genesisAccounts,proto3" json:"genesis_accounts,omitempty"` - // is_genesis_event is a boolean that indicates if the genesis event has occured - IsGenesisEvent bool `protobuf:"varint,2,opt,name=is_genesis_event,json=isGenesisEvent,proto3" json:"is_genesis_event,omitempty"` + // If true, then full usage of the canonical ibc transfer channel is enabled. + // Note: in v3.1.0 and prior this field marked the completion of the 'genesis event' + // Keeping and renaming the field enables a seamless upgrade https://www.notion.so/dymension/ADR-x-Genesis-Bridge-Phase-2-89769aa551b5440b9ed403a101775ce1?pvs=4#89698384d815435b87393dbe45bc5a74 + // to the new genesis transfer protocol + // Note: if this field is false, ibc transfers may still be allowed in one or either direction. + TransfersEnabled bool `protobuf:"varint,2,opt,name=transfers_enabled,json=transfersEnabled,proto3" json:"transfers_enabled,omitempty"` } func (m *RollappGenesisState) Reset() { *m = RollappGenesisState{} } func (m *RollappGenesisState) String() string { return proto.CompactTextString(m) } func (*RollappGenesisState) ProtoMessage() {} func (*RollappGenesisState) Descriptor() ([]byte, []int) { - return fileDescriptor_2c072320fdc0abd9, []int{1} + return fileDescriptor_2c072320fdc0abd9, []int{0} } func (m *RollappGenesisState) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -120,16 +67,9 @@ func (m *RollappGenesisState) XXX_DiscardUnknown() { var xxx_messageInfo_RollappGenesisState proto.InternalMessageInfo -func (m *RollappGenesisState) GetGenesisAccounts() []*GenesisAccount { +func (m *RollappGenesisState) GetTransfersEnabled() bool { if m != nil { - return m.GenesisAccounts - } - return nil -} - -func (m *RollappGenesisState) GetIsGenesisEvent() bool { - if m != nil { - return m.IsGenesisEvent + return m.TransfersEnabled } return false } @@ -150,8 +90,6 @@ type Rollapp struct { // permissionedAddresses is a bech32-encoded address list of the sequencers that are allowed to serve this rollappId. // In the case of an empty list, the rollapp is considered permissionless. PermissionedAddresses []string `protobuf:"bytes,5,rep,name=permissionedAddresses,proto3" json:"permissionedAddresses,omitempty"` - // tokenMetadata is a list of TokenMetadata that are registered on this rollapp - TokenMetadata []*TokenMetadata `protobuf:"bytes,6,rep,name=tokenMetadata,proto3" json:"tokenMetadata,omitempty"` // genesis_state is a partial repr of the state the hub can expect the rollapp to be in upon genesis GenesisState RollappGenesisState `protobuf:"bytes,7,opt,name=genesis_state,json=genesisState,proto3" json:"genesis_state"` // channel_id will be set to the canonical IBC channel of the rollapp. @@ -166,7 +104,7 @@ func (m *Rollapp) Reset() { *m = Rollapp{} } func (m *Rollapp) String() string { return proto.CompactTextString(m) } func (*Rollapp) ProtoMessage() {} func (*Rollapp) Descriptor() ([]byte, []int) { - return fileDescriptor_2c072320fdc0abd9, []int{2} + return fileDescriptor_2c072320fdc0abd9, []int{1} } func (m *Rollapp) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -230,13 +168,6 @@ func (m *Rollapp) GetPermissionedAddresses() []string { return nil } -func (m *Rollapp) GetTokenMetadata() []*TokenMetadata { - if m != nil { - return m.TokenMetadata - } - return nil -} - func (m *Rollapp) GetGenesisState() RollappGenesisState { if m != nil { return m.GenesisState @@ -280,7 +211,7 @@ func (m *RollappSummary) Reset() { *m = RollappSummary{} } func (m *RollappSummary) String() string { return proto.CompactTextString(m) } func (*RollappSummary) ProtoMessage() {} func (*RollappSummary) Descriptor() ([]byte, []int) { - return fileDescriptor_2c072320fdc0abd9, []int{3} + return fileDescriptor_2c072320fdc0abd9, []int{2} } func (m *RollappSummary) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -331,7 +262,6 @@ func (m *RollappSummary) GetLatestFinalizedStateIndex() *StateInfoIndex { } func init() { - proto.RegisterType((*GenesisAccount)(nil), "dymensionxyz.dymension.rollapp.GenesisAccount") proto.RegisterType((*RollappGenesisState)(nil), "dymensionxyz.dymension.rollapp.RollappGenesisState") proto.RegisterType((*Rollapp)(nil), "dymensionxyz.dymension.rollapp.Rollapp") proto.RegisterType((*RollappSummary)(nil), "dymensionxyz.dymension.rollapp.RollappSummary") @@ -340,84 +270,39 @@ func init() { func init() { proto.RegisterFile("dymension/rollapp/rollapp.proto", fileDescriptor_2c072320fdc0abd9) } var fileDescriptor_2c072320fdc0abd9 = []byte{ - // 586 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0x4b, 0x6f, 0xd3, 0x40, - 0x10, 0x8e, 0x49, 0x49, 0x9b, 0x2d, 0x2d, 0xd1, 0xf2, 0xd0, 0xb6, 0x2a, 0x6e, 0x14, 0x71, 0xb0, - 0x90, 0xb0, 0xd5, 0x87, 0xc4, 0xb9, 0xe5, 0xa5, 0x1e, 0xe0, 0xe0, 0x70, 0xa1, 0x07, 0xa2, 0x8d, - 0x3d, 0x75, 0x57, 0xb5, 0x77, 0xc3, 0xee, 0x26, 0x4a, 0xfa, 0x2b, 0x38, 0xf3, 0x8b, 0x7a, 0xa3, - 0x47, 0x4e, 0x08, 0x25, 0x7f, 0x82, 0x23, 0xf2, 0x7a, 0x9d, 0x26, 0x4a, 0x21, 0x88, 0x93, 0xfd, - 0xcd, 0xe3, 0x9b, 0x99, 0x6f, 0x46, 0x8b, 0x76, 0xe3, 0x51, 0x06, 0x5c, 0x31, 0xc1, 0x03, 0x29, - 0xd2, 0x94, 0xf6, 0x7a, 0xe5, 0xd7, 0xef, 0x49, 0xa1, 0x05, 0x76, 0xa7, 0x01, 0xc3, 0xd1, 0xa5, - 0x3f, 0x05, 0xbe, 0x8d, 0xda, 0x7e, 0x98, 0x88, 0x44, 0x98, 0xd0, 0x20, 0xff, 0x2b, 0xb2, 0xb6, - 0x5b, 0x8b, 0xb4, 0x4a, 0x53, 0x0d, 0x1d, 0xc6, 0xcf, 0xca, 0x98, 0x9d, 0xc5, 0x98, 0x2e, 0xe5, - 0x17, 0xd6, 0xeb, 0x46, 0x42, 0x65, 0x42, 0x05, 0x5d, 0xaa, 0x20, 0x18, 0xec, 0x75, 0x41, 0xd3, - 0xbd, 0x20, 0x12, 0x8c, 0x17, 0xfe, 0x56, 0x84, 0x36, 0xdf, 0x02, 0x07, 0xc5, 0xd4, 0x51, 0x14, - 0x89, 0x3e, 0xd7, 0xf8, 0x05, 0xaa, 0xd1, 0x2c, 0xff, 0x23, 0x4e, 0xd3, 0xf1, 0xd6, 0xf7, 0xb7, - 0xfc, 0x82, 0xc2, 0xcf, 0x29, 0x7c, 0x4b, 0xe1, 0xbf, 0x14, 0x8c, 0x1f, 0xaf, 0x5c, 0xfd, 0xd8, - 0xad, 0x84, 0x36, 0x1c, 0x13, 0xb4, 0x4a, 0xe3, 0x58, 0x82, 0x52, 0xe4, 0x4e, 0xd3, 0xf1, 0xea, - 0x61, 0x09, 0x5b, 0x5f, 0x1d, 0xf4, 0x20, 0x2c, 0x7a, 0xb3, 0xc5, 0xda, 0xf9, 0x14, 0xf8, 0x23, - 0x6a, 0x24, 0x05, 0xee, 0xd0, 0xa2, 0xba, 0x22, 0x4e, 0xb3, 0xea, 0xad, 0xef, 0xfb, 0xfe, 0xdf, - 0xf5, 0xf2, 0xe7, 0x9b, 0x0e, 0xef, 0x27, 0x73, 0x58, 0x61, 0x0f, 0x35, 0x98, 0xea, 0x94, 0xec, - 0x30, 0x00, 0xae, 0x4d, 0x57, 0x6b, 0xe1, 0x26, 0x53, 0x36, 0xf9, 0x75, 0x6e, 0x6d, 0x7d, 0xab, - 0xa2, 0x55, 0xdb, 0x1c, 0xde, 0x41, 0x75, 0x5b, 0xe0, 0x24, 0x36, 0xe3, 0xd7, 0xc3, 0x1b, 0x43, - 0x3e, 0x60, 0x24, 0x81, 0x6a, 0x21, 0xcb, 0x01, 0x2d, 0xcc, 0x3d, 0x03, 0x90, 0x79, 0x83, 0xa4, - 0xda, 0x74, 0xbc, 0x95, 0xb0, 0x84, 0xf8, 0x29, 0xda, 0xc8, 0xe8, 0xb0, 0x0d, 0x9f, 0xfb, 0xc0, - 0x23, 0x90, 0x8a, 0xac, 0x18, 0xff, 0xbc, 0x11, 0x1f, 0xa2, 0x47, 0x3d, 0x90, 0x19, 0x53, 0x79, - 0x0e, 0xc4, 0x47, 0x85, 0x6e, 0xa0, 0xc8, 0xdd, 0x66, 0xd5, 0xab, 0x87, 0xb7, 0x3b, 0x71, 0x1b, - 0x6d, 0x68, 0x71, 0x01, 0xfc, 0x1d, 0x68, 0x1a, 0x53, 0x4d, 0x49, 0xcd, 0x68, 0xf7, 0x7c, 0x99, - 0x76, 0x1f, 0x66, 0x93, 0xc2, 0x79, 0x0e, 0xfc, 0x09, 0x6d, 0x94, 0xaa, 0x99, 0x53, 0x23, 0xab, - 0xe6, 0x0a, 0x0e, 0x96, 0x91, 0xde, 0xb2, 0x5f, 0x7b, 0x1f, 0xf7, 0x92, 0xd9, 0x9d, 0x3f, 0x41, - 0x28, 0x3a, 0xa7, 0x9c, 0x43, 0xda, 0x61, 0x31, 0x59, 0x2b, 0x34, 0xb6, 0x96, 0x93, 0x18, 0x3f, - 0x46, 0xb5, 0x33, 0x29, 0x2e, 0x81, 0x93, 0xba, 0xd9, 0x96, 0x45, 0xf8, 0x19, 0x6a, 0x48, 0x48, - 0x98, 0xd2, 0x20, 0x21, 0x7e, 0x05, 0x5c, 0x64, 0x8a, 0x20, 0x23, 0xce, 0x82, 0xbd, 0xf5, 0xcb, - 0x41, 0x9b, 0xb6, 0x9d, 0x76, 0x3f, 0xcb, 0xa8, 0x1c, 0x2d, 0x59, 0xec, 0x29, 0x6a, 0xa4, 0x54, - 0x83, 0xd2, 0xa6, 0xc5, 0x13, 0x1e, 0xc3, 0xd0, 0x6c, 0xf8, 0x1f, 0xee, 0xd0, 0x66, 0x9c, 0x09, - 0x93, 0x15, 0x2e, 0xf0, 0xe0, 0x14, 0x6d, 0x15, 0xb6, 0x37, 0x8c, 0xd3, 0x94, 0x5d, 0x42, 0x3c, - 0x53, 0xa4, 0xfa, 0x5f, 0x45, 0xfe, 0x4c, 0x78, 0xfc, 0xfe, 0x6a, 0xec, 0x3a, 0xd7, 0x63, 0xd7, - 0xf9, 0x39, 0x76, 0x9d, 0x2f, 0x13, 0xb7, 0x72, 0x3d, 0x71, 0x2b, 0xdf, 0x27, 0x6e, 0xe5, 0xf4, - 0x30, 0x61, 0xfa, 0xbc, 0xdf, 0xf5, 0x23, 0x91, 0x05, 0xb3, 0xe5, 0x6e, 0x40, 0x30, 0x38, 0x08, - 0x86, 0xd3, 0x37, 0x44, 0x8f, 0x7a, 0xa0, 0xba, 0x35, 0xf3, 0x4a, 0x1c, 0xfc, 0x0e, 0x00, 0x00, - 0xff, 0xff, 0x75, 0x02, 0x7c, 0xc2, 0xe0, 0x04, 0x00, 0x00, -} - -func (m *GenesisAccount) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *GenesisAccount) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *GenesisAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Address) > 0 { - i -= len(m.Address) - copy(dAtA[i:], m.Address) - i = encodeVarintRollapp(dAtA, i, uint64(len(m.Address))) - i-- - dAtA[i] = 0x12 - } - { - size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintRollapp(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + // 498 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x53, 0xcd, 0x6e, 0x13, 0x31, + 0x10, 0x8e, 0x9b, 0x90, 0x1f, 0x97, 0xa2, 0x60, 0x7e, 0x64, 0x2a, 0xd8, 0x46, 0x11, 0x87, 0x08, + 0xa4, 0x5d, 0xb5, 0xe9, 0x0b, 0x50, 0xf1, 0x97, 0x1e, 0x38, 0x6c, 0x6e, 0x3d, 0x10, 0x39, 0xeb, + 0xc9, 0xd6, 0xd2, 0xae, 0x1d, 0x6c, 0x27, 0x4a, 0x72, 0xe2, 0x11, 0x78, 0xac, 0x1e, 0x7b, 0xe4, + 0x84, 0x50, 0xf2, 0x12, 0x1c, 0xd1, 0x7a, 0x37, 0x69, 0x50, 0x0a, 0x95, 0x38, 0xed, 0xce, 0x37, + 0xf3, 0x7d, 0x33, 0xf3, 0x8d, 0x8c, 0x8f, 0xf8, 0x3c, 0x05, 0x69, 0x84, 0x92, 0x81, 0x56, 0x49, + 0xc2, 0xc6, 0xe3, 0xf5, 0xd7, 0x1f, 0x6b, 0x65, 0x15, 0xf1, 0x36, 0x05, 0xb3, 0xf9, 0xc2, 0xdf, + 0x04, 0x7e, 0x51, 0x75, 0xf8, 0x38, 0x56, 0xb1, 0x72, 0xa5, 0x41, 0xf6, 0x97, 0xb3, 0x0e, 0xdb, + 0xbb, 0xb2, 0xc6, 0x32, 0x0b, 0x03, 0x21, 0x47, 0xeb, 0x1a, 0x2f, 0x52, 0x26, 0x55, 0x26, 0x18, + 0x32, 0x03, 0xc1, 0xf4, 0x78, 0x08, 0x96, 0x1d, 0x07, 0x91, 0x12, 0x32, 0xcf, 0xb7, 0x3f, 0xe2, + 0x47, 0x61, 0xce, 0xfd, 0x00, 0x12, 0x8c, 0x30, 0xfd, 0x4c, 0x81, 0xbc, 0xc6, 0x0f, 0xad, 0x66, + 0xd2, 0x8c, 0x40, 0x9b, 0x01, 0x48, 0x36, 0x4c, 0x80, 0xd3, 0xbd, 0x16, 0xea, 0xd4, 0xc3, 0xe6, + 0x26, 0xf1, 0x2e, 0xc7, 0xcf, 0x2b, 0x75, 0xd4, 0xdc, 0x6b, 0x7f, 0x2d, 0xe3, 0x5a, 0x21, 0x45, + 0x9e, 0xe3, 0x46, 0x31, 0x51, 0x8f, 0x53, 0xd4, 0x42, 0x9d, 0x46, 0x78, 0x03, 0x10, 0x8a, 0x6b, + 0x91, 0x06, 0x66, 0x95, 0x76, 0x92, 0x8d, 0x70, 0x1d, 0x66, 0x99, 0x29, 0xe8, 0x6c, 0x23, 0x5a, + 0x6e, 0xa1, 0x4e, 0x25, 0x5c, 0x87, 0xe4, 0x25, 0x3e, 0x48, 0xd9, 0xac, 0x0f, 0x5f, 0x26, 0x20, + 0x23, 0xd0, 0x86, 0x56, 0x5c, 0xfe, 0x4f, 0x90, 0x9c, 0xe2, 0x27, 0x63, 0xd0, 0xa9, 0x30, 0x19, + 0x07, 0xf8, 0x1b, 0xce, 0x35, 0x18, 0x03, 0x86, 0xde, 0x6b, 0x95, 0x3b, 0x8d, 0xf0, 0xf6, 0x24, + 0xf9, 0x8c, 0x0f, 0xe2, 0x7c, 0xf9, 0x81, 0xf3, 0x8f, 0xd6, 0x5a, 0xa8, 0xb3, 0x7f, 0xd2, 0xf5, + 0xff, 0x7d, 0x15, 0xff, 0x16, 0xe3, 0xce, 0x2a, 0x57, 0x3f, 0x8e, 0x4a, 0xe1, 0xfd, 0x78, 0xdb, + 0xcc, 0x17, 0x18, 0x47, 0x97, 0x4c, 0x4a, 0x48, 0x06, 0x82, 0xd3, 0x7a, 0x6e, 0x47, 0x81, 0xf4, + 0x38, 0x79, 0x8a, 0xab, 0x23, 0xad, 0x16, 0x20, 0x69, 0xc3, 0x19, 0x5c, 0x44, 0xe4, 0x15, 0x6e, + 0x6a, 0x88, 0x85, 0xb1, 0xa0, 0x81, 0xbf, 0x05, 0xa9, 0x52, 0x43, 0xb1, 0xdb, 0x63, 0x07, 0x3f, + 0xaf, 0xd4, 0xab, 0xcd, 0x5a, 0xfb, 0x17, 0xc2, 0x0f, 0x8a, 0xa1, 0xfa, 0x93, 0x34, 0x65, 0x7a, + 0x7e, 0xc7, 0x25, 0x2e, 0x70, 0x33, 0x61, 0x16, 0x8c, 0x75, 0x83, 0xf6, 0x24, 0x87, 0x99, 0x3b, + 0xc9, 0xfe, 0x89, 0x7f, 0xd7, 0xf2, 0x05, 0x63, 0xa4, 0x1c, 0x2b, 0xdc, 0xd1, 0x21, 0x09, 0x7e, + 0x96, 0x63, 0xef, 0x85, 0x64, 0x89, 0x58, 0x00, 0xdf, 0x6a, 0x52, 0xfe, 0xaf, 0x26, 0x7f, 0x17, + 0x3c, 0xfb, 0x74, 0xb5, 0xf4, 0xd0, 0xf5, 0xd2, 0x43, 0x3f, 0x97, 0x1e, 0xfa, 0xb6, 0xf2, 0x4a, + 0xd7, 0x2b, 0xaf, 0xf4, 0x7d, 0xe5, 0x95, 0x2e, 0x4e, 0x63, 0x61, 0x2f, 0x27, 0x43, 0x3f, 0x52, + 0x69, 0xb0, 0xdd, 0xee, 0x26, 0x08, 0xa6, 0xdd, 0x60, 0xb6, 0x79, 0x42, 0x76, 0x3e, 0x06, 0x33, + 0xac, 0xba, 0xe7, 0xd1, 0xfd, 0x1d, 0x00, 0x00, 0xff, 0xff, 0xcf, 0x3e, 0x28, 0x34, 0xbb, 0x03, + 0x00, 0x00, } func (m *RollappGenesisState) Marshal() (dAtA []byte, err error) { @@ -440,9 +325,9 @@ func (m *RollappGenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.IsGenesisEvent { + if m.TransfersEnabled { i-- - if m.IsGenesisEvent { + if m.TransfersEnabled { dAtA[i] = 1 } else { dAtA[i] = 0 @@ -450,20 +335,6 @@ func (m *RollappGenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x10 } - if len(m.GenesisAccounts) > 0 { - for iNdEx := len(m.GenesisAccounts) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.GenesisAccounts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintRollapp(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } return len(dAtA) - i, nil } @@ -523,20 +394,6 @@ func (m *Rollapp) MarshalToSizedBuffer(dAtA []byte) (int, error) { } i-- dAtA[i] = 0x3a - if len(m.TokenMetadata) > 0 { - for iNdEx := len(m.TokenMetadata) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.TokenMetadata[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintRollapp(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x32 - } - } if len(m.PermissionedAddresses) > 0 { for iNdEx := len(m.PermissionedAddresses) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.PermissionedAddresses[iNdEx]) @@ -638,34 +495,13 @@ func encodeVarintRollapp(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } -func (m *GenesisAccount) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = m.Amount.Size() - n += 1 + l + sovRollapp(uint64(l)) - l = len(m.Address) - if l > 0 { - n += 1 + l + sovRollapp(uint64(l)) - } - return n -} - func (m *RollappGenesisState) Size() (n int) { if m == nil { return 0 } var l int _ = l - if len(m.GenesisAccounts) > 0 { - for _, e := range m.GenesisAccounts { - l = e.Size() - n += 1 + l + sovRollapp(uint64(l)) - } - } - if m.IsGenesisEvent { + if m.TransfersEnabled { n += 2 } return n @@ -697,12 +533,6 @@ func (m *Rollapp) Size() (n int) { n += 1 + l + sovRollapp(uint64(l)) } } - if len(m.TokenMetadata) > 0 { - for _, e := range m.TokenMetadata { - l = e.Size() - n += 1 + l + sovRollapp(uint64(l)) - } - } l = m.GenesisState.Size() n += 1 + l + sovRollapp(uint64(l)) l = len(m.ChannelId) @@ -748,121 +578,6 @@ func sovRollapp(x uint64) (n int) { func sozRollapp(x uint64) (n int) { return sovRollapp(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *GenesisAccount) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRollapp - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: GenesisAccount: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: GenesisAccount: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRollapp - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthRollapp - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthRollapp - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRollapp - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthRollapp - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthRollapp - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Address = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipRollapp(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthRollapp - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *RollappGenesisState) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -892,43 +607,9 @@ func (m *RollappGenesisState) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: RollappGenesisState: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field GenesisAccounts", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRollapp - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthRollapp - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthRollapp - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.GenesisAccounts = append(m.GenesisAccounts, &GenesisAccount{}) - if err := m.GenesisAccounts[len(m.GenesisAccounts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex case 2: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field IsGenesisEvent", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field TransfersEnabled", wireType) } var v int for shift := uint(0); ; shift += 7 { @@ -945,7 +626,7 @@ func (m *RollappGenesisState) Unmarshal(dAtA []byte) error { break } } - m.IsGenesisEvent = bool(v != 0) + m.TransfersEnabled = bool(v != 0) default: iNdEx = preIndex skippy, err := skipRollapp(dAtA[iNdEx:]) @@ -1130,40 +811,6 @@ func (m *Rollapp) Unmarshal(dAtA []byte) error { } m.PermissionedAddresses = append(m.PermissionedAddresses, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TokenMetadata", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRollapp - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthRollapp - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthRollapp - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.TokenMetadata = append(m.TokenMetadata, &TokenMetadata{}) - if err := m.TokenMetadata[len(m.TokenMetadata)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex case 7: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field GenesisState", wireType) diff --git a/x/rollapp/types/token_metadata.go b/x/rollapp/types/token_metadata.go deleted file mode 100644 index 9df221d28..000000000 --- a/x/rollapp/types/token_metadata.go +++ /dev/null @@ -1,42 +0,0 @@ -package types - -import ( - "errors" - - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" -) - -// Validate performs a basic validation of the coin metadata fields. -// Inherits from x/bank metadata and following same spec of x/bank/types/metadata.go -func (m *TokenMetadata) Validate() error { - if m == nil { - return errors.New("token metadata cannot be nil") - } - - bankMetadata := m.ConvertToBankMetadata() - return bankMetadata.Validate() -} - -// ConvertToBankMetadata converts TokenMetadata to Metadata of x/bank/types -func (m *TokenMetadata) ConvertToBankMetadata() banktypes.Metadata { - var denomUnits []*banktypes.DenomUnit - - for _, denomUnit := range m.DenomUnits { - denomUnits = append(denomUnits, &banktypes.DenomUnit{ - Denom: denomUnit.Denom, - Exponent: denomUnit.Exponent, - Aliases: denomUnit.Aliases, - }) - } - - return banktypes.Metadata{ - Description: m.Description, - DenomUnits: denomUnits, - Base: m.Base, - Display: m.Display, - Name: m.Name, - Symbol: m.Symbol, - URI: m.URI, - URIHash: m.URIHash, - } -} diff --git a/x/rollapp/types/token_metadata_test.go b/x/rollapp/types/token_metadata_test.go deleted file mode 100644 index b66000542..000000000 --- a/x/rollapp/types/token_metadata_test.go +++ /dev/null @@ -1,296 +0,0 @@ -package types - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/codec" -) - -// TestMetadataValidate tests Validate method of TokenMetadata. -// Testcases are copied from x/bank/types/metadata_test.go -func TestMetadataValidate(t *testing.T) { - testCases := []struct { - name string - metadata TokenMetadata - expErr bool - }{ - { - "non-empty coins", - TokenMetadata{ - Name: "RollApp RAX", - Symbol: "rax", - Description: "The native staking token of RollApp XYZ", - DenomUnits: []*DenomUnit{ - {"urax", uint32(0), []string{"microrax"}}, - {"mrax", uint32(3), []string{"millirax"}}, - {"rax", uint32(6), nil}, - }, - Base: "urax", - Display: "rax", - }, - false, - }, - { - "duplicate exponent", // this testcase is not in x/bank/types/metadata_test.go - TokenMetadata{ - Name: "RollApp RAX", - Symbol: "rax", - Description: "The native staking token of RollApp XYZ", - DenomUnits: []*DenomUnit{ - {"urax", uint32(0), nil}, - {"urax2", uint32(0), nil}, - {"rax", uint32(6), nil}, - }, - Base: "urax", - Display: "rax", - }, - true, - }, - { - "base coin is display coin", - TokenMetadata{ - Name: "RollApp RAX", - Symbol: "rax", - Description: "The native staking token of RollApp XYZ", - DenomUnits: []*DenomUnit{ - {"rax", uint32(0), []string{"rax"}}, - }, - Base: "rax", - Display: "rax", - }, - false, - }, - {"empty metadata", TokenMetadata{}, true}, - { - "blank name", - TokenMetadata{ - Name: "", - }, - true, - }, - { - "blank symbol", - TokenMetadata{ - Name: "RollApp RAX", - Symbol: "", - }, - true, - }, - { - "invalid base denom", - TokenMetadata{ - Name: "RollApp RAX", - Symbol: "rax", - Base: "", - }, - true, - }, - { - "invalid display denom", - TokenMetadata{ - Name: "RollApp RAX", - Symbol: "rax", - Base: "urax", - Display: "", - }, - true, - }, - { - "duplicate denom unit", - TokenMetadata{ - Name: "RollApp RAX", - Symbol: "rax", - Description: "The native staking token of RollApp XYZ", - DenomUnits: []*DenomUnit{ - {"urax", uint32(0), []string{"microrax"}}, - {"urax", uint32(1), []string{"microrax"}}, - }, - Base: "urax", - Display: "rax", - }, - true, - }, - { - "invalid denom unit", - TokenMetadata{ - Name: "RollApp RAX", - Symbol: "rax", - Description: "The native staking token of RollApp XYZ", - DenomUnits: []*DenomUnit{ - {"", uint32(0), []string{"microrax"}}, - }, - Base: "urax", - Display: "rax", - }, - true, - }, - { - "invalid denom unit alias", - TokenMetadata{ - Name: "RollApp RAX", - Symbol: "rax", - Description: "The native staking token of RollApp XYZ", - DenomUnits: []*DenomUnit{ - {"urax", uint32(0), []string{""}}, - }, - Base: "urax", - Display: "rax", - }, - true, - }, - { - "duplicate denom unit alias", - TokenMetadata{ - Name: "RollApp RAX", - Symbol: "rax", - Description: "The native staking token of RollApp XYZ", - DenomUnits: []*DenomUnit{ - {"urax", uint32(0), []string{"microrax", "microrax"}}, - }, - Base: "urax", - Display: "rax", - }, - true, - }, - { - "no base denom unit", - TokenMetadata{ - Name: "RollApp RAX", - Symbol: "rax", - Description: "The native staking token of RollApp XYZ", - DenomUnits: []*DenomUnit{ - {"mrax", uint32(3), []string{"millirax"}}, - {"rax", uint32(6), nil}, - }, - Base: "urax", - Display: "rax", - }, - true, - }, - { - "base denom exponent not zero", - TokenMetadata{ - Name: "RollApp RAX", - Symbol: "rax", - Description: "The native staking token of RollApp XYZ", - DenomUnits: []*DenomUnit{ - {"urax", uint32(1), []string{"microrax"}}, - {"mrax", uint32(3), []string{"millirax"}}, - {"rax", uint32(6), nil}, - }, - Base: "urax", - Display: "rax", - }, - true, - }, - { - "invalid denom unit", - TokenMetadata{ - Name: "RollApp RAX", - Symbol: "rax", - Description: "The native staking token of RollApp XYZ", - DenomUnits: []*DenomUnit{ - {"urax", uint32(0), []string{"microrax"}}, - {"", uint32(3), []string{"millirax"}}, - }, - Base: "urax", - Display: "urax", - }, - true, - }, - { - "no display denom unit", - TokenMetadata{ - Name: "RollApp RAX", - Symbol: "rax", - Description: "The native staking token of RollApp XYZ", - DenomUnits: []*DenomUnit{ - {"urax", uint32(0), []string{"microrax"}}, - }, - Base: "urax", - Display: "rax", - }, - true, - }, - { - "denom units not sorted", - TokenMetadata{ - Name: "RollApp RAX", - Symbol: "rax", - Description: "The native staking token of RollApp XYZ", - DenomUnits: []*DenomUnit{ - {"urax", uint32(0), []string{"microrax"}}, - {"rax", uint32(6), nil}, - {"mrax", uint32(3), []string{"millirax"}}, - }, - Base: "urax", - Display: "rax", - }, - true, - }, - } - - for _, tc := range testCases { - tc := tc - t.Run(tc.name, func(t *testing.T) { - err := tc.metadata.Validate() - - if tc.expErr { - require.Error(t, err) - } else { - require.NoError(t, err) - } - }) - } -} - -// TestMarshalJSONMetaData tests MarshalJSON for TokenMetadata. -// Testcases are copied from x/bank/types/metadata_test.go -func TestMarshalJSONMetaData(t *testing.T) { - cdc := codec.NewLegacyAmino() - - testCases := []struct { - name string - input []TokenMetadata - strOutput string - }{ - {"nil metadata", nil, `null`}, - {"empty metadata", []TokenMetadata{}, `[]`}, - { - "non-empty coins", - []TokenMetadata{ - { - Description: "The native staking token of RollApp XYZ", - DenomUnits: []*DenomUnit{ - {"urax", uint32(0), []string{"microrax"}}, // The default exponent value 0 is omitted in the json - {"mrax", uint32(3), []string{"millirax"}}, - {"rax", uint32(6), nil}, - }, - Base: "urax", - Display: "rax", - }, - }, - `[{"description":"The native staking token of RollApp XYZ","denom_units":[{"denom":"urax","aliases":["microrax"]},{"denom":"mrax","exponent":3,"aliases":["millirax"]},{"denom":"rax","exponent":6}],"base":"urax","display":"rax"}]`, - }, - } - - for _, tc := range testCases { - tc := tc - t.Run(tc.name, func(t *testing.T) { - bz, err := cdc.MarshalJSON(tc.input) - require.NoError(t, err) - require.Equal(t, tc.strOutput, string(bz)) - - var newMetadata []TokenMetadata - require.NoError(t, cdc.UnmarshalJSON(bz, &newMetadata)) - - if len(tc.input) == 0 { - require.Nil(t, newMetadata) - } else { - require.Equal(t, tc.input, newMetadata) - } - }) - } -} diff --git a/x/rollapp/types/transfer.go b/x/rollapp/types/transfer.go new file mode 100644 index 000000000..8febf394d --- /dev/null +++ b/x/rollapp/types/transfer.go @@ -0,0 +1,30 @@ +package types + +import ( + "fmt" + + "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" +) + +type TransferData struct { + transfertypes.FungibleTokenPacketData + // Rollapp will be the nil if the packet is not to/from a registered rollapp + Rollapp *Rollapp +} + +// IsRollapp returns whether the transfer came from a rollapp or was sent to a rollapp +func (d TransferData) IsRollapp() bool { + return d.Rollapp != nil +} + +// MustAmountInt returns the int amount. Should call validateBasic first! +func (d TransferData) MustAmountInt() math.Int { + x, ok := sdk.NewIntFromString(d.Amount) + if !ok { + panic(fmt.Sprintf("parse transfer amount to Int: %s", d.Amount)) + } + return x +} diff --git a/x/rollapp/types/tx.pb.go b/x/rollapp/types/tx.pb.go index f505708f0..213a29702 100644 --- a/x/rollapp/types/tx.pb.go +++ b/x/rollapp/types/tx.pb.go @@ -6,21 +6,24 @@ package types import ( context "context" fmt "fmt" + io "io" + math "math" + math_bits "math/bits" + _ "github.com/gogo/protobuf/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" - io "io" - math "math" - math_bits "math/bits" ) // Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf +var ( + _ = proto.Marshal + _ = fmt.Errorf + _ = math.Inf +) // This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. @@ -41,10 +44,10 @@ type MsgCreateRollapp struct { // sequencers that are allowed to serve this rollappId. // In the case of an empty list, the rollapp is considered permissionless PermissionedAddresses []string `protobuf:"bytes,7,rep,name=permissionedAddresses,proto3" json:"permissionedAddresses,omitempty"` - // metadata provides the client information for all the registered tokens. - Metadatas []TokenMetadata `protobuf:"bytes,8,rep,name=metadatas,proto3" json:"metadatas"` - // genesis_accounts for the rollapp on the hub - GenesisAccounts []GenesisAccount `protobuf:"bytes,9,rep,name=genesis_accounts,json=genesisAccounts,proto3" json:"genesis_accounts"` + // enable ibc transfers initially? Must be set false if intending + // to send genesis transfers. Should be true if not intending to send genesis transfers + // see https://github.com/dymensionxyz/dymension/issues/922 for more info + TransfersEnabled bool `protobuf:"varint,10,opt,name=transfersEnabled,proto3" json:"transfersEnabled,omitempty"` } func (m *MsgCreateRollapp) Reset() { *m = MsgCreateRollapp{} } @@ -53,9 +56,11 @@ func (*MsgCreateRollapp) ProtoMessage() {} func (*MsgCreateRollapp) Descriptor() ([]byte, []int) { return fileDescriptor_935cc363af28220c, []int{0} } + func (m *MsgCreateRollapp) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } + func (m *MsgCreateRollapp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { return xxx_messageInfo_MsgCreateRollapp.Marshal(b, m, deterministic) @@ -68,12 +73,15 @@ func (m *MsgCreateRollapp) XXX_Marshal(b []byte, deterministic bool) ([]byte, er return b[:n], nil } } + func (m *MsgCreateRollapp) XXX_Merge(src proto.Message) { xxx_messageInfo_MsgCreateRollapp.Merge(m, src) } + func (m *MsgCreateRollapp) XXX_Size() int { return m.Size() } + func (m *MsgCreateRollapp) XXX_DiscardUnknown() { xxx_messageInfo_MsgCreateRollapp.DiscardUnknown(m) } @@ -108,22 +116,14 @@ func (m *MsgCreateRollapp) GetPermissionedAddresses() []string { return nil } -func (m *MsgCreateRollapp) GetMetadatas() []TokenMetadata { +func (m *MsgCreateRollapp) GetTransfersEnabled() bool { if m != nil { - return m.Metadatas + return m.TransfersEnabled } - return nil + return false } -func (m *MsgCreateRollapp) GetGenesisAccounts() []GenesisAccount { - if m != nil { - return m.GenesisAccounts - } - return nil -} - -type MsgCreateRollappResponse struct { -} +type MsgCreateRollappResponse struct{} func (m *MsgCreateRollappResponse) Reset() { *m = MsgCreateRollappResponse{} } func (m *MsgCreateRollappResponse) String() string { return proto.CompactTextString(m) } @@ -131,9 +131,11 @@ func (*MsgCreateRollappResponse) ProtoMessage() {} func (*MsgCreateRollappResponse) Descriptor() ([]byte, []int) { return fileDescriptor_935cc363af28220c, []int{1} } + func (m *MsgCreateRollappResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } + func (m *MsgCreateRollappResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { return xxx_messageInfo_MsgCreateRollappResponse.Marshal(b, m, deterministic) @@ -146,12 +148,15 @@ func (m *MsgCreateRollappResponse) XXX_Marshal(b []byte, deterministic bool) ([] return b[:n], nil } } + func (m *MsgCreateRollappResponse) XXX_Merge(src proto.Message) { xxx_messageInfo_MsgCreateRollappResponse.Merge(m, src) } + func (m *MsgCreateRollappResponse) XXX_Size() int { return m.Size() } + func (m *MsgCreateRollappResponse) XXX_DiscardUnknown() { xxx_messageInfo_MsgCreateRollappResponse.DiscardUnknown(m) } @@ -185,9 +190,11 @@ func (*MsgUpdateState) ProtoMessage() {} func (*MsgUpdateState) Descriptor() ([]byte, []int) { return fileDescriptor_935cc363af28220c, []int{2} } + func (m *MsgUpdateState) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } + func (m *MsgUpdateState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { return xxx_messageInfo_MsgUpdateState.Marshal(b, m, deterministic) @@ -200,12 +207,15 @@ func (m *MsgUpdateState) XXX_Marshal(b []byte, deterministic bool) ([]byte, erro return b[:n], nil } } + func (m *MsgUpdateState) XXX_Merge(src proto.Message) { xxx_messageInfo_MsgUpdateState.Merge(m, src) } + func (m *MsgUpdateState) XXX_Size() int { return m.Size() } + func (m *MsgUpdateState) XXX_DiscardUnknown() { xxx_messageInfo_MsgUpdateState.DiscardUnknown(m) } @@ -261,8 +271,7 @@ func (m *MsgUpdateState) GetBDs() BlockDescriptors { return BlockDescriptors{} } -type MsgUpdateStateResponse struct { -} +type MsgUpdateStateResponse struct{} func (m *MsgUpdateStateResponse) Reset() { *m = MsgUpdateStateResponse{} } func (m *MsgUpdateStateResponse) String() string { return proto.CompactTextString(m) } @@ -270,9 +279,11 @@ func (*MsgUpdateStateResponse) ProtoMessage() {} func (*MsgUpdateStateResponse) Descriptor() ([]byte, []int) { return fileDescriptor_935cc363af28220c, []int{3} } + func (m *MsgUpdateStateResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } + func (m *MsgUpdateStateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { return xxx_messageInfo_MsgUpdateStateResponse.Marshal(b, m, deterministic) @@ -285,175 +296,70 @@ func (m *MsgUpdateStateResponse) XXX_Marshal(b []byte, deterministic bool) ([]by return b[:n], nil } } + func (m *MsgUpdateStateResponse) XXX_Merge(src proto.Message) { xxx_messageInfo_MsgUpdateStateResponse.Merge(m, src) } + func (m *MsgUpdateStateResponse) XXX_Size() int { return m.Size() } + func (m *MsgUpdateStateResponse) XXX_DiscardUnknown() { xxx_messageInfo_MsgUpdateStateResponse.DiscardUnknown(m) } var xxx_messageInfo_MsgUpdateStateResponse proto.InternalMessageInfo -// MsgRollappGenesisEvent is the message type for triggering the genesis event of the rollapp -type MsgRollappGenesisEvent struct { - // address is the bech32-encoded address of the sender - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` - // channel_id is the rollapp channel id on the hub - ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` - // rollapp_id is the rollapp id we want to mint tokens on the hub. - // Used for validation against channel_id to reduce error surface. - RollappId string `protobuf:"bytes,3,opt,name=rollapp_id,json=rollappId,proto3" json:"rollapp_id,omitempty"` -} - -func (m *MsgRollappGenesisEvent) Reset() { *m = MsgRollappGenesisEvent{} } -func (m *MsgRollappGenesisEvent) String() string { return proto.CompactTextString(m) } -func (*MsgRollappGenesisEvent) ProtoMessage() {} -func (*MsgRollappGenesisEvent) Descriptor() ([]byte, []int) { - return fileDescriptor_935cc363af28220c, []int{4} -} -func (m *MsgRollappGenesisEvent) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgRollappGenesisEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgRollappGenesisEvent.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgRollappGenesisEvent) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgRollappGenesisEvent.Merge(m, src) -} -func (m *MsgRollappGenesisEvent) XXX_Size() int { - return m.Size() -} -func (m *MsgRollappGenesisEvent) XXX_DiscardUnknown() { - xxx_messageInfo_MsgRollappGenesisEvent.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgRollappGenesisEvent proto.InternalMessageInfo - -func (m *MsgRollappGenesisEvent) GetAddress() string { - if m != nil { - return m.Address - } - return "" -} - -func (m *MsgRollappGenesisEvent) GetChannelId() string { - if m != nil { - return m.ChannelId - } - return "" -} - -func (m *MsgRollappGenesisEvent) GetRollappId() string { - if m != nil { - return m.RollappId - } - return "" -} - -type MsgRollappGenesisEventResponse struct { -} - -func (m *MsgRollappGenesisEventResponse) Reset() { *m = MsgRollappGenesisEventResponse{} } -func (m *MsgRollappGenesisEventResponse) String() string { return proto.CompactTextString(m) } -func (*MsgRollappGenesisEventResponse) ProtoMessage() {} -func (*MsgRollappGenesisEventResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_935cc363af28220c, []int{5} -} -func (m *MsgRollappGenesisEventResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgRollappGenesisEventResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgRollappGenesisEventResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgRollappGenesisEventResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgRollappGenesisEventResponse.Merge(m, src) -} -func (m *MsgRollappGenesisEventResponse) XXX_Size() int { - return m.Size() -} -func (m *MsgRollappGenesisEventResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgRollappGenesisEventResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgRollappGenesisEventResponse proto.InternalMessageInfo - func init() { proto.RegisterType((*MsgCreateRollapp)(nil), "dymensionxyz.dymension.rollapp.MsgCreateRollapp") proto.RegisterType((*MsgCreateRollappResponse)(nil), "dymensionxyz.dymension.rollapp.MsgCreateRollappResponse") proto.RegisterType((*MsgUpdateState)(nil), "dymensionxyz.dymension.rollapp.MsgUpdateState") proto.RegisterType((*MsgUpdateStateResponse)(nil), "dymensionxyz.dymension.rollapp.MsgUpdateStateResponse") - proto.RegisterType((*MsgRollappGenesisEvent)(nil), "dymensionxyz.dymension.rollapp.MsgRollappGenesisEvent") - proto.RegisterType((*MsgRollappGenesisEventResponse)(nil), "dymensionxyz.dymension.rollapp.MsgRollappGenesisEventResponse") } func init() { proto.RegisterFile("dymension/rollapp/tx.proto", fileDescriptor_935cc363af28220c) } var fileDescriptor_935cc363af28220c = []byte{ - // 596 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0x41, 0x6f, 0xd3, 0x4c, - 0x10, 0x8d, 0xeb, 0x7e, 0xed, 0x97, 0x8d, 0x0a, 0xd5, 0x02, 0xd5, 0xca, 0x2a, 0x6e, 0x14, 0x71, - 0xc8, 0x05, 0x1b, 0xb5, 0x15, 0xe2, 0x84, 0xd4, 0x50, 0x44, 0x7b, 0x08, 0x02, 0xb7, 0x5c, 0xb8, - 0x44, 0x5b, 0x7b, 0xe4, 0x58, 0x8d, 0x77, 0xcd, 0xee, 0xa6, 0x4a, 0xe1, 0xca, 0x85, 0x03, 0x12, - 0x3f, 0xab, 0xc7, 0x1e, 0x11, 0x07, 0x84, 0xda, 0x3f, 0x82, 0xd6, 0x5e, 0x3b, 0x49, 0x1b, 0x91, - 0xb6, 0xa7, 0x78, 0xde, 0x9b, 0xf7, 0x76, 0xf2, 0x76, 0x6c, 0xe4, 0x44, 0xa7, 0x29, 0x30, 0x99, - 0x70, 0xe6, 0x0b, 0x3e, 0x18, 0xd0, 0x2c, 0xf3, 0xd5, 0xc8, 0xcb, 0x04, 0x57, 0x1c, 0xbb, 0x15, - 0x37, 0x3a, 0xfd, 0xec, 0x55, 0x85, 0x67, 0x1a, 0x9d, 0xf6, 0x75, 0xed, 0xd1, 0x80, 0x87, 0xc7, - 0xbd, 0x08, 0x64, 0x28, 0x92, 0x4c, 0x71, 0x51, 0x38, 0x39, 0xeb, 0x33, 0x3a, 0x29, 0x3b, 0x36, - 0xec, 0xc6, 0x75, 0xd6, 0xfc, 0x9a, 0x86, 0x87, 0x31, 0x8f, 0x79, 0xfe, 0xe8, 0xeb, 0xa7, 0x02, - 0x6d, 0xfd, 0x5a, 0x40, 0xab, 0x5d, 0x19, 0xbf, 0x12, 0x40, 0x15, 0x04, 0x85, 0x00, 0x13, 0xb4, - 0x1c, 0x6a, 0x80, 0x0b, 0x62, 0x35, 0xad, 0x76, 0x3d, 0x28, 0x4b, 0xbc, 0x8e, 0xea, 0xc6, 0x75, - 0x3f, 0x22, 0x0b, 0x39, 0x37, 0x06, 0xf0, 0x13, 0xb4, 0x92, 0xd2, 0xd1, 0x01, 0x7c, 0x1a, 0x02, - 0x0b, 0x41, 0x48, 0xb2, 0xd4, 0xb4, 0xda, 0x8b, 0xc1, 0x34, 0x88, 0xb7, 0xd1, 0xa3, 0x0c, 0x44, - 0x9a, 0x48, 0x3d, 0x2c, 0x44, 0x3b, 0x51, 0x24, 0x40, 0x4a, 0x90, 0x64, 0xb9, 0x69, 0xb7, 0xeb, - 0xc1, 0x6c, 0x12, 0xbf, 0x47, 0xf5, 0x14, 0x14, 0x8d, 0xa8, 0xa2, 0x92, 0xfc, 0xdf, 0xb4, 0xdb, - 0x8d, 0xcd, 0xa7, 0xde, 0xbf, 0xb3, 0xf5, 0x0e, 0xf9, 0x31, 0xb0, 0xae, 0x51, 0x75, 0x16, 0xcf, - 0x7e, 0x6f, 0xd4, 0x82, 0xb1, 0x0b, 0xee, 0xa1, 0xd5, 0x18, 0x18, 0xc8, 0x44, 0xf6, 0x68, 0x18, - 0xf2, 0x21, 0x53, 0x92, 0xd4, 0x73, 0x67, 0x6f, 0x9e, 0xf3, 0x9b, 0x42, 0xb7, 0x53, 0xc8, 0x8c, - 0xf5, 0xfd, 0x78, 0x0a, 0x95, 0x2d, 0x07, 0x91, 0xab, 0xd9, 0x06, 0x20, 0x33, 0xce, 0x24, 0xb4, - 0xbe, 0x2e, 0xa0, 0x7b, 0x5d, 0x19, 0x7f, 0xc8, 0x22, 0xaa, 0xe0, 0x40, 0x51, 0x05, 0x77, 0x8e, - 0xbd, 0x89, 0x1a, 0x52, 0x51, 0xa1, 0xf6, 0x20, 0x89, 0xfb, 0x8a, 0xd8, 0x79, 0xe8, 0x93, 0x90, - 0xd6, 0xb3, 0x61, 0xda, 0xd1, 0x7b, 0x25, 0xc9, 0x62, 0xce, 0x8f, 0x01, 0xbc, 0x86, 0x96, 0x76, - 0x77, 0xde, 0x51, 0xd5, 0x27, 0xff, 0xe5, 0xd6, 0xa6, 0xd2, 0xf3, 0x9c, 0x80, 0xd0, 0xff, 0xdb, - 0x5c, 0x64, 0x59, 0xe2, 0x3d, 0x64, 0x77, 0x76, 0xf5, 0x85, 0x59, 0xed, 0xc6, 0xe6, 0xb3, 0x79, - 0x61, 0xe5, 0xc7, 0xec, 0x56, 0xeb, 0x2c, 0x4d, 0x5c, 0xda, 0xa2, 0x45, 0xd0, 0xda, 0x74, 0x0a, - 0x55, 0x40, 0x59, 0xce, 0x98, 0xd8, 0x4c, 0xde, 0xaf, 0x4f, 0x80, 0x29, 0x3d, 0x17, 0x2d, 0xf6, - 0xa2, 0xcc, 0xc9, 0x94, 0xf8, 0x31, 0x42, 0x61, 0x9f, 0x32, 0x06, 0x83, 0x5e, 0x52, 0x05, 0x65, - 0x90, 0xfd, 0x48, 0xd3, 0x66, 0x26, 0x4d, 0xdb, 0x57, 0x72, 0x6c, 0x35, 0x91, 0x3b, 0xfb, 0xc4, - 0x72, 0xa6, 0xcd, 0x6f, 0x36, 0xb2, 0xbb, 0x32, 0xc6, 0x5f, 0xd0, 0xca, 0xf4, 0x1b, 0x33, 0x37, - 0x83, 0xab, 0x7b, 0xe0, 0xbc, 0xb8, 0xad, 0xa2, 0x1c, 0x02, 0x0f, 0x51, 0x63, 0x72, 0x6b, 0xbc, - 0x1b, 0x18, 0x4d, 0xf4, 0x3b, 0xcf, 0x6f, 0xd7, 0x5f, 0x1d, 0xfb, 0xdd, 0x42, 0x0f, 0x0e, 0x45, - 0x12, 0xc7, 0x20, 0xa6, 0x6e, 0xe3, 0x26, 0x7e, 0x33, 0x32, 0x75, 0x5e, 0xde, 0x4d, 0x57, 0xce, - 0xd3, 0x79, 0x7b, 0x76, 0xe1, 0x5a, 0xe7, 0x17, 0xae, 0xf5, 0xe7, 0xc2, 0xb5, 0x7e, 0x5c, 0xba, - 0xb5, 0xf3, 0x4b, 0xb7, 0xf6, 0xf3, 0xd2, 0xad, 0x7d, 0xdc, 0x8e, 0x13, 0xd5, 0x1f, 0x1e, 0x79, - 0x21, 0x4f, 0xfd, 0xc9, 0x33, 0xc6, 0x85, 0x7f, 0xb2, 0xe5, 0x8f, 0xc6, 0xdf, 0xea, 0xd3, 0x0c, - 0xe4, 0xd1, 0x52, 0xfe, 0x41, 0xdc, 0xfa, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x68, 0x10, 0x75, 0xf5, - 0xcd, 0x05, 0x00, 0x00, + // 484 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x53, 0xcd, 0x6e, 0xd3, 0x40, + 0x10, 0xce, 0x36, 0x26, 0x8d, 0x37, 0x2a, 0x8a, 0x56, 0x50, 0xad, 0x2c, 0xe4, 0x5a, 0x11, 0x07, + 0x8b, 0x83, 0x8d, 0xda, 0x0a, 0x71, 0x6d, 0x08, 0x52, 0xa9, 0x14, 0x84, 0x5c, 0x71, 0xe1, 0x82, + 0x1c, 0x7b, 0x70, 0x2c, 0x62, 0xaf, 0xd9, 0xd9, 0x54, 0x09, 0x5c, 0x79, 0x00, 0x1e, 0xab, 0xc7, + 0x1e, 0x39, 0x55, 0x28, 0x79, 0x0a, 0x6e, 0xc8, 0x8e, 0x9d, 0x9f, 0x06, 0x01, 0xe1, 0xb4, 0x3b, + 0xdf, 0xcc, 0x7c, 0x33, 0xf3, 0xed, 0x2c, 0x35, 0xc2, 0x69, 0x02, 0x29, 0xc6, 0x22, 0x75, 0xa5, + 0x18, 0x8d, 0xfc, 0x2c, 0x73, 0xd5, 0xc4, 0xc9, 0xa4, 0x50, 0x82, 0x99, 0x4b, 0xdf, 0x64, 0xfa, + 0xd9, 0x59, 0x1a, 0x4e, 0x19, 0x68, 0xd8, 0xdb, 0xb9, 0x83, 0x91, 0x08, 0x3e, 0xbe, 0x0f, 0x01, + 0x03, 0x19, 0x67, 0x4a, 0xc8, 0x05, 0x93, 0x71, 0xb4, 0x1d, 0x59, 0x9e, 0x65, 0xc0, 0x83, 0x48, + 0x44, 0xa2, 0xb8, 0xba, 0xf9, 0x6d, 0x81, 0x76, 0x6e, 0x09, 0x6d, 0xf7, 0x31, 0x7a, 0x21, 0xc1, + 0x57, 0xe0, 0x2d, 0x12, 0x18, 0xa7, 0xfb, 0x41, 0x0e, 0x08, 0xc9, 0x89, 0x45, 0x6c, 0xdd, 0xab, + 0x4c, 0xf6, 0x88, 0xea, 0x25, 0xeb, 0xab, 0x90, 0xef, 0x15, 0xbe, 0x15, 0xc0, 0x1e, 0xd3, 0x83, + 0xc4, 0x9f, 0x5c, 0xc2, 0xa7, 0x31, 0xa4, 0x01, 0x48, 0xe4, 0x0d, 0x8b, 0xd8, 0x9a, 0xb7, 0x09, + 0xb2, 0x53, 0xfa, 0x30, 0x03, 0x99, 0xc4, 0x98, 0x37, 0x0b, 0xe1, 0x59, 0x18, 0x4a, 0x40, 0x04, + 0xe4, 0xfb, 0x56, 0xdd, 0xd6, 0xbd, 0xdf, 0x3b, 0xd9, 0x13, 0xda, 0x56, 0xd2, 0x4f, 0xf1, 0x03, + 0x48, 0x7c, 0x99, 0xfa, 0x83, 0x11, 0x84, 0x9c, 0x5a, 0xc4, 0x6e, 0x7a, 0x5b, 0xf8, 0x85, 0xd6, + 0x6c, 0xb6, 0xf5, 0x0b, 0xad, 0xa9, 0xb7, 0x69, 0xc7, 0xa0, 0xfc, 0xee, 0x7c, 0x1e, 0x60, 0x26, + 0x52, 0x84, 0xce, 0xd7, 0x3d, 0x7a, 0xbf, 0x8f, 0xd1, 0xdb, 0x2c, 0xf4, 0x15, 0x5c, 0x2a, 0x5f, + 0xc1, 0x7f, 0x8f, 0x6e, 0xd1, 0x16, 0x2a, 0x5f, 0xaa, 0x73, 0x88, 0xa3, 0xa1, 0xe2, 0xf5, 0x62, + 0xf0, 0x75, 0x28, 0xcf, 0x4f, 0xc7, 0x49, 0x37, 0x7f, 0x3d, 0xe4, 0x5a, 0xe1, 0x5f, 0x01, 0xec, + 0x90, 0x36, 0x7a, 0x67, 0x6f, 0x7c, 0x35, 0xe4, 0xf7, 0x0a, 0xea, 0xd2, 0xca, 0xfb, 0xb9, 0x02, + 0x99, 0x8b, 0x51, 0x8a, 0x59, 0x99, 0xec, 0x9c, 0xd6, 0xbb, 0xbd, 0x5c, 0x34, 0x62, 0xb7, 0x8e, + 0x9f, 0x3a, 0x7f, 0x5e, 0x24, 0xa7, 0x28, 0xd3, 0x5b, 0x2e, 0x0d, 0x76, 0xb5, 0xeb, 0xdb, 0xa3, + 0x9a, 0x97, 0x53, 0x74, 0x38, 0x3d, 0xdc, 0x54, 0xa1, 0x12, 0xe8, 0xf8, 0x27, 0xa1, 0xf5, 0x3e, + 0x46, 0xec, 0x0b, 0x3d, 0xd8, 0xdc, 0x90, 0xbf, 0xd6, 0xbb, 0xab, 0xb9, 0xf1, 0x7c, 0xd7, 0x8c, + 0xaa, 0x09, 0x36, 0xa6, 0xad, 0xf5, 0x17, 0x72, 0xfe, 0x81, 0x68, 0x2d, 0xde, 0x78, 0xb6, 0x5b, + 0x7c, 0x55, 0xb6, 0xfb, 0xfa, 0x7a, 0x66, 0x92, 0x9b, 0x99, 0x49, 0x7e, 0xcc, 0x4c, 0xf2, 0x6d, + 0x6e, 0xd6, 0x6e, 0xe6, 0x66, 0xed, 0xfb, 0xdc, 0xac, 0xbd, 0x3b, 0x8d, 0x62, 0x35, 0x1c, 0x0f, + 0x9c, 0x40, 0x24, 0xee, 0x3a, 0xf7, 0xca, 0x70, 0xaf, 0x4e, 0xdc, 0xc9, 0xea, 0xb7, 0x4f, 0x33, + 0xc0, 0x41, 0xa3, 0xf8, 0x70, 0x27, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0xaa, 0x81, 0xc7, 0x8d, + 0x0f, 0x04, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn +var ( + _ context.Context + _ grpc.ClientConn +) // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. @@ -465,7 +371,6 @@ const _ = grpc.SupportPackageIsVersion4 type MsgClient interface { CreateRollapp(ctx context.Context, in *MsgCreateRollapp, opts ...grpc.CallOption) (*MsgCreateRollappResponse, error) UpdateState(ctx context.Context, in *MsgUpdateState, opts ...grpc.CallOption) (*MsgUpdateStateResponse, error) - TriggerGenesisEvent(ctx context.Context, in *MsgRollappGenesisEvent, opts ...grpc.CallOption) (*MsgRollappGenesisEventResponse, error) } type msgClient struct { @@ -494,35 +399,22 @@ func (c *msgClient) UpdateState(ctx context.Context, in *MsgUpdateState, opts .. return out, nil } -func (c *msgClient) TriggerGenesisEvent(ctx context.Context, in *MsgRollappGenesisEvent, opts ...grpc.CallOption) (*MsgRollappGenesisEventResponse, error) { - out := new(MsgRollappGenesisEventResponse) - err := c.cc.Invoke(ctx, "/dymensionxyz.dymension.rollapp.Msg/TriggerGenesisEvent", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - // MsgServer is the server API for Msg service. type MsgServer interface { CreateRollapp(context.Context, *MsgCreateRollapp) (*MsgCreateRollappResponse, error) UpdateState(context.Context, *MsgUpdateState) (*MsgUpdateStateResponse, error) - TriggerGenesisEvent(context.Context, *MsgRollappGenesisEvent) (*MsgRollappGenesisEventResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. -type UnimplementedMsgServer struct { -} +type UnimplementedMsgServer struct{} func (*UnimplementedMsgServer) CreateRollapp(ctx context.Context, req *MsgCreateRollapp) (*MsgCreateRollappResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method CreateRollapp not implemented") } + func (*UnimplementedMsgServer) UpdateState(ctx context.Context, req *MsgUpdateState) (*MsgUpdateStateResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateState not implemented") } -func (*UnimplementedMsgServer) TriggerGenesisEvent(ctx context.Context, req *MsgRollappGenesisEvent) (*MsgRollappGenesisEventResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method TriggerGenesisEvent not implemented") -} func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) @@ -564,24 +456,6 @@ func _Msg_UpdateState_Handler(srv interface{}, ctx context.Context, dec func(int return interceptor(ctx, in, info, handler) } -func _Msg_TriggerGenesisEvent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgRollappGenesisEvent) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).TriggerGenesisEvent(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/dymensionxyz.dymension.rollapp.Msg/TriggerGenesisEvent", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).TriggerGenesisEvent(ctx, req.(*MsgRollappGenesisEvent)) - } - return interceptor(ctx, in, info, handler) -} - var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "dymensionxyz.dymension.rollapp.Msg", HandlerType: (*MsgServer)(nil), @@ -594,10 +468,6 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "UpdateState", Handler: _Msg_UpdateState_Handler, }, - { - MethodName: "TriggerGenesisEvent", - Handler: _Msg_TriggerGenesisEvent_Handler, - }, }, Streams: []grpc.StreamDesc{}, Metadata: "dymension/rollapp/tx.proto", @@ -623,33 +493,15 @@ func (m *MsgCreateRollapp) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.GenesisAccounts) > 0 { - for iNdEx := len(m.GenesisAccounts) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.GenesisAccounts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x4a - } - } - if len(m.Metadatas) > 0 { - for iNdEx := len(m.Metadatas) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Metadatas[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x42 + if m.TransfersEnabled { + i-- + if m.TransfersEnabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 } + i-- + dAtA[i] = 0x50 } if len(m.PermissionedAddresses) > 0 { for iNdEx := len(m.PermissionedAddresses) - 1; iNdEx >= 0; iNdEx-- { @@ -797,73 +649,6 @@ func (m *MsgUpdateStateResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } -func (m *MsgRollappGenesisEvent) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgRollappGenesisEvent) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgRollappGenesisEvent) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.RollappId) > 0 { - i -= len(m.RollappId) - copy(dAtA[i:], m.RollappId) - i = encodeVarintTx(dAtA, i, uint64(len(m.RollappId))) - i-- - dAtA[i] = 0x1a - } - if len(m.ChannelId) > 0 { - i -= len(m.ChannelId) - copy(dAtA[i:], m.ChannelId) - i = encodeVarintTx(dAtA, i, uint64(len(m.ChannelId))) - i-- - dAtA[i] = 0x12 - } - if len(m.Address) > 0 { - i -= len(m.Address) - copy(dAtA[i:], m.Address) - i = encodeVarintTx(dAtA, i, uint64(len(m.Address))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *MsgRollappGenesisEventResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgRollappGenesisEventResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgRollappGenesisEventResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil -} - func encodeVarintTx(dAtA []byte, offset int, v uint64) int { offset -= sovTx(v) base := offset @@ -875,6 +660,7 @@ func encodeVarintTx(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } + func (m *MsgCreateRollapp) Size() (n int) { if m == nil { return 0 @@ -898,17 +684,8 @@ func (m *MsgCreateRollapp) Size() (n int) { n += 1 + l + sovTx(uint64(l)) } } - if len(m.Metadatas) > 0 { - for _, e := range m.Metadatas { - l = e.Size() - n += 1 + l + sovTx(uint64(l)) - } - } - if len(m.GenesisAccounts) > 0 { - for _, e := range m.GenesisAccounts { - l = e.Size() - n += 1 + l + sovTx(uint64(l)) - } + if m.TransfersEnabled { + n += 2 } return n } @@ -963,42 +740,14 @@ func (m *MsgUpdateStateResponse) Size() (n int) { return n } -func (m *MsgRollappGenesisEvent) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Address) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.ChannelId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.RollappId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - return n -} - -func (m *MsgRollappGenesisEventResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n -} - func sovTx(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } + func sozTx(x uint64) (n int) { return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } + func (m *MsgCreateRollapp) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -1143,45 +892,11 @@ func (m *MsgCreateRollapp) Unmarshal(dAtA []byte) error { } m.PermissionedAddresses = append(m.PermissionedAddresses, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex - case 8: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Metadatas", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Metadatas = append(m.Metadatas, TokenMetadata{}) - if err := m.Metadatas[len(m.Metadatas)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 9: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field GenesisAccounts", wireType) + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TransfersEnabled", wireType) } - var msglen int + var v int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -1191,26 +906,12 @@ func (m *MsgCreateRollapp) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.GenesisAccounts = append(m.GenesisAccounts, GenesisAccount{}) - if err := m.GenesisAccounts[len(m.GenesisAccounts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex + m.TransfersEnabled = bool(v != 0) default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -1232,6 +933,7 @@ func (m *MsgCreateRollapp) Unmarshal(dAtA []byte) error { } return nil } + func (m *MsgCreateRollappResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -1282,6 +984,7 @@ func (m *MsgCreateRollappResponse) Unmarshal(dAtA []byte) error { } return nil } + func (m *MsgUpdateState) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -1518,6 +1221,7 @@ func (m *MsgUpdateState) Unmarshal(dAtA []byte) error { } return nil } + func (m *MsgUpdateStateResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -1568,202 +1272,7 @@ func (m *MsgUpdateStateResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgRollappGenesisEvent) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgRollappGenesisEvent: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRollappGenesisEvent: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Address = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ChannelId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RollappId", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.RollappId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgRollappGenesisEventResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgRollappGenesisEventResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRollappGenesisEventResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func skipTx(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/sequencer/keeper/hook_listener.go b/x/sequencer/keeper/hook_listener.go index cc43dc0d3..6f1053426 100644 --- a/x/sequencer/keeper/hook_listener.go +++ b/x/sequencer/keeper/hook_listener.go @@ -6,21 +6,21 @@ import ( "github.com/dymensionxyz/dymension/v3/x/sequencer/types" ) -var _ rollapptypes.RollappHooks = rollapphook{} +var _ rollapptypes.RollappHooks = rollappHook{} // Hooks wrapper struct for rollapp keeper. -type rollapphook struct { +type rollappHook struct { k Keeper } -// Return the wrapper struct. +// RollappHooks returns the wrapper struct. func (k Keeper) RollappHooks() rollapptypes.RollappHooks { - return rollapphook{ + return rollappHook{ k, } } -func (hook rollapphook) BeforeUpdateState(ctx sdk.Context, seqAddr string, rollappId string) error { +func (hook rollappHook) BeforeUpdateState(ctx sdk.Context, seqAddr string, rollappId string) error { // check to see if the sequencer has been registered before sequencer, found := hook.k.GetSequencer(ctx, seqAddr) if !found { @@ -43,13 +43,13 @@ func (hook rollapphook) BeforeUpdateState(ctx sdk.Context, seqAddr string, rolla return nil } -func (hook rollapphook) AfterStateFinalized(ctx sdk.Context, rollappID string, stateInfo *rollapptypes.StateInfo) error { +func (hook rollappHook) AfterStateFinalized(ctx sdk.Context, rollappID string, stateInfo *rollapptypes.StateInfo) error { return nil } // FraudSubmitted implements the RollappHooks interface // It slashes the sequencer and unbonds all other bonded sequencers -func (hook rollapphook) FraudSubmitted(ctx sdk.Context, rollappID string, height uint64, seqAddr string) error { +func (hook rollappHook) FraudSubmitted(ctx sdk.Context, rollappID string, height uint64, seqAddr string) error { err := hook.k.Slashing(ctx, seqAddr) if err != nil { return err diff --git a/x/sequencer/keeper/msg_server_create_sequencer.go b/x/sequencer/keeper/msg_server_create_sequencer.go index 335bf49bd..80d76720b 100644 --- a/x/sequencer/keeper/msg_server_create_sequencer.go +++ b/x/sequencer/keeper/msg_server_create_sequencer.go @@ -2,6 +2,7 @@ package keeper import ( "context" + "slices" "strconv" sdk "github.com/cosmos/cosmos-sdk/types" @@ -33,21 +34,10 @@ func (k msgServer) CreateSequencer(goCtx context.Context, msg *types.MsgCreateSe } // check if there are permissionedAddresses. - // if the list is not empty, it means that only premissioned sequencers can be added + // if the list is not empty, it means that only permissioned sequencers can be added permissionedAddresses := rollapp.PermissionedAddresses - if len(permissionedAddresses) > 0 { - bPermissioned := false - // check to see if the sequencer is in the permissioned list - for _, addr := range permissionedAddresses { - if addr == msg.Creator { - // Found! - bPermissioned = true - break - } - } - if !bPermissioned { - return nil, types.ErrSequencerNotPermissioned - } + if 0 < len(permissionedAddresses) && !slices.Contains(permissionedAddresses, msg.Creator) { + return nil, types.ErrSequencerNotPermissioned } // check to see if the sequencer has enough balance and deduct the bond diff --git a/x/sequencer/keeper/sequencer.go b/x/sequencer/keeper/sequencer.go index b138ec49d..44d884e5d 100644 --- a/x/sequencer/keeper/sequencer.go +++ b/x/sequencer/keeper/sequencer.go @@ -17,8 +17,8 @@ func (k Keeper) SetSequencer(ctx sdk.Context, sequencer types.Sequencer) { sequencer.SequencerAddress, ), b) - seqByrollappKey := types.SequencerByRollappByStatusKey(sequencer.RollappId, sequencer.SequencerAddress, sequencer.Status) - store.Set(seqByrollappKey, b) + seqByRollappKey := types.SequencerByRollappByStatusKey(sequencer.RollappId, sequencer.SequencerAddress, sequencer.Status) + store.Set(seqByRollappKey, b) // To support InitGenesis scenario if sequencer.Status == types.Unbonding { @@ -26,14 +26,13 @@ func (k Keeper) SetSequencer(ctx sdk.Context, sequencer types.Sequencer) { } } -// Update sequencer status func (k Keeper) UpdateSequencer(ctx sdk.Context, sequencer types.Sequencer, oldStatus types.OperatingStatus) { store := ctx.KVStore(k.storeKey) b := k.cdc.MustMarshal(&sequencer) store.Set(types.SequencerKey(sequencer.SequencerAddress), b) - seqByrollappKey := types.SequencerByRollappByStatusKey(sequencer.RollappId, sequencer.SequencerAddress, sequencer.Status) - store.Set(seqByrollappKey, b) + seqByRollappKey := types.SequencerByRollappByStatusKey(sequencer.RollappId, sequencer.SequencerAddress, sequencer.Status) + store.Set(seqByRollappKey, b) // status changed, need to remove old status key if sequencer.Status != oldStatus { @@ -121,7 +120,7 @@ func (k Keeper) GetSequencersByRollapp(ctx sdk.Context, rollappId string) (list return } -// GetSequencersByRollapp returns a sequencersByRollapp from its index +// GetSequencersByRollappByStatus returns a sequencersByRollapp from its index func (k Keeper) GetSequencersByRollappByStatus(ctx sdk.Context, rollappId string, status types.OperatingStatus) (list []types.Sequencer) { prefixKey := types.SequencersByRollappByStatusKey(rollappId, status) store := prefix.NewStore(ctx.KVStore(k.storeKey), prefixKey) diff --git a/x/sequencer/keeper/slashing.go b/x/sequencer/keeper/slashing.go index 02285669f..668cd646c 100644 --- a/x/sequencer/keeper/slashing.go +++ b/x/sequencer/keeper/slashing.go @@ -33,7 +33,7 @@ func (k Keeper) Slashing(ctx sdk.Context, seqAddr string) error { seq.Tokens = sdk.Coins{} oldStatus := seq.Status - wasPropser := seq.Proposer + wasProposer := seq.Proposer // in case we are slashing an unbonding sequencer, we need to remove it from the unbonding queue if oldStatus == types.Unbonding { k.removeUnbondingSequencer(ctx, seq) @@ -57,7 +57,7 @@ func (k Keeper) Slashing(ctx sdk.Context, seqAddr string) error { ) // rotate proposer if the slashed sequencer was the proposer - if wasPropser { + if wasProposer { k.RotateProposer(ctx, seq.RollappId) } diff --git a/x/sequencer/keeper/slashing_test.go b/x/sequencer/keeper/slashing_test.go index 839635c6e..87f68e4b0 100644 --- a/x/sequencer/keeper/slashing_test.go +++ b/x/sequencer/keeper/slashing_test.go @@ -10,13 +10,13 @@ import ( func (suite *SequencerTestSuite) assertSlashed(seqAddr string) { seq, found := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, seqAddr) suite.Require().True(found) - suite.Assert().True(seq.Jailed) - suite.Assert().Equal(types.Unbonded, seq.Status) - suite.Assert().Equal(sdk.Coins(nil), seq.Tokens) + suite.True(seq.Jailed) + suite.Equal(types.Unbonded, seq.Status) + suite.Equal(sdk.Coins(nil), seq.Tokens) sequencers := suite.App.SequencerKeeper.GetMatureUnbondingSequencers(suite.Ctx, suite.Ctx.BlockTime()) for _, s := range sequencers { - suite.Assert().NotEqual(s.SequencerAddress, seqAddr) + suite.NotEqual(s.SequencerAddress, seqAddr) } } @@ -27,7 +27,7 @@ func (suite *SequencerTestSuite) TestSlashingUnknownSequencer() { keeper := suite.App.SequencerKeeper err := keeper.Slashing(suite.Ctx, "unknown_sequencer") - suite.Assert().ErrorIs(err, types.ErrUnknownSequencer) + suite.ErrorIs(err, types.ErrUnknownSequencer) } func (suite *SequencerTestSuite) TestSlashingUnbondedSequencer() { @@ -50,10 +50,10 @@ func (suite *SequencerTestSuite) TestSlashingUnbondedSequencer() { seq, found := keeper.GetSequencer(suite.Ctx, seqAddr) suite.Require().True(found) - suite.Assert().Equal(seq.SequencerAddress, seqAddr) - suite.Assert().Equal(seq.Status, types.Unbonded) + suite.Equal(seq.SequencerAddress, seqAddr) + suite.Equal(seq.Status, types.Unbonded) err = keeper.Slashing(suite.Ctx, seqAddr) - suite.Assert().ErrorIs(err, types.ErrInvalidSequencerStatus) + suite.ErrorIs(err, types.ErrInvalidSequencerStatus) } func (suite *SequencerTestSuite) TestSlashingUnbondingSequencer() { @@ -72,9 +72,9 @@ func (suite *SequencerTestSuite) TestSlashingUnbondingSequencer() { seq, ok := keeper.GetSequencer(suite.Ctx, seqAddr) suite.Require().True(ok) - suite.Assert().Equal(seq.Status, types.Unbonding) + suite.Equal(seq.Status, types.Unbonding) err = keeper.Slashing(suite.Ctx, seqAddr) - suite.Assert().NoError(err) + suite.NoError(err) suite.assertSlashed(seqAddr) } @@ -92,21 +92,21 @@ func (suite *SequencerTestSuite) TestSlashingPropserSequencer() { seq, ok := keeper.GetSequencer(suite.Ctx, seqAddr) suite.Require().True(ok) - suite.Assert().Equal(seq.Status, types.Bonded) - suite.Assert().True(seq.Proposer) + suite.Equal(seq.Status, types.Bonded) + suite.True(seq.Proposer) seq2, ok := keeper.GetSequencer(suite.Ctx, seqAddr2) suite.Require().True(ok) - suite.Assert().Equal(seq2.Status, types.Bonded) - suite.Assert().False(seq2.Proposer) + suite.Equal(seq2.Status, types.Bonded) + suite.False(seq2.Proposer) err := keeper.Slashing(suite.Ctx, seqAddr) - suite.Assert().NoError(err) + suite.NoError(err) suite.assertSlashed(seqAddr) seq2, ok = keeper.GetSequencer(suite.Ctx, seqAddr2) suite.Require().True(ok) - suite.Assert().Equal(seq2.Status, types.Bonded) - suite.Assert().True(seq2.Proposer) + suite.Equal(seq2.Status, types.Bonded) + suite.True(seq2.Proposer) } diff --git a/x/sequencer/types/sequencer.go b/x/sequencer/types/sequencer.go index 6d4800782..2cf0a5d6b 100644 --- a/x/sequencer/types/sequencer.go +++ b/x/sequencer/types/sequencer.go @@ -12,7 +12,6 @@ func (seq Sequencer) IsBonded() bool { return seq.Status == Bonded } -// is proposer func (seq Sequencer) IsProposer() bool { return seq.Proposer } diff --git a/x/transferinject/doc.go b/x/transferinject/doc.go new file mode 100644 index 000000000..97f5847db --- /dev/null +++ b/x/transferinject/doc.go @@ -0,0 +1,2 @@ +// Package transferinject module provides IBC middleware for sending and acknowledging IBC packets with injecting additional packet metadata to IBC packets. +package transferinject diff --git a/x/transferinject/ibc_middleware.go b/x/transferinject/ibc_middleware.go deleted file mode 100644 index 23e33f5b6..000000000 --- a/x/transferinject/ibc_middleware.go +++ /dev/null @@ -1,169 +0,0 @@ -// Package transferinject module provides IBC middleware for sending and acknowledging IBC packets with injecting additional packet metadata to IBC packets. -package transferinject - -import ( - . "slices" - - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - errortypes "github.com/cosmos/cosmos-sdk/types/errors" - capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types" - - "github.com/dymensionxyz/dymension/v3/x/transferinject/types" -) - -type IBCSendMiddleware struct { - porttypes.ICS4Wrapper - - rollappKeeper types.RollappKeeper - bankKeeper types.BankKeeper -} - -// NewIBCSendMiddleware creates a new ICS4Wrapper. -// It intercepts outgoing IBC packets and adds token metadata to the memo if the rollapp doesn't have it. -// This is a solution for adding token metadata to fungible tokens transferred over IBC, -// targeted at rollapps that don't have the token metadata for the token being transferred. -// More info here: https://www.notion.so/dymension/ADR-x-IBC-Denom-Metadata-Transfer-From-Hub-to-Rollapp-d3791f524ac849a9a3eb44d17968a30b -func NewIBCSendMiddleware( - ics porttypes.ICS4Wrapper, - rollappKeeper types.RollappKeeper, - bankKeeper types.BankKeeper, -) *IBCSendMiddleware { - return &IBCSendMiddleware{ - ICS4Wrapper: ics, - rollappKeeper: rollappKeeper, - bankKeeper: bankKeeper, - } -} - -// SendPacket wraps IBC ChannelKeeper's SendPacket function -func (m *IBCSendMiddleware) SendPacket( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - destinationPort string, destinationChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - data []byte, -) (sequence uint64, err error) { - packet := new(transfertypes.FungibleTokenPacketData) - if err = types.ModuleCdc.UnmarshalJSON(data, packet); err != nil { - return 0, errorsmod.Wrapf(errortypes.ErrJSONUnmarshal, "unmarshal ICS-20 transfer packet data: %s", err.Error()) - } - - if types.MemoAlreadyHasPacketMetadata(packet.Memo) { - return 0, types.ErrMemoTransferInjectAlreadyExists - } - - rollapp, err := m.rollappKeeper.ExtractRollappFromChannel(ctx, destinationPort, destinationChannel) - if err != nil { - return 0, errorsmod.Wrapf(errortypes.ErrInvalidRequest, "extract rollapp from packet: %s", err.Error()) - } - - // TODO: currently we check if receiving chain is a rollapp, consider that other chains also might want this feature - // meaning, find a better way to check if the receiving chain supports this middleware - if rollapp == nil { - return m.ICS4Wrapper.SendPacket(ctx, chanCap, destinationPort, destinationChannel, timeoutHeight, timeoutTimestamp, data) - } - - if transfertypes.ReceiverChainIsSource(destinationPort, destinationChannel, packet.Denom) { - return m.ICS4Wrapper.SendPacket(ctx, chanCap, destinationPort, destinationChannel, timeoutHeight, timeoutTimestamp, data) - } - - // Check if the rollapp already contains the denom metadata by matching the base of the denom metadata. - // At the first match, we assume that the rollapp already contains the metadata. - // It would be technically possible to have a race condition where the denom metadata is added to the rollapp - // from another packet before this packet is acknowledged. - if Contains(rollapp.RegisteredDenoms, packet.Denom) { - return m.ICS4Wrapper.SendPacket(ctx, chanCap, destinationPort, destinationChannel, timeoutHeight, timeoutTimestamp, data) - } - - // get the denom metadata from the bank keeper, if it doesn't exist, move on to the next middleware in the chain - denomMetadata, ok := m.bankKeeper.GetDenomMetaData(ctx, packet.Denom) - if !ok { - return m.ICS4Wrapper.SendPacket(ctx, chanCap, destinationPort, destinationChannel, timeoutHeight, timeoutTimestamp, data) - } - - packet.Memo, err = types.AddDenomMetadataToMemo(packet.Memo, denomMetadata) - if err != nil { - return 0, errorsmod.Wrapf(errortypes.ErrUnauthorized, "add denom metadata to memo: %s", err.Error()) - } - - data, err = types.ModuleCdc.MarshalJSON(packet) - if err != nil { - return 0, errorsmod.Wrapf(errortypes.ErrJSONMarshal, "marshal ICS-20 transfer packet data: %s", err.Error()) - } - - return m.ICS4Wrapper.SendPacket(ctx, chanCap, destinationPort, destinationChannel, timeoutHeight, timeoutTimestamp, data) -} - -type IBCAckMiddleware struct { - porttypes.IBCModule - - rollappKeeper types.RollappKeeper -} - -// NewIBCAckMiddleware creates a new IBCModule. -// It intercepts acknowledged incoming IBC packets and adds token metadata that had just been registered on the rollapp itself, -// to the local rollapp record. -func NewIBCAckMiddleware( - ibc porttypes.IBCModule, - rollappKeeper types.RollappKeeper, -) *IBCAckMiddleware { - return &IBCAckMiddleware{ - IBCModule: ibc, - rollappKeeper: rollappKeeper, - } -} - -// OnAcknowledgementPacket adds the token metadata to the rollapp if it doesn't exist -func (m *IBCAckMiddleware) OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, - relayer sdk.AccAddress, -) error { - var ack channeltypes.Acknowledgement - if err := types.ModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { - return errorsmod.Wrapf(errortypes.ErrJSONUnmarshal, "unmarshal ICS-20 transfer packet acknowledgement: %v", err) - } - - if !ack.Success() { - return m.IBCModule.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) - } - - var data transfertypes.FungibleTokenPacketData - if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { - return errorsmod.Wrapf(errortypes.ErrJSONUnmarshal, "unmarshal ICS-20 transfer packet data: %s", err.Error()) - } - - packetMetadata, err := types.ParsePacketMetadata(data.Memo) - if err != nil { - return m.IBCModule.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) - } - - dm := packetMetadata.DenomMetadata - if dm == nil { - return m.IBCModule.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) - } - - rollapp, err := m.rollappKeeper.ExtractRollappFromChannel(ctx, packet.SourcePort, packet.SourceChannel) - if err != nil { - return errorsmod.Wrapf(errortypes.ErrInvalidRequest, "extract rollapp from packet: %s", err.Error()) - } - if rollapp == nil { - return errorsmod.Wrapf(errortypes.ErrNotFound, "rollapp not found") - } - - if !Contains(rollapp.RegisteredDenoms, dm.Base) { - // add the new token denom base to the list of rollapp's registered denoms - rollapp.RegisteredDenoms = append(rollapp.RegisteredDenoms, dm.Base) - - m.rollappKeeper.SetRollapp(ctx, *rollapp) - } - - return m.IBCModule.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) -} diff --git a/x/transferinject/ibc_middleware_test.go b/x/transferinject/ibc_middleware_test.go deleted file mode 100644 index 40976b657..000000000 --- a/x/transferinject/ibc_middleware_test.go +++ /dev/null @@ -1,478 +0,0 @@ -package transferinject_test - -import ( - "fmt" - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - errortypes "github.com/cosmos/cosmos-sdk/types/errors" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types" - "github.com/stretchr/testify/require" - - rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" - "github.com/dymensionxyz/dymension/v3/x/transferinject" - "github.com/dymensionxyz/dymension/v3/x/transferinject/types" -) - -func TestIBCMiddleware_SendPacket(t *testing.T) { - type fields struct { - ICS4Wrapper porttypes.ICS4Wrapper - rollappKeeper types.RollappKeeper - bankKeeper types.BankKeeper - } - type args struct { - destinationPort string - destinationChannel string - data *transfertypes.FungibleTokenPacketData - } - tests := []struct { - name string - fields fields - args args - wantSentData []byte - wantErr error - }{ - { - name: "success: added denom metadata to memo", - fields: fields{ - ICS4Wrapper: &mockICS4Wrapper{}, - rollappKeeper: &mockRollappKeeper{ - returnRollapp: &rollapptypes.Rollapp{}, - }, - bankKeeper: mockBankKeeper{ - returnMetadata: validDenomMetadata, - }, - }, - args: args{ - destinationPort: "port", - destinationChannel: "channel", - data: &transfertypes.FungibleTokenPacketData{ - Denom: "adym", - }, - }, - wantSentData: types.ModuleCdc.MustMarshalJSON(&transfertypes.FungibleTokenPacketData{ - Denom: "adym", - Memo: addDenomMetadataToPacketData("", validDenomMetadata), - }), - }, { - name: "success: added denom metadata to non-empty user memo", - fields: fields{ - ICS4Wrapper: &mockICS4Wrapper{}, - rollappKeeper: &mockRollappKeeper{ - returnRollapp: &rollapptypes.Rollapp{}, - }, - bankKeeper: mockBankKeeper{ - returnMetadata: validDenomMetadata, - }, - }, - args: args{ - destinationPort: "port", - destinationChannel: "channel", - data: &transfertypes.FungibleTokenPacketData{ - Denom: "adym", - Memo: "thanks for the sweater, grandma!", - }, - }, - wantSentData: types.ModuleCdc.MustMarshalJSON(&transfertypes.FungibleTokenPacketData{ - Denom: "adym", - Memo: addDenomMetadataToPacketData("thanks for the sweater, grandma!", validDenomMetadata), - }), - }, { - name: "error: denom metadata already in memo", - fields: fields{ - ICS4Wrapper: &mockICS4Wrapper{}, - }, - args: args{ - destinationPort: "port", - destinationChannel: "channel", - data: &transfertypes.FungibleTokenPacketData{ - Denom: "adym", - Memo: `{"transferinject":{}}`, - }, - }, - wantSentData: []byte(""), - wantErr: types.ErrMemoTransferInjectAlreadyExists, - }, { - name: "error: extract rollapp from channel", - fields: fields{ - ICS4Wrapper: &mockICS4Wrapper{}, - rollappKeeper: &mockRollappKeeper{ - err: errortypes.ErrInvalidRequest, - }, - }, - args: args{ - destinationPort: "port", - destinationChannel: "channel", - data: &transfertypes.FungibleTokenPacketData{ - Denom: "adym", - }, - }, - wantSentData: []byte(""), - wantErr: errortypes.ErrInvalidRequest, - }, { - name: "send unaltered: rollapp not found", - fields: fields{ - ICS4Wrapper: &mockICS4Wrapper{}, - rollappKeeper: &mockRollappKeeper{}, - }, - args: args{ - destinationPort: "port", - destinationChannel: "channel", - data: &transfertypes.FungibleTokenPacketData{ - Denom: "adym", - Memo: "user memo", - }, - }, - wantSentData: types.ModuleCdc.MustMarshalJSON(&transfertypes.FungibleTokenPacketData{ - Denom: "adym", - Memo: "user memo", - }), - }, { - name: "send unaltered: receiver chain is source", - fields: fields{ - ICS4Wrapper: &mockICS4Wrapper{}, - rollappKeeper: &mockRollappKeeper{ - returnRollapp: &rollapptypes.Rollapp{}, - }, - bankKeeper: mockBankKeeper{ - returnMetadata: validDenomMetadata, - }, - }, - args: args{ - destinationPort: "transfer", - destinationChannel: "channel-56", - data: &transfertypes.FungibleTokenPacketData{ - Denom: "transfer/channel-56/alex", - }, - }, - wantSentData: types.ModuleCdc.MustMarshalJSON(&transfertypes.FungibleTokenPacketData{ - Denom: "transfer/channel-56/alex", - }), - }, { - name: "send unaltered: denom metadata already in rollapp", - fields: fields{ - ICS4Wrapper: &mockICS4Wrapper{}, - rollappKeeper: &mockRollappKeeper{ - returnRollapp: &rollapptypes.Rollapp{ - RegisteredDenoms: []string{"adym"}, - }, - }, - }, - args: args{ - destinationPort: "port", - destinationChannel: "channel", - data: &transfertypes.FungibleTokenPacketData{ - Denom: "adym", - }, - }, - wantSentData: types.ModuleCdc.MustMarshalJSON(&transfertypes.FungibleTokenPacketData{ - Denom: "adym", - }), - }, { - name: "error: get denom metadata", - fields: fields{ - ICS4Wrapper: &mockICS4Wrapper{}, - rollappKeeper: &mockRollappKeeper{ - returnRollapp: &rollapptypes.Rollapp{}, - }, - bankKeeper: mockBankKeeper{}, - }, - args: args{ - destinationPort: "port", - destinationChannel: "channel", - data: &transfertypes.FungibleTokenPacketData{ - Denom: "adym", - }, - }, - wantSentData: types.ModuleCdc.MustMarshalJSON(&transfertypes.FungibleTokenPacketData{ - Denom: "adym", - }), - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := transferinject.NewIBCSendMiddleware(tt.fields.ICS4Wrapper, tt.fields.rollappKeeper, tt.fields.bankKeeper) - - data := types.ModuleCdc.MustMarshalJSON(tt.args.data) - - _, err := m.SendPacket( - sdk.Context{}, - &capabilitytypes.Capability{}, - tt.args.destinationPort, - tt.args.destinationChannel, - clienttypes.Height{}, - 0, - data, - ) - if tt.wantErr == nil { - require.NoError(t, err) - } else { - require.ErrorIs(t, err, tt.wantErr) - } - require.Equal(t, string(tt.wantSentData), string(tt.fields.ICS4Wrapper.(*mockICS4Wrapper).sentData)) - }) - } -} - -func TestIBCMiddleware_OnAcknowledgementPacket(t *testing.T) { - type fields struct { - IBCModule porttypes.IBCModule - rollappKeeper types.RollappKeeper - } - type args struct { - packetData *transfertypes.FungibleTokenPacketData - acknowledgement []byte - } - tests := []struct { - name string - fields fields - args args - wantRollapp *rollapptypes.Rollapp - wantErr error - }{ - { - name: "success: added token metadata to rollapp", - fields: fields{ - IBCModule: mockIBCModule{}, - rollappKeeper: &mockRollappKeeper{ - returnRollapp: &rollapptypes.Rollapp{}, - }, - }, - args: args{ - packetData: &transfertypes.FungibleTokenPacketData{ - Denom: "adym", - Memo: addDenomMetadataToPacketData("", validDenomMetadata), - }, - acknowledgement: okAck(), - }, - wantRollapp: &rollapptypes.Rollapp{ - RegisteredDenoms: []string{validDenomMetadata.Base}, - }, - }, { - name: "success: added token metadata to rollapp with user memo", - fields: fields{ - IBCModule: mockIBCModule{}, - rollappKeeper: &mockRollappKeeper{ - returnRollapp: &rollapptypes.Rollapp{}, - }, - }, - args: args{ - packetData: &transfertypes.FungibleTokenPacketData{ - Denom: "adym", - Memo: addDenomMetadataToPacketData("user memo", validDenomMetadata), - }, - acknowledgement: okAck(), - }, - wantRollapp: &rollapptypes.Rollapp{ - RegisteredDenoms: []string{validDenomMetadata.Base}, - }, - }, { - name: "return early: error acknowledgement", - fields: fields{ - rollappKeeper: &mockRollappKeeper{}, - IBCModule: mockIBCModule{}, - }, - args: args{ - acknowledgement: badAck(), - }, - wantRollapp: nil, - }, { - name: "return early: no memo", - fields: fields{ - rollappKeeper: &mockRollappKeeper{}, - IBCModule: mockIBCModule{}, - }, - args: args{ - packetData: &transfertypes.FungibleTokenPacketData{ - Denom: "adym", - }, - acknowledgement: okAck(), - }, - wantRollapp: nil, - }, { - name: "return early: no packet metadata in memo", - fields: fields{ - rollappKeeper: &mockRollappKeeper{}, - IBCModule: mockIBCModule{}, - }, - args: args{ - packetData: &transfertypes.FungibleTokenPacketData{ - Denom: "adym", - Memo: "user memo", - }, - acknowledgement: okAck(), - }, - wantRollapp: nil, - }, { - name: "return early: no denom metadata in memo", - fields: fields{ - rollappKeeper: &mockRollappKeeper{}, - IBCModule: mockIBCModule{}, - }, - args: args{ - packetData: &transfertypes.FungibleTokenPacketData{ - Denom: "adym", - Memo: `{"transferinject":{}}`, - }, - acknowledgement: okAck(), - }, - wantRollapp: nil, - }, { - name: "error: extract rollapp from channel", - fields: fields{ - IBCModule: mockIBCModule{}, - rollappKeeper: &mockRollappKeeper{ - err: errortypes.ErrInvalidRequest, - }, - }, - args: args{ - packetData: &transfertypes.FungibleTokenPacketData{ - Denom: "adym", - Memo: addDenomMetadataToPacketData("", validDenomMetadata), - }, - acknowledgement: okAck(), - }, - wantRollapp: nil, - wantErr: errortypes.ErrInvalidRequest, - }, { - name: "error: rollapp not found", - fields: fields{ - IBCModule: mockIBCModule{}, - rollappKeeper: &mockRollappKeeper{}, - }, - args: args{ - packetData: &transfertypes.FungibleTokenPacketData{ - Denom: "adym", - Memo: addDenomMetadataToPacketData("", validDenomMetadata), - }, - acknowledgement: okAck(), - }, - wantRollapp: nil, - wantErr: errortypes.ErrNotFound, - }, { - name: "return early: rollapp already has token metadata", - fields: fields{ - IBCModule: mockIBCModule{}, - rollappKeeper: &mockRollappKeeper{ - returnRollapp: &rollapptypes.Rollapp{ - RegisteredDenoms: []string{validDenomMetadata.Base}, - }, - }, - }, - args: args{ - packetData: &transfertypes.FungibleTokenPacketData{ - Denom: "adym", - Memo: addDenomMetadataToPacketData("", validDenomMetadata), - }, - acknowledgement: okAck(), - }, - wantRollapp: &rollapptypes.Rollapp{ - RegisteredDenoms: []string{validDenomMetadata.Base}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := transferinject.NewIBCAckMiddleware(tt.fields.IBCModule, tt.fields.rollappKeeper) - - packet := channeltypes.Packet{} - - if tt.args.packetData != nil { - packet.Data = types.ModuleCdc.MustMarshalJSON(tt.args.packetData) - } - - err := m.OnAcknowledgementPacket(sdk.Context{}, packet, tt.args.acknowledgement, sdk.AccAddress{}) - - if tt.wantErr == nil { - require.NoError(t, err) - } else { - require.ErrorIs(t, err, tt.wantErr) - } - - require.Equal(t, tt.wantRollapp, tt.fields.rollappKeeper.(*mockRollappKeeper).returnRollapp) - }) - } -} - -var validDenomMetadata = banktypes.Metadata{ - Description: "Denom of the Hub", - Base: "adym", - Display: "DYM", - Name: "DYM", - Symbol: "adym", - DenomUnits: []*banktypes.DenomUnit{ - { - Denom: "adym", - Exponent: 0, - }, { - Denom: "DYM", - Exponent: 18, - }, - }, -} - -func addDenomMetadataToPacketData(memo string, metadata banktypes.Metadata) string { - memo, _ = types.AddDenomMetadataToMemo(memo, metadata) - return memo -} - -func okAck() []byte { - ack := channeltypes.NewResultAcknowledgement([]byte{}) - return types.ModuleCdc.MustMarshalJSON(&ack) -} - -func badAck() []byte { - ack := channeltypes.NewErrorAcknowledgement(fmt.Errorf("unsuccessful")) - return types.ModuleCdc.MustMarshalJSON(&ack) -} - -type mockICS4Wrapper struct { - porttypes.ICS4Wrapper - sentData []byte -} - -func (m *mockICS4Wrapper) SendPacket( - _ sdk.Context, - _ *capabilitytypes.Capability, - _ string, _ string, - _ clienttypes.Height, - _ uint64, - data []byte, -) (sequence uint64, err error) { - m.sentData = data - return 0, nil -} - -type mockIBCModule struct { - porttypes.IBCModule -} - -func (m mockIBCModule) OnAcknowledgementPacket(sdk.Context, channeltypes.Packet, []byte, sdk.AccAddress) error { - return nil -} - -type mockBankKeeper struct { - returnMetadata banktypes.Metadata -} - -func (m mockBankKeeper) GetDenomMetaData(sdk.Context, string) (banktypes.Metadata, bool) { - return m.returnMetadata, m.returnMetadata.Base != "" -} - -type mockRollappKeeper struct { - returnRollapp *rollapptypes.Rollapp - err error -} - -func (m *mockRollappKeeper) SetRollapp(_ sdk.Context, rollapp rollapptypes.Rollapp) { - m.returnRollapp = &rollapp -} - -func (m *mockRollappKeeper) ExtractRollappFromChannel(sdk.Context, string, string) (*rollapptypes.Rollapp, error) { - return m.returnRollapp, m.err -} diff --git a/x/transferinject/ibc_module.go b/x/transferinject/ibc_module.go new file mode 100644 index 000000000..7f8952c95 --- /dev/null +++ b/x/transferinject/ibc_module.go @@ -0,0 +1,76 @@ +// Package transferinject module provides IBC middleware for sending and acknowledging IBC packets with injecting additional packet metadata to IBC packets. +package transferinject + +import ( + "errors" + . "slices" + + "github.com/dymensionxyz/dymension/v3/utils/gerr" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + errortypes "github.com/cosmos/cosmos-sdk/types/errors" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types" + + "github.com/dymensionxyz/dymension/v3/x/transferinject/types" +) + +type IBCModule struct { + porttypes.IBCModule + + rollappKeeper types.RollappKeeper +} + +// NewIBCModule creates a new IBCModule. +// It intercepts acknowledged incoming IBC packets and adds token metadata that had just been registered on the rollapp itself, +// to the local rollapp record. +func NewIBCModule( + ibc porttypes.IBCModule, + rollappKeeper types.RollappKeeper, +) *IBCModule { + return &IBCModule{ + IBCModule: ibc, + rollappKeeper: rollappKeeper, + } +} + +// OnAcknowledgementPacket adds the token metadata to the rollapp if it doesn't exist +func (m *IBCModule) OnAcknowledgementPacket( + ctx sdk.Context, + packet channeltypes.Packet, + acknowledgement []byte, + relayer sdk.AccAddress, +) error { + var ack channeltypes.Acknowledgement + if err := types.ModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { + return errorsmod.Wrap(errors.Join(err, errortypes.ErrJSONUnmarshal), "ics20 transfer packet ack") + } + + if !ack.Success() { + return m.IBCModule.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) + } + + transfer, err := m.rollappKeeper.GetValidTransfer(ctx, packet.GetData(), packet.GetSourcePort(), packet.GetSourceChannel()) + if err != nil { + return errorsmod.Wrap(err, "get valid transfer from sent packet") + } + + packetMetadata, err := types.ParsePacketMetadata(transfer.GetMemo()) + if err != nil { + return m.IBCModule.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) + } + + if !transfer.IsRollapp() { + return errorsmod.Wrap(errors.Join(gerr.ErrNotFound, errortypes.ErrInvalidRequest), "got a memo so should get rollapp, but didnt") + } + + if !Contains(transfer.Rollapp.RegisteredDenoms, packetMetadata.DenomMetadata.Base) { + // add the new token denom base to the list of rollapp's registered denoms + transfer.Rollapp.RegisteredDenoms = append(transfer.Rollapp.RegisteredDenoms, packetMetadata.DenomMetadata.Base) + + m.rollappKeeper.SetRollapp(ctx, *transfer.Rollapp) + } + + return m.IBCModule.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) +} diff --git a/x/transferinject/ibc_module_test.go b/x/transferinject/ibc_module_test.go new file mode 100644 index 000000000..13253edf5 --- /dev/null +++ b/x/transferinject/ibc_module_test.go @@ -0,0 +1,199 @@ +package transferinject_test + +import ( + "fmt" + "testing" + + "github.com/dymensionxyz/dymension/v3/utils/gerr" + + errortypes "github.com/cosmos/cosmos-sdk/types/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types" + "github.com/stretchr/testify/require" + + rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" + "github.com/dymensionxyz/dymension/v3/x/transferinject" + "github.com/dymensionxyz/dymension/v3/x/transferinject/types" +) + +func TestIBCModule_OnAcknowledgementPacket(t *testing.T) { + type fields struct { + packetData *transfertypes.FungibleTokenPacketData + ack []byte + ibcModule porttypes.IBCModule + rollappKeeper *mockRollappKeeper + } + tests := []struct { + name string + fields fields + wantRollapp *rollapptypes.Rollapp + wantErr error + }{ + { + name: "success: added token metadata to rollapp", + fields: fields{ + ibcModule: mockIBCModule{}, + rollappKeeper: &mockRollappKeeper{ + rollapp: &rollapptypes.Rollapp{}, + }, + packetData: &transfertypes.FungibleTokenPacketData{ + Denom: "adym", + Memo: addDenomMetadataToExistingMemo("", validDenomMetadata), + }, + ack: okAck(), + }, + wantRollapp: &rollapptypes.Rollapp{ + RegisteredDenoms: []string{validDenomMetadata.Base}, + }, + }, { + name: "success: added token metadata to rollapp with user memo", + fields: fields{ + ibcModule: mockIBCModule{}, + rollappKeeper: &mockRollappKeeper{ + rollapp: &rollapptypes.Rollapp{}, + }, + packetData: &transfertypes.FungibleTokenPacketData{ + Denom: "adym", + Memo: addDenomMetadataToExistingMemo("user memo", validDenomMetadata), + }, + ack: okAck(), + }, + wantRollapp: &rollapptypes.Rollapp{ + RegisteredDenoms: []string{validDenomMetadata.Base}, + }, + }, { + name: "return early: error ack", + fields: fields{ + rollappKeeper: &mockRollappKeeper{}, + ibcModule: mockIBCModule{}, + ack: errAck(), + }, + wantRollapp: nil, + }, { + name: "return early: no memo", + fields: fields{ + rollappKeeper: &mockRollappKeeper{}, + ibcModule: mockIBCModule{}, + packetData: &transfertypes.FungibleTokenPacketData{ + Denom: "adym", + }, + ack: okAck(), + }, + wantRollapp: nil, + }, { + name: "return early: no packet metadata in memo", + fields: fields{ + rollappKeeper: &mockRollappKeeper{}, + ibcModule: mockIBCModule{}, + packetData: &transfertypes.FungibleTokenPacketData{ + Denom: "adym", + Memo: "user memo", + }, + ack: okAck(), + }, + wantRollapp: nil, + }, { + name: "return early: no denom metadata in memo", + fields: fields{ + rollappKeeper: &mockRollappKeeper{}, + ibcModule: mockIBCModule{}, + packetData: &transfertypes.FungibleTokenPacketData{ + Denom: "adym", + Memo: `{"transferinject":{}}`, + }, + ack: okAck(), + }, + wantRollapp: nil, + }, { + name: "error: extract rollapp from channel", + fields: fields{ + ibcModule: mockIBCModule{}, + rollappKeeper: &mockRollappKeeper{ + err: errortypes.ErrInvalidRequest, + }, + packetData: &transfertypes.FungibleTokenPacketData{ + Denom: "adym", + Memo: addDenomMetadataToExistingMemo("", validDenomMetadata), + }, + ack: okAck(), + }, + wantRollapp: nil, + wantErr: errortypes.ErrInvalidRequest, + }, { + name: "error: rollapp not found", + fields: fields{ + ibcModule: mockIBCModule{}, + rollappKeeper: &mockRollappKeeper{}, + packetData: &transfertypes.FungibleTokenPacketData{ + Denom: "adym", + Memo: addDenomMetadataToExistingMemo("", validDenomMetadata), + }, + ack: okAck(), + }, + wantRollapp: nil, + wantErr: gerr.ErrNotFound, + }, { + name: "return early: rollapp already has token metadata", + fields: fields{ + ibcModule: mockIBCModule{}, + rollappKeeper: &mockRollappKeeper{ + rollapp: &rollapptypes.Rollapp{ + RegisteredDenoms: []string{validDenomMetadata.Base}, + }, + }, + packetData: &transfertypes.FungibleTokenPacketData{ + Denom: "adym", + Memo: addDenomMetadataToExistingMemo("", validDenomMetadata), + }, + ack: okAck(), + }, + wantRollapp: &rollapptypes.Rollapp{ + RegisteredDenoms: []string{validDenomMetadata.Base}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.fields.rollappKeeper.transfer = tt.fields.packetData + + m := transferinject.NewIBCModule(tt.fields.ibcModule, tt.fields.rollappKeeper) + + packet := channeltypes.Packet{} + + if tt.fields.packetData != nil { + packet.Data = types.ModuleCdc.MustMarshalJSON(tt.fields.packetData) + } + + err := m.OnAcknowledgementPacket(sdk.Context{}, packet, tt.fields.ack, sdk.AccAddress{}) + + if tt.wantErr == nil { + require.NoError(t, err) + } else { + require.ErrorIs(t, err, tt.wantErr) + } + + require.Equal(t, tt.wantRollapp, tt.fields.rollappKeeper.rollapp) + }) + } +} + +func okAck() []byte { + ack := channeltypes.NewResultAcknowledgement([]byte{}) + return types.ModuleCdc.MustMarshalJSON(&ack) +} + +func errAck() []byte { + ack := channeltypes.NewErrorAcknowledgement(fmt.Errorf("unsuccessful")) + return types.ModuleCdc.MustMarshalJSON(&ack) +} + +type mockIBCModule struct { + porttypes.IBCModule +} + +func (m mockIBCModule) OnAcknowledgementPacket(sdk.Context, channeltypes.Packet, []byte, sdk.AccAddress) error { + return nil +} diff --git a/x/transferinject/ics4_wrapper.go b/x/transferinject/ics4_wrapper.go new file mode 100644 index 000000000..dba23f16b --- /dev/null +++ b/x/transferinject/ics4_wrapper.go @@ -0,0 +1,98 @@ +package transferinject + +import ( + "errors" + . "slices" + + "github.com/dymensionxyz/dymension/v3/utils/gerr" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + errortypes "github.com/cosmos/cosmos-sdk/types/errors" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types" + + "github.com/dymensionxyz/dymension/v3/x/transferinject/types" +) + +type ICS4Wrapper struct { + porttypes.ICS4Wrapper + + rollappKeeper types.RollappKeeper + bankKeeper types.BankKeeper +} + +// NewICS4Wrapper creates a new ICS4Wrapper. +// It intercepts outgoing IBC packets and adds token metadata to the memo if the rollapp doesn't have it. +// This is a solution for adding token metadata to fungible tokens transferred over IBC, +// targeted at rollapps that don't have the token metadata for the token being transferred. +// More info here: https://www.notion.so/dymension/ADR-x-IBC-Denom-Metadata-Transfer-From-Hub-to-Rollapp-d3791f524ac849a9a3eb44d17968a30b +func NewICS4Wrapper( + next porttypes.ICS4Wrapper, + rollappKeeper types.RollappKeeper, + bankKeeper types.BankKeeper, +) *ICS4Wrapper { + return &ICS4Wrapper{ + ICS4Wrapper: next, + rollappKeeper: rollappKeeper, + bankKeeper: bankKeeper, + } +} + +// SendPacket wraps IBC ChannelKeeper's SendPacket function +func (m *ICS4Wrapper) SendPacket( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + srcPort string, srcChan string, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, + data []byte, +) (sequence uint64, err error) { + transfer, err := m.rollappKeeper.GetValidTransfer(ctx, data, srcPort, srcChan) + if err != nil { + return 0, errorsmod.Wrap(err, "transfer inject: get valid transfer") + } + + if types.MemoAlreadyHasPacketMetadata(transfer.GetMemo()) { + return 0, types.ErrMemoTransferInjectAlreadyExists + } + + if + // TODO: currently we check if receiving chain is a rollapp, consider that other chains also might want this feature + // meaning, find a better way to check if the receiving chain supports this middleware + !transfer.IsRollapp() || // proceed as normal + transfertypes.ReceiverChainIsSource(srcPort, srcChan, transfer.Denom) { + return m.ICS4Wrapper.SendPacket(ctx, chanCap, srcPort, srcChan, timeoutHeight, timeoutTimestamp, data) + } + + // Check if the rollapp already contains the denom metadata by matching the base of the denom metadata. + // At the first match, we assume that the rollapp already contains the metadata. + // It would be technically possible to have a race condition where the denom metadata is added to the rollapp + // from another packet before this packet is acknowledged. + if Contains(transfer.Rollapp.RegisteredDenoms, transfer.GetDenom()) { + return m.ICS4Wrapper.SendPacket(ctx, chanCap, srcPort, srcChan, timeoutHeight, timeoutTimestamp, data) + } + + // get the denom metadata from the bank keeper, if it doesn't exist, move on to the next middleware in the chain + denomMetadata, ok := m.bankKeeper.GetDenomMetaData(ctx, transfer.GetDenom()) + if !ok { + return m.ICS4Wrapper.SendPacket(ctx, chanCap, srcPort, srcChan, timeoutHeight, timeoutTimestamp, data) + } + + transfer.Memo, err = types.AddDenomMetadataToMemo(transfer.Memo, denomMetadata) + if err != nil { + if errors.Is(err, types.ErrMemoTransferInjectAlreadyExists) { + err = errors.Join(err, gerr.ErrPermissionDenied) + } + return 0, errorsmod.Wrap(err, "transfer inject: add denom metadata to memo") + } + + data, err = types.ModuleCdc.MarshalJSON(&transfer.FungibleTokenPacketData) + if err != nil { + return 0, errorsmod.Wrap(errors.Join(err, errortypes.ErrJSONMarshal), "transfer inject: ics20 transfer packet data") + } + + return m.ICS4Wrapper.SendPacket(ctx, chanCap, srcPort, srcChan, timeoutHeight, timeoutTimestamp, data) +} diff --git a/x/transferinject/ics4_wrapper_test.go b/x/transferinject/ics4_wrapper_test.go new file mode 100644 index 000000000..309e760b7 --- /dev/null +++ b/x/transferinject/ics4_wrapper_test.go @@ -0,0 +1,229 @@ +package transferinject_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types" + "github.com/stretchr/testify/require" + + rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" + "github.com/dymensionxyz/dymension/v3/x/transferinject" + "github.com/dymensionxyz/dymension/v3/x/transferinject/types" +) + +func TestICS4Wrapper_SendPacket(t *testing.T) { + type fields struct { + rollappKeeper *mockRollappKeeper + bankKeeper types.BankKeeper + srcPort string + srcChannel string + data *transfertypes.FungibleTokenPacketData + } + tests := []struct { + name string + fields fields + wantSentData []byte + wantErr error + }{ + { + name: "success: added denom metadata to memo", + fields: fields{ + rollappKeeper: &mockRollappKeeper{ + rollapp: &rollapptypes.Rollapp{}, + }, + bankKeeper: mockBankKeeper{ + returnMetadata: validDenomMetadata, + }, + srcPort: "port", + srcChannel: "channel", + data: &transfertypes.FungibleTokenPacketData{ + Denom: "adym", + }, + }, + wantSentData: types.ModuleCdc.MustMarshalJSON(&transfertypes.FungibleTokenPacketData{ + Denom: "adym", + Memo: addDenomMetadataToExistingMemo("", validDenomMetadata), + }), + }, { + name: "success: added denom metadata to non-empty user memo", + fields: fields{ + rollappKeeper: &mockRollappKeeper{ + rollapp: &rollapptypes.Rollapp{}, + }, + bankKeeper: mockBankKeeper{ + returnMetadata: validDenomMetadata, + }, + srcPort: "port", + srcChannel: "channel", + data: &transfertypes.FungibleTokenPacketData{ + Denom: "adym", + Memo: "thanks for the sweater, grandma!", + }, + }, + wantSentData: types.ModuleCdc.MustMarshalJSON(&transfertypes.FungibleTokenPacketData{ + Denom: "adym", + Memo: addDenomMetadataToExistingMemo("thanks for the sweater, grandma!", validDenomMetadata), + }), + }, { + name: "error: denom metadata already in memo", + fields: fields{ + rollappKeeper: &mockRollappKeeper{}, + bankKeeper: mockBankKeeper{}, + srcPort: "port", + srcChannel: "channel", + data: &transfertypes.FungibleTokenPacketData{ + Denom: "adym", + Memo: `{"transferinject":{}}`, + }, + }, + wantSentData: []byte(""), + wantErr: types.ErrMemoTransferInjectAlreadyExists, + }, { + name: "send unaltered: rollapp not found", + fields: fields{ + rollappKeeper: &mockRollappKeeper{}, + bankKeeper: mockBankKeeper{}, + srcPort: "port", + srcChannel: "channel", + data: &transfertypes.FungibleTokenPacketData{ + Denom: "adym", + Memo: "user memo", + }, + }, + wantSentData: types.ModuleCdc.MustMarshalJSON(&transfertypes.FungibleTokenPacketData{ + Denom: "adym", + Memo: "user memo", + }), + }, { + name: "send unaltered: receiver chain is source", + fields: fields{ + rollappKeeper: &mockRollappKeeper{ + rollapp: &rollapptypes.Rollapp{}, + }, + bankKeeper: mockBankKeeper{ + returnMetadata: validDenomMetadata, + }, + srcPort: "transfer", + srcChannel: "channel-56", + data: &transfertypes.FungibleTokenPacketData{ + Denom: "transfer/channel-56/alex", + }, + }, + wantSentData: types.ModuleCdc.MustMarshalJSON(&transfertypes.FungibleTokenPacketData{ + Denom: "transfer/channel-56/alex", + }), + }, { + name: "send unaltered: denom metadata already in rollapp", + fields: fields{ + rollappKeeper: &mockRollappKeeper{ + rollapp: &rollapptypes.Rollapp{ + RegisteredDenoms: []string{"adym"}, + }, + }, + bankKeeper: mockBankKeeper{}, + srcPort: "port", + srcChannel: "channel", + data: &transfertypes.FungibleTokenPacketData{ + Denom: "adym", + }, + }, + wantSentData: types.ModuleCdc.MustMarshalJSON(&transfertypes.FungibleTokenPacketData{ + Denom: "adym", + }), + }, { + name: "error: get denom metadata", + fields: fields{ + rollappKeeper: &mockRollappKeeper{ + rollapp: &rollapptypes.Rollapp{}, + }, + bankKeeper: mockBankKeeper{}, + srcPort: "port", + srcChannel: "channel", + data: &transfertypes.FungibleTokenPacketData{ + Denom: "adym", + }, + }, + wantSentData: types.ModuleCdc.MustMarshalJSON(&transfertypes.FungibleTokenPacketData{ + Denom: "adym", + }), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ics4 := mockICS4Wrapper{} + tt.fields.rollappKeeper.transfer = tt.fields.data + + m := transferinject.NewICS4Wrapper(&ics4, tt.fields.rollappKeeper, tt.fields.bankKeeper) + + data := types.ModuleCdc.MustMarshalJSON(tt.fields.data) + + _, err := m.SendPacket( + sdk.Context{}, + &capabilitytypes.Capability{}, + tt.fields.srcPort, + tt.fields.srcChannel, + clienttypes.Height{}, + 0, + data, + ) + if tt.wantErr == nil { + require.NoError(t, err) + } else { + require.ErrorIs(t, err, tt.wantErr) + } + require.Equal(t, string(tt.wantSentData), string(ics4.sentData)) + }) + } +} + +var validDenomMetadata = banktypes.Metadata{ + Description: "Denom of the Hub", + Base: "adym", + Display: "DYM", + Name: "DYM", + Symbol: "adym", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: "adym", + Exponent: 0, + }, { + Denom: "DYM", + Exponent: 18, + }, + }, +} + +func addDenomMetadataToExistingMemo(memo string, metadata banktypes.Metadata) string { + memo, _ = types.AddDenomMetadataToMemo(memo, metadata) + return memo +} + +type mockICS4Wrapper struct { + porttypes.ICS4Wrapper + sentData []byte +} + +func (m *mockICS4Wrapper) SendPacket( + _ sdk.Context, + _ *capabilitytypes.Capability, + _ string, _ string, + _ clienttypes.Height, + _ uint64, + data []byte, +) (sequence uint64, err error) { + m.sentData = data + return 0, nil +} + +type mockBankKeeper struct { + returnMetadata banktypes.Metadata +} + +func (m mockBankKeeper) GetDenomMetaData(sdk.Context, string) (banktypes.Metadata, bool) { + return m.returnMetadata, m.returnMetadata.Base != "" +} diff --git a/x/transferinject/types/expected_keepers.go b/x/transferinject/types/expected_keepers.go index b03cf0585..08d34f7da 100644 --- a/x/transferinject/types/expected_keepers.go +++ b/x/transferinject/types/expected_keepers.go @@ -3,7 +3,6 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/bank/types" - rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) @@ -14,9 +13,9 @@ type BankKeeper interface { type RollappKeeper interface { SetRollapp(ctx sdk.Context, rollapp rollapptypes.Rollapp) - ExtractRollappFromChannel( + GetValidTransfer( ctx sdk.Context, - rollappPortOnHub string, - rollappChannelOnHub string, - ) (*rollapptypes.Rollapp, error) + packetData []byte, + raPortOnHub, raChanOnHub string, + ) (data rollapptypes.TransferData, err error) } diff --git a/x/transferinject/types/packet_metadata.go b/x/transferinject/types/packet_metadata.go index 1ee40bb31..60ee670ba 100644 --- a/x/transferinject/types/packet_metadata.go +++ b/x/transferinject/types/packet_metadata.go @@ -4,6 +4,8 @@ import ( "encoding/json" "fmt" + "github.com/dymensionxyz/dymension/v3/utils/gerr" + errorsmod "cosmossdk.io/errors" errortypes "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -41,6 +43,10 @@ func ParsePacketMetadata(input string) (*TransferInject, error) { return nil, ErrMemoTransferInjectEmpty } + if memo.TransferInject.DenomMetadata == nil { + return nil, errorsmod.Wrap(gerr.ErrNotFound, "denom metadata") + } + return memo.TransferInject, nil } diff --git a/x/transferinject/util_test.go b/x/transferinject/util_test.go new file mode 100644 index 000000000..e48f47ad9 --- /dev/null +++ b/x/transferinject/util_test.go @@ -0,0 +1,28 @@ +package transferinject_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" +) + +type mockRollappKeeper struct { + rollapp *rollapptypes.Rollapp + transfer *transfertypes.FungibleTokenPacketData + err error +} + +func (m *mockRollappKeeper) GetValidTransfer(ctx sdk.Context, packetData []byte, raPortOnHub, raChanOnHub string) (data rollapptypes.TransferData, err error) { + ret := rollapptypes.TransferData{} + if m.transfer != nil { + ret.FungibleTokenPacketData = *m.transfer + } + if m.rollapp != nil { + ret.Rollapp = m.rollapp + } + return ret, nil +} + +func (m *mockRollappKeeper) SetRollapp(_ sdk.Context, rollapp rollapptypes.Rollapp) { + m.rollapp = &rollapp +}