From 308a1044b76e35dc36b7d54da696f85b9a2d9c79 Mon Sep 17 00:00:00 2001 From: emidev98 Date: Wed, 30 Aug 2023 19:25:48 +0300 Subject: [PATCH 1/5] wip: bank hooks --- app/app.go | 4 +-- custom/bank/keeper/hooks.go | 25 +++++++++++++ custom/bank/keeper/keeper.go | 33 ++++++++++++++++++ custom/bank/module.go | 54 +++++++++++++++++++++++++++++ custom/bank/types/expected_hooks.go | 17 +++++++++ 5 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 custom/bank/keeper/hooks.go create mode 100644 custom/bank/keeper/keeper.go create mode 100644 custom/bank/module.go create mode 100644 custom/bank/types/expected_hooks.go diff --git a/app/app.go b/app/app.go index 4837fff9..30e43406 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" pobabci "github.com/skip-mev/pob/abci" pobmempool "github.com/skip-mev/pob/mempool" @@ -735,7 +735,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..740ae26c --- /dev/null +++ b/custom/bank/keeper/hooks.go @@ -0,0 +1,25 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank/types" + customterratypes "github.com/terra-money/core/v2/custom/bank/types" +) + +// Implements StakingHooks interface +var _ customterratypes.BankHooks = types.BaseSendKeeper{} + +// TrackBeforeSend executes the TrackBeforeSend hook if registered. +func (k types.BaseSendKeeper) 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 types.BaseSendKeeper) 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 +} diff --git a/custom/bank/keeper/keeper.go b/custom/bank/keeper/keeper.go new file mode 100644 index 00000000..9d098ba6 --- /dev/null +++ b/custom/bank/keeper/keeper.go @@ -0,0 +1,33 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + accountkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + + 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 +} + +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, + } + + return keeper +} diff --git a/custom/bank/module.go b/custom/bank/module.go new file mode 100644 index 00000000..5691872a --- /dev/null +++ b/custom/bank/module.go @@ -0,0 +1,54 @@ +package bank + +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "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/alliance/custom/bank/keeper" + customtypes "github.com/terra-money/core/v2/custom/bank/types" +) + +// 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 + hooks customtypes.BankHooks +} + +// 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, accountKeeper, ss) + + return AppModule{ + AppModule: mod, + hooks: nil, + } +} + +// Set the bank hooks +func (am *AppModule) SetHooks(bh customtypes.BankHooks) *AppModule { + if am.hooks != nil { + panic("cannot set bank hooks twice") + } + + am.hooks = bh + + return am +} + +// SendCoins transfers amt coins from a sending account to a receiving account. +// An error is returned upon failure. +func (am AppModule) 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 := am.hooks.BlockBeforeSend(ctx, fromAddr, toAddr, amt) + if err != nil { + return err + } + am.hooks.TrackBeforeSend(ctx, fromAddr, toAddr, amt) + + return am.SendCoins(ctx, fromAddr, toAddr, amt) +} 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 +} From 8438c9d06f5f30cbac6352811b51e0bcdb8e5555 Mon Sep 17 00:00:00 2001 From: emidev98 Date: Thu, 31 Aug 2023 17:33:33 +0300 Subject: [PATCH 2/5] wip: bank hooks --- app/app.go | 12 +++++++++--- custom/bank/keeper/hooks.go | 33 +++++++++++++++++++++++++++++---- custom/bank/keeper/keeper.go | 25 +++++++++++++++++++++++++ custom/bank/module.go | 32 ++------------------------------ x/tokenfactory/keeper/keeper.go | 9 +++++---- 5 files changed, 70 insertions(+), 41 deletions(-) diff --git a/app/app.go b/app/app.go index 30e43406..12a380cd 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" - 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, @@ -544,6 +544,12 @@ func NewTerraApp( appCodec, ) + app.BankKeeper.SetHooks( + custombankkeeper.NewMultiBankHooks( + app.TokenFactoryKeeper.Hooks(), + ), + ) + // Create IBC Keeper app.IBCKeeper = ibckeeper.NewKeeper( appCodec, diff --git a/custom/bank/keeper/hooks.go b/custom/bank/keeper/hooks.go index 740ae26c..7bb01cf6 100644 --- a/custom/bank/keeper/hooks.go +++ b/custom/bank/keeper/hooks.go @@ -2,24 +2,49 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/bank/types" customterratypes "github.com/terra-money/core/v2/custom/bank/types" ) // Implements StakingHooks interface -var _ customterratypes.BankHooks = types.BaseSendKeeper{} +var _ customterratypes.BankHooks = Keeper{} // TrackBeforeSend executes the TrackBeforeSend hook if registered. -func (k types.BaseSendKeeper) TrackBeforeSend(ctx sdk.Context, from, to sdk.AccAddress, amount sdk.Coins) { +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 types.BaseSendKeeper) BlockBeforeSend(ctx sdk.Context, from, to sdk.AccAddress, amount sdk.Coins) error { +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 index 9d098ba6..7aff2713 100644 --- a/custom/bank/keeper/keeper.go +++ b/custom/bank/keeper/keeper.go @@ -3,6 +3,7 @@ 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" @@ -31,3 +32,27 @@ func NewBaseKeeper( 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.BaseKeeper.SendCoins(ctx, fromAddr, toAddr, amt) +} diff --git a/custom/bank/module.go b/custom/bank/module.go index 5691872a..c680ed44 100644 --- a/custom/bank/module.go +++ b/custom/bank/module.go @@ -2,13 +2,11 @@ package bank import ( "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" "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/alliance/custom/bank/keeper" - customtypes "github.com/terra-money/core/v2/custom/bank/types" + 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 @@ -16,39 +14,13 @@ import ( // It modifies the TotalSupply and SupplyOf GRPC queries type AppModule struct { customalliancemod.AppModule - hooks customtypes.BankHooks } // 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, accountKeeper, ss) + mod := customalliancemod.NewAppModule(cdc, keeper.Keeper, accountKeeper, ss) return AppModule{ AppModule: mod, - hooks: nil, } } - -// Set the bank hooks -func (am *AppModule) SetHooks(bh customtypes.BankHooks) *AppModule { - if am.hooks != nil { - panic("cannot set bank hooks twice") - } - - am.hooks = bh - - return am -} - -// SendCoins transfers amt coins from a sending account to a receiving account. -// An error is returned upon failure. -func (am AppModule) 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 := am.hooks.BlockBeforeSend(ctx, fromAddr, toAddr, amt) - if err != nil { - return err - } - am.hooks.TrackBeforeSend(ctx, fromAddr, toAddr, amt) - - return am.SendCoins(ctx, fromAddr, toAddr, amt) -} 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 { From faed2c321560c1af65f6fc3cffa8ba4c399bdba9 Mon Sep 17 00:00:00 2001 From: emidev98 Date: Fri, 1 Sep 2023 15:37:49 +0300 Subject: [PATCH 3/5] feat: ibc-hooks wrap error --- x/tokenfactory/keeper/before_send.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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) } }() From 3d4b9d80492f784a858c02c2406ea514885e6a93 Mon Sep 17 00:00:00 2001 From: emidev98 Date: Mon, 4 Sep 2023 08:59:34 +0800 Subject: [PATCH 4/5] fix: token factory contract keeper --- app/app.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/app/app.go b/app/app.go index 12a380cd..6ed498f6 100644 --- a/app/app.go +++ b/app/app.go @@ -543,13 +543,6 @@ func NewTerraApp( app.DistrKeeper, appCodec, ) - - app.BankKeeper.SetHooks( - custombankkeeper.NewMultiBankHooks( - app.TokenFactoryKeeper.Hooks(), - ), - ) - // Create IBC Keeper app.IBCKeeper = ibckeeper.NewKeeper( appCodec, @@ -680,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 { From c632c5d2b6e9ab6b8a3436e2ed4c180c60b0d667 Mon Sep 17 00:00:00 2001 From: emidev98 Date: Mon, 4 Sep 2023 13:08:57 +0800 Subject: [PATCH 5/5] feat: send coins from module to module without calling hooks --- custom/bank/keeper/keeper.go | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/custom/bank/keeper/keeper.go b/custom/bank/keeper/keeper.go index 7aff2713..bd28a1c1 100644 --- a/custom/bank/keeper/keeper.go +++ b/custom/bank/keeper/keeper.go @@ -7,6 +7,7 @@ import ( 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" ) @@ -14,6 +15,7 @@ import ( type Keeper struct { custombankkeeper.Keeper hooks customterratypes.BankHooks + ak accountkeeper.AccountKeeper } var _ bankkeeper.Keeper = Keeper{} @@ -28,6 +30,7 @@ func NewBaseKeeper( keeper := Keeper{ Keeper: custombankkeeper.NewBaseKeeper(cdc, storeKey, ak, blockedAddrs, authority), hooks: nil, + ak: ak, } return keeper @@ -54,5 +57,22 @@ func (k Keeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.A } k.TrackBeforeSend(ctx, fromAddr, toAddr, amt) - return k.Keeper.BaseKeeper.SendCoins(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) }