diff --git a/app/app.go b/app/app.go index 4837fff9..6ed498f6 100644 --- a/app/app.go +++ b/app/app.go @@ -141,12 +141,12 @@ import ( tokenfactorykeeper "github.com/terra-money/core/v2/x/tokenfactory/keeper" tokenfactorytypes "github.com/terra-money/core/v2/x/tokenfactory/types" - alliancebank "github.com/terra-money/alliance/custom/bank" - bankkeeper "github.com/terra-money/alliance/custom/bank/keeper" "github.com/terra-money/alliance/x/alliance" allianceclient "github.com/terra-money/alliance/x/alliance/client" alliancekeeper "github.com/terra-money/alliance/x/alliance/keeper" alliancetypes "github.com/terra-money/alliance/x/alliance/types" + terracustombank "github.com/terra-money/core/v2/custom/bank" + custombankkeeper "github.com/terra-money/core/v2/custom/bank/keeper" pobabci "github.com/skip-mev/pob/abci" pobmempool "github.com/skip-mev/pob/mempool" @@ -315,7 +315,7 @@ type TerraApp struct { // keepers AccountKeeper authkeeper.AccountKeeper - BankKeeper bankkeeper.Keeper + BankKeeper custombankkeeper.Keeper CapabilityKeeper *capabilitykeeper.Keeper StakingKeeper *stakingkeeper.Keeper SlashingKeeper slashingkeeper.Keeper @@ -451,7 +451,7 @@ func NewTerraApp( terraappconfig.AccountAddressPrefix, authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) - app.BankKeeper = bankkeeper.NewBaseKeeper( + app.BankKeeper = custombankkeeper.NewBaseKeeper( appCodec, keys[banktypes.StoreKey], app.AccountKeeper, @@ -543,7 +543,6 @@ func NewTerraApp( app.DistrKeeper, appCodec, ) - // Create IBC Keeper app.IBCKeeper = ibckeeper.NewKeeper( appCodec, @@ -674,7 +673,15 @@ func NewTerraApp( ) app.Ics20WasmHooks.ContractKeeper = &app.WasmKeeper - + // Setup the contract app.WasmKeeper before the + // hook for the BankKeeper othrwise the WasmKeeper + // will be nil inside the hooks. + app.TokenFactoryKeeper.SetContractKeeper(app.WasmKeeper) + app.BankKeeper.SetHooks( + custombankkeeper.NewMultiBankHooks( + app.TokenFactoryKeeper.Hooks(), + ), + ) // register wasm gov proposal types enabledProposals := GetEnabledProposals() if len(enabledProposals) != 0 { @@ -735,7 +742,7 @@ func NewTerraApp( ), auth.NewAppModule(appCodec, app.AccountKeeper, nil, app.GetSubspace(authtypes.ModuleName)), vesting.NewAppModule(app.AccountKeeper, app.BankKeeper, app.DistrKeeper, app.StakingKeeper), - alliancebank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(alliancetypes.ModuleName)), + terracustombank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(alliancetypes.ModuleName)), capability.NewAppModule(appCodec, *app.CapabilityKeeper, false), crisis.NewAppModule(app.CrisisKeeper, skipGenesisInvariants, app.GetSubspace(crisistypes.ModuleName)), feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry), diff --git a/custom/bank/keeper/hooks.go b/custom/bank/keeper/hooks.go new file mode 100644 index 00000000..7bb01cf6 --- /dev/null +++ b/custom/bank/keeper/hooks.go @@ -0,0 +1,50 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + customterratypes "github.com/terra-money/core/v2/custom/bank/types" +) + +// Implements StakingHooks interface +var _ customterratypes.BankHooks = Keeper{} + +// TrackBeforeSend executes the TrackBeforeSend hook if registered. +func (k Keeper) TrackBeforeSend(ctx sdk.Context, from, to sdk.AccAddress, amount sdk.Coins) { + if k.hooks != nil { + k.hooks.TrackBeforeSend(ctx, from, to, amount) + } +} + +// BlockBeforeSend executes the BlockBeforeSend hook if registered. +func (k Keeper) BlockBeforeSend(ctx sdk.Context, from, to sdk.AccAddress, amount sdk.Coins) error { + if k.hooks != nil { + return k.hooks.BlockBeforeSend(ctx, from, to, amount) + } + return nil +} + +// MultiBankHooks combine multiple bank hooks, all hook functions are run in array sequence +type MultiBankHooks []customterratypes.BankHooks + +// NewMultiBankHooks takes a list of BankHooks and returns a MultiBankHooks +func NewMultiBankHooks(hooks ...customterratypes.BankHooks) MultiBankHooks { + return hooks +} + +// TrackBeforeSend runs the TrackBeforeSend hooks in order for each BankHook in a MultiBankHooks struct +func (h MultiBankHooks) TrackBeforeSend(ctx sdk.Context, from, to sdk.AccAddress, amount sdk.Coins) { + for i := range h { + h[i].TrackBeforeSend(ctx, from, to, amount) + } +} + +// BlockBeforeSend runs the BlockBeforeSend hooks in order for each BankHook in a MultiBankHooks struct +func (h MultiBankHooks) BlockBeforeSend(ctx sdk.Context, from, to sdk.AccAddress, amount sdk.Coins) error { + for i := range h { + err := h[i].BlockBeforeSend(ctx, from, to, amount) + if err != nil { + return err + } + } + return nil +} diff --git a/custom/bank/keeper/keeper.go b/custom/bank/keeper/keeper.go new file mode 100644 index 00000000..bd28a1c1 --- /dev/null +++ b/custom/bank/keeper/keeper.go @@ -0,0 +1,78 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + accountkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + custombankkeeper "github.com/terra-money/alliance/custom/bank/keeper" + customterratypes "github.com/terra-money/core/v2/custom/bank/types" +) + +type Keeper struct { + custombankkeeper.Keeper + hooks customterratypes.BankHooks + ak accountkeeper.AccountKeeper +} + +var _ bankkeeper.Keeper = Keeper{} + +func NewBaseKeeper( + cdc codec.BinaryCodec, + storeKey storetypes.StoreKey, + ak accountkeeper.AccountKeeper, + blockedAddrs map[string]bool, + authority string, +) Keeper { + keeper := Keeper{ + Keeper: custombankkeeper.NewBaseKeeper(cdc, storeKey, ak, blockedAddrs, authority), + hooks: nil, + ak: ak, + } + + return keeper +} + +// Set the bank hooks +func (k *Keeper) SetHooks(bh customterratypes.BankHooks) *Keeper { + if k.hooks != nil { + panic("cannot set bank hooks twice") + } + + k.hooks = bh + + return k +} + +// SendCoins transfers amt coins from a sending account to a receiving account. +// An error is returned upon failure. +func (k Keeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error { + // BlockBeforeSend hook should always be called before the TrackBeforeSend hook. + err := k.BlockBeforeSend(ctx, fromAddr, toAddr, amt) + if err != nil { + return err + } + k.TrackBeforeSend(ctx, fromAddr, toAddr, amt) + + return k.Keeper.SendCoins(ctx, fromAddr, toAddr, amt) +} + +// SendCoinsFromModuleToManyAccounts transfers coins from a ModuleAccount to multiple AccAddresses. +// It will panic if the module account does not exist. An error is returned if +// the recipient address is black-listed or if sending the tokens fails. +func (k Keeper) SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error { + senderAddr := k.ak.GetModuleAddress(senderModule) + if senderAddr == nil { + panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", senderModule)) + } + + recipientAcc := k.ak.GetModuleAccount(ctx, recipientModule) + if recipientAcc == nil { + panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", recipientModule)) + } + + return k.Keeper.SendCoins(ctx, senderAddr, recipientAcc.GetAddress(), amt) +} diff --git a/custom/bank/module.go b/custom/bank/module.go new file mode 100644 index 00000000..c680ed44 --- /dev/null +++ b/custom/bank/module.go @@ -0,0 +1,26 @@ +package bank + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/bank/exported" + "github.com/cosmos/cosmos-sdk/x/bank/types" + + customalliancemod "github.com/terra-money/alliance/custom/bank" + custombankkeeper "github.com/terra-money/core/v2/custom/bank/keeper" +) + +// AppModule wraps around the bank module and the bank keeper to return the right total supply ignoring bonded tokens +// that the alliance module minted to rebalance the voting power +// It modifies the TotalSupply and SupplyOf GRPC queries +type AppModule struct { + customalliancemod.AppModule +} + +// NewAppModule creates a new AppModule object +func NewAppModule(cdc codec.Codec, keeper custombankkeeper.Keeper, accountKeeper types.AccountKeeper, ss exported.Subspace) AppModule { + mod := customalliancemod.NewAppModule(cdc, keeper.Keeper, accountKeeper, ss) + + return AppModule{ + AppModule: mod, + } +} diff --git a/custom/bank/types/expected_hooks.go b/custom/bank/types/expected_hooks.go new file mode 100644 index 00000000..6ff4dc74 --- /dev/null +++ b/custom/bank/types/expected_hooks.go @@ -0,0 +1,17 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Event Hooks +// These can be utilized to communicate between a bank keeper and another +// keeper which must take particular actions when sends happen. +// The second keeper must implement this interface, which then the +// bank keeper can call. + +// BankHooks event hooks for bank sends +type BankHooks interface { + TrackBeforeSend(ctx sdk.Context, from, to sdk.AccAddress, amount sdk.Coins) // Must be before any send is executed + BlockBeforeSend(ctx sdk.Context, from, to sdk.AccAddress, amount sdk.Coins) error // Must be before any send is executed +} diff --git a/x/tokenfactory/keeper/before_send.go b/x/tokenfactory/keeper/before_send.go index 99e36019..55911eee 100644 --- a/x/tokenfactory/keeper/before_send.go +++ b/x/tokenfactory/keeper/before_send.go @@ -92,7 +92,7 @@ func (h Hooks) BlockBeforeSend(ctx sdk.Context, from, to sdk.AccAddress, amount func (k Keeper) callBeforeSendListener(ctx sdk.Context, from, to sdk.AccAddress, amount sdk.Coins, blockBeforeSend bool) (err error) { defer func() { if r := recover(); r != nil { - err = types.ErrTrackBeforeSendOutOfGas + err = errorsmod.Wrapf(types.ErrTrackBeforeSendOutOfGas, "%v", r) } }() diff --git a/x/tokenfactory/keeper/keeper.go b/x/tokenfactory/keeper/keeper.go index 528d5051..9dd7f3ed 100644 --- a/x/tokenfactory/keeper/keeper.go +++ b/x/tokenfactory/keeper/keeper.go @@ -2,6 +2,7 @@ package keeper import ( "fmt" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cometbft/cometbft/libs/log" @@ -10,9 +11,9 @@ import ( storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/terra-money/core/v2/x/tokenfactory/types" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + customtypes "github.com/terra-money/core/v2/custom/bank/keeper" + "github.com/terra-money/core/v2/x/tokenfactory/types" ) type ( @@ -22,7 +23,7 @@ type ( paramSpace paramtypes.Subspace accountKeeper types.AccountKeeper - bankKeeper types.BankKeeper + bankKeeper customtypes.Keeper contractKeeper types.ContractKeeper communityPoolKeeper types.CommunityPoolKeeper @@ -36,7 +37,7 @@ func NewKeeper( storeKey storetypes.StoreKey, paramSpace paramtypes.Subspace, accountKeeper types.AccountKeeper, - bankKeeper types.BankKeeper, + bankKeeper customtypes.Keeper, communityPoolKeeper types.CommunityPoolKeeper, cdc codec.BinaryCodec, ) Keeper {