Skip to content

Commit

Permalink
chore(uibc): refactore to make the uibc stack more modular (#2343)
Browse files Browse the repository at this point in the history
* refactore x/uibc

* fix build

* rename

* move ibc quota logic to quota keeper

* update middleware implementation

* fixes

* lint

* review

* lint

* fix test
  • Loading branch information
robert-zaremba authored Dec 4, 2023
1 parent fba6dec commit 809fa08
Show file tree
Hide file tree
Showing 26 changed files with 269 additions and 254 deletions.
10 changes: 5 additions & 5 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ import (
uibcmodule "github.com/umee-network/umee/v6/x/uibc/module"
uibcoracle "github.com/umee-network/umee/v6/x/uibc/oracle"
uibcquota "github.com/umee-network/umee/v6/x/uibc/quota"
uibcquotakeeper "github.com/umee-network/umee/v6/x/uibc/quota/keeper"
"github.com/umee-network/umee/v6/x/uibc/uics20"

"github.com/umee-network/umee/v6/x/metoken"
metokenkeeper "github.com/umee-network/umee/v6/x/metoken/keeper"
Expand Down Expand Up @@ -275,7 +275,7 @@ type UmeeApp struct {
LeverageKeeper leveragekeeper.Keeper
IncentiveKeeper incentivekeeper.Keeper
OracleKeeper oraclekeeper.Keeper
UIbcQuotaKeeperB uibcquotakeeper.Builder
UIbcQuotaKeeperB uibcquota.KeeperBuilder
UGovKeeperB ugovkeeper.Builder
MetokenKeeperB metokenkeeper.Builder

Expand Down Expand Up @@ -549,7 +549,7 @@ func New(
)

// UIbcQuotaKeeper implements ibcporttypes.ICS4Wrapper
app.UIbcQuotaKeeperB = uibcquotakeeper.NewKeeperBuilder(
app.UIbcQuotaKeeperB = uibcquota.NewKeeperBuilder(
appCodec, keys[uibc.StoreKey],
app.LeverageKeeper, uibcoracle.FromUmeeAvgPriceOracle(app.OracleKeeper), app.UGovKeeperB.EmergencyGroup,
)
Expand All @@ -566,7 +566,7 @@ func New(
- IBC Rate Limit Middleware
**********/

quotaICS4 := uibcquota.NewICS4(app.IBCKeeper.ChannelKeeper, app.UIbcQuotaKeeperB)
quotaICS4 := uics20.NewICS4(app.IBCKeeper.ChannelKeeper, app.UIbcQuotaKeeperB)

// Create Transfer Keeper and pass IBCFeeKeeper as expected Channel and PortKeeper
// since fee middleware will wrap the IBCKeeper for underlying application.
Expand All @@ -581,7 +581,7 @@ func New(
var transferStack ibcporttypes.IBCModule
transferStack = ibctransfer.NewIBCModule(app.IBCTransferKeeper)
// transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper)
transferStack = uibcquota.NewICS20Module(transferStack, app.UIbcQuotaKeeperB, appCodec)
transferStack = uics20.NewICS20Module(transferStack, app.UIbcQuotaKeeperB, appCodec)

// Create Interchain Accounts Controller Stack
// SendPacket, since it is originating from the application to core IBC:
Expand Down
9 changes: 4 additions & 5 deletions x/uibc/module/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,22 @@ import (
abci "github.com/cometbft/cometbft/abci/types"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/umee-network/umee/v6/x/uibc/quota/keeper"
"github.com/umee-network/umee/v6/x/uibc/quota"
)

// BeginBlock implements BeginBlock for the x/uibc module.
func BeginBlock(ctx sdk.Context, k keeper.Keeper) {
func BeginBlock(ctx sdk.Context, k quota.Keeper) {
logger := ctx.Logger().With("module", "uibc")
quotaExpires, err := k.GetExpire()
if err != nil {
// TODO, use logger as argument
logger.Error("can't get quota exipre", "error", err)
logger.Error("can't get quota expire", "error", err)
return
}

// reset quotas
if quotaExpires == nil || quotaExpires.Before(ctx.BlockTime()) {
if err = k.ResetAllQuotas(); err != nil {
logger.Error("can't get quota exipre", "error", err)
logger.Error("can't get quota expire", "error", err)
} else {
logger.Info("IBC Quota Reset")
ctx.EventManager().EmitEvent(
Expand Down
30 changes: 15 additions & 15 deletions x/uibc/module/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import (
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
"github.com/umee-network/umee/v6/util"
ibctransfer "github.com/umee-network/umee/v6/x/uibc"
"github.com/umee-network/umee/v6/x/uibc"
"github.com/umee-network/umee/v6/x/uibc/client/cli"
"github.com/umee-network/umee/v6/x/uibc/quota/keeper"
"github.com/umee-network/umee/v6/x/uibc/quota"
)

var (
Expand All @@ -35,7 +35,7 @@ func NewAppModuleBasic(cdc codec.Codec) AppModuleBasic {

// DefaultGenesis implements module.AppModuleBasic
func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage {
return cdc.MustMarshalJSON(ibctransfer.DefaultGenesisState())
return cdc.MustMarshalJSON(uibc.DefaultGenesisState())
}

// GetQueryCmd implements module.AppModuleBasic
Expand All @@ -50,31 +50,31 @@ func (AppModuleBasic) GetTxCmd() *cobra.Command {

// Name implements module.AppModuleBasic
func (AppModuleBasic) Name() string {
return ibctransfer.ModuleName
return uibc.ModuleName
}

// RegisterGRPCGatewayRoutes implements module.AppModuleBasic
func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) {
err := ibctransfer.RegisterQueryHandlerClient(
context.Background(), mux, ibctransfer.NewQueryClient(clientCtx))
err := uibc.RegisterQueryHandlerClient(
context.Background(), mux, uibc.NewQueryClient(clientCtx))
util.Panic(err)
}

// RegisterInterfaces implements module.AppModuleBasic
func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) {
ibctransfer.RegisterInterfaces(registry)
uibc.RegisterInterfaces(registry)
}

// RegisterLegacyAminoCodec implements module.AppModuleBasic
func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
ibctransfer.RegisterLegacyAminoCodec(cdc)
uibc.RegisterLegacyAminoCodec(cdc)
}

// ValidateGenesis implements module.AppModuleBasic
func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error {
var gs ibctransfer.GenesisState
var gs uibc.GenesisState
if err := cdc.UnmarshalJSON(bz, &gs); err != nil {
return fmt.Errorf("failed to unmarshal %s genesis state: %w", ibctransfer.ModuleName, err)
return fmt.Errorf("failed to unmarshal %s genesis state: %w", uibc.ModuleName, err)
}

return gs.Validate()
Expand All @@ -83,10 +83,10 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingCo
// AppModule represents the AppModule for this module
type AppModule struct {
AppModuleBasic
kb keeper.Builder
kb quota.KeeperBuilder
}

func NewAppModule(cdc codec.Codec, kb keeper.Builder) AppModule {
func NewAppModule(cdc codec.Codec, kb quota.KeeperBuilder) AppModule {
return AppModule{
AppModuleBasic: NewAppModuleBasic(cdc),
kb: kb,
Expand All @@ -101,7 +101,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw

// InitGenesis implements module.AppModule
func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate {
var genState ibctransfer.GenesisState
var genState uibc.GenesisState
cdc.MustUnmarshalJSON(data, &genState)
am.kb.InitGenesis(ctx, genState)

Expand All @@ -118,8 +118,8 @@ func (AppModule) RegisterInvariants(sdk.InvariantRegistry) {}

// RegisterServices implements module.AppModule
func (am AppModule) RegisterServices(cfg module.Configurator) {
ibctransfer.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.kb))
ibctransfer.RegisterQueryServer(cfg.QueryServer(), keeper.NewQuerier(am.kb))
uibc.RegisterMsgServer(cfg.MsgServer(), quota.NewMsgServerImpl(am.kb))
uibc.RegisterQueryServer(cfg.QueryServer(), quota.NewQuerier(am.kb))
}

// BeginBlock executes all ABCI BeginBlock logic respective to the x/uibc module.
Expand Down
6 changes: 3 additions & 3 deletions x/uibc/quota/keeper/genesis.go → x/uibc/quota/genesis.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package keeper
package quota

import (
sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -8,7 +8,7 @@ import (

// InitGenesis initializes the x/uibc module's state from a provided genesis
// state.
func (kb Builder) InitGenesis(ctx sdk.Context, genState uibc.GenesisState) {
func (kb KeeperBuilder) InitGenesis(ctx sdk.Context, genState uibc.GenesisState) {
k := kb.Keeper(&ctx)
err := k.SetParams(genState.Params)
util.Panic(err)
Expand All @@ -23,7 +23,7 @@ func (kb Builder) InitGenesis(ctx sdk.Context, genState uibc.GenesisState) {
}

// ExportGenesis returns the x/uibc module's exported genesis state.
func (kb Builder) ExportGenesis(ctx sdk.Context) *uibc.GenesisState {
func (kb KeeperBuilder) ExportGenesis(ctx sdk.Context) *uibc.GenesisState {
k := kb.Keeper(&ctx)
outflows, err := k.GetAllOutflows()
util.Panic(err)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package keeper
package quota

import (
context "context"
Expand All @@ -11,11 +11,11 @@ var _ uibc.QueryServer = Querier{}

// Querier implements a QueryServer for the x/uibc module.
type Querier struct {
Builder
KeeperBuilder
}

func NewQuerier(kb Builder) Querier {
return Querier{Builder: kb}
func NewQuerier(kb KeeperBuilder) Querier {
return Querier{KeeperBuilder: kb}
}

// Params returns params of the x/uibc module.
Expand Down
82 changes: 82 additions & 0 deletions x/uibc/quota/ibc_middleware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package quota

import (
"cosmossdk.io/errors"
sdkmath "cosmossdk.io/math"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
ics20types "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types"
channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
"github.com/cosmos/ibc-go/v7/modules/core/exported"

ibcutil "github.com/umee-network/umee/v6/util/ibc"
"github.com/umee-network/umee/v6/util/sdkutil"
"github.com/umee-network/umee/v6/x/uibc"
)

func (k Keeper) IBCOnSendPacket(packet []byte) error {
params := k.GetParams()

if !params.IbcStatus.IBCTransferEnabled() {
return ics20types.ErrSendDisabled
}

funds, denom, err := ibcutil.GetFundsFromPacket(packet)
if err != nil {
return errors.Wrap(err, "bad packet in rate limit's SendPacket")
}

if params.IbcStatus.OutflowQuotaEnabled() {
if err := k.CheckAndUpdateQuota(denom, funds); err != nil {
return errors.Wrap(err, "sendPacket over the IBC Quota")
}
}

return nil
}

func (k Keeper) IBCOnRecvPacket(packet channeltypes.Packet) exported.Acknowledgement {
params := k.GetParams()
if !params.IbcStatus.IBCTransferEnabled() {
return channeltypes.NewErrorAcknowledgement(ics20types.ErrReceiveDisabled)
}

if params.IbcStatus.OutflowQuotaEnabled() {
var data ics20types.FungibleTokenPacketData
if err := ics20types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil {
ackErr := sdkerrors.ErrInvalidType.Wrap("cannot unmarshal ICS-20 transfer packet data")
return channeltypes.NewErrorAcknowledgement(ackErr)
}

isSourceChain := ics20types.SenderChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), data.Denom)
ackErr := k.RecordIBCInflow(packet, data.Denom, data.Amount, isSourceChain)
if ackErr != nil {
return ackErr
}
}

return nil
}

// IBCRevertQuotaUpdate must be called on packet acknnowledgemenet error or timeout to revert
// necessary changes.
func (k Keeper) IBCRevertQuotaUpdate(amount, denom string) {
params := k.GetParams()
if !params.IbcStatus.OutflowQuotaEnabled() {
return
}
if err := k.revertQuotaUpdateStr(amount, denom); err != nil {
k.ctx.Logger().Error("revert quota update error", "err", err)
sdkutil.Emit(k.ctx, &uibc.EventBadRevert{
FailureType: "ibc-ack",
Packet: amount + denom,
})
}
}

func (k Keeper) revertQuotaUpdateStr(amount, denom string) error {
amountInt, ok := sdkmath.NewIntFromString(amount)
if !ok {
return sdkerrors.ErrInvalidRequest.Wrapf("invalid transfer amount %s", amount)
}
return k.UndoUpdateQuota(denom, amountInt)
}
Loading

0 comments on commit 809fa08

Please sign in to comment.