mirror of
				https://github.com/0glabs/0g-chain.git
				synced 2025-11-04 12:47:48 +00:00 
			
		
		
		
	feat: Use x/precisebank for x/evm keeper (#1960)
Replace x/evmutil EvmBankKeeper usage for x/evm
This commit is contained in:
		
							parent
							
								
									9de9de671e
								
							
						
					
					
						commit
						d2d661276e
					
				@ -550,7 +550,6 @@ func NewApp(
 | 
			
		||||
		app.accountKeeper,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// TODO: Pass this to evmkeeper.NewKeeper() instead of evmutilKeeper
 | 
			
		||||
	app.precisebankKeeper = precisebankkeeper.NewKeeper(
 | 
			
		||||
		app.appCodec,
 | 
			
		||||
		keys[precisebanktypes.StoreKey],
 | 
			
		||||
@ -558,11 +557,13 @@ func NewApp(
 | 
			
		||||
		app.accountKeeper,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	evmBankKeeper := evmutilkeeper.NewEvmBankKeeper(app.evmutilKeeper, app.bankKeeper, app.accountKeeper)
 | 
			
		||||
	app.evmKeeper = evmkeeper.NewKeeper(
 | 
			
		||||
		appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey],
 | 
			
		||||
		govAuthAddr,
 | 
			
		||||
		app.accountKeeper, evmBankKeeper, app.stakingKeeper, app.feeMarketKeeper,
 | 
			
		||||
		app.accountKeeper,
 | 
			
		||||
		app.precisebankKeeper, // x/precisebank in place of x/bank
 | 
			
		||||
		app.stakingKeeper,
 | 
			
		||||
		app.feeMarketKeeper,
 | 
			
		||||
		nil, // precompiled contracts
 | 
			
		||||
		geth.NewEVM,
 | 
			
		||||
		options.EVMTrace,
 | 
			
		||||
 | 
			
		||||
@ -1,281 +0,0 @@
 | 
			
		||||
package keeper
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	errorsmod "cosmossdk.io/errors"
 | 
			
		||||
	sdkmath "cosmossdk.io/math"
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
 | 
			
		||||
	evmtypes "github.com/evmos/ethermint/x/evm/types"
 | 
			
		||||
 | 
			
		||||
	"github.com/kava-labs/kava/x/evmutil/types"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// EvmDenom is the gas denom used by the evm
 | 
			
		||||
	EvmDenom = "akava"
 | 
			
		||||
 | 
			
		||||
	// CosmosDenom is the gas denom used by the kava app
 | 
			
		||||
	CosmosDenom = "ukava"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ConversionMultiplier is the conversion multiplier between akava and ukava
 | 
			
		||||
var ConversionMultiplier = sdkmath.NewInt(1_000_000_000_000)
 | 
			
		||||
 | 
			
		||||
var _ evmtypes.BankKeeper = EvmBankKeeper{}
 | 
			
		||||
 | 
			
		||||
// EvmBankKeeper is a BankKeeper wrapper for the x/evm module to allow the use
 | 
			
		||||
// of the 18 decimal akava coin on the evm.
 | 
			
		||||
// x/evm consumes gas and send coins by minting and burning akava coins in its module
 | 
			
		||||
// account and then sending the funds to the target account.
 | 
			
		||||
// This keeper uses both the ukava coin and a separate akava balance to manage the
 | 
			
		||||
// extra precision needed by the evm.
 | 
			
		||||
type EvmBankKeeper struct {
 | 
			
		||||
	akavaKeeper Keeper
 | 
			
		||||
	bk          types.BankKeeper
 | 
			
		||||
	ak          types.AccountKeeper
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewEvmBankKeeper(akavaKeeper Keeper, bk types.BankKeeper, ak types.AccountKeeper) EvmBankKeeper {
 | 
			
		||||
	return EvmBankKeeper{
 | 
			
		||||
		akavaKeeper: akavaKeeper,
 | 
			
		||||
		bk:          bk,
 | 
			
		||||
		ak:          ak,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetBalance returns the total **spendable** balance of akava for a given account by address.
 | 
			
		||||
func (k EvmBankKeeper) GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin {
 | 
			
		||||
	if denom != EvmDenom {
 | 
			
		||||
		panic(fmt.Errorf("only evm denom %s is supported by EvmBankKeeper", EvmDenom))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	spendableCoins := k.bk.SpendableCoins(ctx, addr)
 | 
			
		||||
	ukava := spendableCoins.AmountOf(CosmosDenom)
 | 
			
		||||
	akava := k.akavaKeeper.GetBalance(ctx, addr)
 | 
			
		||||
	total := ukava.Mul(ConversionMultiplier).Add(akava)
 | 
			
		||||
	return sdk.NewCoin(EvmDenom, total)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SendCoins transfers akava coins from a AccAddress to an AccAddress.
 | 
			
		||||
func (k EvmBankKeeper) SendCoins(ctx sdk.Context, senderAddr sdk.AccAddress, recipientAddr sdk.AccAddress, amt sdk.Coins) error {
 | 
			
		||||
	// SendCoins method is not used by the evm module, but is required by the
 | 
			
		||||
	// evmtypes.BankKeeper interface. This must be updated if the evm module
 | 
			
		||||
	// is updated to use SendCoins.
 | 
			
		||||
	panic("not implemented")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SendCoinsFromModuleToAccount transfers akava coins from a ModuleAccount to an AccAddress.
 | 
			
		||||
// It will panic if the module account does not exist. An error is returned if the recipient
 | 
			
		||||
// address is black-listed or if sending the tokens fails.
 | 
			
		||||
func (k EvmBankKeeper) SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error {
 | 
			
		||||
	ukava, akava, err := SplitAkavaCoins(amt)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ukava.Amount.IsPositive() {
 | 
			
		||||
		if err := k.bk.SendCoinsFromModuleToAccount(ctx, senderModule, recipientAddr, sdk.NewCoins(ukava)); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	senderAddr := k.GetModuleAddress(senderModule)
 | 
			
		||||
	if err := k.ConvertOneUkavaToAkavaIfNeeded(ctx, senderAddr, akava); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := k.akavaKeeper.SendBalance(ctx, senderAddr, recipientAddr, akava); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return k.ConvertAkavaToUkava(ctx, recipientAddr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SendCoinsFromAccountToModule transfers akava coins from an AccAddress to a ModuleAccount.
 | 
			
		||||
// It will panic if the module account does not exist.
 | 
			
		||||
func (k EvmBankKeeper) SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error {
 | 
			
		||||
	ukava, akavaNeeded, err := SplitAkavaCoins(amt)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ukava.IsPositive() {
 | 
			
		||||
		if err := k.bk.SendCoinsFromAccountToModule(ctx, senderAddr, recipientModule, sdk.NewCoins(ukava)); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := k.ConvertOneUkavaToAkavaIfNeeded(ctx, senderAddr, akavaNeeded); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	recipientAddr := k.GetModuleAddress(recipientModule)
 | 
			
		||||
	if err := k.akavaKeeper.SendBalance(ctx, senderAddr, recipientAddr, akavaNeeded); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return k.ConvertAkavaToUkava(ctx, recipientAddr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MintCoins mints akava coins by minting the equivalent ukava coins and any remaining akava coins.
 | 
			
		||||
// It will panic if the module account does not exist or is unauthorized.
 | 
			
		||||
func (k EvmBankKeeper) MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error {
 | 
			
		||||
	ukava, akava, err := SplitAkavaCoins(amt)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ukava.IsPositive() {
 | 
			
		||||
		if err := k.bk.MintCoins(ctx, moduleName, sdk.NewCoins(ukava)); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	recipientAddr := k.GetModuleAddress(moduleName)
 | 
			
		||||
	if err := k.akavaKeeper.AddBalance(ctx, recipientAddr, akava); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return k.ConvertAkavaToUkava(ctx, recipientAddr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BurnCoins burns akava coins by burning the equivalent ukava coins and any remaining akava coins.
 | 
			
		||||
// It will panic if the module account does not exist or is unauthorized.
 | 
			
		||||
func (k EvmBankKeeper) BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error {
 | 
			
		||||
	ukava, akava, err := SplitAkavaCoins(amt)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ukava.IsPositive() {
 | 
			
		||||
		if err := k.bk.BurnCoins(ctx, moduleName, sdk.NewCoins(ukava)); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	moduleAddr := k.GetModuleAddress(moduleName)
 | 
			
		||||
	if err := k.ConvertOneUkavaToAkavaIfNeeded(ctx, moduleAddr, akava); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return k.akavaKeeper.RemoveBalance(ctx, moduleAddr, akava)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsSendEnabledCoins checks the coins provided and returns an ErrSendDisabled
 | 
			
		||||
// if any of the coins are not configured for sending. Returns nil if sending is
 | 
			
		||||
// enabled for all provided coins.
 | 
			
		||||
func (k EvmBankKeeper) IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error {
 | 
			
		||||
	// IsSendEnabledCoins method is not used by the evm module, but is required by the
 | 
			
		||||
	// evmtypes.BankKeeper interface. This must be updated if the evm module
 | 
			
		||||
	// is updated to use IsSendEnabledCoins.
 | 
			
		||||
	panic("not implemented")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ConvertOneUkavaToAkavaIfNeeded converts 1 ukava to akava for an address if
 | 
			
		||||
// its akava balance is smaller than the akavaNeeded amount.
 | 
			
		||||
func (k EvmBankKeeper) ConvertOneUkavaToAkavaIfNeeded(ctx sdk.Context, addr sdk.AccAddress, akavaNeeded sdkmath.Int) error {
 | 
			
		||||
	akavaBal := k.akavaKeeper.GetBalance(ctx, addr)
 | 
			
		||||
	if akavaBal.GTE(akavaNeeded) {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ukavaToStore := sdk.NewCoins(sdk.NewCoin(CosmosDenom, sdk.OneInt()))
 | 
			
		||||
	if err := k.bk.SendCoinsFromAccountToModule(ctx, addr, types.ModuleName, ukavaToStore); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// add 1ukava equivalent of akava to addr
 | 
			
		||||
	akavaToReceive := ConversionMultiplier
 | 
			
		||||
	if err := k.akavaKeeper.AddBalance(ctx, addr, akavaToReceive); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ConvertAkavaToUkava converts all available akava to ukava for a given AccAddress.
 | 
			
		||||
func (k EvmBankKeeper) ConvertAkavaToUkava(ctx sdk.Context, addr sdk.AccAddress) error {
 | 
			
		||||
	totalAkava := k.akavaKeeper.GetBalance(ctx, addr)
 | 
			
		||||
	ukava, _, err := SplitAkavaCoins(sdk.NewCoins(sdk.NewCoin(EvmDenom, totalAkava)))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// do nothing if account does not have enough akava for a single ukava
 | 
			
		||||
	ukavaToReceive := ukava.Amount
 | 
			
		||||
	if !ukavaToReceive.IsPositive() {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// remove akava used for converting to ukava
 | 
			
		||||
	akavaToBurn := ukavaToReceive.Mul(ConversionMultiplier)
 | 
			
		||||
	finalBal := totalAkava.Sub(akavaToBurn)
 | 
			
		||||
	if err := k.akavaKeeper.SetBalance(ctx, addr, finalBal); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fromAddr := k.GetModuleAddress(types.ModuleName)
 | 
			
		||||
	if err := k.bk.SendCoins(ctx, fromAddr, addr, sdk.NewCoins(ukava)); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (k EvmBankKeeper) GetModuleAddress(moduleName string) sdk.AccAddress {
 | 
			
		||||
	addr := k.ak.GetModuleAddress(moduleName)
 | 
			
		||||
	if addr == nil {
 | 
			
		||||
		panic(errorsmod.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", moduleName))
 | 
			
		||||
	}
 | 
			
		||||
	return addr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SplitAkavaCoins splits akava coins to the equivalent ukava coins and any remaining akava balance.
 | 
			
		||||
// An error will be returned if the coins are not valid or if the coins are not the akava denom.
 | 
			
		||||
func SplitAkavaCoins(coins sdk.Coins) (sdk.Coin, sdkmath.Int, error) {
 | 
			
		||||
	akava := sdk.ZeroInt()
 | 
			
		||||
	ukava := sdk.NewCoin(CosmosDenom, sdk.ZeroInt())
 | 
			
		||||
 | 
			
		||||
	if len(coins) == 0 {
 | 
			
		||||
		return ukava, akava, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := ValidateEvmCoins(coins); err != nil {
 | 
			
		||||
		return ukava, akava, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// note: we should always have len(coins) == 1 here since coins cannot have dup denoms after we validate.
 | 
			
		||||
	coin := coins[0]
 | 
			
		||||
	remainingBalance := coin.Amount.Mod(ConversionMultiplier)
 | 
			
		||||
	if remainingBalance.IsPositive() {
 | 
			
		||||
		akava = remainingBalance
 | 
			
		||||
	}
 | 
			
		||||
	ukavaAmount := coin.Amount.Quo(ConversionMultiplier)
 | 
			
		||||
	if ukavaAmount.IsPositive() {
 | 
			
		||||
		ukava = sdk.NewCoin(CosmosDenom, ukavaAmount)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ukava, akava, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ValidateEvmCoins validates the coins from evm is valid and is the EvmDenom (akava).
 | 
			
		||||
func ValidateEvmCoins(coins sdk.Coins) error {
 | 
			
		||||
	if len(coins) == 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// validate that coins are non-negative, sorted, and no dup denoms
 | 
			
		||||
	if err := coins.Validate(); err != nil {
 | 
			
		||||
		return errorsmod.Wrap(sdkerrors.ErrInvalidCoins, coins.String())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// validate that coin denom is akava
 | 
			
		||||
	if len(coins) != 1 || coins[0].Denom != EvmDenom {
 | 
			
		||||
		errMsg := fmt.Sprintf("invalid evm coin denom, only %s is supported", EvmDenom)
 | 
			
		||||
		return errorsmod.Wrap(sdkerrors.ErrInvalidCoins, errMsg)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
@ -1,798 +0,0 @@
 | 
			
		||||
package keeper_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	sdkmath "cosmossdk.io/math"
 | 
			
		||||
	tmtime "github.com/cometbft/cometbft/types/time"
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
	"github.com/stretchr/testify/suite"
 | 
			
		||||
 | 
			
		||||
	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
 | 
			
		||||
	vesting "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
 | 
			
		||||
	evmtypes "github.com/evmos/ethermint/x/evm/types"
 | 
			
		||||
 | 
			
		||||
	"github.com/kava-labs/kava/x/evmutil/keeper"
 | 
			
		||||
	"github.com/kava-labs/kava/x/evmutil/testutil"
 | 
			
		||||
	"github.com/kava-labs/kava/x/evmutil/types"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type evmBankKeeperTestSuite struct {
 | 
			
		||||
	testutil.Suite
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (suite *evmBankKeeperTestSuite) SetupTest() {
 | 
			
		||||
	suite.Suite.SetupTest()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (suite *evmBankKeeperTestSuite) TestGetBalance_ReturnsSpendable() {
 | 
			
		||||
	startingCoins := sdk.NewCoins(sdk.NewInt64Coin("ukava", 10))
 | 
			
		||||
	startingAkava := sdkmath.NewInt(100)
 | 
			
		||||
 | 
			
		||||
	now := tmtime.Now()
 | 
			
		||||
	endTime := now.Add(24 * time.Hour)
 | 
			
		||||
	bacc := authtypes.NewBaseAccountWithAddress(suite.Addrs[0])
 | 
			
		||||
	vacc := vesting.NewContinuousVestingAccount(bacc, startingCoins, now.Unix(), endTime.Unix())
 | 
			
		||||
	suite.AccountKeeper.SetAccount(suite.Ctx, vacc)
 | 
			
		||||
 | 
			
		||||
	err := suite.App.FundAccount(suite.Ctx, suite.Addrs[0], startingCoins)
 | 
			
		||||
	suite.Require().NoError(err)
 | 
			
		||||
	err = suite.Keeper.SetBalance(suite.Ctx, suite.Addrs[0], startingAkava)
 | 
			
		||||
	suite.Require().NoError(err)
 | 
			
		||||
 | 
			
		||||
	coin := suite.EvmBankKeeper.GetBalance(suite.Ctx, suite.Addrs[0], "akava")
 | 
			
		||||
	suite.Require().Equal(startingAkava, coin.Amount)
 | 
			
		||||
 | 
			
		||||
	ctx := suite.Ctx.WithBlockTime(now.Add(12 * time.Hour))
 | 
			
		||||
	coin = suite.EvmBankKeeper.GetBalance(ctx, suite.Addrs[0], "akava")
 | 
			
		||||
	suite.Require().Equal(sdkmath.NewIntFromUint64(5_000_000_000_100), coin.Amount)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (suite *evmBankKeeperTestSuite) TestGetBalance_NotEvmDenom() {
 | 
			
		||||
	suite.Require().Panics(func() {
 | 
			
		||||
		suite.EvmBankKeeper.GetBalance(suite.Ctx, suite.Addrs[0], "ukava")
 | 
			
		||||
	})
 | 
			
		||||
	suite.Require().Panics(func() {
 | 
			
		||||
		suite.EvmBankKeeper.GetBalance(suite.Ctx, suite.Addrs[0], "busd")
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (suite *evmBankKeeperTestSuite) TestGetBalance() {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name           string
 | 
			
		||||
		startingAmount sdk.Coins
 | 
			
		||||
		expAmount      sdkmath.Int
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			"ukava with akava",
 | 
			
		||||
			sdk.NewCoins(
 | 
			
		||||
				sdk.NewInt64Coin("akava", 100),
 | 
			
		||||
				sdk.NewInt64Coin("ukava", 10),
 | 
			
		||||
			),
 | 
			
		||||
			sdkmath.NewInt(10_000_000_000_100),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"just akava",
 | 
			
		||||
			sdk.NewCoins(
 | 
			
		||||
				sdk.NewInt64Coin("akava", 100),
 | 
			
		||||
				sdk.NewInt64Coin("busd", 100),
 | 
			
		||||
			),
 | 
			
		||||
			sdkmath.NewInt(100),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"just ukava",
 | 
			
		||||
			sdk.NewCoins(
 | 
			
		||||
				sdk.NewInt64Coin("ukava", 10),
 | 
			
		||||
				sdk.NewInt64Coin("busd", 100),
 | 
			
		||||
			),
 | 
			
		||||
			sdkmath.NewInt(10_000_000_000_000),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"no ukava or akava",
 | 
			
		||||
			sdk.NewCoins(),
 | 
			
		||||
			sdk.ZeroInt(),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"with avaka that is more than 1 ukava",
 | 
			
		||||
			sdk.NewCoins(
 | 
			
		||||
				sdk.NewInt64Coin("akava", 20_000_000_000_220),
 | 
			
		||||
				sdk.NewInt64Coin("ukava", 11),
 | 
			
		||||
			),
 | 
			
		||||
			sdkmath.NewInt(31_000_000_000_220),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		suite.Run(tt.name, func() {
 | 
			
		||||
			suite.SetupTest()
 | 
			
		||||
 | 
			
		||||
			suite.FundAccountWithKava(suite.Addrs[0], tt.startingAmount)
 | 
			
		||||
			coin := suite.EvmBankKeeper.GetBalance(suite.Ctx, suite.Addrs[0], "akava")
 | 
			
		||||
			suite.Require().Equal(tt.expAmount, coin.Amount)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (suite *evmBankKeeperTestSuite) TestSendCoinsFromModuleToAccount() {
 | 
			
		||||
	startingModuleCoins := sdk.NewCoins(
 | 
			
		||||
		sdk.NewInt64Coin("akava", 200),
 | 
			
		||||
		sdk.NewInt64Coin("ukava", 100),
 | 
			
		||||
	)
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name           string
 | 
			
		||||
		sendCoins      sdk.Coins
 | 
			
		||||
		startingAccBal sdk.Coins
 | 
			
		||||
		expAccBal      sdk.Coins
 | 
			
		||||
		hasErr         bool
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			"send more than 1 ukava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 12_000_000_000_010)),
 | 
			
		||||
			sdk.Coins{},
 | 
			
		||||
			sdk.NewCoins(
 | 
			
		||||
				sdk.NewInt64Coin("akava", 10),
 | 
			
		||||
				sdk.NewInt64Coin("ukava", 12),
 | 
			
		||||
			),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"send less than 1 ukava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 122)),
 | 
			
		||||
			sdk.Coins{},
 | 
			
		||||
			sdk.NewCoins(
 | 
			
		||||
				sdk.NewInt64Coin("akava", 122),
 | 
			
		||||
				sdk.NewInt64Coin("ukava", 0),
 | 
			
		||||
			),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"send an exact amount of ukava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 98_000_000_000_000)),
 | 
			
		||||
			sdk.Coins{},
 | 
			
		||||
			sdk.NewCoins(
 | 
			
		||||
				sdk.NewInt64Coin("akava", 0o0),
 | 
			
		||||
				sdk.NewInt64Coin("ukava", 98),
 | 
			
		||||
			),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"send no akava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 0)),
 | 
			
		||||
			sdk.Coins{},
 | 
			
		||||
			sdk.NewCoins(
 | 
			
		||||
				sdk.NewInt64Coin("akava", 0),
 | 
			
		||||
				sdk.NewInt64Coin("ukava", 0),
 | 
			
		||||
			),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"errors if sending other coins",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 500), sdk.NewInt64Coin("busd", 1000)),
 | 
			
		||||
			sdk.Coins{},
 | 
			
		||||
			sdk.Coins{},
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"errors if not enough total akava to cover",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 100_000_000_001_000)),
 | 
			
		||||
			sdk.Coins{},
 | 
			
		||||
			sdk.Coins{},
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"errors if not enough ukava to cover",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 200_000_000_000_000)),
 | 
			
		||||
			sdk.Coins{},
 | 
			
		||||
			sdk.Coins{},
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"converts receiver's akava to ukava if there's enough akava after the transfer",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 99_000_000_000_200)),
 | 
			
		||||
			sdk.NewCoins(
 | 
			
		||||
				sdk.NewInt64Coin("akava", 999_999_999_900),
 | 
			
		||||
				sdk.NewInt64Coin("ukava", 1),
 | 
			
		||||
			),
 | 
			
		||||
			sdk.NewCoins(
 | 
			
		||||
				sdk.NewInt64Coin("akava", 100),
 | 
			
		||||
				sdk.NewInt64Coin("ukava", 101),
 | 
			
		||||
			),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"converts all of receiver's akava to ukava even if somehow receiver has more than 1ukava of akava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 12_000_000_000_100)),
 | 
			
		||||
			sdk.NewCoins(
 | 
			
		||||
				sdk.NewInt64Coin("akava", 5_999_999_999_990),
 | 
			
		||||
				sdk.NewInt64Coin("ukava", 1),
 | 
			
		||||
			),
 | 
			
		||||
			sdk.NewCoins(
 | 
			
		||||
				sdk.NewInt64Coin("akava", 90),
 | 
			
		||||
				sdk.NewInt64Coin("ukava", 19),
 | 
			
		||||
			),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"swap 1 ukava for akava if module account doesn't have enough akava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 99_000_000_001_000)),
 | 
			
		||||
			sdk.NewCoins(
 | 
			
		||||
				sdk.NewInt64Coin("akava", 200),
 | 
			
		||||
				sdk.NewInt64Coin("ukava", 1),
 | 
			
		||||
			),
 | 
			
		||||
			sdk.NewCoins(
 | 
			
		||||
				sdk.NewInt64Coin("akava", 1200),
 | 
			
		||||
				sdk.NewInt64Coin("ukava", 100),
 | 
			
		||||
			),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		suite.Run(tt.name, func() {
 | 
			
		||||
			suite.SetupTest()
 | 
			
		||||
 | 
			
		||||
			suite.FundAccountWithKava(suite.Addrs[0], tt.startingAccBal)
 | 
			
		||||
			suite.FundModuleAccountWithKava(evmtypes.ModuleName, startingModuleCoins)
 | 
			
		||||
 | 
			
		||||
			// fund our module with some ukava to account for converting extra akava back to ukava
 | 
			
		||||
			suite.FundModuleAccountWithKava(types.ModuleName, sdk.NewCoins(sdk.NewInt64Coin("ukava", 10)))
 | 
			
		||||
 | 
			
		||||
			err := suite.EvmBankKeeper.SendCoinsFromModuleToAccount(suite.Ctx, evmtypes.ModuleName, suite.Addrs[0], tt.sendCoins)
 | 
			
		||||
			if tt.hasErr {
 | 
			
		||||
				suite.Require().Error(err)
 | 
			
		||||
				return
 | 
			
		||||
			} else {
 | 
			
		||||
				suite.Require().NoError(err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// check ukava
 | 
			
		||||
			ukavaSender := suite.BankKeeper.GetBalance(suite.Ctx, suite.Addrs[0], "ukava")
 | 
			
		||||
			suite.Require().Equal(tt.expAccBal.AmountOf("ukava").Int64(), ukavaSender.Amount.Int64())
 | 
			
		||||
 | 
			
		||||
			// check akava
 | 
			
		||||
			actualAkava := suite.Keeper.GetBalance(suite.Ctx, suite.Addrs[0])
 | 
			
		||||
			suite.Require().Equal(tt.expAccBal.AmountOf("akava").Int64(), actualAkava.Int64())
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (suite *evmBankKeeperTestSuite) TestSendCoinsFromAccountToModule() {
 | 
			
		||||
	startingAccCoins := sdk.NewCoins(
 | 
			
		||||
		sdk.NewInt64Coin("akava", 200),
 | 
			
		||||
		sdk.NewInt64Coin("ukava", 100),
 | 
			
		||||
	)
 | 
			
		||||
	startingModuleCoins := sdk.NewCoins(
 | 
			
		||||
		sdk.NewInt64Coin("akava", 100_000_000_000),
 | 
			
		||||
	)
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name           string
 | 
			
		||||
		sendCoins      sdk.Coins
 | 
			
		||||
		expSenderCoins sdk.Coins
 | 
			
		||||
		expModuleCoins sdk.Coins
 | 
			
		||||
		hasErr         bool
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			"send more than 1 ukava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 12_000_000_000_010)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 190), sdk.NewInt64Coin("ukava", 88)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 100_000_000_010), sdk.NewInt64Coin("ukava", 12)),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"send less than 1 ukava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 122)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 78), sdk.NewInt64Coin("ukava", 100)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 100_000_000_122), sdk.NewInt64Coin("ukava", 0)),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"send an exact amount of ukava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 98_000_000_000_000)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 200), sdk.NewInt64Coin("ukava", 2)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 100_000_000_000), sdk.NewInt64Coin("ukava", 98)),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"send no akava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 0)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 200), sdk.NewInt64Coin("ukava", 100)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 100_000_000_000), sdk.NewInt64Coin("ukava", 0)),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"errors if sending other coins",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 500), sdk.NewInt64Coin("busd", 1000)),
 | 
			
		||||
			sdk.Coins{},
 | 
			
		||||
			sdk.Coins{},
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"errors if have dup coins",
 | 
			
		||||
			sdk.Coins{
 | 
			
		||||
				sdk.NewInt64Coin("akava", 12_000_000_000_000),
 | 
			
		||||
				sdk.NewInt64Coin("akava", 2_000_000_000_000),
 | 
			
		||||
			},
 | 
			
		||||
			sdk.Coins{},
 | 
			
		||||
			sdk.Coins{},
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"errors if not enough total akava to cover",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 100_000_000_001_000)),
 | 
			
		||||
			sdk.Coins{},
 | 
			
		||||
			sdk.Coins{},
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"errors if not enough ukava to cover",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 200_000_000_000_000)),
 | 
			
		||||
			sdk.Coins{},
 | 
			
		||||
			sdk.Coins{},
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"converts 1 ukava to akava if not enough akava to cover",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 99_001_000_000_000)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 999_000_000_200), sdk.NewInt64Coin("ukava", 0)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 101_000_000_000), sdk.NewInt64Coin("ukava", 99)),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"converts receiver's akava to ukava if there's enough akava after the transfer",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 5_900_000_000_200)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 100_000_000_000), sdk.NewInt64Coin("ukava", 94)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 200), sdk.NewInt64Coin("ukava", 6)),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		suite.Run(tt.name, func() {
 | 
			
		||||
			suite.SetupTest()
 | 
			
		||||
			suite.FundAccountWithKava(suite.Addrs[0], startingAccCoins)
 | 
			
		||||
			suite.FundModuleAccountWithKava(evmtypes.ModuleName, startingModuleCoins)
 | 
			
		||||
 | 
			
		||||
			err := suite.EvmBankKeeper.SendCoinsFromAccountToModule(suite.Ctx, suite.Addrs[0], evmtypes.ModuleName, tt.sendCoins)
 | 
			
		||||
			if tt.hasErr {
 | 
			
		||||
				suite.Require().Error(err)
 | 
			
		||||
				return
 | 
			
		||||
			} else {
 | 
			
		||||
				suite.Require().NoError(err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// check sender balance
 | 
			
		||||
			ukavaSender := suite.BankKeeper.GetBalance(suite.Ctx, suite.Addrs[0], "ukava")
 | 
			
		||||
			suite.Require().Equal(tt.expSenderCoins.AmountOf("ukava").Int64(), ukavaSender.Amount.Int64())
 | 
			
		||||
			actualAkava := suite.Keeper.GetBalance(suite.Ctx, suite.Addrs[0])
 | 
			
		||||
			suite.Require().Equal(tt.expSenderCoins.AmountOf("akava").Int64(), actualAkava.Int64())
 | 
			
		||||
 | 
			
		||||
			// check module balance
 | 
			
		||||
			moduleAddr := suite.AccountKeeper.GetModuleAddress(evmtypes.ModuleName)
 | 
			
		||||
			ukavaSender = suite.BankKeeper.GetBalance(suite.Ctx, moduleAddr, "ukava")
 | 
			
		||||
			suite.Require().Equal(tt.expModuleCoins.AmountOf("ukava").Int64(), ukavaSender.Amount.Int64())
 | 
			
		||||
			actualAkava = suite.Keeper.GetBalance(suite.Ctx, moduleAddr)
 | 
			
		||||
			suite.Require().Equal(tt.expModuleCoins.AmountOf("akava").Int64(), actualAkava.Int64())
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (suite *evmBankKeeperTestSuite) TestBurnCoins() {
 | 
			
		||||
	startingUkava := sdkmath.NewInt(100)
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name       string
 | 
			
		||||
		burnCoins  sdk.Coins
 | 
			
		||||
		expUkava   sdkmath.Int
 | 
			
		||||
		expAkava   sdkmath.Int
 | 
			
		||||
		hasErr     bool
 | 
			
		||||
		akavaStart sdkmath.Int
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			"burn more than 1 ukava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 12_021_000_000_002)),
 | 
			
		||||
			sdkmath.NewInt(88),
 | 
			
		||||
			sdkmath.NewInt(100_000_000_000),
 | 
			
		||||
			false,
 | 
			
		||||
			sdkmath.NewInt(121_000_000_002),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"burn less than 1 ukava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 122)),
 | 
			
		||||
			sdkmath.NewInt(100),
 | 
			
		||||
			sdkmath.NewInt(878),
 | 
			
		||||
			false,
 | 
			
		||||
			sdkmath.NewInt(1000),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"burn an exact amount of ukava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 98_000_000_000_000)),
 | 
			
		||||
			sdkmath.NewInt(2),
 | 
			
		||||
			sdkmath.NewInt(10),
 | 
			
		||||
			false,
 | 
			
		||||
			sdkmath.NewInt(10),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"burn no akava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 0)),
 | 
			
		||||
			startingUkava,
 | 
			
		||||
			sdk.ZeroInt(),
 | 
			
		||||
			false,
 | 
			
		||||
			sdk.ZeroInt(),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"errors if burning other coins",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 500), sdk.NewInt64Coin("busd", 1000)),
 | 
			
		||||
			startingUkava,
 | 
			
		||||
			sdkmath.NewInt(100),
 | 
			
		||||
			true,
 | 
			
		||||
			sdkmath.NewInt(100),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"errors if have dup coins",
 | 
			
		||||
			sdk.Coins{
 | 
			
		||||
				sdk.NewInt64Coin("akava", 12_000_000_000_000),
 | 
			
		||||
				sdk.NewInt64Coin("akava", 2_000_000_000_000),
 | 
			
		||||
			},
 | 
			
		||||
			startingUkava,
 | 
			
		||||
			sdk.ZeroInt(),
 | 
			
		||||
			true,
 | 
			
		||||
			sdk.ZeroInt(),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"errors if burn amount is negative",
 | 
			
		||||
			sdk.Coins{sdk.Coin{Denom: "akava", Amount: sdkmath.NewInt(-100)}},
 | 
			
		||||
			startingUkava,
 | 
			
		||||
			sdkmath.NewInt(50),
 | 
			
		||||
			true,
 | 
			
		||||
			sdkmath.NewInt(50),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"errors if not enough akava to cover burn",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 100_999_000_000_000)),
 | 
			
		||||
			sdkmath.NewInt(0),
 | 
			
		||||
			sdkmath.NewInt(99_000_000_000),
 | 
			
		||||
			true,
 | 
			
		||||
			sdkmath.NewInt(99_000_000_000),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"errors if not enough ukava to cover burn",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 200_000_000_000_000)),
 | 
			
		||||
			sdkmath.NewInt(100),
 | 
			
		||||
			sdk.ZeroInt(),
 | 
			
		||||
			true,
 | 
			
		||||
			sdk.ZeroInt(),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"converts 1 ukava to akava if not enough akava to cover",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 12_021_000_000_002)),
 | 
			
		||||
			sdkmath.NewInt(87),
 | 
			
		||||
			sdkmath.NewInt(980_000_000_000),
 | 
			
		||||
			false,
 | 
			
		||||
			sdkmath.NewInt(1_000_000_002),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		suite.Run(tt.name, func() {
 | 
			
		||||
			suite.SetupTest()
 | 
			
		||||
			startingCoins := sdk.NewCoins(
 | 
			
		||||
				sdk.NewCoin("ukava", startingUkava),
 | 
			
		||||
				sdk.NewCoin("akava", tt.akavaStart),
 | 
			
		||||
			)
 | 
			
		||||
			suite.FundModuleAccountWithKava(evmtypes.ModuleName, startingCoins)
 | 
			
		||||
 | 
			
		||||
			err := suite.EvmBankKeeper.BurnCoins(suite.Ctx, evmtypes.ModuleName, tt.burnCoins)
 | 
			
		||||
			if tt.hasErr {
 | 
			
		||||
				suite.Require().Error(err)
 | 
			
		||||
				return
 | 
			
		||||
			} else {
 | 
			
		||||
				suite.Require().NoError(err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// check ukava
 | 
			
		||||
			ukavaActual := suite.BankKeeper.GetBalance(suite.Ctx, suite.EvmModuleAddr, "ukava")
 | 
			
		||||
			suite.Require().Equal(tt.expUkava, ukavaActual.Amount)
 | 
			
		||||
 | 
			
		||||
			// check akava
 | 
			
		||||
			akavaActual := suite.Keeper.GetBalance(suite.Ctx, suite.EvmModuleAddr)
 | 
			
		||||
			suite.Require().Equal(tt.expAkava, akavaActual)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (suite *evmBankKeeperTestSuite) TestMintCoins() {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name       string
 | 
			
		||||
		mintCoins  sdk.Coins
 | 
			
		||||
		ukava      sdkmath.Int
 | 
			
		||||
		akava      sdkmath.Int
 | 
			
		||||
		hasErr     bool
 | 
			
		||||
		akavaStart sdkmath.Int
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			"mint more than 1 ukava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 12_021_000_000_002)),
 | 
			
		||||
			sdkmath.NewInt(12),
 | 
			
		||||
			sdkmath.NewInt(21_000_000_002),
 | 
			
		||||
			false,
 | 
			
		||||
			sdk.ZeroInt(),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"mint less than 1 ukava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 901_000_000_001)),
 | 
			
		||||
			sdk.ZeroInt(),
 | 
			
		||||
			sdkmath.NewInt(901_000_000_001),
 | 
			
		||||
			false,
 | 
			
		||||
			sdk.ZeroInt(),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"mint an exact amount of ukava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 123_000_000_000_000_000)),
 | 
			
		||||
			sdkmath.NewInt(123_000),
 | 
			
		||||
			sdk.ZeroInt(),
 | 
			
		||||
			false,
 | 
			
		||||
			sdk.ZeroInt(),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"mint no akava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 0)),
 | 
			
		||||
			sdk.ZeroInt(),
 | 
			
		||||
			sdk.ZeroInt(),
 | 
			
		||||
			false,
 | 
			
		||||
			sdk.ZeroInt(),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"errors if minting other coins",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 500), sdk.NewInt64Coin("busd", 1000)),
 | 
			
		||||
			sdk.ZeroInt(),
 | 
			
		||||
			sdkmath.NewInt(100),
 | 
			
		||||
			true,
 | 
			
		||||
			sdkmath.NewInt(100),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"errors if have dup coins",
 | 
			
		||||
			sdk.Coins{
 | 
			
		||||
				sdk.NewInt64Coin("akava", 12_000_000_000_000),
 | 
			
		||||
				sdk.NewInt64Coin("akava", 2_000_000_000_000),
 | 
			
		||||
			},
 | 
			
		||||
			sdk.ZeroInt(),
 | 
			
		||||
			sdk.ZeroInt(),
 | 
			
		||||
			true,
 | 
			
		||||
			sdk.ZeroInt(),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"errors if mint amount is negative",
 | 
			
		||||
			sdk.Coins{sdk.Coin{Denom: "akava", Amount: sdkmath.NewInt(-100)}},
 | 
			
		||||
			sdk.ZeroInt(),
 | 
			
		||||
			sdkmath.NewInt(50),
 | 
			
		||||
			true,
 | 
			
		||||
			sdkmath.NewInt(50),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"adds to existing akava balance",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 12_021_000_000_002)),
 | 
			
		||||
			sdkmath.NewInt(12),
 | 
			
		||||
			sdkmath.NewInt(21_000_000_102),
 | 
			
		||||
			false,
 | 
			
		||||
			sdkmath.NewInt(100),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"convert akava balance to ukava if it exceeds 1 ukava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 10_999_000_000_000)),
 | 
			
		||||
			sdkmath.NewInt(12),
 | 
			
		||||
			sdkmath.NewInt(1_200_000_001),
 | 
			
		||||
			false,
 | 
			
		||||
			sdkmath.NewInt(1_002_200_000_001),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		suite.Run(tt.name, func() {
 | 
			
		||||
			suite.SetupTest()
 | 
			
		||||
			suite.FundModuleAccountWithKava(types.ModuleName, sdk.NewCoins(sdk.NewInt64Coin("ukava", 10)))
 | 
			
		||||
			suite.FundModuleAccountWithKava(evmtypes.ModuleName, sdk.NewCoins(sdk.NewCoin("akava", tt.akavaStart)))
 | 
			
		||||
 | 
			
		||||
			err := suite.EvmBankKeeper.MintCoins(suite.Ctx, evmtypes.ModuleName, tt.mintCoins)
 | 
			
		||||
			if tt.hasErr {
 | 
			
		||||
				suite.Require().Error(err)
 | 
			
		||||
				return
 | 
			
		||||
			} else {
 | 
			
		||||
				suite.Require().NoError(err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// check ukava
 | 
			
		||||
			ukavaActual := suite.BankKeeper.GetBalance(suite.Ctx, suite.EvmModuleAddr, "ukava")
 | 
			
		||||
			suite.Require().Equal(tt.ukava, ukavaActual.Amount)
 | 
			
		||||
 | 
			
		||||
			// check akava
 | 
			
		||||
			akavaActual := suite.Keeper.GetBalance(suite.Ctx, suite.EvmModuleAddr)
 | 
			
		||||
			suite.Require().Equal(tt.akava, akavaActual)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (suite *evmBankKeeperTestSuite) TestValidateEvmCoins() {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name      string
 | 
			
		||||
		coins     sdk.Coins
 | 
			
		||||
		shouldErr bool
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			"valid coins",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 500)),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"dup coins",
 | 
			
		||||
			sdk.Coins{sdk.NewInt64Coin("akava", 500), sdk.NewInt64Coin("akava", 500)},
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"not evm coins",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("ukava", 500)),
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"negative coins",
 | 
			
		||||
			sdk.Coins{sdk.Coin{Denom: "akava", Amount: sdkmath.NewInt(-500)}},
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		suite.Run(tt.name, func() {
 | 
			
		||||
			err := keeper.ValidateEvmCoins(tt.coins)
 | 
			
		||||
			if tt.shouldErr {
 | 
			
		||||
				suite.Require().Error(err)
 | 
			
		||||
			} else {
 | 
			
		||||
				suite.Require().NoError(err)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (suite *evmBankKeeperTestSuite) TestConvertOneUkavaToAkavaIfNeeded() {
 | 
			
		||||
	akavaNeeded := sdkmath.NewInt(200)
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name          string
 | 
			
		||||
		startingCoins sdk.Coins
 | 
			
		||||
		expectedCoins sdk.Coins
 | 
			
		||||
		success       bool
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			"not enough ukava for conversion",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 100)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 100)),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"converts 1 ukava to akava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("ukava", 10), sdk.NewInt64Coin("akava", 100)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("ukava", 9), sdk.NewInt64Coin("akava", 1_000_000_000_100)),
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"conversion not needed",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("ukava", 10), sdk.NewInt64Coin("akava", 200)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("ukava", 10), sdk.NewInt64Coin("akava", 200)),
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		suite.Run(tt.name, func() {
 | 
			
		||||
			suite.SetupTest()
 | 
			
		||||
 | 
			
		||||
			suite.FundAccountWithKava(suite.Addrs[0], tt.startingCoins)
 | 
			
		||||
			err := suite.EvmBankKeeper.ConvertOneUkavaToAkavaIfNeeded(suite.Ctx, suite.Addrs[0], akavaNeeded)
 | 
			
		||||
			moduleKava := suite.BankKeeper.GetBalance(suite.Ctx, suite.AccountKeeper.GetModuleAddress(types.ModuleName), "ukava")
 | 
			
		||||
			if tt.success {
 | 
			
		||||
				suite.Require().NoError(err)
 | 
			
		||||
				if tt.startingCoins.AmountOf("akava").LT(akavaNeeded) {
 | 
			
		||||
					suite.Require().Equal(sdk.OneInt(), moduleKava.Amount)
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				suite.Require().Error(err)
 | 
			
		||||
				suite.Require().Equal(sdk.ZeroInt(), moduleKava.Amount)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			akava := suite.Keeper.GetBalance(suite.Ctx, suite.Addrs[0])
 | 
			
		||||
			suite.Require().Equal(tt.expectedCoins.AmountOf("akava"), akava)
 | 
			
		||||
			ukava := suite.BankKeeper.GetBalance(suite.Ctx, suite.Addrs[0], "ukava")
 | 
			
		||||
			suite.Require().Equal(tt.expectedCoins.AmountOf("ukava"), ukava.Amount)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (suite *evmBankKeeperTestSuite) TestConvertAkavaToUkava() {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name          string
 | 
			
		||||
		startingCoins sdk.Coins
 | 
			
		||||
		expectedCoins sdk.Coins
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			"not enough ukava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 100)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 100), sdk.NewInt64Coin("ukava", 0)),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"converts akava for 1 ukava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("ukava", 10), sdk.NewInt64Coin("akava", 1_000_000_000_003)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("ukava", 11), sdk.NewInt64Coin("akava", 3)),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"converts more than 1 ukava of akava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("ukava", 10), sdk.NewInt64Coin("akava", 8_000_000_000_123)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("ukava", 18), sdk.NewInt64Coin("akava", 123)),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		suite.Run(tt.name, func() {
 | 
			
		||||
			suite.SetupTest()
 | 
			
		||||
 | 
			
		||||
			err := suite.App.FundModuleAccount(suite.Ctx, types.ModuleName, sdk.NewCoins(sdk.NewInt64Coin("ukava", 10)))
 | 
			
		||||
			suite.Require().NoError(err)
 | 
			
		||||
			suite.FundAccountWithKava(suite.Addrs[0], tt.startingCoins)
 | 
			
		||||
			err = suite.EvmBankKeeper.ConvertAkavaToUkava(suite.Ctx, suite.Addrs[0])
 | 
			
		||||
			suite.Require().NoError(err)
 | 
			
		||||
			akava := suite.Keeper.GetBalance(suite.Ctx, suite.Addrs[0])
 | 
			
		||||
			suite.Require().Equal(tt.expectedCoins.AmountOf("akava"), akava)
 | 
			
		||||
			ukava := suite.BankKeeper.GetBalance(suite.Ctx, suite.Addrs[0], "ukava")
 | 
			
		||||
			suite.Require().Equal(tt.expectedCoins.AmountOf("ukava"), ukava.Amount)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (suite *evmBankKeeperTestSuite) TestSplitAkavaCoins() {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name          string
 | 
			
		||||
		coins         sdk.Coins
 | 
			
		||||
		expectedCoins sdk.Coins
 | 
			
		||||
		shouldErr     bool
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			"invalid coins",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("ukava", 500)),
 | 
			
		||||
			nil,
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"empty coins",
 | 
			
		||||
			sdk.NewCoins(),
 | 
			
		||||
			sdk.NewCoins(),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ukava & akava coins",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 8_000_000_000_123)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("ukava", 8), sdk.NewInt64Coin("akava", 123)),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"only akava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 10_123)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 10_123)),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"only ukava",
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("akava", 5_000_000_000_000)),
 | 
			
		||||
			sdk.NewCoins(sdk.NewInt64Coin("ukava", 5)),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		suite.Run(tt.name, func() {
 | 
			
		||||
			ukava, akava, err := keeper.SplitAkavaCoins(tt.coins)
 | 
			
		||||
			if tt.shouldErr {
 | 
			
		||||
				suite.Require().Error(err)
 | 
			
		||||
			} else {
 | 
			
		||||
				suite.Require().NoError(err)
 | 
			
		||||
				suite.Require().Equal(tt.expectedCoins.AmountOf("ukava"), ukava.Amount)
 | 
			
		||||
				suite.Require().Equal(tt.expectedCoins.AmountOf("akava"), akava)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestEvmBankKeeperTestSuite(t *testing.T) {
 | 
			
		||||
	suite.Run(t, new(evmBankKeeperTestSuite))
 | 
			
		||||
}
 | 
			
		||||
@ -11,8 +11,6 @@ import (
 | 
			
		||||
 | 
			
		||||
// RegisterInvariants registers the swap module invariants
 | 
			
		||||
func RegisterInvariants(ir sdk.InvariantRegistry, bankK types.BankKeeper, k Keeper) {
 | 
			
		||||
	ir.RegisterRoute(types.ModuleName, "fully-backed", FullyBackedInvariant(bankK, k))
 | 
			
		||||
	ir.RegisterRoute(types.ModuleName, "small-balances", SmallBalancesInvariant(bankK, k))
 | 
			
		||||
	ir.RegisterRoute(types.ModuleName, "cosmos-coins-fully-backed", CosmosCoinsFullyBackedInvariant(bankK, k))
 | 
			
		||||
	// Disable this invariant due to some issues with it requiring some staking params to be set in genesis.
 | 
			
		||||
	// ir.RegisterRoute(types.ModuleName, "backed-conversion-coins", BackedCoinsInvariant(bankK, k))
 | 
			
		||||
@ -21,57 +19,11 @@ func RegisterInvariants(ir sdk.InvariantRegistry, bankK types.BankKeeper, k Keep
 | 
			
		||||
// AllInvariants runs all invariants of the swap module
 | 
			
		||||
func AllInvariants(bankK types.BankKeeper, k Keeper) sdk.Invariant {
 | 
			
		||||
	return func(ctx sdk.Context) (string, bool) {
 | 
			
		||||
		if res, stop := FullyBackedInvariant(bankK, k)(ctx); stop {
 | 
			
		||||
			return res, stop
 | 
			
		||||
		}
 | 
			
		||||
		if res, stop := BackedCoinsInvariant(bankK, k)(ctx); stop {
 | 
			
		||||
			return res, stop
 | 
			
		||||
		}
 | 
			
		||||
		if res, stop := CosmosCoinsFullyBackedInvariant(bankK, k)(ctx); stop {
 | 
			
		||||
			return res, stop
 | 
			
		||||
		}
 | 
			
		||||
		return SmallBalancesInvariant(bankK, k)(ctx)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FullyBackedInvariant ensures all minor balances are backed by the coins in the module account.
 | 
			
		||||
//
 | 
			
		||||
// The module balance can be greater than the sum of all minor balances. This can happen in rare cases
 | 
			
		||||
// where the evm module burns tokens.
 | 
			
		||||
func FullyBackedInvariant(bankK types.BankKeeper, k Keeper) sdk.Invariant {
 | 
			
		||||
	broken := false
 | 
			
		||||
	message := sdk.FormatInvariant(types.ModuleName, "fully backed broken", "sum of minor balances greater than module account")
 | 
			
		||||
 | 
			
		||||
	return func(ctx sdk.Context) (string, bool) {
 | 
			
		||||
		totalMinorBalances := sdk.ZeroInt()
 | 
			
		||||
		k.IterateAllAccounts(ctx, func(acc types.Account) bool {
 | 
			
		||||
			totalMinorBalances = totalMinorBalances.Add(acc.Balance)
 | 
			
		||||
			return false
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		bankAddr := authtypes.NewModuleAddress(types.ModuleName)
 | 
			
		||||
		bankBalance := bankK.GetBalance(ctx, bankAddr, CosmosDenom).Amount.Mul(ConversionMultiplier)
 | 
			
		||||
 | 
			
		||||
		broken = totalMinorBalances.GT(bankBalance)
 | 
			
		||||
 | 
			
		||||
		return message, broken
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SmallBalancesInvariant ensures all minor balances are less than the overflow amount, beyond this they should be converted to the major denom.
 | 
			
		||||
func SmallBalancesInvariant(_ types.BankKeeper, k Keeper) sdk.Invariant {
 | 
			
		||||
	broken := false
 | 
			
		||||
	message := sdk.FormatInvariant(types.ModuleName, "small balances broken", "minor balances not all less than overflow")
 | 
			
		||||
 | 
			
		||||
	return func(ctx sdk.Context) (string, bool) {
 | 
			
		||||
		k.IterateAllAccounts(ctx, func(account types.Account) bool {
 | 
			
		||||
			if account.Balance.GTE(ConversionMultiplier) {
 | 
			
		||||
				broken = true
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
			return false
 | 
			
		||||
		})
 | 
			
		||||
		return message, broken
 | 
			
		||||
		return CosmosCoinsFullyBackedInvariant(bankK, k)(ctx)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -43,7 +43,7 @@ func (suite *invariantTestSuite) SetupValidState() {
 | 
			
		||||
	for i := 0; i < 4; i++ {
 | 
			
		||||
		suite.Keeper.SetAccount(suite.Ctx, *types.NewAccount(
 | 
			
		||||
			suite.Addrs[i],
 | 
			
		||||
			keeper.ConversionMultiplier.QuoRaw(2),
 | 
			
		||||
			sdkmath.NewInt(10000000000),
 | 
			
		||||
		))
 | 
			
		||||
	}
 | 
			
		||||
	suite.FundModuleAccountWithKava(
 | 
			
		||||
@ -131,45 +131,6 @@ func (suite *invariantTestSuite) runInvariant(route string, invariant func(bankK
 | 
			
		||||
	return dMessage, dBroken
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (suite *invariantTestSuite) TestFullyBackedInvariant() {
 | 
			
		||||
	// default state is valid
 | 
			
		||||
	_, broken := suite.runInvariant("fully-backed", keeper.FullyBackedInvariant)
 | 
			
		||||
	suite.Equal(false, broken)
 | 
			
		||||
 | 
			
		||||
	suite.SetupValidState()
 | 
			
		||||
	_, broken = suite.runInvariant("fully-backed", keeper.FullyBackedInvariant)
 | 
			
		||||
	suite.Equal(false, broken)
 | 
			
		||||
 | 
			
		||||
	// break invariant by increasing total minor balances above module balance
 | 
			
		||||
	suite.Keeper.AddBalance(suite.Ctx, suite.Addrs[0], sdk.OneInt())
 | 
			
		||||
 | 
			
		||||
	message, broken := suite.runInvariant("fully-backed", keeper.FullyBackedInvariant)
 | 
			
		||||
	suite.Equal("evmutil: fully backed broken invariant\nsum of minor balances greater than module account\n", message)
 | 
			
		||||
	suite.Equal(true, broken)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (suite *invariantTestSuite) TestSmallBalances() {
 | 
			
		||||
	// default state is valid
 | 
			
		||||
	_, broken := suite.runInvariant("small-balances", keeper.SmallBalancesInvariant)
 | 
			
		||||
	suite.Equal(false, broken)
 | 
			
		||||
 | 
			
		||||
	suite.SetupValidState()
 | 
			
		||||
	_, broken = suite.runInvariant("small-balances", keeper.SmallBalancesInvariant)
 | 
			
		||||
	suite.Equal(false, broken)
 | 
			
		||||
 | 
			
		||||
	// increase minor balance at least above conversion multiplier
 | 
			
		||||
	suite.Keeper.AddBalance(suite.Ctx, suite.Addrs[0], keeper.ConversionMultiplier)
 | 
			
		||||
	// add same number of ukava to avoid breaking other invariants
 | 
			
		||||
	amt := sdk.NewCoins(sdk.NewInt64Coin(keeper.CosmosDenom, 1))
 | 
			
		||||
	suite.Require().NoError(
 | 
			
		||||
		suite.App.FundModuleAccount(suite.Ctx, types.ModuleName, amt),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	message, broken := suite.runInvariant("small-balances", keeper.SmallBalancesInvariant)
 | 
			
		||||
	suite.Equal("evmutil: small balances broken invariant\nminor balances not all less than overflow\n", message)
 | 
			
		||||
	suite.Equal(true, broken)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// the cosmos-coins-fully-backed invariant depends on 1-to-1 mapping of module balance to erc20s
 | 
			
		||||
// if coins can be sent directly to the module account, this assumption is broken.
 | 
			
		||||
// this test verifies that coins cannot be directly sent to the module account.
 | 
			
		||||
 | 
			
		||||
@ -50,7 +50,6 @@ type Suite struct {
 | 
			
		||||
	BankKeeper     bankkeeper.Keeper
 | 
			
		||||
	AccountKeeper  authkeeper.AccountKeeper
 | 
			
		||||
	Keeper         keeper.Keeper
 | 
			
		||||
	EvmBankKeeper  keeper.EvmBankKeeper
 | 
			
		||||
	Addrs          []sdk.AccAddress
 | 
			
		||||
	EvmModuleAddr  sdk.AccAddress
 | 
			
		||||
	QueryClient    types.QueryClient
 | 
			
		||||
@ -68,7 +67,6 @@ func (suite *Suite) SetupTest() {
 | 
			
		||||
	suite.BankKeeper = tApp.GetBankKeeper()
 | 
			
		||||
	suite.AccountKeeper = tApp.GetAccountKeeper()
 | 
			
		||||
	suite.Keeper = tApp.GetEvmutilKeeper()
 | 
			
		||||
	suite.EvmBankKeeper = keeper.NewEvmBankKeeper(tApp.GetEvmutilKeeper(), suite.BankKeeper, suite.AccountKeeper)
 | 
			
		||||
	suite.EvmModuleAddr = suite.AccountKeeper.GetModuleAddress(evmtypes.ModuleName)
 | 
			
		||||
 | 
			
		||||
	// test evm user keys that have no minting permissions
 | 
			
		||||
 | 
			
		||||
@ -19,7 +19,11 @@ type AccountKeeper interface {
 | 
			
		||||
 | 
			
		||||
// BankKeeper defines the expected bank keeper interface
 | 
			
		||||
type BankKeeper interface {
 | 
			
		||||
	evmtypes.BankKeeper
 | 
			
		||||
	GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin
 | 
			
		||||
	SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
 | 
			
		||||
	SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
 | 
			
		||||
	MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error
 | 
			
		||||
	BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error
 | 
			
		||||
 | 
			
		||||
	GetSupply(ctx sdk.Context, denom string) sdk.Coin
 | 
			
		||||
	SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user