2481 lines
86 KiB
Go
2481 lines
86 KiB
Go
package keeper_test
|
|
|
|
import (
|
|
"context"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
"go.uber.org/mock/gomock"
|
|
|
|
"cosmossdk.io/core/address"
|
|
coreevent "cosmossdk.io/core/event"
|
|
"cosmossdk.io/core/header"
|
|
coretesting "cosmossdk.io/core/testing"
|
|
"cosmossdk.io/core/testing/queryclient"
|
|
errorsmod "cosmossdk.io/errors"
|
|
"cosmossdk.io/log"
|
|
"cosmossdk.io/math"
|
|
storetypes "cosmossdk.io/store/types"
|
|
"cosmossdk.io/x/bank/keeper"
|
|
banktestutil "cosmossdk.io/x/bank/testutil"
|
|
banktypes "cosmossdk.io/x/bank/types"
|
|
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil"
|
|
"github.com/cosmos/cosmos-sdk/runtime"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
|
moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
|
|
"github.com/cosmos/cosmos-sdk/types/query"
|
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
|
vesting "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
|
|
)
|
|
|
|
const (
|
|
fooDenom = "foo"
|
|
barDenom = "bar"
|
|
ibcPath = "transfer/channel-0"
|
|
ibcBaseDenom = "farboo"
|
|
incompleteBaseDenom = "incomplete"
|
|
incompletePath = "factory/someaddr"
|
|
metaDataDescription = "IBC Token from %s"
|
|
initialPower = int64(100)
|
|
holder = "holder"
|
|
multiPerm = "multiple permissions account"
|
|
randomPerm = "random permission"
|
|
)
|
|
|
|
var (
|
|
holderAcc = authtypes.NewEmptyModuleAccount(holder)
|
|
randomAcc = authtypes.NewEmptyModuleAccount(randomPerm)
|
|
burnerAcc = authtypes.NewEmptyModuleAccount(authtypes.Burner, authtypes.Burner, authtypes.Staking)
|
|
minterAcc = authtypes.NewEmptyModuleAccount(authtypes.Minter, authtypes.Minter)
|
|
mintAcc = authtypes.NewEmptyModuleAccount(banktypes.MintModuleName, authtypes.Minter)
|
|
multiPermAcc = authtypes.NewEmptyModuleAccount(multiPerm, authtypes.Burner, authtypes.Minter, authtypes.Staking)
|
|
|
|
baseAcc = authtypes.NewBaseAccountWithAddress(sdk.AccAddress([]byte("baseAcc")))
|
|
|
|
accAddrs = []sdk.AccAddress{
|
|
sdk.AccAddress([]byte("addr1_______________")),
|
|
sdk.AccAddress([]byte("addr2_______________")),
|
|
sdk.AccAddress([]byte("addr3_______________")),
|
|
sdk.AccAddress([]byte("addr4_______________")),
|
|
sdk.AccAddress([]byte("addr5_______________")),
|
|
}
|
|
|
|
// The default power validators are initialized to have within tests
|
|
initTokens = sdk.TokensFromConsensusPower(initialPower, sdk.DefaultPowerReduction)
|
|
initCoins = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens))
|
|
)
|
|
|
|
func newFooCoin(amt int64) sdk.Coin {
|
|
return sdk.NewInt64Coin(fooDenom, amt)
|
|
}
|
|
|
|
func newBarCoin(amt int64) sdk.Coin {
|
|
return sdk.NewInt64Coin(barDenom, amt)
|
|
}
|
|
|
|
func newIbcCoin(amt int64) sdk.Coin {
|
|
return sdk.NewInt64Coin(getIBCDenom(ibcPath, ibcBaseDenom), amt)
|
|
}
|
|
|
|
func newIncompleteMetadataCoin(amt int64) sdk.Coin {
|
|
return sdk.NewInt64Coin(incompletePath+"/"+incompleteBaseDenom, amt)
|
|
}
|
|
|
|
func getIBCDenom(path, baseDenom string) string {
|
|
return fmt.Sprintf("%s/%s", "ibc", hex.EncodeToString(getIBCHash(path, baseDenom)))
|
|
}
|
|
|
|
func getIBCHash(path, baseDenom string) []byte {
|
|
hash := sha256.Sum256([]byte(path + "/" + baseDenom))
|
|
return hash[:]
|
|
}
|
|
|
|
func addIBCMetadata(ctx context.Context, k keeper.BaseKeeper) {
|
|
metadata := banktypes.Metadata{
|
|
Description: fmt.Sprintf(metaDataDescription, ibcPath),
|
|
DenomUnits: []*banktypes.DenomUnit{
|
|
{
|
|
Denom: ibcBaseDenom,
|
|
Exponent: 0,
|
|
},
|
|
},
|
|
// Setting base as IBChash Denom as SetDenomMetaData uses Base as storeKey
|
|
// and the bank keeper will only have the IBCHash to get the denom metadata
|
|
Base: getIBCDenom(ibcPath, ibcBaseDenom),
|
|
Display: ibcPath + "/" + ibcBaseDenom,
|
|
}
|
|
k.SetDenomMetaData(ctx, metadata)
|
|
}
|
|
|
|
func addIncompleteMetadata(ctx context.Context, k keeper.BaseKeeper) {
|
|
metadata := banktypes.Metadata{
|
|
Description: "Incomplete metadata without display field",
|
|
DenomUnits: []*banktypes.DenomUnit{
|
|
{
|
|
Denom: incompleteBaseDenom,
|
|
Exponent: 0,
|
|
},
|
|
},
|
|
Base: incompletePath + "/" + incompleteBaseDenom,
|
|
// Not setting any Display value
|
|
}
|
|
k.SetDenomMetaData(ctx, metadata)
|
|
}
|
|
|
|
type KeeperTestSuite struct {
|
|
suite.Suite
|
|
|
|
ctx coretesting.TestContext
|
|
env coretesting.TestEnvironment
|
|
bankKeeper keeper.BaseKeeper
|
|
addrCdc address.Codec
|
|
authKeeper *banktestutil.MockAccountKeeper
|
|
|
|
queryClient banktypes.QueryClient
|
|
msgServer banktypes.MsgServer
|
|
|
|
encCfg moduletestutil.TestEncodingConfig
|
|
}
|
|
|
|
func TestKeeperTestSuite(t *testing.T) {
|
|
suite.Run(t, new(KeeperTestSuite))
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) SetupTest() {
|
|
encCfg := moduletestutil.MakeTestEncodingConfig(codectestutil.CodecOptions{})
|
|
testEnironmentConfig := coretesting.TestEnvironmentConfig{
|
|
ModuleName: banktypes.ModuleName,
|
|
Logger: log.NewNopLogger(),
|
|
MsgRouter: nil,
|
|
QueryRouter: nil,
|
|
}
|
|
|
|
ctx, env := coretesting.NewTestEnvironment(testEnironmentConfig)
|
|
ctx = ctx.WithHeaderInfo(header.Info{Time: time.Now()})
|
|
|
|
ac := codectestutil.CodecOptions{}.GetAddressCodec()
|
|
addr, err := ac.BytesToString(accAddrs[4])
|
|
suite.Require().NoError(err)
|
|
authority, err := ac.BytesToString(authtypes.NewModuleAddress(banktypes.GovModuleName))
|
|
suite.Require().NoError(err)
|
|
|
|
// gomock initializations
|
|
ctrl := gomock.NewController(suite.T())
|
|
authKeeper := banktestutil.NewMockAccountKeeper(ctrl)
|
|
authKeeper.EXPECT().AddressCodec().Return(ac).AnyTimes()
|
|
suite.ctx = ctx
|
|
suite.authKeeper = authKeeper
|
|
suite.addrCdc = ac
|
|
suite.bankKeeper = keeper.NewBaseKeeper(
|
|
env.Environment,
|
|
encCfg.Codec,
|
|
suite.authKeeper,
|
|
map[string]bool{addr: true},
|
|
authority,
|
|
)
|
|
|
|
suite.Require().NoError(suite.bankKeeper.SetParams(ctx, banktypes.Params{
|
|
DefaultSendEnabled: banktypes.DefaultDefaultSendEnabled,
|
|
}))
|
|
|
|
queryHelper := queryclient.NewQueryHelper(codec.NewProtoCodec(encCfg.InterfaceRegistry).GRPCCodec())
|
|
banktypes.RegisterQueryServer(queryHelper, suite.bankKeeper)
|
|
banktypes.RegisterInterfaces(encCfg.InterfaceRegistry)
|
|
|
|
suite.queryClient = banktypes.NewQueryClient(queryHelper)
|
|
suite.msgServer = keeper.NewMsgServerImpl(suite.bankKeeper)
|
|
suite.encCfg = encCfg
|
|
suite.env = env
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) mockMintCoins(moduleAcc *authtypes.ModuleAccount) {
|
|
suite.authKeeper.EXPECT().GetModuleAccount(suite.ctx, moduleAcc.Name).Return(moduleAcc)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) mockSendCoinsFromModuleToAccount(moduleAcc *authtypes.ModuleAccount, _ sdk.AccAddress) {
|
|
suite.authKeeper.EXPECT().GetModuleAddress(moduleAcc.Name).Return(moduleAcc.GetAddress())
|
|
suite.authKeeper.EXPECT().GetAccount(suite.ctx, moduleAcc.GetAddress()).Return(moduleAcc)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) mockBurnCoins(moduleAcc *authtypes.ModuleAccount) {
|
|
suite.authKeeper.EXPECT().GetAccount(suite.ctx, moduleAcc.GetAddress()).Return(moduleAcc).AnyTimes()
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) mockSendCoinsFromModuleToModule(sender, receiver *authtypes.ModuleAccount) {
|
|
suite.authKeeper.EXPECT().GetModuleAddress(sender.Name).Return(sender.GetAddress())
|
|
suite.authKeeper.EXPECT().GetModuleAccount(suite.ctx, receiver.Name).Return(receiver)
|
|
suite.authKeeper.EXPECT().GetAccount(suite.ctx, sender.GetAddress()).Return(sender)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) mockSendCoinsFromAccountToModule(acc *authtypes.BaseAccount, moduleAcc *authtypes.ModuleAccount) {
|
|
suite.authKeeper.EXPECT().GetModuleAccount(suite.ctx, moduleAcc.Name).Return(moduleAcc)
|
|
suite.authKeeper.EXPECT().GetAccount(suite.ctx, acc.GetAddress()).Return(acc)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) mockSendCoins(ctx context.Context, sender sdk.AccountI, _ sdk.AccAddress) {
|
|
suite.authKeeper.EXPECT().GetAccount(ctx, sender.GetAddress()).Return(sender)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) mockFundAccount(receiver sdk.AccAddress) {
|
|
suite.mockMintCoins(mintAcc)
|
|
suite.mockSendCoinsFromModuleToAccount(mintAcc, receiver)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) mockInputOutputCoins(inputs []sdk.AccountI, _ []sdk.AccAddress) {
|
|
for _, input := range inputs {
|
|
suite.authKeeper.EXPECT().GetAccount(suite.ctx, input.GetAddress()).Return(input)
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) mockValidateBalance(acc sdk.AccountI) {
|
|
suite.authKeeper.EXPECT().GetAccount(suite.ctx, acc.GetAddress()).Return(acc)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) mockSpendableCoins(ctx context.Context, acc sdk.AccountI) {
|
|
suite.authKeeper.EXPECT().GetAccount(ctx, acc.GetAddress()).Return(acc)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) mockDelegateCoinsFromAccountToModule(acc *authtypes.BaseAccount, moduleAcc *authtypes.ModuleAccount) {
|
|
suite.authKeeper.EXPECT().GetModuleAccount(suite.ctx, moduleAcc.Name).Return(moduleAcc)
|
|
suite.mockDelegateCoins(suite.ctx, acc, moduleAcc)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) mockUndelegateCoinsFromModuleToAccount(moduleAcc *authtypes.ModuleAccount, accAddr *authtypes.BaseAccount) {
|
|
suite.authKeeper.EXPECT().GetModuleAccount(suite.ctx, moduleAcc.Name).Return(moduleAcc)
|
|
suite.mockUnDelegateCoins(suite.ctx, accAddr, moduleAcc)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) mockDelegateCoins(ctx context.Context, acc, mAcc sdk.AccountI) {
|
|
vacc, ok := acc.(banktypes.VestingAccount)
|
|
if ok {
|
|
suite.authKeeper.EXPECT().SetAccount(ctx, vacc)
|
|
}
|
|
suite.authKeeper.EXPECT().GetAccount(ctx, acc.GetAddress()).Return(acc)
|
|
suite.authKeeper.EXPECT().GetAccount(ctx, mAcc.GetAddress()).Return(mAcc)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) mockUnDelegateCoins(ctx context.Context, acc, mAcc sdk.AccountI) {
|
|
vacc, ok := acc.(banktypes.VestingAccount)
|
|
if ok {
|
|
suite.authKeeper.EXPECT().SetAccount(ctx, vacc)
|
|
}
|
|
suite.authKeeper.EXPECT().GetAccount(ctx, acc.GetAddress()).Return(acc)
|
|
suite.authKeeper.EXPECT().GetAccount(ctx, mAcc.GetAddress()).Return(mAcc)
|
|
suite.authKeeper.EXPECT().GetAccount(ctx, mAcc.GetAddress()).Return(mAcc)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestAppendSendRestriction() {
|
|
var calls []int
|
|
testRestriction := func(index int) banktypes.SendRestrictionFn {
|
|
return func(_ context.Context, _, _ sdk.AccAddress, _ sdk.Coins) (sdk.AccAddress, error) {
|
|
calls = append(calls, index)
|
|
return nil, nil
|
|
}
|
|
}
|
|
|
|
bk := suite.bankKeeper
|
|
|
|
// Initial append of the test restriction.
|
|
bk.SetSendRestriction(nil)
|
|
bk.AppendSendRestriction(testRestriction(1))
|
|
_, _ = bk.GetSendRestrictionFn()(suite.ctx, nil, nil, nil)
|
|
suite.Require().Equal([]int{1}, calls, "restriction calls after first append")
|
|
|
|
// Append the test restriction again.
|
|
calls = nil
|
|
bk.AppendSendRestriction(testRestriction(2))
|
|
_, _ = bk.GetSendRestrictionFn()(suite.ctx, nil, nil, nil)
|
|
suite.Require().Equal([]int{1, 2}, calls, "restriction calls after second append")
|
|
|
|
// make sure the original bank keeper has the restrictions too.
|
|
calls = nil
|
|
_, _ = suite.bankKeeper.GetSendRestrictionFn()(suite.ctx, nil, nil, nil)
|
|
suite.Require().Equal([]int{1, 2}, calls, "restriction calls from original bank keeper")
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestPrependSendRestriction() {
|
|
var calls []int
|
|
testRestriction := func(index int) banktypes.SendRestrictionFn {
|
|
return func(_ context.Context, _, _ sdk.AccAddress, _ sdk.Coins) (sdk.AccAddress, error) {
|
|
calls = append(calls, index)
|
|
return nil, nil
|
|
}
|
|
}
|
|
|
|
bk := suite.bankKeeper
|
|
|
|
// Initial append of the test restriction.
|
|
bk.SetSendRestriction(nil)
|
|
bk.PrependSendRestriction(testRestriction(1))
|
|
_, _ = bk.GetSendRestrictionFn()(suite.ctx, nil, nil, nil)
|
|
suite.Require().Equal([]int{1}, calls, "restriction calls after first append")
|
|
|
|
// Append the test restriction again.
|
|
calls = nil
|
|
bk.PrependSendRestriction(testRestriction(2))
|
|
_, _ = bk.GetSendRestrictionFn()(suite.ctx, nil, nil, nil)
|
|
suite.Require().Equal([]int{2, 1}, calls, "restriction calls after second append")
|
|
|
|
// make sure the original bank keeper has the restrictions too.
|
|
calls = nil
|
|
_, _ = suite.bankKeeper.GetSendRestrictionFn()(suite.ctx, nil, nil, nil)
|
|
suite.Require().Equal([]int{2, 1}, calls, "restriction calls from original bank keeper")
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestGetAuthority() {
|
|
env := runtime.NewEnvironment(runtime.NewKVStoreService(storetypes.NewKVStoreKey(banktypes.StoreKey)), coretesting.NewNopLogger())
|
|
NewKeeperWithAuthority := func(authority string) keeper.BaseKeeper {
|
|
return keeper.NewBaseKeeper(
|
|
env,
|
|
moduletestutil.MakeTestEncodingConfig(codectestutil.CodecOptions{}).Codec,
|
|
suite.authKeeper,
|
|
nil,
|
|
authority,
|
|
)
|
|
}
|
|
govAddr, err := suite.addrCdc.BytesToString(authtypes.NewModuleAddress(banktypes.GovModuleName))
|
|
suite.Require().NoError(err)
|
|
modAddr, err := suite.addrCdc.BytesToString(authtypes.NewModuleAddress(banktypes.MintModuleName))
|
|
suite.Require().NoError(err)
|
|
|
|
tests := map[string]string{
|
|
"some random account": "cosmos139f7kncmglres2nf3h4hc4tade85ekfr8sulz5",
|
|
"gov module account": govAddr,
|
|
"another module account": modAddr,
|
|
}
|
|
|
|
for name, expected := range tests {
|
|
suite.T().Run(name, func(t *testing.T) {
|
|
kpr := NewKeeperWithAuthority(expected)
|
|
actual := kpr.GetAuthority()
|
|
suite.Require().Equal(expected, actual)
|
|
})
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestSupply() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
keeper := suite.bankKeeper
|
|
|
|
// add module accounts to supply keeper
|
|
genesisSupply, _, err := keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{})
|
|
require.NoError(err)
|
|
|
|
initialPower := int64(100)
|
|
initTokens := sdk.TokensFromConsensusPower(initialPower, sdk.DefaultPowerReduction)
|
|
initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens))
|
|
|
|
// set burnerAcc balance
|
|
suite.mockMintCoins(minterAcc)
|
|
require.NoError(keeper.MintCoins(ctx, authtypes.Minter, initCoins))
|
|
|
|
suite.mockSendCoinsFromModuleToAccount(minterAcc, burnerAcc.GetAddress())
|
|
require.NoError(keeper.SendCoinsFromModuleToAccount(ctx, authtypes.Minter, burnerAcc.GetAddress(), initCoins))
|
|
|
|
total, _, err := keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{})
|
|
require.NoError(err)
|
|
|
|
expTotalSupply := initCoins.Add(genesisSupply...)
|
|
require.Equal(expTotalSupply, total)
|
|
|
|
// burning all supplied tokens
|
|
suite.mockBurnCoins(burnerAcc)
|
|
require.NoError(keeper.BurnCoins(ctx, burnerAcc.GetAddress(), initCoins))
|
|
|
|
total, _, err = keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{})
|
|
require.NoError(err)
|
|
require.Equal(total, genesisSupply)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestSendCoinsFromModuleToAccount_Blocklist() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
keeper := suite.bankKeeper
|
|
|
|
suite.mockMintCoins(mintAcc)
|
|
require.NoError(keeper.MintCoins(ctx, banktypes.MintModuleName, initCoins))
|
|
|
|
suite.authKeeper.EXPECT().GetModuleAddress(mintAcc.Name).Return(mintAcc.GetAddress())
|
|
require.Error(keeper.SendCoinsFromModuleToAccount(
|
|
ctx, banktypes.MintModuleName, accAddrs[4], initCoins,
|
|
))
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestSupply_DelegateUndelegateCoins() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
authKeeper, keeper := suite.authKeeper, suite.bankKeeper
|
|
|
|
// set initial balances
|
|
suite.mockMintCoins(mintAcc)
|
|
require.NoError(keeper.MintCoins(ctx, banktypes.MintModuleName, initCoins))
|
|
|
|
suite.mockSendCoinsFromModuleToAccount(mintAcc, holderAcc.GetAddress())
|
|
require.NoError(keeper.SendCoinsFromModuleToAccount(ctx, banktypes.MintModuleName, holderAcc.GetAddress(), initCoins))
|
|
|
|
authKeeper.EXPECT().GetModuleAddress("").Return(nil)
|
|
err := keeper.SendCoinsFromModuleToAccount(ctx, "", holderAcc.GetAddress(), initCoins)
|
|
require.Error(err)
|
|
|
|
authKeeper.EXPECT().GetModuleAddress(burnerAcc.Name).Return(burnerAcc.GetAddress())
|
|
authKeeper.EXPECT().GetModuleAccount(ctx, "").Return(nil)
|
|
err = keeper.SendCoinsFromModuleToModule(ctx, authtypes.Burner, "", initCoins)
|
|
require.Error(err)
|
|
|
|
authKeeper.EXPECT().GetModuleAddress("").Return(nil)
|
|
err = keeper.SendCoinsFromModuleToAccount(ctx, "", baseAcc.GetAddress(), initCoins)
|
|
require.Error(err)
|
|
|
|
authKeeper.EXPECT().GetModuleAddress(holderAcc.Name).Return(holderAcc.GetAddress())
|
|
authKeeper.EXPECT().GetAccount(suite.ctx, holderAcc.GetAddress()).Return(holderAcc)
|
|
require.Error(
|
|
keeper.SendCoinsFromModuleToAccount(ctx, holderAcc.GetName(), baseAcc.GetAddress(), initCoins.Add(initCoins...)),
|
|
)
|
|
suite.mockSendCoinsFromModuleToModule(holderAcc, burnerAcc)
|
|
require.NoError(
|
|
keeper.SendCoinsFromModuleToModule(ctx, holderAcc.GetName(), authtypes.Burner, initCoins),
|
|
)
|
|
|
|
require.Equal(sdk.NewCoins(), keeper.GetAllBalances(ctx, holderAcc.GetAddress()))
|
|
require.Equal(initCoins, keeper.GetAllBalances(ctx, burnerAcc.GetAddress()))
|
|
|
|
suite.mockSendCoinsFromModuleToAccount(burnerAcc, baseAcc.GetAddress())
|
|
require.NoError(
|
|
keeper.SendCoinsFromModuleToAccount(ctx, authtypes.Burner, baseAcc.GetAddress(), initCoins),
|
|
)
|
|
require.Equal(sdk.NewCoins(), keeper.GetAllBalances(ctx, burnerAcc.GetAddress()))
|
|
require.Equal(initCoins, keeper.GetAllBalances(ctx, baseAcc.GetAddress()))
|
|
|
|
suite.mockDelegateCoinsFromAccountToModule(baseAcc, burnerAcc)
|
|
|
|
require.NoError(keeper.DelegateCoinsFromAccountToModule(ctx, baseAcc.GetAddress(), authtypes.Burner, initCoins))
|
|
require.Equal(sdk.NewCoins(), keeper.GetAllBalances(ctx, baseAcc.GetAddress()))
|
|
require.Equal(initCoins, keeper.GetAllBalances(ctx, burnerAcc.GetAddress()))
|
|
|
|
suite.mockUndelegateCoinsFromModuleToAccount(burnerAcc, baseAcc)
|
|
require.NoError(keeper.UndelegateCoinsFromModuleToAccount(ctx, authtypes.Burner, baseAcc.GetAddress(), initCoins))
|
|
require.Equal(sdk.NewCoins(), keeper.GetAllBalances(ctx, burnerAcc.GetAddress()))
|
|
require.Equal(initCoins, keeper.GetAllBalances(ctx, baseAcc.GetAddress()))
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestSupply_SendCoins() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
authKeeper, keeper := suite.authKeeper, suite.bankKeeper
|
|
|
|
// set initial balances
|
|
suite.mockMintCoins(mintAcc)
|
|
require.NoError(keeper.MintCoins(ctx, banktypes.MintModuleName, initCoins))
|
|
|
|
suite.mockSendCoinsFromModuleToAccount(mintAcc, holderAcc.GetAddress())
|
|
require.NoError(keeper.SendCoinsFromModuleToAccount(ctx, banktypes.MintModuleName, holderAcc.GetAddress(), initCoins))
|
|
|
|
authKeeper.EXPECT().GetModuleAddress("").Return(nil)
|
|
err := keeper.SendCoinsFromModuleToModule(ctx, "", holderAcc.GetName(), initCoins)
|
|
require.Error(err)
|
|
|
|
authKeeper.EXPECT().GetModuleAddress(burnerAcc.Name).Return(burnerAcc.GetAddress())
|
|
authKeeper.EXPECT().GetModuleAccount(ctx, "").Return(nil)
|
|
err = keeper.SendCoinsFromModuleToModule(ctx, authtypes.Burner, "", initCoins)
|
|
require.Error(err)
|
|
|
|
authKeeper.EXPECT().GetModuleAddress("").Return(nil)
|
|
err = keeper.SendCoinsFromModuleToAccount(ctx, "", baseAcc.GetAddress(), initCoins)
|
|
require.Error(err)
|
|
|
|
authKeeper.EXPECT().GetModuleAddress(holderAcc.Name).Return(holderAcc.GetAddress())
|
|
authKeeper.EXPECT().GetAccount(suite.ctx, holderAcc.GetAddress()).Return(holderAcc)
|
|
require.Error(
|
|
keeper.SendCoinsFromModuleToAccount(ctx, holderAcc.GetName(), baseAcc.GetAddress(), initCoins.Add(initCoins...)),
|
|
)
|
|
|
|
suite.mockSendCoinsFromModuleToModule(holderAcc, burnerAcc)
|
|
require.NoError(
|
|
keeper.SendCoinsFromModuleToModule(ctx, holderAcc.GetName(), authtypes.Burner, initCoins),
|
|
)
|
|
|
|
require.Equal(sdk.NewCoins(), keeper.GetAllBalances(ctx, holderAcc.GetAddress()))
|
|
require.Equal(initCoins, keeper.GetAllBalances(ctx, burnerAcc.GetAddress()))
|
|
|
|
suite.mockSendCoinsFromModuleToAccount(burnerAcc, baseAcc.GetAddress())
|
|
require.NoError(
|
|
keeper.SendCoinsFromModuleToAccount(ctx, authtypes.Burner, baseAcc.GetAddress(), initCoins),
|
|
)
|
|
require.Equal(sdk.NewCoins(), keeper.GetAllBalances(ctx, burnerAcc.GetAddress()))
|
|
require.Equal(initCoins, keeper.GetAllBalances(ctx, baseAcc.GetAddress()))
|
|
|
|
suite.mockSendCoinsFromAccountToModule(baseAcc, burnerAcc)
|
|
|
|
require.NoError(keeper.SendCoinsFromAccountToModule(ctx, baseAcc.GetAddress(), authtypes.Burner, initCoins))
|
|
require.Equal(sdk.NewCoins(), keeper.GetAllBalances(ctx, baseAcc.GetAddress()))
|
|
require.Equal(initCoins, keeper.GetAllBalances(ctx, burnerAcc.GetAddress()))
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestSupply_MintCoins() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
authKeeper, keeper := suite.authKeeper, suite.bankKeeper
|
|
|
|
initialSupply, _, err := keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{})
|
|
require.NoError(err)
|
|
|
|
authKeeper.EXPECT().GetModuleAccount(ctx, "").Return(nil)
|
|
err = keeper.MintCoins(ctx, "", initCoins)
|
|
require.Error(err)
|
|
require.ErrorContains(err, "module account does not exist")
|
|
|
|
suite.mockMintCoins(burnerAcc)
|
|
err = keeper.MintCoins(ctx, authtypes.Burner, initCoins)
|
|
require.Error(err)
|
|
require.ErrorContains(err, fmt.Sprintf("module account %s does not have permissions to mint tokens: unauthorized", authtypes.Burner))
|
|
|
|
suite.mockMintCoins(minterAcc)
|
|
require.Error(keeper.MintCoins(ctx, authtypes.Minter, sdk.Coins{sdk.Coin{Denom: "denom", Amount: math.NewInt(-10)}}), "insufficient coins")
|
|
|
|
authKeeper.EXPECT().GetModuleAccount(ctx, randomPerm).Return(nil)
|
|
err = keeper.MintCoins(ctx, randomPerm, initCoins)
|
|
require.Error(err)
|
|
|
|
suite.mockMintCoins(minterAcc)
|
|
require.NoError(keeper.MintCoins(ctx, authtypes.Minter, initCoins))
|
|
|
|
require.Equal(initCoins, keeper.GetAllBalances(ctx, minterAcc.GetAddress()))
|
|
totalSupply, _, err := keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{})
|
|
require.NoError(err)
|
|
|
|
require.Equal(initialSupply.Add(initCoins...), totalSupply)
|
|
|
|
// test same functionality on module account with multiple permissions
|
|
initialSupply, _, err = keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{})
|
|
require.NoError(err)
|
|
|
|
suite.mockMintCoins(multiPermAcc)
|
|
require.NoError(keeper.MintCoins(ctx, multiPermAcc.GetName(), initCoins))
|
|
|
|
totalSupply, _, err = keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{})
|
|
require.NoError(err)
|
|
require.Equal(initCoins, keeper.GetAllBalances(ctx, multiPermAcc.GetAddress()))
|
|
require.Equal(initialSupply.Add(initCoins...), totalSupply)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestSupply_BurnCoins() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
authKeeper, keeper := suite.authKeeper, suite.bankKeeper
|
|
|
|
// set burnerAcc balance
|
|
suite.mockMintCoins(minterAcc)
|
|
require.NoError(keeper.MintCoins(ctx, authtypes.Minter, initCoins))
|
|
suite.mockSendCoinsFromModuleToAccount(minterAcc, burnerAcc.GetAddress())
|
|
require.NoError(keeper.SendCoinsFromModuleToAccount(ctx, authtypes.Minter, burnerAcc.GetAddress(), initCoins))
|
|
|
|
// inflate supply
|
|
suite.mockMintCoins(minterAcc)
|
|
require.NoError(keeper.MintCoins(ctx, authtypes.Minter, initCoins))
|
|
|
|
supplyAfterInflation, _, err := keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{})
|
|
require.NoError(err)
|
|
|
|
authKeeper.EXPECT().GetAccount(ctx, sdk.AccAddress{}).Return(nil)
|
|
require.Error(keeper.BurnCoins(ctx, sdk.AccAddress{}, initCoins), "no account")
|
|
|
|
authKeeper.EXPECT().GetAccount(ctx, minterAcc.GetAddress()).Return(nil)
|
|
require.Error(keeper.BurnCoins(ctx, minterAcc.GetAddress(), initCoins), "invalid permission")
|
|
|
|
authKeeper.EXPECT().GetAccount(ctx, randomAcc.GetAddress()).Return(nil)
|
|
require.Error(keeper.BurnCoins(ctx, randomAcc.GetAddress(), supplyAfterInflation), "random permission")
|
|
|
|
suite.mockBurnCoins(burnerAcc)
|
|
require.Error(keeper.BurnCoins(ctx, burnerAcc.GetAddress(), supplyAfterInflation), "insufficient coins")
|
|
|
|
suite.mockBurnCoins(burnerAcc)
|
|
require.NoError(keeper.BurnCoins(ctx, burnerAcc.GetAddress(), initCoins))
|
|
|
|
suite.mockBurnCoins(burnerAcc)
|
|
require.ErrorContains(keeper.BurnCoins(ctx, burnerAcc.GetAddress(), sdk.Coins{sdk.Coin{Denom: "asd", Amount: math.NewInt(-1)}}), "-1asd: invalid coins")
|
|
|
|
supplyAfterBurn, _, err := keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{})
|
|
require.NoError(err)
|
|
require.Equal(sdk.NewCoins(), keeper.GetAllBalances(ctx, burnerAcc.GetAddress()))
|
|
require.Equal(supplyAfterInflation.Sub(initCoins...), supplyAfterBurn)
|
|
|
|
// test same functionality on module account with multiple permissions
|
|
suite.mockMintCoins(minterAcc)
|
|
require.NoError(keeper.MintCoins(ctx, authtypes.Minter, initCoins))
|
|
|
|
supplyAfterInflation, _, err = keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{})
|
|
require.NoError(err)
|
|
|
|
suite.mockSendCoins(ctx, minterAcc, multiPermAcc.GetAddress())
|
|
require.NoError(keeper.SendCoins(ctx, minterAcc.GetAddress(), multiPermAcc.GetAddress(), initCoins))
|
|
|
|
suite.mockBurnCoins(multiPermAcc)
|
|
require.NoError(keeper.BurnCoins(ctx, multiPermAcc.GetAddress(), initCoins))
|
|
|
|
supplyAfterBurn, _, err = keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{})
|
|
require.NoError(err)
|
|
require.Equal(sdk.NewCoins(), keeper.GetAllBalances(ctx, multiPermAcc.GetAddress()))
|
|
require.Equal(supplyAfterInflation.Sub(initCoins...), supplyAfterBurn)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestSendCoinsNewAccount() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
balances := sdk.NewCoins(newFooCoin(100), newBarCoin(50))
|
|
|
|
suite.mockFundAccount(accAddrs[0])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], balances))
|
|
|
|
acc0 := authtypes.NewBaseAccountWithAddress(accAddrs[0])
|
|
acc1Balances := suite.bankKeeper.GetAllBalances(ctx, accAddrs[0])
|
|
require.Equal(balances, acc1Balances)
|
|
|
|
suite.bankKeeper.GetAllBalances(ctx, accAddrs[1])
|
|
require.Empty(suite.bankKeeper.GetAllBalances(ctx, accAddrs[1]))
|
|
|
|
sendAmt := sdk.NewCoins(newFooCoin(50), newBarCoin(50))
|
|
suite.mockSendCoins(ctx, acc0, accAddrs[1])
|
|
require.NoError(suite.bankKeeper.SendCoins(ctx, accAddrs[0], accAddrs[1], sendAmt))
|
|
|
|
acc2Balances := suite.bankKeeper.GetAllBalances(ctx, accAddrs[1])
|
|
acc1Balances = suite.bankKeeper.GetAllBalances(ctx, accAddrs[0])
|
|
require.Equal(sendAmt, acc2Balances)
|
|
updatedAcc1Bal := balances.Sub(sendAmt...)
|
|
require.Len(acc1Balances, len(updatedAcc1Bal))
|
|
require.Equal(acc1Balances, updatedAcc1Bal)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestInputOutputNewAccount() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
|
|
balances := sdk.NewCoins(newFooCoin(100), newBarCoin(50))
|
|
|
|
suite.mockFundAccount(accAddrs[0])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], balances))
|
|
|
|
acc1Balances := suite.bankKeeper.GetAllBalances(ctx, accAddrs[0])
|
|
require.Equal(balances, acc1Balances)
|
|
|
|
require.Empty(suite.bankKeeper.GetAllBalances(ctx, accAddrs[1]))
|
|
|
|
acc0StrAddr, err := suite.addrCdc.BytesToString(accAddrs[0])
|
|
suite.Require().NoError(err)
|
|
acc1StrAddr, err := suite.addrCdc.BytesToString(accAddrs[1])
|
|
suite.Require().NoError(err)
|
|
|
|
suite.mockInputOutputCoins([]sdk.AccountI{authtypes.NewBaseAccountWithAddress(accAddrs[0])}, []sdk.AccAddress{accAddrs[1]})
|
|
input := banktypes.Input{
|
|
Address: acc0StrAddr, Coins: sdk.NewCoins(newFooCoin(30), newBarCoin(10)),
|
|
}
|
|
outputs := []banktypes.Output{
|
|
{Address: acc1StrAddr, Coins: sdk.NewCoins(newFooCoin(30), newBarCoin(10))},
|
|
}
|
|
|
|
require.NoError(suite.bankKeeper.InputOutputCoins(ctx, input, outputs))
|
|
|
|
expected := sdk.NewCoins(newFooCoin(30), newBarCoin(10))
|
|
acc2Balances := suite.bankKeeper.GetAllBalances(ctx, accAddrs[1])
|
|
require.Equal(expected, acc2Balances)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestInputOutputCoins() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
balances := sdk.NewCoins(newFooCoin(90), newBarCoin(30))
|
|
|
|
acc0 := authtypes.NewBaseAccountWithAddress(accAddrs[0])
|
|
|
|
acc0StrAddr, err := suite.addrCdc.BytesToString(accAddrs[0])
|
|
suite.Require().NoError(err)
|
|
acc1StrAddr, err := suite.addrCdc.BytesToString(accAddrs[1])
|
|
suite.Require().NoError(err)
|
|
acc2StrAddr, err := suite.addrCdc.BytesToString(accAddrs[2])
|
|
suite.Require().NoError(err)
|
|
|
|
input := banktypes.Input{
|
|
Address: acc0StrAddr, Coins: sdk.NewCoins(newFooCoin(60), newBarCoin(20)),
|
|
}
|
|
outputs := []banktypes.Output{
|
|
{Address: acc1StrAddr, Coins: sdk.NewCoins(newFooCoin(30), newBarCoin(10))},
|
|
{Address: acc2StrAddr, Coins: sdk.NewCoins(newFooCoin(30), newBarCoin(10))},
|
|
}
|
|
|
|
require.Error(suite.bankKeeper.InputOutputCoins(ctx, input, []banktypes.Output{}))
|
|
|
|
suite.authKeeper.EXPECT().GetAccount(suite.ctx, accAddrs[0]).Return(acc0)
|
|
require.Error(suite.bankKeeper.InputOutputCoins(ctx, input, outputs))
|
|
|
|
suite.mockFundAccount(accAddrs[0])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], balances))
|
|
|
|
insufficientInput := banktypes.Input{
|
|
Address: acc0StrAddr,
|
|
Coins: sdk.NewCoins(newFooCoin(300), newBarCoin(100)),
|
|
}
|
|
insufficientOutputs := []banktypes.Output{
|
|
{Address: acc1StrAddr, Coins: sdk.NewCoins(newFooCoin(300), newBarCoin(100))},
|
|
{Address: acc2StrAddr, Coins: sdk.NewCoins(newFooCoin(300), newBarCoin(100))},
|
|
}
|
|
|
|
require.Error(suite.bankKeeper.InputOutputCoins(ctx, insufficientInput, insufficientOutputs))
|
|
|
|
suite.mockInputOutputCoins([]sdk.AccountI{acc0}, accAddrs[1:3])
|
|
require.NoError(suite.bankKeeper.InputOutputCoins(ctx, input, outputs))
|
|
|
|
acc1Balances := suite.bankKeeper.GetAllBalances(ctx, accAddrs[0])
|
|
expected := sdk.NewCoins(newFooCoin(30), newBarCoin(10))
|
|
require.Equal(expected, acc1Balances)
|
|
|
|
acc2Balances := suite.bankKeeper.GetAllBalances(ctx, accAddrs[1])
|
|
require.Equal(expected, acc2Balances)
|
|
|
|
acc3Balances := suite.bankKeeper.GetAllBalances(ctx, accAddrs[2])
|
|
require.Equal(expected, acc3Balances)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestInputOutputCoinsWithRestrictions() {
|
|
type restrictionArgs struct {
|
|
ctx context.Context
|
|
fromAddr sdk.AccAddress
|
|
toAddr sdk.AccAddress
|
|
amt sdk.Coins
|
|
}
|
|
var actualRestrictionArgs []*restrictionArgs
|
|
restrictionError := func(messages ...string) banktypes.SendRestrictionFn {
|
|
i := -1
|
|
return func(ctx context.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) (sdk.AccAddress, error) {
|
|
actualRestrictionArgs = append(actualRestrictionArgs, &restrictionArgs{
|
|
ctx: ctx,
|
|
fromAddr: fromAddr,
|
|
toAddr: toAddr,
|
|
amt: amt,
|
|
})
|
|
i++
|
|
if i < len(messages) {
|
|
if len(messages[i]) > 0 {
|
|
return nil, errors.New(messages[i])
|
|
}
|
|
}
|
|
return toAddr, nil
|
|
}
|
|
}
|
|
restrictionPassthrough := func() banktypes.SendRestrictionFn {
|
|
return func(ctx context.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) (sdk.AccAddress, error) {
|
|
actualRestrictionArgs = append(actualRestrictionArgs, &restrictionArgs{
|
|
ctx: ctx,
|
|
fromAddr: fromAddr,
|
|
toAddr: toAddr,
|
|
amt: amt,
|
|
})
|
|
return toAddr, nil
|
|
}
|
|
}
|
|
restrictionNewTo := func(newToAddrs ...sdk.AccAddress) banktypes.SendRestrictionFn {
|
|
i := -1
|
|
return func(ctx context.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) (sdk.AccAddress, error) {
|
|
actualRestrictionArgs = append(actualRestrictionArgs, &restrictionArgs{
|
|
ctx: ctx,
|
|
fromAddr: fromAddr,
|
|
toAddr: toAddr,
|
|
amt: amt,
|
|
})
|
|
i++
|
|
if i < len(newToAddrs) {
|
|
if len(newToAddrs[i]) > 0 {
|
|
return newToAddrs[i], nil
|
|
}
|
|
}
|
|
return toAddr, nil
|
|
}
|
|
}
|
|
type expBals struct {
|
|
from sdk.Coins
|
|
to1 sdk.Coins
|
|
to2 sdk.Coins
|
|
}
|
|
|
|
setupCtx := suite.ctx
|
|
balances := sdk.NewCoins(newFooCoin(1000), newBarCoin(500))
|
|
fromAddr := accAddrs[0]
|
|
fromStrAddr, err := suite.addrCdc.BytesToString(fromAddr)
|
|
suite.Require().NoError(err)
|
|
fromAcc := authtypes.NewBaseAccountWithAddress(fromAddr)
|
|
inputAccs := []sdk.AccountI{fromAcc}
|
|
suite.authKeeper.EXPECT().GetAccount(suite.ctx, inputAccs[0].GetAddress()).Return(inputAccs[0]).AnyTimes()
|
|
toAddr1 := accAddrs[1]
|
|
toAddr1Str, err := suite.addrCdc.BytesToString(toAddr1)
|
|
suite.Require().NoError(err)
|
|
toAddr2 := accAddrs[2]
|
|
toAddr2Str, err := suite.addrCdc.BytesToString(toAddr2)
|
|
suite.Require().NoError(err)
|
|
|
|
suite.mockFundAccount(accAddrs[0])
|
|
suite.Require().NoError(banktestutil.FundAccount(setupCtx, suite.bankKeeper, accAddrs[0], balances))
|
|
|
|
tests := []struct {
|
|
name string
|
|
fn banktypes.SendRestrictionFn
|
|
inputCoins sdk.Coins
|
|
outputs []banktypes.Output
|
|
outputAddrs []sdk.AccAddress
|
|
expArgs []*restrictionArgs
|
|
expErr string
|
|
expBals expBals
|
|
}{
|
|
{
|
|
name: "nil restriction",
|
|
fn: nil,
|
|
inputCoins: sdk.NewCoins(newFooCoin(5)),
|
|
outputs: []banktypes.Output{{Address: toAddr1Str, Coins: sdk.NewCoins(newFooCoin(5))}},
|
|
outputAddrs: []sdk.AccAddress{toAddr1},
|
|
expBals: expBals{
|
|
from: sdk.NewCoins(newFooCoin(995), newBarCoin(500)),
|
|
to1: sdk.NewCoins(newFooCoin(5)),
|
|
to2: sdk.Coins{},
|
|
},
|
|
},
|
|
{
|
|
name: "passthrough restriction single output",
|
|
fn: restrictionPassthrough(),
|
|
inputCoins: sdk.NewCoins(newFooCoin(10)),
|
|
outputs: []banktypes.Output{{Address: toAddr1Str, Coins: sdk.NewCoins(newFooCoin(10))}},
|
|
outputAddrs: []sdk.AccAddress{toAddr1},
|
|
expArgs: []*restrictionArgs{
|
|
{
|
|
ctx: suite.ctx,
|
|
fromAddr: fromAddr,
|
|
toAddr: toAddr1,
|
|
amt: sdk.NewCoins(newFooCoin(10)),
|
|
},
|
|
},
|
|
expBals: expBals{
|
|
from: sdk.NewCoins(newFooCoin(985), newBarCoin(500)),
|
|
to1: sdk.NewCoins(newFooCoin(15)),
|
|
to2: sdk.Coins{},
|
|
},
|
|
},
|
|
{
|
|
name: "new to restriction single output",
|
|
fn: restrictionNewTo(toAddr2),
|
|
inputCoins: sdk.NewCoins(newFooCoin(26)),
|
|
outputs: []banktypes.Output{{Address: toAddr1Str, Coins: sdk.NewCoins(newFooCoin(26))}},
|
|
outputAddrs: []sdk.AccAddress{toAddr2},
|
|
expArgs: []*restrictionArgs{
|
|
{
|
|
ctx: suite.ctx,
|
|
fromAddr: fromAddr,
|
|
toAddr: toAddr1,
|
|
amt: sdk.NewCoins(newFooCoin(26)),
|
|
},
|
|
},
|
|
expBals: expBals{
|
|
from: sdk.NewCoins(newFooCoin(959), newBarCoin(500)),
|
|
to1: sdk.NewCoins(newFooCoin(15)),
|
|
to2: sdk.NewCoins(newFooCoin(26)),
|
|
},
|
|
},
|
|
{
|
|
name: "error restriction single output",
|
|
fn: restrictionError("restriction test error"),
|
|
inputCoins: sdk.NewCoins(newBarCoin(88)),
|
|
outputs: []banktypes.Output{{Address: toAddr1Str, Coins: sdk.NewCoins(newBarCoin(88))}},
|
|
outputAddrs: []sdk.AccAddress{},
|
|
expArgs: []*restrictionArgs{
|
|
{
|
|
ctx: suite.ctx,
|
|
fromAddr: fromAddr,
|
|
toAddr: toAddr1,
|
|
amt: sdk.NewCoins(newBarCoin(88)),
|
|
},
|
|
},
|
|
expErr: "restriction test error",
|
|
expBals: expBals{
|
|
from: sdk.NewCoins(newFooCoin(959), newBarCoin(500)),
|
|
to1: sdk.NewCoins(newFooCoin(15)),
|
|
to2: sdk.NewCoins(newFooCoin(26)),
|
|
},
|
|
},
|
|
{
|
|
name: "passthrough restriction two outputs",
|
|
fn: restrictionPassthrough(),
|
|
inputCoins: sdk.NewCoins(newFooCoin(11), newBarCoin(12)),
|
|
outputs: []banktypes.Output{
|
|
{Address: toAddr1Str, Coins: sdk.NewCoins(newFooCoin(11))},
|
|
{Address: toAddr2Str, Coins: sdk.NewCoins(newBarCoin(12))},
|
|
},
|
|
outputAddrs: []sdk.AccAddress{toAddr1, toAddr2},
|
|
expArgs: []*restrictionArgs{
|
|
{
|
|
ctx: suite.ctx,
|
|
fromAddr: fromAddr,
|
|
toAddr: toAddr1,
|
|
amt: sdk.NewCoins(newFooCoin(11)),
|
|
},
|
|
{
|
|
ctx: suite.ctx,
|
|
fromAddr: fromAddr,
|
|
toAddr: toAddr2,
|
|
amt: sdk.NewCoins(newBarCoin(12)),
|
|
},
|
|
},
|
|
expBals: expBals{
|
|
from: sdk.NewCoins(newFooCoin(948), newBarCoin(488)),
|
|
to1: sdk.NewCoins(newFooCoin(26)),
|
|
to2: sdk.NewCoins(newFooCoin(26), newBarCoin(12)),
|
|
},
|
|
},
|
|
{
|
|
name: "error restriction two outputs error on second",
|
|
fn: restrictionError("", "second restriction error"),
|
|
inputCoins: sdk.NewCoins(newFooCoin(44)),
|
|
outputs: []banktypes.Output{
|
|
{Address: toAddr1Str, Coins: sdk.NewCoins(newFooCoin(12))},
|
|
{Address: toAddr2Str, Coins: sdk.NewCoins(newFooCoin(32))},
|
|
},
|
|
outputAddrs: []sdk.AccAddress{toAddr1},
|
|
expArgs: []*restrictionArgs{
|
|
{
|
|
ctx: suite.ctx,
|
|
fromAddr: fromAddr,
|
|
toAddr: toAddr1,
|
|
amt: sdk.NewCoins(newFooCoin(12)),
|
|
},
|
|
{
|
|
ctx: suite.ctx,
|
|
fromAddr: fromAddr,
|
|
toAddr: toAddr2,
|
|
amt: sdk.NewCoins(newFooCoin(32)),
|
|
},
|
|
},
|
|
expErr: "second restriction error",
|
|
expBals: expBals{
|
|
from: sdk.NewCoins(newFooCoin(948), newBarCoin(488)),
|
|
to1: sdk.NewCoins(newFooCoin(26)),
|
|
to2: sdk.NewCoins(newFooCoin(26), newBarCoin(12)),
|
|
},
|
|
},
|
|
{
|
|
name: "new to restriction two outputs",
|
|
fn: restrictionNewTo(toAddr2, toAddr1),
|
|
inputCoins: sdk.NewCoins(newBarCoin(35)),
|
|
outputs: []banktypes.Output{
|
|
{Address: toAddr1Str, Coins: sdk.NewCoins(newBarCoin(10))},
|
|
{Address: toAddr2Str, Coins: sdk.NewCoins(newBarCoin(25))},
|
|
},
|
|
outputAddrs: []sdk.AccAddress{toAddr1, toAddr2},
|
|
expArgs: []*restrictionArgs{
|
|
{
|
|
ctx: suite.ctx,
|
|
fromAddr: fromAddr,
|
|
toAddr: toAddr1,
|
|
amt: sdk.NewCoins(newBarCoin(10)),
|
|
},
|
|
{
|
|
ctx: suite.ctx,
|
|
fromAddr: fromAddr,
|
|
toAddr: toAddr2,
|
|
amt: sdk.NewCoins(newBarCoin(25)),
|
|
},
|
|
},
|
|
expBals: expBals{
|
|
from: sdk.NewCoins(newFooCoin(948), newBarCoin(453)),
|
|
to1: sdk.NewCoins(newFooCoin(26), newBarCoin(25)),
|
|
to2: sdk.NewCoins(newFooCoin(26), newBarCoin(22)),
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
suite.Run(tc.name, func() {
|
|
existingSendRestrictionFn := suite.bankKeeper.GetSendRestrictionFn()
|
|
defer suite.bankKeeper.SetSendRestriction(existingSendRestrictionFn)
|
|
actualRestrictionArgs = nil
|
|
suite.bankKeeper.SetSendRestriction(tc.fn)
|
|
ctx := suite.ctx
|
|
input := banktypes.Input{
|
|
Address: fromStrAddr,
|
|
Coins: tc.inputCoins,
|
|
}
|
|
|
|
var err error
|
|
testFunc := func() {
|
|
err = suite.bankKeeper.InputOutputCoins(ctx, input, tc.outputs)
|
|
}
|
|
suite.Require().NotPanics(testFunc, "InputOutputCoins")
|
|
if len(tc.expErr) > 0 {
|
|
suite.Assert().EqualError(err, tc.expErr, "InputOutputCoins error")
|
|
} else {
|
|
suite.Assert().NoError(err, "InputOutputCoins error")
|
|
}
|
|
if len(tc.expArgs) > 0 {
|
|
for i, expArgs := range tc.expArgs {
|
|
suite.Assert().Equal(expArgs.ctx, actualRestrictionArgs[i].ctx, "[%d] ctx provided to restriction", i)
|
|
suite.Assert().Equal(expArgs.fromAddr, actualRestrictionArgs[i].fromAddr, "[%d] fromAddr provided to restriction", i)
|
|
suite.Assert().Equal(expArgs.toAddr, actualRestrictionArgs[i].toAddr, "[%d] toAddr provided to restriction", i)
|
|
suite.Assert().Equal(expArgs.amt.String(), actualRestrictionArgs[i].amt.String(), "[%d] amt provided to restriction", i)
|
|
}
|
|
} else {
|
|
suite.Assert().Nil(actualRestrictionArgs, "args provided to a restriction")
|
|
}
|
|
fromBal := suite.bankKeeper.GetAllBalances(ctx, fromAddr)
|
|
suite.Assert().Equal(tc.expBals.from.String(), fromBal.String(), "fromAddr balance")
|
|
to1Bal := suite.bankKeeper.GetAllBalances(ctx, toAddr1)
|
|
suite.Assert().Equal(tc.expBals.to1.String(), to1Bal.String(), "toAddr1 balance")
|
|
to2Bal := suite.bankKeeper.GetAllBalances(ctx, toAddr2)
|
|
suite.Assert().Equal(tc.expBals.to2.String(), to2Bal.String(), "toAddr2 balance")
|
|
})
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestSendCoins() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
balances := sdk.NewCoins(newFooCoin(100), newBarCoin(50))
|
|
|
|
acc0 := authtypes.NewBaseAccountWithAddress(accAddrs[0])
|
|
|
|
suite.mockFundAccount(accAddrs[1])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[1], balances))
|
|
|
|
sendAmt := sdk.NewCoins(newFooCoin(50), newBarCoin(25))
|
|
suite.authKeeper.EXPECT().GetAccount(suite.ctx, accAddrs[0]).Return(acc0)
|
|
require.Error(suite.bankKeeper.SendCoins(ctx, accAddrs[0], accAddrs[1], sendAmt))
|
|
|
|
suite.mockFundAccount(accAddrs[0])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], balances))
|
|
suite.mockSendCoins(ctx, acc0, accAddrs[1])
|
|
require.NoError(suite.bankKeeper.SendCoins(ctx, accAddrs[0], accAddrs[1], sendAmt))
|
|
|
|
acc1Balances := suite.bankKeeper.GetAllBalances(ctx, accAddrs[0])
|
|
expected := sdk.NewCoins(newFooCoin(50), newBarCoin(25))
|
|
require.Equal(expected, acc1Balances)
|
|
|
|
acc2Balances := suite.bankKeeper.GetAllBalances(ctx, accAddrs[1])
|
|
expected = sdk.NewCoins(newFooCoin(150), newBarCoin(75))
|
|
require.Equal(expected, acc2Balances)
|
|
|
|
// we sent all foo coins to acc2, so foo balance should be deleted for acc1 and bar should be still there
|
|
var coins []sdk.Coin
|
|
suite.bankKeeper.IterateAccountBalances(ctx, accAddrs[0], func(c sdk.Coin) (stop bool) {
|
|
coins = append(coins, c)
|
|
return true
|
|
})
|
|
require.Len(coins, 1)
|
|
require.Equal(newBarCoin(25), coins[0], "expected only bar coins in the account balance, got: %v", coins)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestSendCoinsWithRestrictions() {
|
|
type restrictionArgs struct {
|
|
ctx context.Context
|
|
fromAddr sdk.AccAddress
|
|
toAddr sdk.AccAddress
|
|
amt sdk.Coins
|
|
}
|
|
var actualRestrictionArgs *restrictionArgs
|
|
restrictionError := func(message string) banktypes.SendRestrictionFn {
|
|
return func(ctx context.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) (sdk.AccAddress, error) {
|
|
actualRestrictionArgs = &restrictionArgs{
|
|
ctx: ctx,
|
|
fromAddr: fromAddr,
|
|
toAddr: toAddr,
|
|
amt: amt,
|
|
}
|
|
return nil, errors.New(message)
|
|
}
|
|
}
|
|
restrictionPassthrough := func() banktypes.SendRestrictionFn {
|
|
return func(ctx context.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) (sdk.AccAddress, error) {
|
|
actualRestrictionArgs = &restrictionArgs{
|
|
ctx: ctx,
|
|
fromAddr: fromAddr,
|
|
toAddr: toAddr,
|
|
amt: amt,
|
|
}
|
|
return toAddr, nil
|
|
}
|
|
}
|
|
restrictionNewTo := func(newToAddr sdk.AccAddress) banktypes.SendRestrictionFn {
|
|
return func(ctx context.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) (sdk.AccAddress, error) {
|
|
actualRestrictionArgs = &restrictionArgs{
|
|
ctx: ctx,
|
|
fromAddr: fromAddr,
|
|
toAddr: toAddr,
|
|
amt: amt,
|
|
}
|
|
return newToAddr, nil
|
|
}
|
|
}
|
|
type expBals struct {
|
|
from sdk.Coins
|
|
to1 sdk.Coins
|
|
to2 sdk.Coins
|
|
}
|
|
|
|
setupCtx := suite.ctx
|
|
balances := sdk.NewCoins(newFooCoin(1000), newBarCoin(500))
|
|
fromAddr := accAddrs[0]
|
|
fromAcc := authtypes.NewBaseAccountWithAddress(fromAddr)
|
|
toAddr1 := accAddrs[1]
|
|
toAddr2 := accAddrs[2]
|
|
|
|
suite.mockFundAccount(accAddrs[0])
|
|
suite.Require().NoError(banktestutil.FundAccount(setupCtx, suite.bankKeeper, accAddrs[0], balances))
|
|
|
|
tests := []struct {
|
|
name string
|
|
fn banktypes.SendRestrictionFn
|
|
toAddr sdk.AccAddress
|
|
finalAddr sdk.AccAddress
|
|
amt sdk.Coins
|
|
expArgs *restrictionArgs
|
|
expErr string
|
|
expBals expBals
|
|
}{
|
|
{
|
|
name: "nil restriction",
|
|
fn: nil,
|
|
toAddr: toAddr1,
|
|
finalAddr: toAddr1,
|
|
amt: sdk.NewCoins(newFooCoin(5)),
|
|
expArgs: nil,
|
|
expBals: expBals{
|
|
from: sdk.NewCoins(newFooCoin(995), newBarCoin(500)),
|
|
to1: sdk.NewCoins(newFooCoin(5)),
|
|
to2: sdk.Coins{},
|
|
},
|
|
},
|
|
{
|
|
name: "passthrough restriction",
|
|
fn: restrictionPassthrough(),
|
|
toAddr: toAddr1,
|
|
finalAddr: toAddr1,
|
|
amt: sdk.NewCoins(newFooCoin(10)),
|
|
expArgs: &restrictionArgs{
|
|
ctx: suite.ctx,
|
|
fromAddr: fromAddr,
|
|
toAddr: toAddr1,
|
|
amt: sdk.NewCoins(newFooCoin(10)),
|
|
},
|
|
expBals: expBals{
|
|
from: sdk.NewCoins(newFooCoin(985), newBarCoin(500)),
|
|
to1: sdk.NewCoins(newFooCoin(15)),
|
|
to2: sdk.Coins{},
|
|
},
|
|
},
|
|
{
|
|
name: "new to addr restriction",
|
|
fn: restrictionNewTo(toAddr2),
|
|
toAddr: toAddr1,
|
|
finalAddr: toAddr2,
|
|
amt: sdk.NewCoins(newBarCoin(27)),
|
|
expArgs: &restrictionArgs{
|
|
ctx: suite.ctx,
|
|
fromAddr: fromAddr,
|
|
toAddr: toAddr1,
|
|
amt: sdk.NewCoins(newBarCoin(27)),
|
|
},
|
|
expBals: expBals{
|
|
from: sdk.NewCoins(newFooCoin(985), newBarCoin(473)),
|
|
to1: sdk.NewCoins(newFooCoin(15)),
|
|
to2: sdk.NewCoins(newBarCoin(27)),
|
|
},
|
|
},
|
|
{
|
|
name: "restriction returns error",
|
|
fn: restrictionError("test restriction error"),
|
|
toAddr: toAddr1,
|
|
finalAddr: toAddr1,
|
|
amt: sdk.NewCoins(newFooCoin(100), newBarCoin(200)),
|
|
expArgs: &restrictionArgs{
|
|
ctx: suite.ctx,
|
|
fromAddr: fromAddr,
|
|
toAddr: toAddr1,
|
|
amt: sdk.NewCoins(newFooCoin(100), newBarCoin(200)),
|
|
},
|
|
expErr: "test restriction error",
|
|
expBals: expBals{
|
|
from: sdk.NewCoins(newFooCoin(985), newBarCoin(473)),
|
|
to1: sdk.NewCoins(newFooCoin(15)),
|
|
to2: sdk.NewCoins(newBarCoin(27)),
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
suite.Run(tc.name, func() {
|
|
existingSendRestrictionFn := suite.bankKeeper.GetSendRestrictionFn()
|
|
defer suite.bankKeeper.SetSendRestriction(existingSendRestrictionFn)
|
|
actualRestrictionArgs = nil
|
|
suite.bankKeeper.SetSendRestriction(tc.fn)
|
|
ctx := suite.ctx
|
|
if len(tc.expErr) == 0 {
|
|
suite.mockSendCoins(ctx, fromAcc, tc.finalAddr)
|
|
}
|
|
var err error
|
|
testFunc := func() {
|
|
err = suite.bankKeeper.SendCoins(ctx, fromAddr, tc.toAddr, tc.amt)
|
|
}
|
|
suite.Require().NotPanics(testFunc, "SendCoins")
|
|
if len(tc.expErr) > 0 {
|
|
suite.Assert().EqualError(err, tc.expErr, "SendCoins error")
|
|
} else {
|
|
suite.Assert().NoError(err, "SendCoins error")
|
|
}
|
|
if tc.expArgs != nil {
|
|
suite.Assert().Equal(tc.expArgs.ctx, actualRestrictionArgs.ctx, "ctx provided to restriction")
|
|
suite.Assert().Equal(tc.expArgs.fromAddr, actualRestrictionArgs.fromAddr, "fromAddr provided to restriction")
|
|
suite.Assert().Equal(tc.expArgs.toAddr, actualRestrictionArgs.toAddr, "toAddr provided to restriction")
|
|
suite.Assert().Equal(tc.expArgs.amt.String(), actualRestrictionArgs.amt.String(), "amt provided to restriction")
|
|
} else {
|
|
suite.Assert().Nil(actualRestrictionArgs, "args provided to a restriction")
|
|
}
|
|
fromBal := suite.bankKeeper.GetAllBalances(ctx, fromAddr)
|
|
suite.Assert().Equal(tc.expBals.from.String(), fromBal.String(), "fromAddr balance")
|
|
to1Bal := suite.bankKeeper.GetAllBalances(ctx, toAddr1)
|
|
suite.Assert().Equal(tc.expBals.to1.String(), to1Bal.String(), "toAddr1 balance")
|
|
to2Bal := suite.bankKeeper.GetAllBalances(ctx, toAddr2)
|
|
suite.Assert().Equal(tc.expBals.to2.String(), to2Bal.String(), "toAddr2 balance")
|
|
})
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestSendCoins_Invalid_SendLockedCoins() {
|
|
balances := sdk.NewCoins(newFooCoin(50))
|
|
|
|
now := time.Now()
|
|
endTime := now.Add(24 * time.Hour)
|
|
|
|
origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100))
|
|
sendCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50))
|
|
|
|
acc0 := authtypes.NewBaseAccountWithAddress(accAddrs[0])
|
|
vacc, err := vesting.NewContinuousVestingAccount(acc0, origCoins, now.Unix(), endTime.Unix())
|
|
suite.Require().NoError(err)
|
|
|
|
suite.mockFundAccount(accAddrs[1])
|
|
suite.Require().NoError(banktestutil.FundAccount(suite.ctx, suite.bankKeeper, accAddrs[1], balances))
|
|
|
|
suite.authKeeper.EXPECT().GetAccount(suite.ctx, accAddrs[0]).Return(vacc)
|
|
suite.Require().Error(suite.bankKeeper.SendCoins(suite.ctx, accAddrs[0], accAddrs[1], sendCoins))
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestSendCoins_Invalid_NoSpendableCoins() {
|
|
coin := sdk.NewInt64Coin("stake", 10)
|
|
coins := sdk.NewCoins(coin)
|
|
balances := coins
|
|
|
|
now := time.Now()
|
|
endTime := now.Add(24 * time.Hour)
|
|
|
|
origCoins := coins
|
|
sendCoins := coins
|
|
|
|
acc0 := authtypes.NewBaseAccountWithAddress(accAddrs[0])
|
|
suite.mockFundAccount(accAddrs[0])
|
|
suite.Require().NoError(banktestutil.FundAccount(suite.ctx, suite.bankKeeper, accAddrs[0], balances))
|
|
vacc, err := vesting.NewContinuousVestingAccount(acc0, origCoins, now.Unix(), endTime.Unix())
|
|
suite.Require().NoError(err)
|
|
|
|
suite.authKeeper.EXPECT().GetAccount(suite.ctx, accAddrs[0]).Return(vacc)
|
|
e := errorsmod.Wrapf(
|
|
sdkerrors.ErrInsufficientFunds,
|
|
"spendable balance 0stake is smaller than %s",
|
|
coin,
|
|
)
|
|
suite.Require().EqualError(suite.bankKeeper.SendCoins(suite.ctx, accAddrs[0], accAddrs[1], sendCoins), e.Error())
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestValidateBalance() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
now := time.Now()
|
|
endTime := now.Add(24 * time.Hour)
|
|
|
|
acc0 := authtypes.NewBaseAccountWithAddress(accAddrs[0])
|
|
suite.authKeeper.EXPECT().GetAccount(suite.ctx, accAddrs[0]).Return(nil)
|
|
require.Error(suite.bankKeeper.ValidateBalance(ctx, accAddrs[0]))
|
|
|
|
balances := sdk.NewCoins(newFooCoin(100))
|
|
suite.mockFundAccount(accAddrs[0])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], balances))
|
|
|
|
suite.mockValidateBalance(acc0)
|
|
require.NoError(suite.bankKeeper.ValidateBalance(ctx, accAddrs[0]))
|
|
|
|
acc1 := authtypes.NewBaseAccountWithAddress(accAddrs[1])
|
|
vacc, err := vesting.NewContinuousVestingAccount(acc1, balances.Add(balances...), now.Unix(), endTime.Unix())
|
|
suite.Require().NoError(err)
|
|
|
|
suite.mockFundAccount(accAddrs[1])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[1], balances))
|
|
|
|
suite.mockValidateBalance(vacc)
|
|
require.Error(suite.bankKeeper.ValidateBalance(ctx, accAddrs[1]))
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestSendEnabled() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
enabled := true
|
|
params := banktypes.DefaultParams()
|
|
require.Equal(enabled, params.DefaultSendEnabled)
|
|
|
|
require.NoError(suite.bankKeeper.SetParams(ctx, params))
|
|
|
|
bondCoin := sdk.NewCoin(sdk.DefaultBondDenom, math.OneInt())
|
|
fooCoin := sdk.NewCoin("foocoin", math.OneInt())
|
|
barCoin := sdk.NewCoin("barcoin", math.OneInt())
|
|
|
|
// assert with default (all denom) send enabled both Bar and Bond Denom are enabled
|
|
require.Equal(enabled, suite.bankKeeper.IsSendEnabledCoin(ctx, barCoin))
|
|
require.Equal(enabled, suite.bankKeeper.IsSendEnabledCoin(ctx, bondCoin))
|
|
|
|
// Both coins should be send enabled.
|
|
err := suite.bankKeeper.IsSendEnabledCoins(ctx, fooCoin, bondCoin)
|
|
require.NoError(err)
|
|
|
|
// Set default send_enabled to !enabled, add a foodenom that overrides default as enabled
|
|
params.DefaultSendEnabled = !enabled
|
|
require.NoError(suite.bankKeeper.SetParams(ctx, params))
|
|
suite.bankKeeper.SetSendEnabled(ctx, fooCoin.Denom, enabled)
|
|
|
|
// Expect our specific override to be enabled, others to be !enabled.
|
|
require.Equal(enabled, suite.bankKeeper.IsSendEnabledCoin(ctx, fooCoin))
|
|
require.Equal(!enabled, suite.bankKeeper.IsSendEnabledCoin(ctx, barCoin))
|
|
require.Equal(!enabled, suite.bankKeeper.IsSendEnabledCoin(ctx, bondCoin))
|
|
|
|
// Foo coin should be send enabled.
|
|
err = suite.bankKeeper.IsSendEnabledCoins(ctx, fooCoin)
|
|
require.NoError(err)
|
|
|
|
// Expect an error when one coin is not send enabled.
|
|
err = suite.bankKeeper.IsSendEnabledCoins(ctx, fooCoin, bondCoin)
|
|
require.Error(err)
|
|
|
|
// Expect an error when all coins are not send enabled.
|
|
err = suite.bankKeeper.IsSendEnabledCoins(ctx, bondCoin, barCoin)
|
|
require.Error(err)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestHasBalance() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
|
|
balances := sdk.NewCoins(newFooCoin(100))
|
|
require.False(suite.bankKeeper.HasBalance(ctx, accAddrs[0], newFooCoin(99)))
|
|
|
|
suite.mockFundAccount(accAddrs[0])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], balances))
|
|
require.False(suite.bankKeeper.HasBalance(ctx, accAddrs[0], newFooCoin(101)))
|
|
require.True(suite.bankKeeper.HasBalance(ctx, accAddrs[0], newFooCoin(100)))
|
|
require.True(suite.bankKeeper.HasBalance(ctx, accAddrs[0], newFooCoin(1)))
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestMsgSendEvents() {
|
|
require := suite.Require()
|
|
|
|
acc0 := authtypes.NewBaseAccountWithAddress(accAddrs[0])
|
|
|
|
acc0StrAddr, err := suite.addrCdc.BytesToString(accAddrs[0])
|
|
suite.Require().NoError(err)
|
|
acc1StrAddr, err := suite.addrCdc.BytesToString(accAddrs[1])
|
|
suite.Require().NoError(err)
|
|
|
|
newCoins := sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50))
|
|
suite.mockFundAccount(accAddrs[0])
|
|
require.NoError(banktestutil.FundAccount(suite.ctx, suite.bankKeeper, accAddrs[0], newCoins))
|
|
|
|
suite.mockSendCoins(suite.ctx, acc0, accAddrs[1])
|
|
require.NoError(suite.bankKeeper.SendCoins(suite.ctx, accAddrs[0], accAddrs[1], newCoins))
|
|
event1 := coreevent.Event{
|
|
Type: banktypes.EventTypeTransfer,
|
|
Attributes: func() ([]coreevent.Attribute, error) {
|
|
return []coreevent.Attribute{
|
|
{Key: banktypes.AttributeKeyRecipient, Value: acc1StrAddr},
|
|
{Key: banktypes.AttributeKeySender, Value: acc0StrAddr},
|
|
{Key: sdk.AttributeKeyAmount, Value: newCoins.String()},
|
|
}, nil
|
|
},
|
|
}
|
|
|
|
events := suite.env.EventService().GetEvents(suite.ctx)
|
|
// events are shifted due to the funding account events
|
|
require.Equal(8, len(events))
|
|
require.Equal(event1.Type, events[7].Type)
|
|
attrs1, err := event1.Attributes()
|
|
require.NoError(err)
|
|
|
|
attrs, err := events[7].Attributes()
|
|
require.NoError(err)
|
|
|
|
for i := range attrs1 {
|
|
require.Equal(attrs1[i].Key, attrs[i].Key)
|
|
require.Equal(attrs1[i].Value, attrs[i].Value)
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestMsgMultiSendEvents() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
acc0 := authtypes.NewBaseAccountWithAddress(accAddrs[0])
|
|
|
|
require.NoError(suite.bankKeeper.SetParams(ctx, banktypes.DefaultParams()))
|
|
|
|
acc0StrAddr, err := suite.addrCdc.BytesToString(accAddrs[0])
|
|
suite.Require().NoError(err)
|
|
acc2StrAddr, err := suite.addrCdc.BytesToString(accAddrs[2])
|
|
suite.Require().NoError(err)
|
|
acc3StrAddr, err := suite.addrCdc.BytesToString(accAddrs[3])
|
|
suite.Require().NoError(err)
|
|
|
|
coins := sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50), sdk.NewInt64Coin(barDenom, 100))
|
|
newCoins := sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50))
|
|
newCoins2 := sdk.NewCoins(sdk.NewInt64Coin(barDenom, 100))
|
|
input := banktypes.Input{
|
|
Address: acc0StrAddr,
|
|
Coins: coins,
|
|
}
|
|
outputs := []banktypes.Output{
|
|
{Address: acc2StrAddr, Coins: newCoins},
|
|
{Address: acc3StrAddr, Coins: newCoins2},
|
|
}
|
|
|
|
suite.authKeeper.EXPECT().GetAccount(suite.ctx, accAddrs[0]).Return(acc0)
|
|
require.Error(suite.bankKeeper.InputOutputCoins(ctx, input, outputs))
|
|
|
|
events := suite.env.EventService().GetEvents(suite.ctx)
|
|
require.Equal(0, len(events))
|
|
|
|
// Set addr's coins but not accAddrs[1]'s coins
|
|
suite.mockFundAccount(accAddrs[0])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50), sdk.NewInt64Coin(barDenom, 100))))
|
|
|
|
suite.mockInputOutputCoins([]sdk.AccountI{acc0}, accAddrs[2:4])
|
|
require.NoError(suite.bankKeeper.InputOutputCoins(ctx, input, outputs))
|
|
|
|
events = suite.env.EventService().GetEvents(suite.ctx)
|
|
require.Equal(10, len(events)) // 10 events because account funding causes extra minting + coin_spent + coin_recv events
|
|
|
|
// Set addr's coins and accAddrs[1]'s coins
|
|
suite.mockFundAccount(accAddrs[0])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50))))
|
|
newCoins = sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50))
|
|
|
|
suite.mockFundAccount(accAddrs[0])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], sdk.NewCoins(sdk.NewInt64Coin(barDenom, 100))))
|
|
newCoins2 = sdk.NewCoins(sdk.NewInt64Coin(barDenom, 100))
|
|
|
|
suite.mockInputOutputCoins([]sdk.AccountI{acc0}, accAddrs[2:4])
|
|
require.NoError(suite.bankKeeper.InputOutputCoins(ctx, input, outputs))
|
|
|
|
events = suite.env.EventService().GetEvents(suite.ctx)
|
|
require.Equal(25, len(events)) // 25 due to account funding + coin_spent + coin_recv events
|
|
|
|
event1 := coreevent.Event{
|
|
Type: banktypes.EventTypeTransfer,
|
|
Attributes: func() ([]coreevent.Attribute, error) {
|
|
return []coreevent.Attribute{
|
|
{Key: banktypes.AttributeKeyRecipient, Value: acc2StrAddr},
|
|
{Key: sdk.AttributeKeySender, Value: acc0StrAddr},
|
|
{Key: sdk.AttributeKeyAmount, Value: newCoins.String()},
|
|
}, nil
|
|
},
|
|
}
|
|
|
|
event2 := coreevent.Event{
|
|
Type: banktypes.EventTypeTransfer,
|
|
Attributes: func() ([]coreevent.Attribute, error) {
|
|
attrs := []coreevent.Attribute{
|
|
{Key: banktypes.AttributeKeyRecipient, Value: acc3StrAddr},
|
|
{Key: sdk.AttributeKeySender, Value: acc0StrAddr},
|
|
{Key: sdk.AttributeKeyAmount, Value: newCoins2.String()},
|
|
}
|
|
return attrs, nil
|
|
},
|
|
}
|
|
// events are shifted due to the funding account events
|
|
require.Equal(event1.Type, events[22].Type)
|
|
attrs1, err := event1.Attributes()
|
|
require.NoError(err)
|
|
|
|
attrs, err := events[22].Attributes()
|
|
require.NoError(err)
|
|
|
|
for i := range attrs1 {
|
|
require.Equal(attrs1[i].Key, attrs[i].Key)
|
|
require.Equal(attrs1[i].Value, attrs[i].Value)
|
|
}
|
|
require.Equal(event2.Type, events[24].Type)
|
|
attrs2, err := event2.Attributes()
|
|
require.NoError(err)
|
|
|
|
attrs, err = events[24].Attributes()
|
|
require.NoError(err)
|
|
|
|
for i := range attrs2 {
|
|
require.Equal(attrs2[i].Key, attrs[i].Key)
|
|
require.Equal(attrs2[i].Value, attrs[i].Value)
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestSpendableCoins() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
now := time.Now()
|
|
endTime := now.Add(24 * time.Hour)
|
|
|
|
origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100))
|
|
lockedCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50))
|
|
|
|
acc0 := authtypes.NewBaseAccountWithAddress(accAddrs[0])
|
|
acc1 := authtypes.NewBaseAccountWithAddress(accAddrs[1])
|
|
vacc, err := vesting.NewContinuousVestingAccount(acc0, origCoins, now.Unix(), endTime.Unix())
|
|
suite.Require().NoError(err)
|
|
|
|
suite.mockFundAccount(accAddrs[0])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], origCoins))
|
|
|
|
suite.mockFundAccount(accAddrs[1])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[1], origCoins))
|
|
|
|
suite.mockSpendableCoins(ctx, acc1)
|
|
require.Equal(origCoins, suite.bankKeeper.SpendableCoins(ctx, accAddrs[1]))
|
|
|
|
suite.mockSpendableCoins(ctx, acc1)
|
|
require.Equal(origCoins[0], suite.bankKeeper.SpendableCoin(ctx, accAddrs[1], "stake"))
|
|
|
|
ctx = ctx.WithHeaderInfo(header.Info{Time: now.Add(12 * time.Hour)})
|
|
suite.mockSpendableCoins(ctx, vacc)
|
|
require.Equal(origCoins.Sub(lockedCoins...), suite.bankKeeper.SpendableCoins(ctx, accAddrs[0]))
|
|
|
|
suite.mockSpendableCoins(ctx, vacc)
|
|
require.Equal(origCoins.Sub(lockedCoins...)[0], suite.bankKeeper.SpendableCoin(ctx, accAddrs[0], "stake"))
|
|
|
|
acc2 := authtypes.NewBaseAccountWithAddress(accAddrs[2])
|
|
lockedCoins2 := sdk.NewCoins(sdk.NewInt64Coin("stake", 50), sdk.NewInt64Coin("tarp", 40), sdk.NewInt64Coin("rope", 30))
|
|
balanceCoins2 := sdk.NewCoins(sdk.NewInt64Coin("stake", 49), sdk.NewInt64Coin("tarp", 40), sdk.NewInt64Coin("rope", 31), sdk.NewInt64Coin("pole", 20))
|
|
expCoins2 := sdk.NewCoins(sdk.NewInt64Coin("rope", 1), sdk.NewInt64Coin("pole", 20))
|
|
vacc2, err := vesting.NewPermanentLockedAccount(acc2, lockedCoins2)
|
|
suite.Require().NoError(err)
|
|
|
|
// Go back to the suite's context since mockFundAccount uses that; FundAccount would fail for bad mocking otherwise.
|
|
ctx = suite.ctx
|
|
suite.mockFundAccount(accAddrs[2])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[2], balanceCoins2))
|
|
suite.mockSpendableCoins(ctx, vacc2)
|
|
require.Equal(expCoins2, suite.bankKeeper.SpendableCoins(ctx, accAddrs[2]))
|
|
suite.mockSpendableCoins(ctx, vacc2)
|
|
require.Equal(sdk.NewInt64Coin("stake", 0), suite.bankKeeper.SpendableCoin(ctx, accAddrs[2], "stake"))
|
|
suite.mockSpendableCoins(ctx, vacc2)
|
|
require.Equal(sdk.NewInt64Coin("tarp", 0), suite.bankKeeper.SpendableCoin(ctx, accAddrs[2], "tarp"))
|
|
suite.mockSpendableCoins(ctx, vacc2)
|
|
require.Equal(sdk.NewInt64Coin("rope", 1), suite.bankKeeper.SpendableCoin(ctx, accAddrs[2], "rope"))
|
|
suite.mockSpendableCoins(ctx, vacc2)
|
|
require.Equal(sdk.NewInt64Coin("pole", 20), suite.bankKeeper.SpendableCoin(ctx, accAddrs[2], "pole"))
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestVestingAccountSend() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
now := time.Now()
|
|
endTime := now.Add(24 * time.Hour)
|
|
|
|
origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100))
|
|
sendCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50))
|
|
|
|
acc0 := authtypes.NewBaseAccountWithAddress(accAddrs[0])
|
|
vacc, err := vesting.NewContinuousVestingAccount(acc0, origCoins, now.Unix(), endTime.Unix())
|
|
suite.Require().NoError(err)
|
|
|
|
suite.mockFundAccount(accAddrs[0])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], origCoins))
|
|
|
|
// require that no coins be sendable at the beginning of the vesting schedule
|
|
suite.authKeeper.EXPECT().GetAccount(ctx, accAddrs[0]).Return(vacc)
|
|
require.Error(suite.bankKeeper.SendCoins(ctx, accAddrs[0], accAddrs[1], sendCoins))
|
|
|
|
// receive some coins
|
|
suite.mockFundAccount(accAddrs[0])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], sendCoins))
|
|
// require that all vested coins are spendable plus any received
|
|
ctx = ctx.WithHeaderInfo(header.Info{Time: now.Add(12 * time.Hour)})
|
|
suite.mockSendCoins(ctx, vacc, accAddrs[1])
|
|
require.NoError(suite.bankKeeper.SendCoins(ctx, accAddrs[0], accAddrs[1], sendCoins))
|
|
require.Equal(origCoins, suite.bankKeeper.GetAllBalances(ctx, accAddrs[0]))
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestPeriodicVestingAccountSend() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
now := time.Now()
|
|
origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100))
|
|
sendCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50))
|
|
|
|
periods := vesting.Periods{
|
|
vesting.Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin("stake", 50)}},
|
|
vesting.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin("stake", 25)}},
|
|
vesting.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin("stake", 25)}},
|
|
}
|
|
|
|
acc0 := authtypes.NewBaseAccountWithAddress(accAddrs[0])
|
|
vacc, err := vesting.NewPeriodicVestingAccount(acc0, origCoins, now.Unix(), periods)
|
|
suite.Require().NoError(err)
|
|
|
|
suite.mockFundAccount(accAddrs[0])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], origCoins))
|
|
|
|
// require that no coins be sendable at the beginning of the vesting schedule
|
|
suite.authKeeper.EXPECT().GetAccount(ctx, accAddrs[0]).Return(vacc)
|
|
require.Error(suite.bankKeeper.SendCoins(ctx, accAddrs[0], accAddrs[1], sendCoins))
|
|
|
|
// receive some coins
|
|
suite.mockFundAccount(accAddrs[0])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], sendCoins))
|
|
|
|
// require that all vested coins are spendable plus any received
|
|
ctx = ctx.WithHeaderInfo(header.Info{Time: now.Add(12 * time.Hour)})
|
|
suite.mockSendCoins(ctx, vacc, accAddrs[1])
|
|
require.NoError(suite.bankKeeper.SendCoins(ctx, accAddrs[0], accAddrs[1], sendCoins))
|
|
require.Equal(origCoins, suite.bankKeeper.GetAllBalances(ctx, accAddrs[0]))
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestVestingAccountReceive() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
now := time.Now()
|
|
endTime := now.Add(24 * time.Hour)
|
|
|
|
origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100))
|
|
sendCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50))
|
|
|
|
acc0 := authtypes.NewBaseAccountWithAddress(accAddrs[0])
|
|
acc1 := authtypes.NewBaseAccountWithAddress(accAddrs[1])
|
|
vacc, err := vesting.NewContinuousVestingAccount(acc0, origCoins, now.Unix(), endTime.Unix())
|
|
suite.Require().NoError(err)
|
|
|
|
suite.mockFundAccount(accAddrs[0])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], origCoins))
|
|
|
|
suite.mockFundAccount(accAddrs[1])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[1], origCoins))
|
|
|
|
// send some coins to the vesting account
|
|
suite.mockSendCoins(ctx, acc1, accAddrs[0])
|
|
require.NoError(suite.bankKeeper.SendCoins(ctx, accAddrs[1], accAddrs[0], sendCoins))
|
|
|
|
// require the coins are spendable
|
|
balances := suite.bankKeeper.GetAllBalances(ctx, accAddrs[0])
|
|
require.Equal(origCoins.Add(sendCoins...), balances)
|
|
require.Equal(balances.Sub(vacc.LockedCoins(now)...), sendCoins)
|
|
|
|
// require coins are spendable plus any that have vested
|
|
require.Equal(balances.Sub(vacc.LockedCoins(now.Add(12*time.Hour))...), origCoins)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestPeriodicVestingAccountReceive() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
now := time.Now()
|
|
|
|
origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100))
|
|
sendCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50))
|
|
|
|
acc0 := authtypes.NewBaseAccountWithAddress(accAddrs[0])
|
|
acc1 := authtypes.NewBaseAccountWithAddress(accAddrs[1])
|
|
periods := vesting.Periods{
|
|
vesting.Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin("stake", 50)}},
|
|
vesting.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin("stake", 25)}},
|
|
vesting.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin("stake", 25)}},
|
|
}
|
|
|
|
vacc, err := vesting.NewPeriodicVestingAccount(acc0, origCoins, now.Unix(), periods)
|
|
suite.Require().NoError(err)
|
|
|
|
suite.mockFundAccount(accAddrs[0])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], origCoins))
|
|
|
|
suite.mockFundAccount(accAddrs[1])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[1], origCoins))
|
|
|
|
// send some coins to the vesting account
|
|
suite.mockSendCoins(ctx, acc1, accAddrs[0])
|
|
require.NoError(suite.bankKeeper.SendCoins(ctx, accAddrs[1], accAddrs[0], sendCoins))
|
|
|
|
// require the coins are spendable
|
|
balances := suite.bankKeeper.GetAllBalances(ctx, accAddrs[0])
|
|
require.Equal(origCoins.Add(sendCoins...), balances)
|
|
require.Equal(balances.Sub(vacc.LockedCoins(now)...), sendCoins)
|
|
|
|
// require coins are spendable plus any that have vested
|
|
require.Equal(balances.Sub(vacc.LockedCoins(now.Add(12*time.Hour))...), origCoins)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestDelegateCoins() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
now := time.Now()
|
|
endTime := now.Add(24 * time.Hour)
|
|
|
|
origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100))
|
|
delCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50))
|
|
|
|
acc0 := authtypes.NewBaseAccountWithAddress(accAddrs[0])
|
|
acc1 := authtypes.NewBaseAccountWithAddress(accAddrs[1])
|
|
vacc, err := vesting.NewContinuousVestingAccount(acc0, origCoins, suite.env.HeaderService().HeaderInfo(suite.ctx).Time.Unix(), endTime.Unix())
|
|
suite.Require().NoError(err)
|
|
|
|
suite.mockFundAccount(accAddrs[0])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], origCoins))
|
|
|
|
suite.mockFundAccount(accAddrs[1])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[1], origCoins))
|
|
|
|
ctx = ctx.WithHeaderInfo(header.Info{Time: now.Add(12 * time.Hour)})
|
|
|
|
// require the ability for a non-vesting account to delegate
|
|
suite.mockDelegateCoins(ctx, acc1, holderAcc)
|
|
require.NoError(suite.bankKeeper.DelegateCoins(ctx, accAddrs[1], holderAcc.GetAddress(), delCoins))
|
|
require.Equal(origCoins.Sub(delCoins...), suite.bankKeeper.GetAllBalances(ctx, accAddrs[1]))
|
|
require.Equal(delCoins, suite.bankKeeper.GetAllBalances(ctx, holderAcc.GetAddress()))
|
|
|
|
// require the ability for a vesting account to delegate
|
|
suite.mockDelegateCoins(ctx, vacc, holderAcc)
|
|
require.NoError(suite.bankKeeper.DelegateCoins(ctx, accAddrs[0], holderAcc.GetAddress(), delCoins))
|
|
require.Equal(delCoins, suite.bankKeeper.GetAllBalances(ctx, accAddrs[0]))
|
|
|
|
// require that delegated vesting amount is equal to what was delegated with DelegateCoins
|
|
require.Equal(delCoins, vacc.GetDelegatedVesting())
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestDelegateCoins_Invalid() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
|
|
origCoins := sdk.NewCoins(newFooCoin(100))
|
|
delCoins := sdk.NewCoins(newFooCoin(50))
|
|
|
|
suite.authKeeper.EXPECT().GetAccount(ctx, holderAcc.GetAddress()).Return(nil)
|
|
require.Error(suite.bankKeeper.DelegateCoins(ctx, accAddrs[0], holderAcc.GetAddress(), delCoins))
|
|
|
|
suite.authKeeper.EXPECT().GetAccount(ctx, holderAcc.GetAddress()).Return(holderAcc)
|
|
invalidCoins := sdk.Coins{sdk.Coin{Denom: "fooDenom", Amount: math.NewInt(-50)}}
|
|
require.Error(suite.bankKeeper.DelegateCoins(ctx, accAddrs[0], holderAcc.GetAddress(), invalidCoins))
|
|
|
|
suite.authKeeper.EXPECT().GetAccount(ctx, holderAcc.GetAddress()).Return(holderAcc)
|
|
require.Error(suite.bankKeeper.DelegateCoins(ctx, accAddrs[0], holderAcc.GetAddress(), delCoins))
|
|
|
|
suite.authKeeper.EXPECT().GetAccount(ctx, holderAcc.GetAddress()).Return(holderAcc)
|
|
require.Error(suite.bankKeeper.DelegateCoins(ctx, accAddrs[0], holderAcc.GetAddress(), origCoins.Add(origCoins...)))
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestUndelegateCoins() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
now := time.Now()
|
|
endTime := now.Add(24 * time.Hour)
|
|
|
|
origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100))
|
|
delCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50))
|
|
|
|
acc0 := authtypes.NewBaseAccountWithAddress(accAddrs[0])
|
|
acc1 := authtypes.NewBaseAccountWithAddress(accAddrs[1])
|
|
vacc, err := vesting.NewContinuousVestingAccount(acc0, origCoins, suite.env.HeaderService().HeaderInfo(ctx).Time.Unix(), endTime.Unix())
|
|
suite.Require().NoError(err)
|
|
|
|
suite.mockFundAccount(accAddrs[0])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], origCoins))
|
|
|
|
suite.mockFundAccount(accAddrs[1])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[1], origCoins))
|
|
|
|
ctx = ctx.WithHeaderInfo(header.Info{Time: now.Add(12 * time.Hour)})
|
|
|
|
// require the ability for a non-vesting account to delegate
|
|
suite.mockDelegateCoins(ctx, acc1, holderAcc)
|
|
require.NoError(suite.bankKeeper.DelegateCoins(ctx, accAddrs[1], holderAcc.GetAddress(), delCoins))
|
|
|
|
require.Equal(origCoins.Sub(delCoins...), suite.bankKeeper.GetAllBalances(ctx, accAddrs[1]))
|
|
require.Equal(delCoins, suite.bankKeeper.GetAllBalances(ctx, holderAcc.GetAddress()))
|
|
|
|
// require the ability for a non-vesting account to undelegate
|
|
suite.mockUnDelegateCoins(ctx, acc1, holderAcc)
|
|
require.NoError(suite.bankKeeper.UndelegateCoins(ctx, holderAcc.GetAddress(), accAddrs[1], delCoins))
|
|
|
|
require.Equal(origCoins, suite.bankKeeper.GetAllBalances(ctx, accAddrs[1]))
|
|
require.True(suite.bankKeeper.GetAllBalances(ctx, holderAcc.GetAddress()).Empty())
|
|
|
|
// require the ability for a vesting account to delegate
|
|
suite.mockDelegateCoins(ctx, acc0, holderAcc)
|
|
require.NoError(suite.bankKeeper.DelegateCoins(ctx, accAddrs[0], holderAcc.GetAddress(), delCoins))
|
|
|
|
require.Equal(origCoins.Sub(delCoins...), suite.bankKeeper.GetAllBalances(ctx, accAddrs[0]))
|
|
require.Equal(delCoins, suite.bankKeeper.GetAllBalances(ctx, holderAcc.GetAddress()))
|
|
|
|
// require the ability for a vesting account to undelegate
|
|
suite.mockUnDelegateCoins(ctx, vacc, holderAcc)
|
|
require.NoError(suite.bankKeeper.UndelegateCoins(ctx, holderAcc.GetAddress(), accAddrs[0], delCoins))
|
|
|
|
require.Equal(origCoins, suite.bankKeeper.GetAllBalances(ctx, accAddrs[0]))
|
|
require.True(suite.bankKeeper.GetAllBalances(ctx, holderAcc.GetAddress()).Empty())
|
|
|
|
// require that delegated vesting amount is completely empty, since they were completely undelegated
|
|
require.Empty(vacc.GetDelegatedVesting())
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestUndelegateCoins_Invalid() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
|
|
origCoins := sdk.NewCoins(newFooCoin(100))
|
|
delCoins := sdk.NewCoins(newFooCoin(50))
|
|
|
|
acc0 := authtypes.NewBaseAccountWithAddress(accAddrs[0])
|
|
|
|
suite.authKeeper.EXPECT().GetAccount(ctx, holderAcc.GetAddress()).Return(nil)
|
|
require.Error(suite.bankKeeper.UndelegateCoins(ctx, holderAcc.GetAddress(), accAddrs[0], delCoins))
|
|
|
|
suite.mockFundAccount(accAddrs[0])
|
|
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], origCoins))
|
|
|
|
suite.authKeeper.EXPECT().HasAccount(ctx, accAddrs[0]).Return(false)
|
|
suite.mockDelegateCoins(ctx, acc0, holderAcc)
|
|
require.NoError(suite.bankKeeper.DelegateCoins(ctx, accAddrs[0], holderAcc.GetAddress(), delCoins))
|
|
|
|
suite.authKeeper.EXPECT().GetAccount(ctx, holderAcc.GetAddress()).Return(holderAcc)
|
|
suite.authKeeper.EXPECT().GetAccount(ctx, holderAcc.GetAddress()).Return(holderAcc)
|
|
suite.authKeeper.EXPECT().GetAccount(ctx, acc0.GetAddress()).Return(nil)
|
|
require.Error(suite.bankKeeper.UndelegateCoins(ctx, holderAcc.GetAddress(), accAddrs[0], delCoins))
|
|
|
|
suite.authKeeper.EXPECT().GetAccount(ctx, holderAcc.GetAddress()).Return(holderAcc)
|
|
suite.authKeeper.EXPECT().GetAccount(ctx, holderAcc.GetAddress()).Return(holderAcc)
|
|
require.Error(suite.bankKeeper.UndelegateCoins(ctx, holderAcc.GetAddress(), accAddrs[0], origCoins))
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestSetDenomMetaData() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
|
|
metadata := suite.getTestMetadata()
|
|
|
|
for i := range []int{1, 2} {
|
|
suite.bankKeeper.SetDenomMetaData(ctx, metadata[i])
|
|
}
|
|
|
|
actualMetadata, found := suite.bankKeeper.GetDenomMetaData(ctx, metadata[1].Base)
|
|
require.True(found)
|
|
found = suite.bankKeeper.HasDenomMetaData(ctx, metadata[1].Base)
|
|
require.True(found)
|
|
require.Equal(metadata[1].GetBase(), actualMetadata.GetBase())
|
|
require.Equal(metadata[1].GetDisplay(), actualMetadata.GetDisplay())
|
|
require.Equal(metadata[1].GetDescription(), actualMetadata.GetDescription())
|
|
require.Equal(metadata[1].GetDenomUnits()[1].GetDenom(), actualMetadata.GetDenomUnits()[1].GetDenom())
|
|
require.Equal(metadata[1].GetDenomUnits()[1].GetExponent(), actualMetadata.GetDenomUnits()[1].GetExponent())
|
|
require.Equal(metadata[1].GetDenomUnits()[1].GetAliases(), actualMetadata.GetDenomUnits()[1].GetAliases())
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestIterateAllDenomMetaData() {
|
|
ctx := suite.ctx
|
|
require := suite.Require()
|
|
|
|
expectedMetadata := suite.getTestMetadata()
|
|
// set metadata
|
|
for i := range []int{1, 2} {
|
|
suite.bankKeeper.SetDenomMetaData(ctx, expectedMetadata[i])
|
|
}
|
|
// retrieve metadata
|
|
actualMetadata := make([]banktypes.Metadata, 0)
|
|
suite.bankKeeper.IterateAllDenomMetaData(ctx, func(metadata banktypes.Metadata) bool {
|
|
actualMetadata = append(actualMetadata, metadata)
|
|
return false
|
|
})
|
|
// execute checks
|
|
for i := range []int{1, 2} {
|
|
require.Equal(expectedMetadata[i].GetBase(), actualMetadata[i].GetBase())
|
|
require.Equal(expectedMetadata[i].GetDisplay(), actualMetadata[i].GetDisplay())
|
|
require.Equal(expectedMetadata[i].GetDescription(), actualMetadata[i].GetDescription())
|
|
require.Equal(expectedMetadata[i].GetDenomUnits()[1].GetDenom(), actualMetadata[i].GetDenomUnits()[1].GetDenom())
|
|
require.Equal(expectedMetadata[i].GetDenomUnits()[1].GetExponent(), actualMetadata[i].GetDenomUnits()[1].GetExponent())
|
|
require.Equal(expectedMetadata[i].GetDenomUnits()[1].GetAliases(), actualMetadata[i].GetDenomUnits()[1].GetAliases())
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestBalanceTrackingEvents() {
|
|
require := suite.Require()
|
|
|
|
// mint coins
|
|
suite.mockMintCoins(multiPermAcc)
|
|
require.NoError(
|
|
suite.bankKeeper.MintCoins(
|
|
suite.ctx,
|
|
multiPermAcc.Name,
|
|
sdk.NewCoins(sdk.NewCoin("utxo", math.NewInt(100000)))),
|
|
)
|
|
|
|
// send coins to address
|
|
suite.mockSendCoinsFromModuleToAccount(multiPermAcc, accAddrs[0])
|
|
require.NoError(
|
|
suite.bankKeeper.SendCoinsFromModuleToAccount(
|
|
suite.ctx,
|
|
multiPermAcc.Name,
|
|
accAddrs[0],
|
|
sdk.NewCoins(sdk.NewCoin("utxo", math.NewInt(50000))),
|
|
),
|
|
)
|
|
|
|
// burn coins from module account
|
|
suite.mockBurnCoins(multiPermAcc)
|
|
require.NoError(
|
|
suite.bankKeeper.BurnCoins(
|
|
suite.ctx,
|
|
multiPermAcc.GetAddress(),
|
|
sdk.NewCoins(sdk.NewInt64Coin("utxo", 1000)),
|
|
),
|
|
)
|
|
|
|
// process balances and supply from events
|
|
supply := sdk.NewCoins()
|
|
|
|
balances := make(map[string]sdk.Coins)
|
|
|
|
events := suite.env.EventService().GetEvents(suite.ctx)
|
|
|
|
for _, e := range events {
|
|
attributes, err := e.Attributes()
|
|
suite.Require().NoError(err)
|
|
switch e.Type {
|
|
case banktypes.EventTypeCoinBurn:
|
|
burnedCoins, err := sdk.ParseCoinsNormalized(attributes[1].Value)
|
|
require.NoError(err)
|
|
supply = supply.Sub(burnedCoins...)
|
|
|
|
case banktypes.EventTypeCoinMint:
|
|
mintedCoins, err := sdk.ParseCoinsNormalized(attributes[1].Value)
|
|
require.NoError(err)
|
|
supply = supply.Add(mintedCoins...)
|
|
|
|
case banktypes.EventTypeCoinSpent:
|
|
coinsSpent, err := sdk.ParseCoinsNormalized(attributes[1].Value)
|
|
require.NoError(err)
|
|
_, err = suite.addrCdc.StringToBytes(attributes[0].Value)
|
|
require.NoError(err)
|
|
|
|
balances[attributes[0].Value] = balances[attributes[0].Value].Sub(coinsSpent...)
|
|
|
|
case banktypes.EventTypeCoinReceived:
|
|
coinsRecv, err := sdk.ParseCoinsNormalized(attributes[1].Value)
|
|
require.NoError(err)
|
|
_, err = suite.addrCdc.StringToBytes(attributes[0].Value)
|
|
require.NoError(err)
|
|
balances[attributes[0].Value] = balances[attributes[0].Value].Add(coinsRecv...)
|
|
}
|
|
}
|
|
|
|
// check balance and supply tracking
|
|
require.True(suite.bankKeeper.HasSupply(suite.ctx, "utxo"))
|
|
savedSupply := suite.bankKeeper.GetSupply(suite.ctx, "utxo")
|
|
utxoSupply := savedSupply
|
|
require.Equal(utxoSupply.Amount, supply.AmountOf("utxo"))
|
|
// iterate accounts and check balances
|
|
suite.bankKeeper.IterateAllBalances(suite.ctx, func(address sdk.AccAddress, coin sdk.Coin) (stop bool) {
|
|
// if it's not utxo coin then skip
|
|
if coin.Denom != "utxo" {
|
|
return false
|
|
}
|
|
|
|
addr, err := suite.addrCdc.BytesToString(address)
|
|
suite.Require().NoError(err)
|
|
|
|
balance, exists := balances[addr]
|
|
require.True(exists)
|
|
|
|
expectedUtxo := sdk.NewCoin("utxo", balance.AmountOf(coin.Denom))
|
|
require.Equal(expectedUtxo.String(), coin.String())
|
|
return false
|
|
})
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) getTestMetadata() []banktypes.Metadata {
|
|
return []banktypes.Metadata{
|
|
{
|
|
Name: "Cosmos Hub Atom",
|
|
Symbol: "ATOM",
|
|
Description: "The native staking token of the Cosmos Hub.",
|
|
DenomUnits: []*banktypes.DenomUnit{
|
|
{Denom: "uatom", Exponent: uint32(0), Aliases: []string{"microatom"}},
|
|
{Denom: "matom", Exponent: uint32(3), Aliases: []string{"milliatom"}},
|
|
{Denom: "atom", Exponent: uint32(6), Aliases: nil},
|
|
},
|
|
Base: "uatom",
|
|
Display: "atom",
|
|
},
|
|
{
|
|
Name: "Token",
|
|
Symbol: "TOKEN",
|
|
Description: "The native staking token of the Token Hub.",
|
|
DenomUnits: []*banktypes.DenomUnit{
|
|
{Denom: "1token", Exponent: uint32(5), Aliases: []string{"decitoken"}},
|
|
{Denom: "2token", Exponent: uint32(4), Aliases: []string{"centitoken"}},
|
|
{Denom: "3token", Exponent: uint32(7), Aliases: []string{"dekatoken"}},
|
|
},
|
|
Base: "utoken",
|
|
Display: "token",
|
|
},
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestMintCoinRestrictions() {
|
|
type BankMintingRestrictionFn func(ctx context.Context, coins sdk.Coins) error
|
|
require := suite.Require()
|
|
|
|
type testCase struct {
|
|
coinsToTry sdk.Coin
|
|
expectPass bool
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
restrictionFn BankMintingRestrictionFn
|
|
testCases []testCase
|
|
}{
|
|
{
|
|
"restriction",
|
|
func(_ context.Context, coins sdk.Coins) error {
|
|
for _, coin := range coins {
|
|
if coin.Denom != fooDenom {
|
|
return fmt.Errorf("Module %s only has perms for minting %s coins, tried minting %s coins", banktypes.ModuleName, fooDenom, coin.Denom)
|
|
}
|
|
}
|
|
return nil
|
|
},
|
|
[]testCase{
|
|
{
|
|
coinsToTry: newFooCoin(100),
|
|
expectPass: true,
|
|
},
|
|
{
|
|
coinsToTry: newBarCoin(100),
|
|
expectPass: false,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
keeper := suite.bankKeeper.WithMintCoinsRestriction(banktypes.MintingRestrictionFn(test.restrictionFn))
|
|
for _, testCase := range test.testCases {
|
|
if testCase.expectPass {
|
|
suite.mockMintCoins(multiPermAcc)
|
|
require.NoError(
|
|
keeper.MintCoins(
|
|
suite.ctx,
|
|
multiPermAcc.Name,
|
|
sdk.NewCoins(testCase.coinsToTry),
|
|
),
|
|
)
|
|
} else {
|
|
require.Error(
|
|
keeper.MintCoins(
|
|
suite.ctx,
|
|
multiPermAcc.Name,
|
|
sdk.NewCoins(testCase.coinsToTry),
|
|
),
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestIsSendEnabledDenom() {
|
|
ctx, bankKeeper := suite.ctx, suite.bankKeeper
|
|
require := suite.Require()
|
|
|
|
defaultCoin := "defaultCoin"
|
|
enabledCoin := "enabledCoin"
|
|
disabledCoin := "disabledCoin"
|
|
bankKeeper.DeleteSendEnabled(ctx, defaultCoin)
|
|
bankKeeper.SetSendEnabled(ctx, enabledCoin, true)
|
|
bankKeeper.SetSendEnabled(ctx, disabledCoin, false)
|
|
|
|
tests := []struct {
|
|
denom string
|
|
exp bool
|
|
expDef bool
|
|
}{
|
|
{
|
|
denom: "defaultCoin",
|
|
expDef: true,
|
|
},
|
|
{
|
|
denom: enabledCoin,
|
|
exp: true,
|
|
},
|
|
{
|
|
denom: disabledCoin,
|
|
exp: false,
|
|
},
|
|
}
|
|
|
|
for _, def := range []bool{true, false} {
|
|
params := banktypes.Params{DefaultSendEnabled: def}
|
|
require.NoError(bankKeeper.SetParams(ctx, params))
|
|
|
|
for _, tc := range tests {
|
|
suite.T().Run(fmt.Sprintf("%s default %t", tc.denom, def), func(t *testing.T) {
|
|
actual := suite.bankKeeper.IsSendEnabledDenom(suite.ctx, tc.denom)
|
|
exp := tc.exp
|
|
if tc.expDef {
|
|
exp = def
|
|
}
|
|
|
|
require.Equal(exp, actual)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestGetSendEnabledEntry() {
|
|
ctx, bankKeeper := suite.ctx, suite.bankKeeper
|
|
require := suite.Require()
|
|
|
|
bankKeeper.SetAllSendEnabled(ctx, []*banktypes.SendEnabled{
|
|
{Denom: "gettruecoin", Enabled: true},
|
|
{Denom: "getfalsecoin", Enabled: false},
|
|
})
|
|
|
|
tests := []struct {
|
|
denom string
|
|
expSE banktypes.SendEnabled
|
|
expF bool
|
|
}{
|
|
{
|
|
denom: "missing",
|
|
expSE: banktypes.SendEnabled{},
|
|
expF: false,
|
|
},
|
|
{
|
|
denom: "gettruecoin",
|
|
expSE: banktypes.SendEnabled{Denom: "gettruecoin", Enabled: true},
|
|
expF: true,
|
|
},
|
|
{
|
|
denom: "getfalsecoin",
|
|
expSE: banktypes.SendEnabled{Denom: "getfalsecoin", Enabled: false},
|
|
expF: true,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
suite.T().Run(tc.denom, func(t *testing.T) {
|
|
actualSE, actualF := bankKeeper.GetSendEnabledEntry(ctx, tc.denom)
|
|
require.Equal(tc.expF, actualF, "found")
|
|
require.Equal(tc.expSE, actualSE, "SendEnabled")
|
|
})
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestSetSendEnabled() {
|
|
ctx, bankKeeper := suite.ctx, suite.bankKeeper
|
|
require := suite.Require()
|
|
|
|
tests := []struct {
|
|
name string
|
|
denom string
|
|
value bool
|
|
}{
|
|
{
|
|
name: "very short denom true",
|
|
denom: "f",
|
|
value: true,
|
|
},
|
|
{
|
|
name: "very short denom false",
|
|
denom: "f",
|
|
value: true,
|
|
},
|
|
{
|
|
name: "falseFirstCoin false",
|
|
denom: "falseFirstCoin",
|
|
value: false,
|
|
},
|
|
{
|
|
name: "falseFirstCoin true",
|
|
denom: "falseFirstCoin",
|
|
value: true,
|
|
},
|
|
{
|
|
name: "falseFirstCoin true again",
|
|
denom: "falseFirstCoin",
|
|
value: true,
|
|
},
|
|
{
|
|
name: "trueFirstCoin true",
|
|
denom: "falseFirstCoin",
|
|
value: false,
|
|
},
|
|
{
|
|
name: "trueFirstCoin false",
|
|
denom: "falseFirstCoin",
|
|
value: false,
|
|
},
|
|
{
|
|
name: "trueFirstCoin false again",
|
|
denom: "falseFirstCoin",
|
|
value: false,
|
|
},
|
|
}
|
|
|
|
for _, def := range []bool{true, false} {
|
|
params := banktypes.Params{DefaultSendEnabled: def}
|
|
require.NoError(bankKeeper.SetParams(ctx, params))
|
|
|
|
for _, tc := range tests {
|
|
suite.T().Run(fmt.Sprintf("%s default %t", tc.name, def), func(t *testing.T) {
|
|
bankKeeper.SetSendEnabled(ctx, tc.denom, tc.value)
|
|
actual := bankKeeper.IsSendEnabledDenom(ctx, tc.denom)
|
|
require.Equal(tc.value, actual)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestSetAllSendEnabled() {
|
|
ctx, bankKeeper := suite.ctx, suite.bankKeeper
|
|
require := suite.Require()
|
|
|
|
tests := []struct {
|
|
name string
|
|
sendEnableds []*banktypes.SendEnabled
|
|
}{
|
|
{
|
|
name: "nil",
|
|
sendEnableds: nil,
|
|
},
|
|
{
|
|
name: "empty",
|
|
sendEnableds: []*banktypes.SendEnabled{},
|
|
},
|
|
{
|
|
name: "one true",
|
|
sendEnableds: []*banktypes.SendEnabled{
|
|
{Denom: "aonecoin", Enabled: true},
|
|
},
|
|
},
|
|
{
|
|
name: "one false",
|
|
sendEnableds: []*banktypes.SendEnabled{
|
|
{Denom: "bonecoin", Enabled: false},
|
|
},
|
|
},
|
|
{
|
|
name: "two true",
|
|
sendEnableds: []*banktypes.SendEnabled{
|
|
{Denom: "conecoin", Enabled: true},
|
|
{Denom: "ctwocoin", Enabled: true},
|
|
},
|
|
},
|
|
{
|
|
name: "two true false",
|
|
sendEnableds: []*banktypes.SendEnabled{
|
|
{Denom: "donecoin", Enabled: true},
|
|
{Denom: "dtwocoin", Enabled: false},
|
|
},
|
|
},
|
|
{
|
|
name: "two false true",
|
|
sendEnableds: []*banktypes.SendEnabled{
|
|
{Denom: "eonecoin", Enabled: false},
|
|
{Denom: "etwocoin", Enabled: true},
|
|
},
|
|
},
|
|
{
|
|
name: "two false",
|
|
sendEnableds: []*banktypes.SendEnabled{
|
|
{Denom: "fonecoin", Enabled: false},
|
|
{Denom: "ftwocoin", Enabled: false},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, def := range []bool{true, false} {
|
|
params := banktypes.Params{DefaultSendEnabled: def}
|
|
require.NoError(bankKeeper.SetParams(ctx, params))
|
|
|
|
for _, tc := range tests {
|
|
suite.T().Run(fmt.Sprintf("%s default %t", tc.name, def), func(t *testing.T) {
|
|
bankKeeper.SetAllSendEnabled(ctx, tc.sendEnableds)
|
|
|
|
for _, se := range tc.sendEnableds {
|
|
actual := bankKeeper.IsSendEnabledDenom(ctx, se.Denom)
|
|
require.Equal(se.Enabled, actual, se.Denom)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestDeleteSendEnabled() {
|
|
ctx, bankKeeper := suite.ctx, suite.bankKeeper
|
|
require := suite.Require()
|
|
|
|
for _, def := range []bool{true, false} {
|
|
params := banktypes.Params{DefaultSendEnabled: def}
|
|
require.NoError(bankKeeper.SetParams(ctx, params))
|
|
suite.T().Run(fmt.Sprintf("default %t", def), func(t *testing.T) {
|
|
denom := fmt.Sprintf("somerand%tcoin", !def)
|
|
bankKeeper.SetSendEnabled(ctx, denom, !def)
|
|
require.Equal(!def, bankKeeper.IsSendEnabledDenom(ctx, denom))
|
|
bankKeeper.DeleteSendEnabled(ctx, denom)
|
|
require.Equal(def, bankKeeper.IsSendEnabledDenom(ctx, denom))
|
|
})
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestIterateSendEnabledEntries() {
|
|
ctx, bankKeeper := suite.ctx, suite.bankKeeper
|
|
require := suite.Require()
|
|
|
|
suite.T().Run("no entries to iterate", func(t *testing.T) {
|
|
count := 0
|
|
bankKeeper.IterateSendEnabledEntries(ctx, func(_ string, _ bool) (stop bool) {
|
|
count++
|
|
return false
|
|
})
|
|
|
|
require.Equal(0, count)
|
|
})
|
|
|
|
alpha := strings.Split("abcdefghijklmnopqrstuvwxyz", "")
|
|
denoms := make([]string, len(alpha)*2)
|
|
for i, l := range alpha {
|
|
denoms[i*2] = fmt.Sprintf("%sitercointrue", l)
|
|
denoms[i*2+1] = fmt.Sprintf("%sitercoinfalse", l)
|
|
bankKeeper.SetSendEnabled(ctx, denoms[i*2], true)
|
|
bankKeeper.SetSendEnabled(ctx, denoms[i*2+1], false)
|
|
}
|
|
|
|
for _, def := range []bool{true, false} {
|
|
params := banktypes.Params{DefaultSendEnabled: def}
|
|
require.NoError(bankKeeper.SetParams(ctx, params))
|
|
|
|
var seen []string
|
|
suite.T().Run(fmt.Sprintf("all denoms have expected values default %t", def), func(t *testing.T) {
|
|
bankKeeper.IterateSendEnabledEntries(ctx, func(denom string, sendEnabled bool) (stop bool) {
|
|
seen = append(seen, denom)
|
|
exp := true
|
|
if strings.HasSuffix(denom, "false") {
|
|
exp = false
|
|
}
|
|
|
|
require.Equal(exp, sendEnabled, denom)
|
|
return false
|
|
})
|
|
})
|
|
|
|
suite.T().Run(fmt.Sprintf("all denoms were seen default %t", def), func(t *testing.T) {
|
|
require.ElementsMatch(denoms, seen)
|
|
})
|
|
}
|
|
|
|
bankKeeper.DeleteSendEnabled(ctx, denoms...)
|
|
|
|
suite.T().Run("no entries to iterate again after deleting all of them", func(t *testing.T) {
|
|
count := 0
|
|
bankKeeper.IterateSendEnabledEntries(ctx, func(_ string, _ bool) (stop bool) {
|
|
count++
|
|
return false
|
|
})
|
|
|
|
require.Equal(0, count)
|
|
})
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestGetAllSendEnabledEntries() {
|
|
ctx, bankKeeper := suite.ctx, suite.bankKeeper
|
|
require := suite.Require()
|
|
|
|
suite.T().Run("no entries", func(t *testing.T) {
|
|
actual := bankKeeper.GetAllSendEnabledEntries(ctx)
|
|
require.Len(actual, 0)
|
|
})
|
|
|
|
alpha := strings.Split("abcdefghijklmnopqrstuvwxyz", "")
|
|
denoms := make([]string, len(alpha)*2)
|
|
for i, l := range alpha {
|
|
denoms[i*2] = fmt.Sprintf("%sitercointrue", l)
|
|
denoms[i*2+1] = fmt.Sprintf("%sitercoinfalse", l)
|
|
bankKeeper.SetSendEnabled(ctx, denoms[i*2], true)
|
|
bankKeeper.SetSendEnabled(ctx, denoms[i*2+1], false)
|
|
}
|
|
|
|
for _, def := range []bool{true, false} {
|
|
params := banktypes.Params{DefaultSendEnabled: def}
|
|
require.NoError(bankKeeper.SetParams(ctx, params))
|
|
|
|
var seen []string
|
|
suite.T().Run(fmt.Sprintf("all denoms have expected values default %t", def), func(t *testing.T) {
|
|
actual := bankKeeper.GetAllSendEnabledEntries(ctx)
|
|
for _, se := range actual {
|
|
seen = append(seen, se.Denom)
|
|
exp := true
|
|
if strings.HasSuffix(se.Denom, "false") {
|
|
exp = false
|
|
}
|
|
|
|
require.Equal(exp, se.Enabled, se.Denom)
|
|
}
|
|
})
|
|
|
|
suite.T().Run(fmt.Sprintf("all denoms were seen default %t", def), func(t *testing.T) {
|
|
require.ElementsMatch(denoms, seen)
|
|
})
|
|
}
|
|
|
|
for _, denom := range denoms {
|
|
bankKeeper.DeleteSendEnabled(ctx, denom)
|
|
}
|
|
|
|
suite.T().Run("no entries again after deleting all of them", func(t *testing.T) {
|
|
actual := bankKeeper.GetAllSendEnabledEntries(ctx)
|
|
require.Len(actual, 0)
|
|
})
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestSetParams() {
|
|
ctx, bankKeeper := suite.ctx, suite.bankKeeper
|
|
require := suite.Require()
|
|
|
|
params := banktypes.NewParams(true)
|
|
params.SendEnabled = []*banktypes.SendEnabled{
|
|
{Denom: "paramscointrue", Enabled: true},
|
|
{Denom: "paramscoinfalse", Enabled: false},
|
|
}
|
|
require.NoError(bankKeeper.SetParams(ctx, params))
|
|
|
|
suite.Run("stored params are as expected", func() {
|
|
actual := bankKeeper.GetParams(ctx)
|
|
require.True(actual.DefaultSendEnabled, "DefaultSendEnabled")
|
|
require.Len(actual.SendEnabled, 0, "SendEnabled") //nolint:staticcheck // we're testing the old way here
|
|
})
|
|
|
|
suite.Run("send enabled params converted to store", func() {
|
|
actual := bankKeeper.GetAllSendEnabledEntries(ctx)
|
|
if suite.Assert().Len(actual, 2) {
|
|
require.Equal("paramscoinfalse", actual[0].Denom, "actual[0].Denom")
|
|
require.False(actual[0].Enabled, "actual[0].Enabled")
|
|
require.Equal("paramscointrue", actual[1].Denom, "actual[1].Denom")
|
|
require.True(actual[1].Enabled, "actual[1].Enabled")
|
|
}
|
|
})
|
|
}
|