diff --git a/CHANGELOG.md b/CHANGELOG.md index 20da25bf0bfd..a69702176003 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,7 +43,6 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (baseapp) [#205](https://github.com/crypto-org-chain/cosmos-sdk/pull/205) Add `TxExecutor` baseapp option, add `TxIndex`/`TxCount`/`MsgIndex`/`BlockGasUsed` fields to `Context, to support tx parallel execution. * (baseapp) [#206](https://github.com/crypto-org-chain/cosmos-sdk/pull/206) Support mount object store in baseapp, add `ObjectStore` api in context. * (bank) [#237](https://github.com/crypto-org-chain/cosmos-sdk/pull/237) Support virtual accounts in sending coins. -* (x/bank) [#239](https://github.com/crypto-org-chain/cosmos-sdk/pull/239) Add low level `AddBalance`,`SubBalance` APIs to bank keeper. * [#243](https://github.com/crypto-org-chain/cosmos-sdk/pull/243) Support `RunAtomic` API in `Context` to use new CoW branched cache store. ## [Unreleased-Upstream] diff --git a/x/bank/keeper/keeper.go b/x/bank/keeper/keeper.go index 1a31ffc0f220..26dceca9b66b 100644 --- a/x/bank/keeper/keeper.go +++ b/x/bank/keeper/keeper.go @@ -419,41 +419,6 @@ func (k BaseKeeper) BurnCoins(ctx context.Context, moduleName string, amounts sd return nil } -// AddBalance is low level api to update balance directly, mainly used by evm integration, -// caller should make sure the total supply of the denom not changed and the account exists. -// it's for evm integration, call at your own risk. -// it emits mint event. -func (k BaseKeeper) AddBalance(ctx context.Context, addr sdk.AccAddress, coin sdk.Coin) error { - if err := k.addCoin(ctx, addr, coin); err != nil { - return err - } - - // emit mint event - sdkCtx := sdk.UnwrapSDKContext(ctx) - sdkCtx.EventManager().EmitEvent( - types.NewCoinMintEvent(addr, sdk.NewCoins(coin)), - ) - return nil -} - -// SubBalance is low level api to update balance directly, mainly used by evm integration, -// caller should make sure the total supply of the denom not changed. -// it's for evm integration, call at your own risk. -// it emits burn event. -func (k BaseKeeper) SubBalance(ctx context.Context, addr sdk.AccAddress, coin sdk.Coin) error { - lockedCoins := k.LockedCoins(ctx, addr) - if err := k.subCoin(ctx, addr, coin, lockedCoins); err != nil { - return err - } - - sdkCtx := sdk.UnwrapSDKContext(ctx) - // emit burn event - sdkCtx.EventManager().EmitEvent( - types.NewCoinBurnEvent(addr, sdk.NewCoins(coin)), - ) - return nil -} - // setSupply sets the supply for the given coin func (k BaseKeeper) setSupply(ctx context.Context, coin sdk.Coin) { // Bank invariants and IBC requires to remove zero coins. diff --git a/x/bank/keeper/send.go b/x/bank/keeper/send.go index 037bc83265a8..7f9bd6016506 100644 --- a/x/bank/keeper/send.go +++ b/x/bank/keeper/send.go @@ -8,6 +8,7 @@ import ( "cosmossdk.io/core/store" errorsmod "cosmossdk.io/errors" "cosmossdk.io/log" + "cosmossdk.io/math" storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/codec" @@ -272,7 +273,29 @@ func (k BaseSendKeeper) subUnlockedCoins(ctx context.Context, addr sdk.AccAddres lockedCoins := k.LockedCoins(ctx, addr) for _, coin := range amt { - if err := k.subCoin(ctx, addr, coin, lockedCoins); err != nil { + balance := k.GetBalance(ctx, addr, coin.Denom) + locked := sdk.NewCoin(coin.Denom, lockedCoins.AmountOf(coin.Denom)) + + spendable, hasNeg := sdk.Coins{balance}.SafeSub(locked) + if hasNeg { + return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, + "locked amount exceeds account balance funds: %s > %s", locked, balance) + } + + if _, hasNeg := spendable.SafeSub(coin); hasNeg { + if len(spendable) == 0 { + spendable = sdk.Coins{sdk.NewCoin(coin.Denom, math.ZeroInt())} + } + return errorsmod.Wrapf( + sdkerrors.ErrInsufficientFunds, + "spendable balance %s is smaller than %s", + spendable, coin, + ) + } + + newBalance := balance.Sub(coin) + + if err := k.setBalance(ctx, addr, newBalance); err != nil { return err } } @@ -285,32 +308,6 @@ func (k BaseSendKeeper) subUnlockedCoins(ctx context.Context, addr sdk.AccAddres return nil } -func (k BaseSendKeeper) subCoin(ctx context.Context, addr sdk.AccAddress, coin sdk.Coin, lockedCoins sdk.Coins) error { - var ( - spendable sdk.Coin - err error - ) - balance := k.GetBalance(ctx, addr, coin.Denom) - locked := sdk.NewCoin(coin.Denom, lockedCoins.AmountOf(coin.Denom)) - if locked.IsZero() { - spendable = balance - } else { - spendable, err = balance.SafeSub(locked) - if err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, - "locked amount exceeds account balance funds: %s > %s", locked, balance) - } - } - if spendable.Amount.LT(coin.Amount) { - return errorsmod.Wrapf( - sdkerrors.ErrInsufficientFunds, - "spendable balance %s is smaller than %s", - spendable, coin, - ) - } - return k.setBalance(ctx, addr, balance.Sub(coin)) -} - // 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 context.Context, addr sdk.AccAddress, amt sdk.Coins) error { @@ -319,7 +316,11 @@ func (k BaseSendKeeper) addCoins(ctx context.Context, addr sdk.AccAddress, amt s } for _, coin := range amt { - if err := k.addCoin(ctx, addr, coin); err != nil { + balance := k.GetBalance(ctx, addr, coin.Denom) + newBalance := balance.Add(coin) + + err := k.setBalance(ctx, addr, newBalance) + if err != nil { return err } } @@ -333,12 +334,6 @@ func (k BaseSendKeeper) addCoins(ctx context.Context, addr sdk.AccAddress, amt s return nil } -func (k BaseSendKeeper) addCoin(ctx context.Context, addr sdk.AccAddress, coin sdk.Coin) error { - balance := k.GetBalance(ctx, addr, coin.Denom) - newBalance := balance.Add(coin) - return k.setBalance(ctx, addr, newBalance) -} - // setBalance sets the coin balance for an account by address. func (k BaseSendKeeper) setBalance(ctx context.Context, addr sdk.AccAddress, balance sdk.Coin) error { if !balance.IsValid() {