From 8df230b4c7c498ada476ad3a58d113e0aec312b5 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin <114929630+mtsitrin@users.noreply.github.com> Date: Wed, 4 Dec 2024 14:36:44 +0200 Subject: [PATCH] feat(denommetadata): charge extra fee for IBC denom metadata registration (#1609) --- app/keepers/keepers.go | 2 +- ibctesting/eibc_test.go | 5 +---- x/denommetadata/ibc_middleware.go | 20 +++++++++++++++++++- x/denommetadata/ibc_middleware_test.go | 20 ++++++++++++++++++-- x/denommetadata/types/expected_keepers.go | 5 +++++ x/rollapp/types/params.go | 2 +- 6 files changed, 45 insertions(+), 9 deletions(-) diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index b696b5cdf..5338a2c7f 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -554,7 +554,7 @@ func (a *AppKeepers) InitTransferStack() { packetforwardkeeper.DefaultRefundTransferPacketTimeoutTimestamp, ) - a.TransferStack = denommetadatamodule.NewIBCModule(a.TransferStack, a.DenomMetadataKeeper, a.RollappKeeper) + a.TransferStack = denommetadatamodule.NewIBCModule(a.TransferStack, a.DenomMetadataKeeper, a.RollappKeeper, a.TxFeesKeeper) // already instantiated in SetupHooks() a.delayedAckMiddleware.Setup( delayedackmodule.WithIBCModule(a.TransferStack), diff --git a/ibctesting/eibc_test.go b/ibctesting/eibc_test.go index 089899cb2..0548fce29 100644 --- a/ibctesting/eibc_test.go +++ b/ibctesting/eibc_test.go @@ -379,10 +379,7 @@ func (s *eibcSuite) TestEIBCDemandOrderFulfillment() { } 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 - return true + return s.hubChain().App.GetIBCKeeper().ChannelKeeper.HasPacketCommitment(s.rollappCtx(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) } // TestTimeoutEIBCDemandOrderFulfillment: when a packet hub->rollapp times out, or gets an error ack, than eIBC can be used to recover quickly. diff --git a/x/denommetadata/ibc_middleware.go b/x/denommetadata/ibc_middleware.go index 54e850c07..7fbc63054 100644 --- a/x/denommetadata/ibc_middleware.go +++ b/x/denommetadata/ibc_middleware.go @@ -15,9 +15,12 @@ import ( "github.com/dymensionxyz/sdk-utils/utils/uevent" "github.com/dymensionxyz/sdk-utils/utils/uibc" + commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" "github.com/dymensionxyz/dymension/v3/x/denommetadata/types" ) +var RegistrationFeeAmt = commontypes.DYM.QuoRaw(10) // 0.1 DYM + var _ porttypes.IBCModule = &IBCModule{} // IBCModule implements the ICS26 callbacks for the transfer middleware @@ -25,6 +28,7 @@ type IBCModule struct { porttypes.IBCModule keeper types.DenomMetadataKeeper rollappKeeper types.RollappKeeper + txFeesKeeper types.TxFeesKeeper } // NewIBCModule creates a new IBCModule given the keepers and underlying application @@ -32,11 +36,13 @@ func NewIBCModule( app porttypes.IBCModule, keeper types.DenomMetadataKeeper, rollappKeeper types.RollappKeeper, + txFeesKeeper types.TxFeesKeeper, ) IBCModule { return IBCModule{ IBCModule: app, keeper: keeper, rollappKeeper: rollappKeeper, + txFeesKeeper: txFeesKeeper, } } @@ -87,9 +93,21 @@ func (im IBCModule) OnRecvPacket( return im.IBCModule.OnRecvPacket(ctx, packet, relayer) } + // charge denom metadata registration fee + baseDenom, err := im.txFeesKeeper.GetBaseDenom(ctx) + if err != nil { + return uevent.NewErrorAcknowledgement(ctx, err) + } + + registrationFee := sdk.NewCoin(baseDenom, RegistrationFeeAmt) + err = im.txFeesKeeper.ChargeFeesFromPayer(ctx, relayer, registrationFee, nil) + if err != nil { + return uevent.NewErrorAcknowledgement(ctx, err) + } + + // adjust the denom metadata with the IBC denom dm.Base = ibcDenom dm.DenomUnits[0].Denom = dm.Base - if err = im.keeper.CreateDenomMetadata(ctx, *dm); err != nil { if errorsmod.IsOf(err, gerrc.ErrAlreadyExists) { return im.IBCModule.OnRecvPacket(ctx, packet, relayer) diff --git a/x/denommetadata/ibc_middleware_test.go b/x/denommetadata/ibc_middleware_test.go index c61f6bf78..bd20618c7 100644 --- a/x/denommetadata/ibc_middleware_test.go +++ b/x/denommetadata/ibc_middleware_test.go @@ -29,6 +29,7 @@ func TestIBCModule_OnRecvPacket(t *testing.T) { name string keeper *mockDenomMetadataKeeper rollappKeeper *mockRollappKeeper + txFeesKeeper *mockTxFeeKeeper memoData *memoData wantAck exported.Acknowledgement @@ -109,7 +110,7 @@ func TestIBCModule_OnRecvPacket(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { app := &mockIBCModule{} - im := denommetadata.NewIBCModule(app, tt.keeper, tt.rollappKeeper) + im := denommetadata.NewIBCModule(app, tt.keeper, tt.rollappKeeper, tt.txFeesKeeper) var memo string if tt.memoData != nil { memo = mustMarshalJSON(tt.memoData) @@ -345,6 +346,7 @@ func TestIBCModule_OnAcknowledgementPacket(t *testing.T) { type fields struct { IBCModule porttypes.IBCModule rollappKeeper *mockRollappKeeper + txFeesKeeper *mockTxFeeKeeper } type args struct { packetData *transfertypes.FungibleTokenPacketData @@ -524,7 +526,7 @@ func TestIBCModule_OnAcknowledgementPacket(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - m := denommetadata.NewIBCModule(tt.fields.IBCModule, nil, tt.fields.rollappKeeper) + m := denommetadata.NewIBCModule(tt.fields.IBCModule, nil, tt.fields.rollappKeeper, tt.fields.txFeesKeeper) packet := channeltypes.Packet{} @@ -745,3 +747,17 @@ func (m mockBankKeeper) SetDenomMetaData(ctx sdk.Context, denomMetaData banktype func (m mockBankKeeper) GetDenomMetaData(sdk.Context, string) (banktypes.Metadata, bool) { return m.returnMetadata, m.returnMetadata.Base != "" } + +type mockTxFeeKeeper struct { + err error +} + +// ChargeFeesFromPayer implements types.TxFeesKeeper. +func (m *mockTxFeeKeeper) ChargeFeesFromPayer(ctx sdk.Context, payer sdk.AccAddress, takerFeeCoin sdk.Coin, beneficiary *sdk.AccAddress) error { + return m.err +} + +// GetBaseDenom implements types.TxFeesKeeper. +func (m *mockTxFeeKeeper) GetBaseDenom(ctx sdk.Context) (denom string, err error) { + return "adym", nil +} diff --git a/x/denommetadata/types/expected_keepers.go b/x/denommetadata/types/expected_keepers.go index d8bb59f8d..7a5754e70 100644 --- a/x/denommetadata/types/expected_keepers.go +++ b/x/denommetadata/types/expected_keepers.go @@ -29,3 +29,8 @@ type RollappKeeper interface { HasRegisteredDenom(ctx sdk.Context, rollappID, denom string) (bool, error) ClearRegisteredDenoms(ctx sdk.Context, rollappID string) error } + +type TxFeesKeeper interface { + GetBaseDenom(ctx sdk.Context) (denom string, err error) + ChargeFeesFromPayer(ctx sdk.Context, payer sdk.AccAddress, takerFeeCoin sdk.Coin, beneficiary *sdk.AccAddress) error +} diff --git a/x/rollapp/types/params.go b/x/rollapp/types/params.go index f0d56393a..f7751dc3d 100644 --- a/x/rollapp/types/params.go +++ b/x/rollapp/types/params.go @@ -26,7 +26,7 @@ var ( KeyMinSequencerBondGlobal = []byte("KeyMinSequencerBondGlobal") - DefaultAppRegistrationFee = commontypes.DYMCoin + DefaultAppRegistrationFee = commontypes.Dym(sdk.NewInt(1)) DefaultMinSequencerBondGlobalCoin = commontypes.Dym(sdk.NewInt(100)) )