Skip to content

Commit

Permalink
Add recipient checker logics to bank send (#526)
Browse files Browse the repository at this point in the history
## Describe your changes and provide context
Allow checkers to be registered with bank send keeper so that certain
recipients can be blocked. For example, to block a temp address (created
by EVM module before address association) from receiving after its main
address is associated, one would register a checker as follows:
```
app.BankKeeper.RegisterRecipientChecker(func(ctx sdk.Context, recipient sdk.AccAddress) bool {
    castEvmAddress := common.BytesToAddress(recipient)
    _, isAssociated := app.EvmKeeper.GetSeiAddress(ctx, castEvmAddress)
    return !isAssociated
})
```

## Testing performed to validate your change
unit test
  • Loading branch information
codchen authored Jul 22, 2024
1 parent b0473e9 commit 8653b19
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 7 deletions.
3 changes: 3 additions & 0 deletions types/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ var (
// ErrEVMVMError defines an error for an evm vm error (eg. revert)
ErrEVMVMError = Register(RootCodespace, 45, "evm reverted")

// ErrInvalidRecipient defines an error for sending to disallowed recipients in bank
ErrInvalidRecipient = Register(RootCodespace, 46, "invalid bank recipient")

// ErrPanic is only set when we recover from a panic, so we know to
// redact potentially sensitive system info
ErrPanic = Register(UndefinedCodespace, 111222, "panic")
Expand Down
18 changes: 18 additions & 0 deletions x/bank/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1361,6 +1361,24 @@ func (suite *IntegrationTestSuite) TestSetDenomMetaData() {
suite.Require().Equal(metadata[1].GetDenomUnits()[1].GetAliases(), actualMetadata.GetDenomUnits()[1].GetAliases())
}

func (suite *IntegrationTestSuite) TestCanSendTo() {
app, ctx := suite.app, suite.ctx
badAddr := sdk.AccAddress([]byte("addr1_______________"))
goodAddr := sdk.AccAddress([]byte("addr2_______________"))
sourceAddr := sdk.AccAddress([]byte("addr3_______________"))
app.AccountKeeper.SetAccount(ctx, app.AccountKeeper.NewAccountWithAddress(ctx, badAddr))
app.AccountKeeper.SetAccount(ctx, app.AccountKeeper.NewAccountWithAddress(ctx, goodAddr))
app.AccountKeeper.SetAccount(ctx, app.AccountKeeper.NewAccountWithAddress(ctx, sourceAddr))
suite.Require().NoError(simapp.FundAccount(app.BankKeeper, ctx, sourceAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(100)))))
checker := func(_ sdk.Context, addr sdk.AccAddress) bool { return !addr.Equals(badAddr) }
app.BankKeeper.RegisterRecipientChecker(checker)
amt := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10)))
suite.Require().Nil(app.BankKeeper.SendCoins(ctx, sourceAddr, goodAddr, amt))
suite.Require().NotNil(app.BankKeeper.SendCoins(ctx, sourceAddr, badAddr, amt))
suite.Require().Nil(app.BankKeeper.SendCoinsAndWei(ctx, sourceAddr, goodAddr, sdk.OneInt(), sdk.ZeroInt()))
suite.Require().NotNil(app.BankKeeper.SendCoinsAndWei(ctx, sourceAddr, badAddr, sdk.OneInt(), sdk.ZeroInt()))
}

func (suite *IntegrationTestSuite) TestIterateAllDenomMetaData() {
app, ctx := suite.app, suite.ctx

Expand Down
38 changes: 31 additions & 7 deletions x/bank/keeper/send.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@ type SendKeeper interface {
IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error

BlockedAddr(addr sdk.AccAddress) bool
RegisterRecipientChecker(RecipientChecker)
}

type RecipientChecker = func(ctx sdk.Context, recipient sdk.AccAddress) bool

var _ SendKeeper = (*BaseSendKeeper)(nil)
var OneUseiInWei sdk.Int = sdk.NewInt(1_000_000_000_000)

Expand All @@ -47,20 +50,22 @@ type BaseSendKeeper struct {
paramSpace paramtypes.Subspace

// list of addresses that are restricted from receiving transactions
blockedAddrs map[string]bool
blockedAddrs map[string]bool
recipientCheckers *[]RecipientChecker
}

func NewBaseSendKeeper(
cdc codec.BinaryCodec, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace paramtypes.Subspace, blockedAddrs map[string]bool,
) BaseSendKeeper {

return BaseSendKeeper{
BaseViewKeeper: NewBaseViewKeeper(cdc, storeKey, ak),
cdc: cdc,
ak: ak,
storeKey: storeKey,
paramSpace: paramSpace,
blockedAddrs: blockedAddrs,
BaseViewKeeper: NewBaseViewKeeper(cdc, storeKey, ak),
cdc: cdc,
ak: ak,
storeKey: storeKey,
paramSpace: paramSpace,
blockedAddrs: blockedAddrs,
recipientCheckers: &[]RecipientChecker{},
}
}

Expand Down Expand Up @@ -232,6 +237,9 @@ func (k BaseSendKeeper) SubUnlockedCoins(ctx sdk.Context, addr sdk.AccAddress, a
// AddCoins increase the addr balance by the given amt. Fails if the provided amt is invalid.
// It emits a coin received event.
func (k BaseSendKeeper) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins, checkNeg bool) error {
if !k.CanSendTo(ctx, addr) {
return sdkerrors.ErrInvalidRecipient
}
if !amt.IsValid() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String())
}
Expand Down Expand Up @@ -360,6 +368,9 @@ func (k BaseSendKeeper) SubWei(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Int
}

func (k BaseSendKeeper) AddWei(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Int) (err error) {
if !k.CanSendTo(ctx, addr) {
return sdkerrors.ErrInvalidRecipient
}
if amt.Equal(sdk.ZeroInt()) {
return nil
}
Expand Down Expand Up @@ -405,6 +416,19 @@ func (k BaseSendKeeper) SendCoinsAndWei(ctx sdk.Context, from sdk.AccAddress, to
return nil
}

func (k BaseSendKeeper) RegisterRecipientChecker(rc RecipientChecker) {
*k.recipientCheckers = append(*k.recipientCheckers, rc)
}

func (k BaseSendKeeper) CanSendTo(ctx sdk.Context, recipient sdk.AccAddress) bool {
for _, rc := range *k.recipientCheckers {
if !rc(ctx, recipient) {
return false
}
}
return true
}

func SplitUseiWeiAmount(amt sdk.Int) (sdk.Int, sdk.Int) {
return amt.Quo(OneUseiInWei), amt.Mod(OneUseiInWei)
}

0 comments on commit 8653b19

Please sign in to comment.