diff --git a/testutil/sample/sample.go b/testutil/sample/sample.go index a0d422a660..22b57c6cde 100644 --- a/testutil/sample/sample.go +++ b/testutil/sample/sample.go @@ -37,7 +37,14 @@ func PubKey(r *rand.Rand) cryptotypes.PubKey { return ed25519.GenPrivKeyFromSecret(seed).PubKey() } -// AccAddress returns a sample account address +// Bech32AccAddress returns a sample account address +func Bech32AccAddress() sdk.AccAddress { + pk := ed25519.GenPrivKey().PubKey() + addr := pk.Address() + return sdk.AccAddress(addr) +} + +// AccAddress returns a sample account address in string func AccAddress() string { pk := ed25519.GenPrivKey().PubKey() addr := pk.Address() diff --git a/x/fungible/keeper/zeta.go b/x/fungible/keeper/zeta.go index e46646ed6f..0a5e72b31d 100644 --- a/x/fungible/keeper/zeta.go +++ b/x/fungible/keeper/zeta.go @@ -4,14 +4,13 @@ import ( "math/big" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/zeta-chain/zetacore/cmd/zetacored/config" "github.com/zeta-chain/zetacore/x/fungible/types" ) // MintZetaToEVMAccount mints ZETA (gas token) to the given address +// NOTE: this method should be used with a temporary context, and it should not be committed if the method returns an error func (k *Keeper) MintZetaToEVMAccount(ctx sdk.Context, to sdk.AccAddress, amount *big.Int) error { - balanceCoin := k.bankKeeper.GetBalance(ctx, to, config.BaseDenom) coins := sdk.NewCoins(sdk.NewCoin(config.BaseDenom, sdk.NewIntFromBigInt(amount))) // Mint coins if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, coins); err != nil { @@ -19,29 +18,5 @@ func (k *Keeper) MintZetaToEVMAccount(ctx sdk.Context, to sdk.AccAddress, amount } // Send minted coins to the receiver - err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, to, coins) - - if err == nil { - // Check expected receiver balance after transfer - balanceCoinAfter := k.bankKeeper.GetBalance(ctx, to, config.BaseDenom) - expCoin := balanceCoin.Add(coins[0]) - - if ok := balanceCoinAfter.IsEqual(expCoin); !ok { - err = sdkerrors.Wrapf( - types.ErrBalanceInvariance, - "invalid coin balance - expected: %v, actual: %v", - expCoin, balanceCoinAfter, - ) - } - } - - if err != nil { - // Revert minting if an error is found. - if err := k.bankKeeper.BurnCoins(ctx, types.ModuleName, coins); err != nil { - return err - } - return err - } - - return nil + return k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, to, coins) } diff --git a/x/fungible/keeper/zeta_test.go b/x/fungible/keeper/zeta_test.go new file mode 100644 index 0000000000..cec34d06ea --- /dev/null +++ b/x/fungible/keeper/zeta_test.go @@ -0,0 +1,77 @@ +package keeper_test + +import ( + "errors" + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/cmd/zetacored/config" + testkeeper "github.com/zeta-chain/zetacore/testutil/keeper" + "github.com/zeta-chain/zetacore/testutil/sample" + "github.com/zeta-chain/zetacore/x/fungible/types" +) + +func TestKeeper_MintZetaToEVMAccount(t *testing.T) { + t.Run("should mint the token in the specified balance", func(t *testing.T) { + k, ctx, sdkk, _ := testkeeper.FungibleKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + acc := sample.Bech32AccAddress() + bal := sdkk.BankKeeper.GetBalance(ctx, acc, config.BaseDenom) + require.True(t, bal.IsZero()) + + err := k.MintZetaToEVMAccount(ctx, acc, big.NewInt(42)) + require.NoError(t, err) + bal = sdkk.BankKeeper.GetBalance(ctx, acc, config.BaseDenom) + require.True(t, bal.Amount.Equal(sdk.NewInt(42))) + }) + + coins42 := sdk.NewCoins(sdk.NewCoin(config.BaseDenom, sdk.NewInt(42))) + + t.Run("should fail if minting fail", func(t *testing.T) { + k, ctx := testkeeper.FungibleKeeperAllMocks(t) + + mockBankKeeper := testkeeper.GetFungibleBankMock(t, k) + + mockBankKeeper.On( + "MintCoins", + ctx, + types.ModuleName, + coins42, + ).Return(errors.New("error")) + + err := k.MintZetaToEVMAccount(ctx, sample.Bech32AccAddress(), big.NewInt(42)) + require.Error(t, err) + + mockBankKeeper.AssertExpectations(t) + }) + + t.Run("should fail if sending coins fail", func(t *testing.T) { + k, ctx := testkeeper.FungibleKeeperAllMocks(t) + acc := sample.Bech32AccAddress() + + mockBankKeeper := testkeeper.GetFungibleBankMock(t, k) + + mockBankKeeper.On( + "MintCoins", + ctx, + types.ModuleName, + coins42, + ).Return(nil) + + mockBankKeeper.On( + "SendCoinsFromModuleToAccount", + ctx, + types.ModuleName, + acc, + coins42, + ).Return(errors.New("error")) + + err := k.MintZetaToEVMAccount(ctx, acc, big.NewInt(42)) + require.Error(t, err) + + mockBankKeeper.AssertExpectations(t) + }) +}