From b0acf678e6e2cebe1a188eee4520a7931cfe854f Mon Sep 17 00:00:00 2001 From: Tony Chen Date: Wed, 3 Jun 2026 10:24:47 +0800 Subject: [PATCH] distribution: align withdraw recipient checks --- sei-cosmos/x/distribution/keeper/keeper.go | 9 +++- .../x/distribution/keeper/keeper_test.go | 43 +++++++++++++++++++ .../x/distribution/types/expected_keepers.go | 1 + 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/sei-cosmos/x/distribution/keeper/keeper.go b/sei-cosmos/x/distribution/keeper/keeper.go index 00771e8c35..38d6583d53 100644 --- a/sei-cosmos/x/distribution/keeper/keeper.go +++ b/sei-cosmos/x/distribution/keeper/keeper.go @@ -63,6 +63,10 @@ func (k Keeper) SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, w return types.ErrSetWithdrawAddrDisabled } + if k.bankKeeper.BlockedAddr(withdrawAddr) { + return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive external funds", withdrawAddr) + } + if !k.bankKeeper.CanSendTo(ctx, withdrawAddr) { return sdkerrors.Wrapf(sdkerrors.ErrInvalidRecipient, "%s is not allowed to receive external funds", withdrawAddr) } @@ -79,7 +83,10 @@ func (k Keeper) SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, w } func (k Keeper) canReceiveWithdrawAddr(ctx sdk.Context, withdrawAddr sdk.AccAddress) bool { - return !k.blockedAddrs[withdrawAddr.String()] && k.bankKeeper.CanSendTo(ctx, withdrawAddr) + if k.blockedAddrs[withdrawAddr.String()] || k.bankKeeper.BlockedAddr(withdrawAddr) { + return false + } + return k.bankKeeper.CanSendTo(ctx, withdrawAddr) } // withdraw rewards from a delegation diff --git a/sei-cosmos/x/distribution/keeper/keeper_test.go b/sei-cosmos/x/distribution/keeper/keeper_test.go index ad0dc3a002..55c7675a84 100644 --- a/sei-cosmos/x/distribution/keeper/keeper_test.go +++ b/sei-cosmos/x/distribution/keeper/keeper_test.go @@ -11,6 +11,7 @@ import ( seiapp "github.com/sei-protocol/sei-chain/app" "github.com/sei-protocol/sei-chain/app/apptesting" sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" + bankkeeper "github.com/sei-protocol/sei-chain/sei-cosmos/x/bank/keeper" "github.com/sei-protocol/sei-chain/sei-cosmos/x/distribution/types" ) @@ -39,6 +40,11 @@ func TestSetWithdrawAddr(t *testing.T) { app.EvmKeeper.SetAddressMapping(ctx, associatedAddr, evmAddr) require.Error(t, app.DistrKeeper.SetWithdrawAddr(ctx, addr[0], castAddr)) + coinbaseAddr := makeCoinbaseAddr() + require.True(t, app.BankKeeper.BlockedAddr(coinbaseAddr)) + require.True(t, app.BankKeeper.CanSendTo(ctx, coinbaseAddr)) + require.Error(t, app.DistrKeeper.SetWithdrawAddr(ctx, addr[0], coinbaseAddr)) + require.Error(t, app.DistrKeeper.SetWithdrawAddr(ctx, addr[0], distrAcc.GetAddress())) } @@ -82,6 +88,43 @@ func TestAfterValidatorRemovedFallsBackForInvalidWithdrawAddress(t *testing.T) { require.Equal(t, balanceBefore.Amount.Add(sdk.NewInt(10)), balanceAfter.Amount) } +func TestAfterValidatorRemovedFallsBackForBlockedWithdrawAddress(t *testing.T) { + app := seiapp.Setup(t, false, false, false) + ctx := app.BaseApp.NewContext(false, tmproto.Header{}) + + addr := seiapp.AddTestAddrs(app, ctx, 1, sdk.NewInt(1000000000)) + valAddr := seiapp.ConvertAddrsToValAddrs(addr)[0] + valAccAddr := sdk.AccAddress(valAddr) + coinbaseAddr := makeCoinbaseAddr() + + require.True(t, app.BankKeeper.BlockedAddr(coinbaseAddr)) + require.True(t, app.BankKeeper.CanSendTo(ctx, coinbaseAddr)) + app.DistrKeeper.SetDelegatorWithdrawAddr(ctx, valAccAddr, coinbaseAddr) + require.Equal(t, valAccAddr.String(), app.DistrKeeper.GetDelegatorWithdrawAddr(ctx, valAccAddr).String()) + + commission := sdk.DecCoins{sdk.NewDecCoin("usei", sdk.NewInt(10))} + coins := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10))) + distrAcc := app.DistrKeeper.GetDistributionAccount(ctx) + require.NoError(t, apptesting.FundModuleAccount(app.BankKeeper, ctx, distrAcc.GetName(), coins)) + app.AccountKeeper.SetModuleAccount(ctx, distrAcc) + + app.DistrKeeper.SetValidatorOutstandingRewards(ctx, valAddr, types.ValidatorOutstandingRewards{Rewards: commission}) + app.DistrKeeper.SetValidatorAccumulatedCommission(ctx, valAddr, types.ValidatorAccumulatedCommission{Commission: commission}) + + balanceBefore := app.BankKeeper.GetBalance(ctx, valAccAddr, "usei") + require.NotPanics(t, func() { + app.DistrKeeper.Hooks().AfterValidatorRemoved(ctx, sdk.ConsAddress{}, valAddr) + }) + balanceAfter := app.BankKeeper.GetBalance(ctx, valAccAddr, "usei") + require.Equal(t, balanceBefore.Amount.Add(sdk.NewInt(10)), balanceAfter.Amount) +} + +func makeCoinbaseAddr() sdk.AccAddress { + bz := append([]byte{}, bankkeeper.CoinbaseAddressPrefix...) + bz = append(bz, []byte("12345678")...) + return sdk.AccAddress(bz) +} + func TestWithdrawValidatorCommission(t *testing.T) { app := seiapp.Setup(t, false, false, false) ctx := app.BaseApp.NewContext(false, tmproto.Header{}) diff --git a/sei-cosmos/x/distribution/types/expected_keepers.go b/sei-cosmos/x/distribution/types/expected_keepers.go index 90232fa816..fe872a4f21 100644 --- a/sei-cosmos/x/distribution/types/expected_keepers.go +++ b/sei-cosmos/x/distribution/types/expected_keepers.go @@ -27,6 +27,7 @@ type BankKeeper interface { SendCoinsFromModuleToModule(ctx sdk.Context, senderModule string, recipientModule string, amt sdk.Coins) error SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + BlockedAddr(addr sdk.AccAddress) bool CanSendTo(ctx sdk.Context, recipient sdk.AccAddress) bool }