From 4cf41d18c2c7bf6c30755086645bf5548220f402 Mon Sep 17 00:00:00 2001 From: drklee3 Date: Tue, 21 May 2024 14:11:13 -0700 Subject: [PATCH] feat(x/precisebank): Implement GetBalance (#1916) Implement GetBalance for extended balances which passes through to `x/bank` for non-extended denoms. This diverges from `x/evmutil` behavior which will panic on non-"akava" calls. Add bank / account keeper mocks for testing, with mockery config for [mockery package setup](https://vektra.github.io/mockery/latest/migrating_to_packages/) --- .mockery.yaml | 16 + app/app.go | 2 + .../keeper/fractional_balance_test.go | 10 +- x/precisebank/keeper/invariants.go | 35 ++ x/precisebank/keeper/invariants_test.go | 101 +++- x/precisebank/keeper/keeper.go | 28 +- x/precisebank/keeper/keeper_test.go | 24 +- x/precisebank/keeper/remainder_amount_test.go | 6 +- x/precisebank/keeper/send.go | 41 ++ x/precisebank/keeper/view.go | 37 ++ x/precisebank/keeper/view_test.go | 117 ++++ x/precisebank/types/expected_keepers.go | 13 +- .../types/mocks/MockAccountKeeper.go | 191 +++++++ x/precisebank/types/mocks/MockBankKeeper.go | 530 ++++++++++++++++++ 14 files changed, 1103 insertions(+), 48 deletions(-) create mode 100644 .mockery.yaml create mode 100644 x/precisebank/keeper/send.go create mode 100644 x/precisebank/keeper/view.go create mode 100644 x/precisebank/keeper/view_test.go create mode 100644 x/precisebank/types/mocks/MockAccountKeeper.go create mode 100644 x/precisebank/types/mocks/MockBankKeeper.go diff --git a/.mockery.yaml b/.mockery.yaml new file mode 100644 index 00000000..0682bfcb --- /dev/null +++ b/.mockery.yaml @@ -0,0 +1,16 @@ +# Generate EXPECT() methods, type-safe methods to generate call expectations +with-expecter: true + +# Generate mocks in adjacent mocks directory to the interfaces +dir: "{{.InterfaceDir}}/mocks" +mockname: "Mock{{.InterfaceName}}" +outpkg: "mocks" +filename: "Mock{{.InterfaceName}}.go" + +packages: + github.com/kava-labs/kava/x/precisebank/types: + # package-specific config + config: + interfaces: + AccountKeeper: + BankKeeper: diff --git a/app/app.go b/app/app.go index 29fb6ea8..bcc8fb61 100644 --- a/app/app.go +++ b/app/app.go @@ -554,6 +554,8 @@ func NewApp( app.precisebankKeeper = precisebankkeeper.NewKeeper( app.appCodec, keys[precisebanktypes.StoreKey], + app.bankKeeper, + app.accountKeeper, ) evmBankKeeper := evmutilkeeper.NewEvmBankKeeper(app.evmutilKeeper, app.bankKeeper, app.accountKeeper) diff --git a/x/precisebank/keeper/fractional_balance_test.go b/x/precisebank/keeper/fractional_balance_test.go index 3650c532..0a604995 100644 --- a/x/precisebank/keeper/fractional_balance_test.go +++ b/x/precisebank/keeper/fractional_balance_test.go @@ -11,7 +11,7 @@ import ( ) func TestSetGetFractionalBalance(t *testing.T) { - tk := NewTestKeeper() + tk := NewMockedTestData(t) ctx, k := tk.ctx, tk.keeper addr := sdk.AccAddress([]byte("test-address")) @@ -97,7 +97,7 @@ func TestSetGetFractionalBalance(t *testing.T) { } func TestSetFractionalBalance_InvalidAddr(t *testing.T) { - tk := NewTestKeeper() + tk := NewMockedTestData(t) ctx, k := tk.ctx, tk.keeper require.PanicsWithError( @@ -111,7 +111,7 @@ func TestSetFractionalBalance_InvalidAddr(t *testing.T) { } func TestSetFractionalBalance_ZeroDeletes(t *testing.T) { - tk := NewTestKeeper() + tk := NewMockedTestData(t) ctx, k := tk.ctx, tk.keeper addr := sdk.AccAddress([]byte("test-address")) @@ -140,7 +140,7 @@ func TestSetFractionalBalance_ZeroDeletes(t *testing.T) { } func TestIterateFractionalBalances(t *testing.T) { - tk := NewTestKeeper() + tk := NewMockedTestData(t) ctx, k := tk.ctx, tk.keeper addrs := []sdk.AccAddress{} @@ -168,7 +168,7 @@ func TestIterateFractionalBalances(t *testing.T) { } func TestGetAggregateSumFractionalBalances(t *testing.T) { - tk := NewTestKeeper() + tk := NewMockedTestData(t) ctx, k := tk.ctx, tk.keeper // Set balances from 1 to 10 diff --git a/x/precisebank/keeper/invariants.go b/x/precisebank/keeper/invariants.go index a7f91f49..70318ff9 100644 --- a/x/precisebank/keeper/invariants.go +++ b/x/precisebank/keeper/invariants.go @@ -17,6 +17,7 @@ func RegisterInvariants( ir.RegisterRoute(types.ModuleName, "balance-remainder-total", BalancedFractionalTotalInvariant(k)) ir.RegisterRoute(types.ModuleName, "valid-fractional-balances", ValidFractionalAmountsInvariant(k)) ir.RegisterRoute(types.ModuleName, "valid-remainder-amount", ValidRemainderAmountInvariant(k)) + ir.RegisterRoute(types.ModuleName, "fractional-denom-not-in-bank", FractionalDenomNotInBankInvariant(k)) } // AllInvariants runs all invariants of the X/precisebank module. @@ -37,6 +38,11 @@ func AllInvariants(k Keeper) sdk.Invariant { return res, stop } + res, stop = FractionalDenomNotInBankInvariant(k)(ctx) + if stop { + return res, stop + } + return "", false } } @@ -121,3 +127,32 @@ func BalancedFractionalTotalInvariant(k Keeper) sdk.Invariant { ), broken } } + +// FractionalDenomNotInBankInvariant checks that the bank does not hold any +// fractional denoms. These assets, e.g. akava, should only exist in the +// x/precisebank module as this is a decimal extension of ukava that shares +// the same total supply and is effectively the same asset. ukava held by this +// module in x/bank backs all fractional balances in x/precisebank. If akava +// somehow ends up in x/bank, then it would both break all expectations of this +// module as well as be double-counted in the total supply. +func FractionalDenomNotInBankInvariant(k Keeper) sdk.Invariant { + return func(ctx sdk.Context) (string, bool) { + extBankSupply := k.bk.GetSupply(ctx, types.ExtendedCoinDenom) + + broken := !extBankSupply.IsZero() + msg := "" + + if broken { + msg = fmt.Sprintf( + "x/bank should not hold any %v but has supply of %v", + types.ExtendedCoinDenom, + extBankSupply, + ) + } + + return sdk.FormatInvariant( + types.ModuleName, "fractional-denom-not-in-bank", + msg, + ), broken + } +} diff --git a/x/precisebank/keeper/invariants_test.go b/x/precisebank/keeper/invariants_test.go index a6fbe2bb..2518c6ef 100644 --- a/x/precisebank/keeper/invariants_test.go +++ b/x/precisebank/keeper/invariants_test.go @@ -10,28 +10,26 @@ import ( "github.com/kava-labs/kava/x/precisebank/keeper" "github.com/kava-labs/kava/x/precisebank/types" + "github.com/kava-labs/kava/x/precisebank/types/mocks" "github.com/stretchr/testify/require" ) func TestBalancedFractionalTotalInvariant(t *testing.T) { - var ctx sdk.Context - var k keeper.Keeper - tests := []struct { name string - setupFn func() + setupFn func(ctx sdk.Context, k keeper.Keeper) wantBroken bool wantMsg string }{ { "valid - empty state", - func() {}, + func(_ sdk.Context, _ keeper.Keeper) {}, false, "", }, { "valid - balances, 0 remainder", - func() { + func(ctx sdk.Context, k keeper.Keeper) { k.SetFractionalBalance(ctx, sdk.AccAddress{1}, types.ConversionFactor().QuoRaw(2)) k.SetFractionalBalance(ctx, sdk.AccAddress{2}, types.ConversionFactor().QuoRaw(2)) }, @@ -40,7 +38,7 @@ func TestBalancedFractionalTotalInvariant(t *testing.T) { }, { "valid - balances, non-zero remainder", - func() { + func(ctx sdk.Context, k keeper.Keeper) { k.SetFractionalBalance(ctx, sdk.AccAddress{1}, types.ConversionFactor().QuoRaw(2)) k.SetFractionalBalance(ctx, sdk.AccAddress{2}, types.ConversionFactor().QuoRaw(2).SubRaw(1)) @@ -51,7 +49,7 @@ func TestBalancedFractionalTotalInvariant(t *testing.T) { }, { "invalid - balances, 0 remainder", - func() { + func(ctx sdk.Context, k keeper.Keeper) { k.SetFractionalBalance(ctx, sdk.AccAddress{1}, types.ConversionFactor().QuoRaw(2)) k.SetFractionalBalance(ctx, sdk.AccAddress{2}, types.ConversionFactor().QuoRaw(2).SubRaw(1)) }, @@ -60,7 +58,7 @@ func TestBalancedFractionalTotalInvariant(t *testing.T) { }, { "invalid - invalid balances, non-zero (insufficient) remainder", - func() { + func(ctx sdk.Context, k keeper.Keeper) { k.SetFractionalBalance(ctx, sdk.AccAddress{1}, types.ConversionFactor().QuoRaw(2)) k.SetFractionalBalance(ctx, sdk.AccAddress{2}, types.ConversionFactor().QuoRaw(2).SubRaw(2)) k.SetRemainderAmount(ctx, sdkmath.OneInt()) @@ -70,7 +68,7 @@ func TestBalancedFractionalTotalInvariant(t *testing.T) { }, { "invalid - invalid balances, non-zero (excess) remainder", - func() { + func(ctx sdk.Context, k keeper.Keeper) { k.SetFractionalBalance(ctx, sdk.AccAddress{1}, types.ConversionFactor().QuoRaw(2)) k.SetFractionalBalance(ctx, sdk.AccAddress{2}, types.ConversionFactor().QuoRaw(2).SubRaw(2)) k.SetRemainderAmount(ctx, sdkmath.NewInt(5)) @@ -83,13 +81,12 @@ func TestBalancedFractionalTotalInvariant(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Reset each time - tk := NewTestKeeper() - ctx, k = tk.ctx, tk.keeper + td := NewMockedTestData(t) - tt.setupFn() + tt.setupFn(td.ctx, td.keeper) - invariantFn := keeper.BalancedFractionalTotalInvariant(k) - msg, broken := invariantFn(ctx) + invariantFn := keeper.BalancedFractionalTotalInvariant(td.keeper) + msg, broken := invariantFn(td.ctx) if tt.wantBroken { require.True(t, broken, "invariant should be broken but is not") @@ -102,25 +99,21 @@ func TestBalancedFractionalTotalInvariant(t *testing.T) { } func TestValidFractionalAmountsInvariant(t *testing.T) { - var ctx sdk.Context - var k keeper.Keeper - var storeKey storetypes.StoreKey - tests := []struct { name string - setupFn func() + setupFn func(ctx sdk.Context, k keeper.Keeper, storeKey storetypes.StoreKey) wantBroken bool wantMsg string }{ { "valid - empty state", - func() {}, + func(_ sdk.Context, _ keeper.Keeper, _ storetypes.StoreKey) {}, false, "", }, { "valid - valid balances", - func() { + func(ctx sdk.Context, k keeper.Keeper, _ storetypes.StoreKey) { k.SetFractionalBalance(ctx, sdk.AccAddress{1}, types.ConversionFactor().QuoRaw(2)) k.SetFractionalBalance(ctx, sdk.AccAddress{2}, types.ConversionFactor().QuoRaw(2)) }, @@ -129,7 +122,7 @@ func TestValidFractionalAmountsInvariant(t *testing.T) { }, { "invalid - exceeds max balance", - func() { + func(ctx sdk.Context, _ keeper.Keeper, storeKey storetypes.StoreKey) { // Requires manual store manipulation so it is unlikely to have // invalid state in practice. SetFractionalBalance will validate // before setting. @@ -151,13 +144,65 @@ func TestValidFractionalAmountsInvariant(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Reset each time - tk := NewTestKeeper() - ctx, k, storeKey = tk.ctx, tk.keeper, tk.storeKey + td := NewMockedTestData(t) - tt.setupFn() + tt.setupFn(td.ctx, td.keeper, td.storeKey) - invariantFn := keeper.ValidFractionalAmountsInvariant(k) - msg, broken := invariantFn(ctx) + invariantFn := keeper.ValidFractionalAmountsInvariant(td.keeper) + msg, broken := invariantFn(td.ctx) + + if tt.wantBroken { + require.True(t, broken, "invariant should be broken but is not") + require.Equal(t, tt.wantMsg, msg) + } else { + require.False(t, broken, "invariant should not be broken but is") + } + }) + } +} + +func TestFractionalDenomNotInBankInvariant(t *testing.T) { + tests := []struct { + name string + setupFn func(ctx sdk.Context, bk *mocks.MockBankKeeper) + wantBroken bool + wantMsg string + }{ + { + "valid - integer denom (ukava) supply", + func(ctx sdk.Context, bk *mocks.MockBankKeeper) { + // No fractional balance in x/bank + // This also enforces there is no GetSupply() call for IntegerCoinDenom / ukava + bk.EXPECT(). + GetSupply(ctx, types.ExtendedCoinDenom). + Return(sdk.NewCoin(types.ExtendedCoinDenom, sdkmath.ZeroInt())). + Once() + }, + false, + "", + }, + { + "invalid - x/bank contains fractional denom (akava)", + func(ctx sdk.Context, bk *mocks.MockBankKeeper) { + bk.EXPECT(). + GetSupply(ctx, types.ExtendedCoinDenom). + Return(sdk.NewCoin(types.ExtendedCoinDenom, sdk.NewInt(1000))). + Once() + }, + true, + "precisebank: fractional-denom-not-in-bank invariant\nx/bank should not hold any akava but has supply of 1000akava\n", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Reset each time + td := NewMockedTestData(t) + + tt.setupFn(td.ctx, td.bk) + + invariantFn := keeper.FractionalDenomNotInBankInvariant(td.keeper) + msg, broken := invariantFn(td.ctx) if tt.wantBroken { require.True(t, broken, "invariant should be broken but is not") diff --git a/x/precisebank/keeper/keeper.go b/x/precisebank/keeper/keeper.go index df39e747..8077dfa3 100644 --- a/x/precisebank/keeper/keeper.go +++ b/x/precisebank/keeper/keeper.go @@ -3,21 +3,43 @@ package keeper import ( "github.com/cosmos/cosmos-sdk/codec" storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + evmtypes "github.com/evmos/ethermint/x/evm/types" + + "github.com/kava-labs/kava/x/precisebank/types" ) -// TODO: Enforce that Keeper implements the expected keeper interfaces -// var _ types.BankKeeper = Keeper{} +// Enforce that Keeper implements the expected keeper interfaces +var _ evmtypes.BankKeeper = Keeper{} // Keeper defines the precisebank module's keeper type Keeper struct { cdc codec.BinaryCodec storeKey storetypes.StoreKey + + bk types.BankKeeper + ak types.AccountKeeper } // NewKeeper creates a new keeper -func NewKeeper(cdc codec.BinaryCodec, storeKey storetypes.StoreKey) Keeper { +func NewKeeper( + cdc codec.BinaryCodec, + storeKey storetypes.StoreKey, + bk types.BankKeeper, + ak types.AccountKeeper, +) Keeper { return Keeper{ cdc: cdc, storeKey: storeKey, + bk: bk, + ak: ak, } } + +func (k Keeper) MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error { + panic("unimplemented") +} + +func (k Keeper) BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error { + panic("unimplemented") +} diff --git a/x/precisebank/keeper/keeper_test.go b/x/precisebank/keeper/keeper_test.go index bc938d06..dba66194 100644 --- a/x/precisebank/keeper/keeper_test.go +++ b/x/precisebank/keeper/keeper_test.go @@ -1,6 +1,8 @@ package keeper_test import ( + "testing" + storetypes "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/testutil" sdk "github.com/cosmos/cosmos-sdk/types" @@ -8,29 +10,39 @@ import ( "github.com/kava-labs/kava/app" "github.com/kava-labs/kava/x/precisebank/keeper" "github.com/kava-labs/kava/x/precisebank/types" + "github.com/kava-labs/kava/x/precisebank/types/mocks" ) -// testKeeper defines necessary fields for testing keeper store methods that -// don't require a full app setup. -type testKeeper struct { +// testData defines necessary fields for testing keeper store methods and mocks +// for unit tests without full app setup. +type testData struct { ctx sdk.Context keeper keeper.Keeper storeKey *storetypes.KVStoreKey + bk *mocks.MockBankKeeper + ak *mocks.MockAccountKeeper } -func NewTestKeeper() testKeeper { +// NewMockedTestData creates a new testData instance with mocked bank and +// account keepers. +func NewMockedTestData(t *testing.T) testData { storeKey := sdk.NewKVStoreKey(types.ModuleName) // Not required by module, but needs to be non-nil for context tKey := sdk.NewTransientStoreKey("transient_test") ctx := testutil.DefaultContext(storeKey, tKey) + bk := mocks.NewMockBankKeeper(t) + ak := mocks.NewMockAccountKeeper(t) + tApp := app.NewTestApp() cdc := tApp.AppCodec() - k := keeper.NewKeeper(cdc, storeKey) + k := keeper.NewKeeper(cdc, storeKey, bk, ak) - return testKeeper{ + return testData{ ctx: ctx, keeper: k, storeKey: storeKey, + bk: bk, + ak: ak, } } diff --git a/x/precisebank/keeper/remainder_amount_test.go b/x/precisebank/keeper/remainder_amount_test.go index 12dde43e..92bbb119 100644 --- a/x/precisebank/keeper/remainder_amount_test.go +++ b/x/precisebank/keeper/remainder_amount_test.go @@ -9,7 +9,7 @@ import ( ) func TestGetSetRemainderAmount(t *testing.T) { - tk := NewTestKeeper() + tk := NewMockedTestData(t) ctx, k, storeKey := tk.ctx, tk.keeper, tk.storeKey // Set amount @@ -31,7 +31,7 @@ func TestGetSetRemainderAmount(t *testing.T) { } func TestInvalidRemainderAmount(t *testing.T) { - tk := NewTestKeeper() + tk := NewMockedTestData(t) ctx, k := tk.ctx, tk.keeper // Set negative amount @@ -46,7 +46,7 @@ func TestInvalidRemainderAmount(t *testing.T) { } func TestDeleteRemainderAmount(t *testing.T) { - tk := NewTestKeeper() + tk := NewMockedTestData(t) ctx, k, storeKey := tk.ctx, tk.keeper, tk.storeKey require.NotPanics(t, func() { diff --git a/x/precisebank/keeper/send.go b/x/precisebank/keeper/send.go new file mode 100644 index 00000000..6980bf0f --- /dev/null +++ b/x/precisebank/keeper/send.go @@ -0,0 +1,41 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// IsSendEnabledCoins uses the parent x/bank keeper to check the coins provided +// and returns an ErrSendDisabled if any of the coins are not configured for +// sending. Returns nil if sending is enabled for all provided coin +func (k Keeper) IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error { + panic("unimplemented") +} + +func (k Keeper) SendCoins( + ctx sdk.Context, + from, to sdk.AccAddress, + amt sdk.Coins, +) error { + // IsSendEnabledCoins() is only used in x/bank in msg server, not in keeper, + // so we should also not use it here to align with x/bank behavior. + + panic("unimplemented") +} + +func (k Keeper) SendCoinsFromAccountToModule( + ctx sdk.Context, + senderAddr sdk.AccAddress, + recipientModule string, + amt sdk.Coins, +) error { + panic("unimplemented") +} + +func (k Keeper) SendCoinsFromModuleToAccount( + ctx sdk.Context, + senderModule string, + recipientAddr sdk.AccAddress, + amt sdk.Coins, +) error { + panic("unimplemented") +} diff --git a/x/precisebank/keeper/view.go b/x/precisebank/keeper/view.go new file mode 100644 index 00000000..ead5a2cf --- /dev/null +++ b/x/precisebank/keeper/view.go @@ -0,0 +1,37 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/kava-labs/kava/x/precisebank/types" +) + +// GetBalance returns the balance of a specific denom for an address. This will +// return the extended balance for the ExtendedCoinDenom, and the regular +// balance for all other denoms. +func (k Keeper) GetBalance( + ctx sdk.Context, + addr sdk.AccAddress, + denom string, +) sdk.Coin { + // Pass through to x/bank for denoms except ExtendedCoinDenom + if denom != types.ExtendedCoinDenom { + return k.bk.GetBalance(ctx, addr, denom) + } + + // x/bank for integer balance - spendable balance only + spendableCoins := k.bk.SpendableCoins(ctx, addr) + integerAmount := spendableCoins.AmountOf(types.IntegerCoinDenom) + + // x/precisebank for fractional balance + fractionalAmount, found := k.GetFractionalBalance(ctx, addr) + if !found { + fractionalAmount = sdk.ZeroInt() + } + + // (Integer * ConversionFactor) + Fractional + fullAmount := integerAmount. + Mul(types.ConversionFactor()). + Add(fractionalAmount) + + return sdk.NewCoin(types.ExtendedCoinDenom, fullAmount) +} diff --git a/x/precisebank/keeper/view_test.go b/x/precisebank/keeper/view_test.go new file mode 100644 index 00000000..d4765835 --- /dev/null +++ b/x/precisebank/keeper/view_test.go @@ -0,0 +1,117 @@ +package keeper_test + +import ( + "testing" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/kava-labs/kava/x/precisebank/types" + "github.com/stretchr/testify/require" +) + +func TestKeeper_GetBalance(t *testing.T) { + tests := []struct { + name string + giveDenom string // queried denom for balance + + giveBankBal sdk.Coins // mocked bank balance for giveAddr + giveFractionalBal sdkmath.Int // stored fractional balance for giveAddr + + wantBal sdk.Coin + }{ + { + "extended denom - no fractional balance", + types.ExtendedCoinDenom, + // queried bank balance in ukava when querying for akava + sdk.NewCoins(sdk.NewCoin(types.IntegerCoinDenom, sdk.NewInt(1000))), + sdkmath.ZeroInt(), + // integer + fractional + sdk.NewCoin(types.ExtendedCoinDenom, sdk.NewInt(1000_000_000_000_000)), + }, + { + "extended denom - with fractional balance", + types.ExtendedCoinDenom, + sdk.NewCoins(sdk.NewCoin(types.IntegerCoinDenom, sdk.NewInt(1000))), + sdkmath.NewInt(100), + // integer + fractional + sdk.NewCoin(types.ExtendedCoinDenom, sdk.NewInt(1000_000_000_000_100)), + }, + { + "extended denom - only fractional balance", + types.ExtendedCoinDenom, + // no coins in bank, only fractional balance + sdk.NewCoins(), + sdkmath.NewInt(100), + sdk.NewCoin(types.ExtendedCoinDenom, sdk.NewInt(100)), + }, + { + "extended denom - max fractional balance", + types.ExtendedCoinDenom, + sdk.NewCoins(sdk.NewCoin(types.IntegerCoinDenom, sdk.NewInt(1000))), + types.ConversionFactor().SubRaw(1), + // integer + fractional + sdk.NewCoin(types.ExtendedCoinDenom, sdk.NewInt(1000_999_999_999_999)), + }, + { + "non-extended denom - ukava returns ukava", + types.IntegerCoinDenom, + sdk.NewCoins(sdk.NewCoin(types.IntegerCoinDenom, sdk.NewInt(1000))), + sdk.ZeroInt(), + sdk.NewCoin("ukava", sdk.NewInt(1000)), + }, + { + "non-extended denom - unaffected by fractional balance", + "ukava", + sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1000))), + sdkmath.NewInt(100), + sdk.NewCoin("ukava", sdk.NewInt(1000)), + }, + { + "unrelated denom - no fractional", + "busd", + sdk.NewCoins(sdk.NewCoin("busd", sdk.NewInt(1000))), + sdk.ZeroInt(), + sdk.NewCoin("busd", sdk.NewInt(1000)), + }, + { + "unrelated denom - unaffected by fractional balance", + "busd", + sdk.NewCoins(sdk.NewCoin("busd", sdk.NewInt(1000))), + sdkmath.NewInt(100), + sdk.NewCoin("busd", sdk.NewInt(1000)), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tk := NewMockedTestData(t) + addr := sdk.AccAddress([]byte("test-address")) + + // Set fractional balance in store before query + tk.keeper.SetFractionalBalance(tk.ctx, addr, tt.giveFractionalBal) + + if tt.giveDenom == types.ExtendedCoinDenom { + // No balance pass through + tk.bk.EXPECT(). + SpendableCoins(tk.ctx, addr). + RunAndReturn(func(_ sdk.Context, _ sdk.AccAddress) sdk.Coins { + return tt.giveBankBal + }). + Once() + } else { + // Pass through to x/bank for denoms except ExtendedCoinDenom + tk.bk.EXPECT(). + GetBalance(tk.ctx, addr, tt.giveDenom). + RunAndReturn(func(ctx sdk.Context, aa sdk.AccAddress, s string) sdk.Coin { + require.Equal(t, s, tt.giveDenom, "unexpected denom passed to x/bank.GetBalance") + + return sdk.NewCoin(tt.giveDenom, tt.giveBankBal.AmountOf(s)) + }). + Once() + } + + bal := tk.keeper.GetBalance(tk.ctx, addr, tt.giveDenom) + require.Equal(t, tt.wantBal, bal) + }) + } +} diff --git a/x/precisebank/types/expected_keepers.go b/x/precisebank/types/expected_keepers.go index 43d2415b..ffcad7a6 100644 --- a/x/precisebank/types/expected_keepers.go +++ b/x/precisebank/types/expected_keepers.go @@ -3,7 +3,6 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - evmtypes "github.com/evmos/ethermint/x/evm/types" ) // AccountKeeper defines the expected account keeper interface @@ -15,9 +14,17 @@ type AccountKeeper interface { // BankKeeper defines the expected bank keeper interface type BankKeeper interface { - evmtypes.BankKeeper - + IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin GetSupply(ctx sdk.Context, denom string) sdk.Coin SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + + BlockedAddr(addr sdk.AccAddress) bool + SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + + MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error + BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error } diff --git a/x/precisebank/types/mocks/MockAccountKeeper.go b/x/precisebank/types/mocks/MockAccountKeeper.go new file mode 100644 index 00000000..982ba7cd --- /dev/null +++ b/x/precisebank/types/mocks/MockAccountKeeper.go @@ -0,0 +1,191 @@ +// Code generated by mockery v2.43.0. DO NOT EDIT. + +package mocks + +import ( + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + mock "github.com/stretchr/testify/mock" + + types "github.com/cosmos/cosmos-sdk/types" +) + +// MockAccountKeeper is an autogenerated mock type for the AccountKeeper type +type MockAccountKeeper struct { + mock.Mock +} + +type MockAccountKeeper_Expecter struct { + mock *mock.Mock +} + +func (_m *MockAccountKeeper) EXPECT() *MockAccountKeeper_Expecter { + return &MockAccountKeeper_Expecter{mock: &_m.Mock} +} + +// GetModuleAccount provides a mock function with given fields: ctx, moduleName +func (_m *MockAccountKeeper) GetModuleAccount(ctx types.Context, moduleName string) authtypes.ModuleAccountI { + ret := _m.Called(ctx, moduleName) + + if len(ret) == 0 { + panic("no return value specified for GetModuleAccount") + } + + var r0 authtypes.ModuleAccountI + if rf, ok := ret.Get(0).(func(types.Context, string) authtypes.ModuleAccountI); ok { + r0 = rf(ctx, moduleName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(authtypes.ModuleAccountI) + } + } + + return r0 +} + +// MockAccountKeeper_GetModuleAccount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetModuleAccount' +type MockAccountKeeper_GetModuleAccount_Call struct { + *mock.Call +} + +// GetModuleAccount is a helper method to define mock.On call +// - ctx types.Context +// - moduleName string +func (_e *MockAccountKeeper_Expecter) GetModuleAccount(ctx interface{}, moduleName interface{}) *MockAccountKeeper_GetModuleAccount_Call { + return &MockAccountKeeper_GetModuleAccount_Call{Call: _e.mock.On("GetModuleAccount", ctx, moduleName)} +} + +func (_c *MockAccountKeeper_GetModuleAccount_Call) Run(run func(ctx types.Context, moduleName string)) *MockAccountKeeper_GetModuleAccount_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(types.Context), args[1].(string)) + }) + return _c +} + +func (_c *MockAccountKeeper_GetModuleAccount_Call) Return(_a0 authtypes.ModuleAccountI) *MockAccountKeeper_GetModuleAccount_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockAccountKeeper_GetModuleAccount_Call) RunAndReturn(run func(types.Context, string) authtypes.ModuleAccountI) *MockAccountKeeper_GetModuleAccount_Call { + _c.Call.Return(run) + return _c +} + +// GetModuleAddress provides a mock function with given fields: moduleName +func (_m *MockAccountKeeper) GetModuleAddress(moduleName string) types.AccAddress { + ret := _m.Called(moduleName) + + if len(ret) == 0 { + panic("no return value specified for GetModuleAddress") + } + + var r0 types.AccAddress + if rf, ok := ret.Get(0).(func(string) types.AccAddress); ok { + r0 = rf(moduleName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(types.AccAddress) + } + } + + return r0 +} + +// MockAccountKeeper_GetModuleAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetModuleAddress' +type MockAccountKeeper_GetModuleAddress_Call struct { + *mock.Call +} + +// GetModuleAddress is a helper method to define mock.On call +// - moduleName string +func (_e *MockAccountKeeper_Expecter) GetModuleAddress(moduleName interface{}) *MockAccountKeeper_GetModuleAddress_Call { + return &MockAccountKeeper_GetModuleAddress_Call{Call: _e.mock.On("GetModuleAddress", moduleName)} +} + +func (_c *MockAccountKeeper_GetModuleAddress_Call) Run(run func(moduleName string)) *MockAccountKeeper_GetModuleAddress_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockAccountKeeper_GetModuleAddress_Call) Return(_a0 types.AccAddress) *MockAccountKeeper_GetModuleAddress_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockAccountKeeper_GetModuleAddress_Call) RunAndReturn(run func(string) types.AccAddress) *MockAccountKeeper_GetModuleAddress_Call { + _c.Call.Return(run) + return _c +} + +// GetSequence provides a mock function with given fields: _a0, _a1 +func (_m *MockAccountKeeper) GetSequence(_a0 types.Context, _a1 types.AccAddress) (uint64, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for GetSequence") + } + + var r0 uint64 + var r1 error + if rf, ok := ret.Get(0).(func(types.Context, types.AccAddress) (uint64, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(types.Context, types.AccAddress) uint64); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Get(0).(uint64) + } + + if rf, ok := ret.Get(1).(func(types.Context, types.AccAddress) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockAccountKeeper_GetSequence_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSequence' +type MockAccountKeeper_GetSequence_Call struct { + *mock.Call +} + +// GetSequence is a helper method to define mock.On call +// - _a0 types.Context +// - _a1 types.AccAddress +func (_e *MockAccountKeeper_Expecter) GetSequence(_a0 interface{}, _a1 interface{}) *MockAccountKeeper_GetSequence_Call { + return &MockAccountKeeper_GetSequence_Call{Call: _e.mock.On("GetSequence", _a0, _a1)} +} + +func (_c *MockAccountKeeper_GetSequence_Call) Run(run func(_a0 types.Context, _a1 types.AccAddress)) *MockAccountKeeper_GetSequence_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(types.Context), args[1].(types.AccAddress)) + }) + return _c +} + +func (_c *MockAccountKeeper_GetSequence_Call) Return(_a0 uint64, _a1 error) *MockAccountKeeper_GetSequence_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockAccountKeeper_GetSequence_Call) RunAndReturn(run func(types.Context, types.AccAddress) (uint64, error)) *MockAccountKeeper_GetSequence_Call { + _c.Call.Return(run) + return _c +} + +// NewMockAccountKeeper creates a new instance of MockAccountKeeper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockAccountKeeper(t interface { + mock.TestingT + Cleanup(func()) +}) *MockAccountKeeper { + mock := &MockAccountKeeper{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/x/precisebank/types/mocks/MockBankKeeper.go b/x/precisebank/types/mocks/MockBankKeeper.go new file mode 100644 index 00000000..b52140a8 --- /dev/null +++ b/x/precisebank/types/mocks/MockBankKeeper.go @@ -0,0 +1,530 @@ +// Code generated by mockery v2.43.0. DO NOT EDIT. + +package mocks + +import ( + mock "github.com/stretchr/testify/mock" + + types "github.com/cosmos/cosmos-sdk/types" +) + +// MockBankKeeper is an autogenerated mock type for the BankKeeper type +type MockBankKeeper struct { + mock.Mock +} + +type MockBankKeeper_Expecter struct { + mock *mock.Mock +} + +func (_m *MockBankKeeper) EXPECT() *MockBankKeeper_Expecter { + return &MockBankKeeper_Expecter{mock: &_m.Mock} +} + +// BlockedAddr provides a mock function with given fields: addr +func (_m *MockBankKeeper) BlockedAddr(addr types.AccAddress) bool { + ret := _m.Called(addr) + + if len(ret) == 0 { + panic("no return value specified for BlockedAddr") + } + + var r0 bool + if rf, ok := ret.Get(0).(func(types.AccAddress) bool); ok { + r0 = rf(addr) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// MockBankKeeper_BlockedAddr_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BlockedAddr' +type MockBankKeeper_BlockedAddr_Call struct { + *mock.Call +} + +// BlockedAddr is a helper method to define mock.On call +// - addr types.AccAddress +func (_e *MockBankKeeper_Expecter) BlockedAddr(addr interface{}) *MockBankKeeper_BlockedAddr_Call { + return &MockBankKeeper_BlockedAddr_Call{Call: _e.mock.On("BlockedAddr", addr)} +} + +func (_c *MockBankKeeper_BlockedAddr_Call) Run(run func(addr types.AccAddress)) *MockBankKeeper_BlockedAddr_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(types.AccAddress)) + }) + return _c +} + +func (_c *MockBankKeeper_BlockedAddr_Call) Return(_a0 bool) *MockBankKeeper_BlockedAddr_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBankKeeper_BlockedAddr_Call) RunAndReturn(run func(types.AccAddress) bool) *MockBankKeeper_BlockedAddr_Call { + _c.Call.Return(run) + return _c +} + +// BurnCoins provides a mock function with given fields: ctx, moduleName, amt +func (_m *MockBankKeeper) BurnCoins(ctx types.Context, moduleName string, amt types.Coins) error { + ret := _m.Called(ctx, moduleName, amt) + + if len(ret) == 0 { + panic("no return value specified for BurnCoins") + } + + var r0 error + if rf, ok := ret.Get(0).(func(types.Context, string, types.Coins) error); ok { + r0 = rf(ctx, moduleName, amt) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBankKeeper_BurnCoins_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BurnCoins' +type MockBankKeeper_BurnCoins_Call struct { + *mock.Call +} + +// BurnCoins is a helper method to define mock.On call +// - ctx types.Context +// - moduleName string +// - amt types.Coins +func (_e *MockBankKeeper_Expecter) BurnCoins(ctx interface{}, moduleName interface{}, amt interface{}) *MockBankKeeper_BurnCoins_Call { + return &MockBankKeeper_BurnCoins_Call{Call: _e.mock.On("BurnCoins", ctx, moduleName, amt)} +} + +func (_c *MockBankKeeper_BurnCoins_Call) Run(run func(ctx types.Context, moduleName string, amt types.Coins)) *MockBankKeeper_BurnCoins_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(types.Context), args[1].(string), args[2].(types.Coins)) + }) + return _c +} + +func (_c *MockBankKeeper_BurnCoins_Call) Return(_a0 error) *MockBankKeeper_BurnCoins_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBankKeeper_BurnCoins_Call) RunAndReturn(run func(types.Context, string, types.Coins) error) *MockBankKeeper_BurnCoins_Call { + _c.Call.Return(run) + return _c +} + +// GetBalance provides a mock function with given fields: ctx, addr, denom +func (_m *MockBankKeeper) GetBalance(ctx types.Context, addr types.AccAddress, denom string) types.Coin { + ret := _m.Called(ctx, addr, denom) + + if len(ret) == 0 { + panic("no return value specified for GetBalance") + } + + var r0 types.Coin + if rf, ok := ret.Get(0).(func(types.Context, types.AccAddress, string) types.Coin); ok { + r0 = rf(ctx, addr, denom) + } else { + r0 = ret.Get(0).(types.Coin) + } + + return r0 +} + +// MockBankKeeper_GetBalance_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBalance' +type MockBankKeeper_GetBalance_Call struct { + *mock.Call +} + +// GetBalance is a helper method to define mock.On call +// - ctx types.Context +// - addr types.AccAddress +// - denom string +func (_e *MockBankKeeper_Expecter) GetBalance(ctx interface{}, addr interface{}, denom interface{}) *MockBankKeeper_GetBalance_Call { + return &MockBankKeeper_GetBalance_Call{Call: _e.mock.On("GetBalance", ctx, addr, denom)} +} + +func (_c *MockBankKeeper_GetBalance_Call) Run(run func(ctx types.Context, addr types.AccAddress, denom string)) *MockBankKeeper_GetBalance_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(types.Context), args[1].(types.AccAddress), args[2].(string)) + }) + return _c +} + +func (_c *MockBankKeeper_GetBalance_Call) Return(_a0 types.Coin) *MockBankKeeper_GetBalance_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBankKeeper_GetBalance_Call) RunAndReturn(run func(types.Context, types.AccAddress, string) types.Coin) *MockBankKeeper_GetBalance_Call { + _c.Call.Return(run) + return _c +} + +// GetSupply provides a mock function with given fields: ctx, denom +func (_m *MockBankKeeper) GetSupply(ctx types.Context, denom string) types.Coin { + ret := _m.Called(ctx, denom) + + if len(ret) == 0 { + panic("no return value specified for GetSupply") + } + + var r0 types.Coin + if rf, ok := ret.Get(0).(func(types.Context, string) types.Coin); ok { + r0 = rf(ctx, denom) + } else { + r0 = ret.Get(0).(types.Coin) + } + + return r0 +} + +// MockBankKeeper_GetSupply_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSupply' +type MockBankKeeper_GetSupply_Call struct { + *mock.Call +} + +// GetSupply is a helper method to define mock.On call +// - ctx types.Context +// - denom string +func (_e *MockBankKeeper_Expecter) GetSupply(ctx interface{}, denom interface{}) *MockBankKeeper_GetSupply_Call { + return &MockBankKeeper_GetSupply_Call{Call: _e.mock.On("GetSupply", ctx, denom)} +} + +func (_c *MockBankKeeper_GetSupply_Call) Run(run func(ctx types.Context, denom string)) *MockBankKeeper_GetSupply_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(types.Context), args[1].(string)) + }) + return _c +} + +func (_c *MockBankKeeper_GetSupply_Call) Return(_a0 types.Coin) *MockBankKeeper_GetSupply_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBankKeeper_GetSupply_Call) RunAndReturn(run func(types.Context, string) types.Coin) *MockBankKeeper_GetSupply_Call { + _c.Call.Return(run) + return _c +} + +// IsSendEnabledCoins provides a mock function with given fields: ctx, coins +func (_m *MockBankKeeper) IsSendEnabledCoins(ctx types.Context, coins ...types.Coin) error { + _va := make([]interface{}, len(coins)) + for _i := range coins { + _va[_i] = coins[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for IsSendEnabledCoins") + } + + var r0 error + if rf, ok := ret.Get(0).(func(types.Context, ...types.Coin) error); ok { + r0 = rf(ctx, coins...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBankKeeper_IsSendEnabledCoins_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsSendEnabledCoins' +type MockBankKeeper_IsSendEnabledCoins_Call struct { + *mock.Call +} + +// IsSendEnabledCoins is a helper method to define mock.On call +// - ctx types.Context +// - coins ...types.Coin +func (_e *MockBankKeeper_Expecter) IsSendEnabledCoins(ctx interface{}, coins ...interface{}) *MockBankKeeper_IsSendEnabledCoins_Call { + return &MockBankKeeper_IsSendEnabledCoins_Call{Call: _e.mock.On("IsSendEnabledCoins", + append([]interface{}{ctx}, coins...)...)} +} + +func (_c *MockBankKeeper_IsSendEnabledCoins_Call) Run(run func(ctx types.Context, coins ...types.Coin)) *MockBankKeeper_IsSendEnabledCoins_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]types.Coin, len(args)-1) + for i, a := range args[1:] { + if a != nil { + variadicArgs[i] = a.(types.Coin) + } + } + run(args[0].(types.Context), variadicArgs...) + }) + return _c +} + +func (_c *MockBankKeeper_IsSendEnabledCoins_Call) Return(_a0 error) *MockBankKeeper_IsSendEnabledCoins_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBankKeeper_IsSendEnabledCoins_Call) RunAndReturn(run func(types.Context, ...types.Coin) error) *MockBankKeeper_IsSendEnabledCoins_Call { + _c.Call.Return(run) + return _c +} + +// MintCoins provides a mock function with given fields: ctx, moduleName, amt +func (_m *MockBankKeeper) MintCoins(ctx types.Context, moduleName string, amt types.Coins) error { + ret := _m.Called(ctx, moduleName, amt) + + if len(ret) == 0 { + panic("no return value specified for MintCoins") + } + + var r0 error + if rf, ok := ret.Get(0).(func(types.Context, string, types.Coins) error); ok { + r0 = rf(ctx, moduleName, amt) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBankKeeper_MintCoins_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MintCoins' +type MockBankKeeper_MintCoins_Call struct { + *mock.Call +} + +// MintCoins is a helper method to define mock.On call +// - ctx types.Context +// - moduleName string +// - amt types.Coins +func (_e *MockBankKeeper_Expecter) MintCoins(ctx interface{}, moduleName interface{}, amt interface{}) *MockBankKeeper_MintCoins_Call { + return &MockBankKeeper_MintCoins_Call{Call: _e.mock.On("MintCoins", ctx, moduleName, amt)} +} + +func (_c *MockBankKeeper_MintCoins_Call) Run(run func(ctx types.Context, moduleName string, amt types.Coins)) *MockBankKeeper_MintCoins_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(types.Context), args[1].(string), args[2].(types.Coins)) + }) + return _c +} + +func (_c *MockBankKeeper_MintCoins_Call) Return(_a0 error) *MockBankKeeper_MintCoins_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBankKeeper_MintCoins_Call) RunAndReturn(run func(types.Context, string, types.Coins) error) *MockBankKeeper_MintCoins_Call { + _c.Call.Return(run) + return _c +} + +// SendCoins provides a mock function with given fields: ctx, fromAddr, toAddr, amt +func (_m *MockBankKeeper) SendCoins(ctx types.Context, fromAddr types.AccAddress, toAddr types.AccAddress, amt types.Coins) error { + ret := _m.Called(ctx, fromAddr, toAddr, amt) + + if len(ret) == 0 { + panic("no return value specified for SendCoins") + } + + var r0 error + if rf, ok := ret.Get(0).(func(types.Context, types.AccAddress, types.AccAddress, types.Coins) error); ok { + r0 = rf(ctx, fromAddr, toAddr, amt) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBankKeeper_SendCoins_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendCoins' +type MockBankKeeper_SendCoins_Call struct { + *mock.Call +} + +// SendCoins is a helper method to define mock.On call +// - ctx types.Context +// - fromAddr types.AccAddress +// - toAddr types.AccAddress +// - amt types.Coins +func (_e *MockBankKeeper_Expecter) SendCoins(ctx interface{}, fromAddr interface{}, toAddr interface{}, amt interface{}) *MockBankKeeper_SendCoins_Call { + return &MockBankKeeper_SendCoins_Call{Call: _e.mock.On("SendCoins", ctx, fromAddr, toAddr, amt)} +} + +func (_c *MockBankKeeper_SendCoins_Call) Run(run func(ctx types.Context, fromAddr types.AccAddress, toAddr types.AccAddress, amt types.Coins)) *MockBankKeeper_SendCoins_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(types.Context), args[1].(types.AccAddress), args[2].(types.AccAddress), args[3].(types.Coins)) + }) + return _c +} + +func (_c *MockBankKeeper_SendCoins_Call) Return(_a0 error) *MockBankKeeper_SendCoins_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBankKeeper_SendCoins_Call) RunAndReturn(run func(types.Context, types.AccAddress, types.AccAddress, types.Coins) error) *MockBankKeeper_SendCoins_Call { + _c.Call.Return(run) + return _c +} + +// SendCoinsFromAccountToModule provides a mock function with given fields: ctx, senderAddr, recipientModule, amt +func (_m *MockBankKeeper) SendCoinsFromAccountToModule(ctx types.Context, senderAddr types.AccAddress, recipientModule string, amt types.Coins) error { + ret := _m.Called(ctx, senderAddr, recipientModule, amt) + + if len(ret) == 0 { + panic("no return value specified for SendCoinsFromAccountToModule") + } + + var r0 error + if rf, ok := ret.Get(0).(func(types.Context, types.AccAddress, string, types.Coins) error); ok { + r0 = rf(ctx, senderAddr, recipientModule, amt) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBankKeeper_SendCoinsFromAccountToModule_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendCoinsFromAccountToModule' +type MockBankKeeper_SendCoinsFromAccountToModule_Call struct { + *mock.Call +} + +// SendCoinsFromAccountToModule is a helper method to define mock.On call +// - ctx types.Context +// - senderAddr types.AccAddress +// - recipientModule string +// - amt types.Coins +func (_e *MockBankKeeper_Expecter) SendCoinsFromAccountToModule(ctx interface{}, senderAddr interface{}, recipientModule interface{}, amt interface{}) *MockBankKeeper_SendCoinsFromAccountToModule_Call { + return &MockBankKeeper_SendCoinsFromAccountToModule_Call{Call: _e.mock.On("SendCoinsFromAccountToModule", ctx, senderAddr, recipientModule, amt)} +} + +func (_c *MockBankKeeper_SendCoinsFromAccountToModule_Call) Run(run func(ctx types.Context, senderAddr types.AccAddress, recipientModule string, amt types.Coins)) *MockBankKeeper_SendCoinsFromAccountToModule_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(types.Context), args[1].(types.AccAddress), args[2].(string), args[3].(types.Coins)) + }) + return _c +} + +func (_c *MockBankKeeper_SendCoinsFromAccountToModule_Call) Return(_a0 error) *MockBankKeeper_SendCoinsFromAccountToModule_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBankKeeper_SendCoinsFromAccountToModule_Call) RunAndReturn(run func(types.Context, types.AccAddress, string, types.Coins) error) *MockBankKeeper_SendCoinsFromAccountToModule_Call { + _c.Call.Return(run) + return _c +} + +// SendCoinsFromModuleToAccount provides a mock function with given fields: ctx, senderModule, recipientAddr, amt +func (_m *MockBankKeeper) SendCoinsFromModuleToAccount(ctx types.Context, senderModule string, recipientAddr types.AccAddress, amt types.Coins) error { + ret := _m.Called(ctx, senderModule, recipientAddr, amt) + + if len(ret) == 0 { + panic("no return value specified for SendCoinsFromModuleToAccount") + } + + var r0 error + if rf, ok := ret.Get(0).(func(types.Context, string, types.AccAddress, types.Coins) error); ok { + r0 = rf(ctx, senderModule, recipientAddr, amt) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBankKeeper_SendCoinsFromModuleToAccount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendCoinsFromModuleToAccount' +type MockBankKeeper_SendCoinsFromModuleToAccount_Call struct { + *mock.Call +} + +// SendCoinsFromModuleToAccount is a helper method to define mock.On call +// - ctx types.Context +// - senderModule string +// - recipientAddr types.AccAddress +// - amt types.Coins +func (_e *MockBankKeeper_Expecter) SendCoinsFromModuleToAccount(ctx interface{}, senderModule interface{}, recipientAddr interface{}, amt interface{}) *MockBankKeeper_SendCoinsFromModuleToAccount_Call { + return &MockBankKeeper_SendCoinsFromModuleToAccount_Call{Call: _e.mock.On("SendCoinsFromModuleToAccount", ctx, senderModule, recipientAddr, amt)} +} + +func (_c *MockBankKeeper_SendCoinsFromModuleToAccount_Call) Run(run func(ctx types.Context, senderModule string, recipientAddr types.AccAddress, amt types.Coins)) *MockBankKeeper_SendCoinsFromModuleToAccount_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(types.Context), args[1].(string), args[2].(types.AccAddress), args[3].(types.Coins)) + }) + return _c +} + +func (_c *MockBankKeeper_SendCoinsFromModuleToAccount_Call) Return(_a0 error) *MockBankKeeper_SendCoinsFromModuleToAccount_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBankKeeper_SendCoinsFromModuleToAccount_Call) RunAndReturn(run func(types.Context, string, types.AccAddress, types.Coins) error) *MockBankKeeper_SendCoinsFromModuleToAccount_Call { + _c.Call.Return(run) + return _c +} + +// SpendableCoins provides a mock function with given fields: ctx, addr +func (_m *MockBankKeeper) SpendableCoins(ctx types.Context, addr types.AccAddress) types.Coins { + ret := _m.Called(ctx, addr) + + if len(ret) == 0 { + panic("no return value specified for SpendableCoins") + } + + var r0 types.Coins + if rf, ok := ret.Get(0).(func(types.Context, types.AccAddress) types.Coins); ok { + r0 = rf(ctx, addr) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(types.Coins) + } + } + + return r0 +} + +// MockBankKeeper_SpendableCoins_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SpendableCoins' +type MockBankKeeper_SpendableCoins_Call struct { + *mock.Call +} + +// SpendableCoins is a helper method to define mock.On call +// - ctx types.Context +// - addr types.AccAddress +func (_e *MockBankKeeper_Expecter) SpendableCoins(ctx interface{}, addr interface{}) *MockBankKeeper_SpendableCoins_Call { + return &MockBankKeeper_SpendableCoins_Call{Call: _e.mock.On("SpendableCoins", ctx, addr)} +} + +func (_c *MockBankKeeper_SpendableCoins_Call) Run(run func(ctx types.Context, addr types.AccAddress)) *MockBankKeeper_SpendableCoins_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(types.Context), args[1].(types.AccAddress)) + }) + return _c +} + +func (_c *MockBankKeeper_SpendableCoins_Call) Return(_a0 types.Coins) *MockBankKeeper_SpendableCoins_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBankKeeper_SpendableCoins_Call) RunAndReturn(run func(types.Context, types.AccAddress) types.Coins) *MockBankKeeper_SpendableCoins_Call { + _c.Call.Return(run) + return _c +} + +// NewMockBankKeeper creates a new instance of MockBankKeeper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockBankKeeper(t interface { + mock.TestingT + Cleanup(func()) +}) *MockBankKeeper { + mock := &MockBankKeeper{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +}