Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(bank): send-hooks #14660

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,11 @@ func NewSimApp(
BlockedAddresses(),
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)
app.BankKeeper.SetHooks(
Copy link
Member

@julienrbrt julienrbrt Jan 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good wanted to get the teams opinion on the changes first. implementing that now.

Copy link
Member

@julienrbrt julienrbrt Jan 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course, this is why I commented:

If this proposal is accepted

Don't do it already, just in case :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lmk when and if the team is looking to move forward with this ser. Have a good weekend sers

banktypes.NewMultiSendHooks(
// register the send hooks here
),
)
app.StakingKeeper = stakingkeeper.NewKeeper(
appCodec, keys[stakingtypes.StoreKey], app.AccountKeeper, app.BankKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)
Expand Down
42 changes: 42 additions & 0 deletions x/bank/keeper/send.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ type BaseSendKeeper struct {
// the address capable of executing a MsgUpdateParams message. Typically, this
// should be the x/gov module account.
authority string
hooks types.SendHooks
}

func NewBaseSendKeeper(
Expand All @@ -79,6 +80,7 @@ func NewBaseSendKeeper(
ak: ak,
storeKey: storeKey,
blockedAddrs: blockedAddrs,
hooks: nil,
authority: authority,
}
}
Expand Down Expand Up @@ -125,6 +127,26 @@ func (k BaseSendKeeper) SetParams(ctx sdk.Context, params types.Params) error {
return nil
}

// Hooks gets the hooks for base send *Keeper {
func (k *BaseSendKeeper) Hooks() types.SendHooks {
if k.hooks == nil {
// return a no-op implementation if no hooks are set
return types.MultiSendHooks{}
}

return k.hooks
}

// SetHooks sets the send hooks. In contrast to other receivers, this method must take a pointer due to nature
// of the hooks interface and SDK start up sequence.
func (k *BaseSendKeeper) SetHooks(sh types.SendHooks) {
if k.hooks != nil {
panic("cannot set bank send hooks twice")
}

k.hooks = sh
}

// InputOutputCoins performs multi-send functionality. It accepts a series of
// inputs that correspond to a series of outputs. It returns an error if the
// inputs and outputs don't line up or if any single transfer of tokens fails.
Expand All @@ -141,6 +163,11 @@ func (k BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.Input,
return err
}

// Run send hooks if present.
if err := k.Hooks().BeforeSend(ctx, inAddress, inAddress, in.Coins); err != nil {
return err
}

err = k.subUnlockedCoins(ctx, inAddress, in.Coins)
if err != nil {
return err
Expand All @@ -160,6 +187,11 @@ func (k BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.Input,
return err
}

// Run After Send hooks if present.
if err := k.Hooks().AfterSend(ctx, outAddress, outAddress, out.Coins); err != nil {
return err
}

if err := k.addCoins(ctx, outAddress, out.Coins); err != nil {
return err
}
Expand Down Expand Up @@ -189,6 +221,11 @@ func (k BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.Input,
// SendCoins transfers amt coins from a sending account to a receiving account.
// An error is returned upon failure.
func (k BaseSendKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error {
// Run send hooks if present.
if err := k.Hooks().BeforeSend(ctx, fromAddr, toAddr, amt); err != nil {
return err
}

err := k.subUnlockedCoins(ctx, fromAddr, amt)
if err != nil {
return err
Expand All @@ -209,6 +246,11 @@ func (k BaseSendKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAd
k.ak.SetAccount(ctx, k.ak.NewAccountWithAddress(ctx, toAddr))
}

// Run After Send hooks if present.
if err := k.Hooks().AfterSend(ctx, fromAddr, toAddr, amt); err != nil {
return err
}

// bech32 encoding is expensive! Only do it once for fromAddr
fromAddrString := fromAddr.String()
ctx.EventManager().EmitEvents(sdk.Events{
Expand Down
34 changes: 34 additions & 0 deletions x/bank/types/hooks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package types

import sdk "github.com/cosmos/cosmos-sdk/types"

type SendHooks interface {
BeforeSend(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amount sdk.Coins) error
AfterSend(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amount sdk.Coins) error
}

type MultiSendHooks []SendHooks

func NewMultiSendHooks(hooks ...SendHooks) MultiSendHooks {
return hooks
}

func (h MultiSendHooks) BeforeSend(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amount sdk.Coins) error {
for i := range h {
if err := h[i].BeforeSend(ctx, fromAddr, toAddr, amount); err != nil {
return err
}
}

return nil
}

func (h MultiSendHooks) AfterSend(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amount sdk.Coins) error {
for i := range h {
if err := h[i].AfterSend(ctx, fromAddr, toAddr, amount); err != nil {
return err
}
}

return nil
}