feat(bank/v2): Send function (#21606)

This commit is contained in:
Hieu Vu 2024-09-12 19:27:45 +07:00 committed by GitHub
parent bf817f89aa
commit a77a92adf1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 682 additions and 3 deletions

View File

@ -1,12 +1,20 @@
package keeper
import (
"context"
"cosmossdk.io/collections"
"cosmossdk.io/collections/indexes"
"cosmossdk.io/core/address"
appmodulev2 "cosmossdk.io/core/appmodule/v2"
"cosmossdk.io/core/event"
errorsmod "cosmossdk.io/errors"
"cosmossdk.io/math"
"cosmossdk.io/x/bank/v2/types"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// Keeper defines the bank/v2 module keeper.
@ -18,6 +26,8 @@ type Keeper struct {
addressCodec address.Codec
schema collections.Schema
params collections.Item[types.Params]
balances *collections.IndexedMap[collections.Pair[[]byte, string], math.Int, BalancesIndexes]
supply collections.Map[string, math.Int]
}
func NewKeeper(authority []byte, addressCodec address.Codec, env appmodulev2.Environment, cdc codec.BinaryCodec) *Keeper {
@ -28,6 +38,8 @@ func NewKeeper(authority []byte, addressCodec address.Codec, env appmodulev2.Env
authority: authority,
addressCodec: addressCodec, // TODO(@julienrbrt): Should we add address codec to the environment?
params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)),
balances: collections.NewIndexedMap(sb, types.BalancesPrefix, "balances", collections.PairKeyCodec(collections.BytesKey, collections.StringKey), sdk.IntValue, newBalancesIndexes(sb)),
supply: collections.NewMap(sb, types.SupplyKey, "supply", collections.StringKey, sdk.IntValue),
}
schema, err := sb.Build()
@ -38,3 +50,205 @@ func NewKeeper(authority []byte, addressCodec address.Codec, env appmodulev2.Env
return k
}
// MintCoins creates new coins from thin air and adds it to the module account.
// An error is returned if the module account does not exist or is unauthorized.
func (k Keeper) MintCoins(ctx context.Context, addr []byte, amounts sdk.Coins) error {
// TODO: Mint restriction & permission
if !amounts.IsValid() {
return errorsmod.Wrap(sdkerrors.ErrInvalidCoins, amounts.String())
}
err := k.addCoins(ctx, addr, amounts)
if err != nil {
return err
}
for _, amount := range amounts {
supply := k.GetSupply(ctx, amount.GetDenom())
supply = supply.Add(amount)
k.setSupply(ctx, supply)
}
addrStr, err := k.addressCodec.BytesToString(addr)
if err != nil {
return err
}
// emit mint event
return k.EventService.EventManager(ctx).EmitKV(
types.EventTypeCoinMint,
event.NewAttribute(types.AttributeKeyMinter, addrStr),
event.NewAttribute(sdk.AttributeKeyAmount, amounts.String()),
)
}
// SendCoins transfers amt coins from a sending account to a receiving account.
// Function take sender & receipient as []byte.
// They can be sdk address or module name.
// An error is returned upon failure.
func (k Keeper) SendCoins(ctx context.Context, from, to []byte, amt sdk.Coins) error {
if !amt.IsValid() {
return errorsmod.Wrap(sdkerrors.ErrInvalidCoins, amt.String())
}
var err error
// TODO: Send restriction
err = k.subUnlockedCoins(ctx, from, amt)
if err != nil {
return err
}
err = k.addCoins(ctx, to, amt)
if err != nil {
return err
}
fromAddrString, err := k.addressCodec.BytesToString(from)
if err != nil {
return err
}
toAddrString, err := k.addressCodec.BytesToString(to)
if err != nil {
return err
}
return k.EventService.EventManager(ctx).EmitKV(
types.EventTypeTransfer,
event.NewAttribute(types.AttributeKeyRecipient, toAddrString),
event.NewAttribute(types.AttributeKeySender, fromAddrString),
event.NewAttribute(sdk.AttributeKeyAmount, amt.String()),
)
}
// GetSupply retrieves the Supply from store
func (k Keeper) GetSupply(ctx context.Context, denom string) sdk.Coin {
amt, err := k.supply.Get(ctx, denom)
if err != nil {
return sdk.NewCoin(denom, math.ZeroInt())
}
return sdk.NewCoin(denom, amt)
}
// GetBalance returns the balance of a specific denomination for a given account
// by address.
func (k Keeper) GetBalance(ctx context.Context, addr []byte, denom string) sdk.Coin {
amt, err := k.balances.Get(ctx, collections.Join(addr, denom))
if err != nil {
return sdk.NewCoin(denom, math.ZeroInt())
}
return sdk.NewCoin(denom, amt)
}
// subUnlockedCoins removes the unlocked amt coins of the given account.
// An error is returned if the resulting balance is negative.
//
// CONTRACT: The provided amount (amt) must be valid, non-negative coins.
//
// A coin_spent event is emitted after the operation.
func (k Keeper) subUnlockedCoins(ctx context.Context, addr []byte, amt sdk.Coins) error {
for _, coin := range amt {
balance := k.GetBalance(ctx, addr, coin.Denom)
spendable := sdk.Coins{balance}
_, hasNeg := spendable.SafeSub(coin)
if hasNeg {
if len(spendable) == 0 {
spendable = sdk.Coins{sdk.Coin{Denom: coin.Denom, Amount: math.ZeroInt()}}
}
return errorsmod.Wrapf(
sdkerrors.ErrInsufficientFunds,
"spendable balance %s is smaller than %s",
spendable, coin,
)
}
newBalance := balance.Sub(coin)
if err := k.setBalance(ctx, addr, newBalance); err != nil {
return err
}
}
addrStr, err := k.addressCodec.BytesToString(addr)
if err != nil {
return err
}
return k.EventService.EventManager(ctx).EmitKV(
types.EventTypeCoinSpent,
event.NewAttribute(types.AttributeKeySpender, addrStr),
event.NewAttribute(sdk.AttributeKeyAmount, amt.String()),
)
}
// addCoins increases the balance of the given address by the specified amount.
//
// CONTRACT: The provided amount (amt) must be valid, non-negative coins.
//
// It emits a coin_received event after the operation.
func (k Keeper) addCoins(ctx context.Context, addr []byte, amt sdk.Coins) error {
for _, coin := range amt {
balance := k.GetBalance(ctx, addr, coin.Denom)
newBalance := balance.Add(coin)
err := k.setBalance(ctx, addr, newBalance)
if err != nil {
return err
}
}
addrStr, err := k.addressCodec.BytesToString(addr)
if err != nil {
return err
}
return k.EventService.EventManager(ctx).EmitKV(
types.EventTypeCoinReceived,
event.NewAttribute(types.AttributeKeyReceiver, addrStr),
event.NewAttribute(sdk.AttributeKeyAmount, amt.String()),
)
}
// setSupply sets the supply for the given coin
func (k Keeper) setSupply(ctx context.Context, coin sdk.Coin) {
// Bank invariants and IBC requires to remove zero coins.
if coin.IsZero() {
_ = k.supply.Remove(ctx, coin.Denom)
} else {
_ = k.supply.Set(ctx, coin.Denom, coin.Amount)
}
}
// setBalance sets the coin balance for an account by address.
func (k Keeper) setBalance(ctx context.Context, addr []byte, balance sdk.Coin) error {
if !balance.IsValid() {
return errorsmod.Wrap(sdkerrors.ErrInvalidCoins, balance.String())
}
// x/bank invariants prohibit persistence of zero balances
if balance.IsZero() {
err := k.balances.Remove(ctx, collections.Join(addr, balance.Denom))
if err != nil {
return err
}
return nil
}
return k.balances.Set(ctx, collections.Join(addr, balance.Denom), balance.Amount)
}
func newBalancesIndexes(sb *collections.SchemaBuilder) BalancesIndexes {
return BalancesIndexes{
Denom: indexes.NewReversePair[math.Int](
sb, types.DenomAddressPrefix, "address_by_denom_index",
collections.PairKeyCodec(collections.BytesKey, collections.StringKey),
indexes.WithReversePairUncheckedValue(), // denom to address indexes were stored as Key: Join(denom, address) Value: []byte{0}, this will migrate the value to []byte{} in a lazy way.
),
}
}
type BalancesIndexes struct {
Denom *indexes.ReversePair[[]byte, string, math.Int]
}

View File

@ -0,0 +1,186 @@
package keeper_test
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/suite"
"cosmossdk.io/core/address"
"cosmossdk.io/core/header"
coretesting "cosmossdk.io/core/testing"
"cosmossdk.io/math"
storetypes "cosmossdk.io/store/types"
"cosmossdk.io/x/bank/v2/keeper"
banktestutil "cosmossdk.io/x/bank/v2/testutil"
banktypes "cosmossdk.io/x/bank/v2/types"
codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil"
"github.com/cosmos/cosmos-sdk/runtime"
"github.com/cosmos/cosmos-sdk/testutil"
sdk "github.com/cosmos/cosmos-sdk/types"
moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)
const (
fooDenom = "foo"
barDenom = "bar"
)
var (
burnerAcc = authtypes.NewEmptyModuleAccount(authtypes.Burner, authtypes.Burner, authtypes.Staking)
mintAcc = authtypes.NewEmptyModuleAccount(banktypes.MintModuleName, authtypes.Minter)
accAddrs = []sdk.AccAddress{
sdk.AccAddress([]byte("addr1_______________")),
sdk.AccAddress([]byte("addr2_______________")),
sdk.AccAddress([]byte("addr3_______________")),
sdk.AccAddress([]byte("addr4_______________")),
sdk.AccAddress([]byte("addr5_______________")),
}
)
func newFooCoin(amt int64) sdk.Coin {
return sdk.NewInt64Coin(fooDenom, amt)
}
func newBarCoin(amt int64) sdk.Coin {
return sdk.NewInt64Coin(barDenom, amt)
}
type KeeperTestSuite struct {
suite.Suite
ctx context.Context
bankKeeper keeper.Keeper
addressCodec address.Codec
}
func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
}
func (suite *KeeperTestSuite) SetupTest() {
key := storetypes.NewKVStoreKey(banktypes.StoreKey)
testCtx := testutil.DefaultContextWithDB(suite.T(), key, storetypes.NewTransientStoreKey("transient_test"))
ctx := testCtx.Ctx.WithHeaderInfo(header.Info{Time: time.Now()})
encCfg := moduletestutil.MakeTestEncodingConfig(codectestutil.CodecOptions{})
env := runtime.NewEnvironment(runtime.NewKVStoreService(key), coretesting.NewNopLogger())
ac := codectestutil.CodecOptions{}.GetAddressCodec()
authority := authtypes.NewModuleAddress("gov")
suite.ctx = ctx
suite.bankKeeper = *keeper.NewKeeper(
authority,
ac,
env,
encCfg.Codec,
)
suite.addressCodec = ac
}
func (suite *KeeperTestSuite) TestSendCoins_Acount_To_Account() {
ctx := suite.ctx
require := suite.Require()
balances := sdk.NewCoins(newFooCoin(100), newBarCoin(50))
sendAmt := sdk.NewCoins(newFooCoin(10), newBarCoin(10))
// Try send with empty balances
err := suite.bankKeeper.SendCoins(ctx, accAddrs[0], accAddrs[1], sendAmt)
require.Error(err)
// Set balances for acc0 and then try send to acc1
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], balances))
require.NoError(suite.bankKeeper.SendCoins(ctx, accAddrs[0], accAddrs[1], sendAmt))
// Check balances
acc0FooBalance := suite.bankKeeper.GetBalance(ctx, accAddrs[0], fooDenom)
require.Equal(acc0FooBalance.Amount, math.NewInt(90))
acc0BarBalance := suite.bankKeeper.GetBalance(ctx, accAddrs[0], barDenom)
require.Equal(acc0BarBalance.Amount, math.NewInt(40))
acc1FooBalance := suite.bankKeeper.GetBalance(ctx, accAddrs[1], fooDenom)
require.Equal(acc1FooBalance.Amount, math.NewInt(10))
acc1BarBalance := suite.bankKeeper.GetBalance(ctx, accAddrs[1], barDenom)
require.Equal(acc1BarBalance.Amount, math.NewInt(10))
}
func (suite *KeeperTestSuite) TestSendCoins_Acount_To_Module() {
ctx := suite.ctx
require := suite.Require()
balances := sdk.NewCoins(newFooCoin(100), newBarCoin(50))
sendAmt := sdk.NewCoins(newFooCoin(10), newBarCoin(10))
// Try send with empty balances
err := suite.bankKeeper.SendCoins(ctx, accAddrs[0], burnerAcc.GetAddress(), sendAmt)
require.Error(err)
// Set balances for acc0 and then try send to acc1
require.NoError(banktestutil.FundAccount(ctx, suite.bankKeeper, accAddrs[0], balances))
require.NoError(suite.bankKeeper.SendCoins(ctx, accAddrs[0], burnerAcc.GetAddress(), sendAmt))
// Check balances
acc0FooBalance := suite.bankKeeper.GetBalance(ctx, accAddrs[0], fooDenom)
require.Equal(acc0FooBalance.Amount, math.NewInt(90))
acc0BarBalance := suite.bankKeeper.GetBalance(ctx, accAddrs[0], barDenom)
require.Equal(acc0BarBalance.Amount, math.NewInt(40))
burnerFooBalance := suite.bankKeeper.GetBalance(ctx, burnerAcc.GetAddress(), fooDenom)
require.Equal(burnerFooBalance.Amount, math.NewInt(10))
burnerBarBalance := suite.bankKeeper.GetBalance(ctx, burnerAcc.GetAddress(), barDenom)
require.Equal(burnerBarBalance.Amount, math.NewInt(10))
}
func (suite *KeeperTestSuite) TestSendCoins_Module_To_Account() {
ctx := suite.ctx
require := suite.Require()
balances := sdk.NewCoins(newFooCoin(100), newBarCoin(50))
require.NoError(suite.bankKeeper.MintCoins(ctx, mintAcc.GetAddress(), balances))
// Try send from burner module
err := suite.bankKeeper.SendCoins(ctx, burnerAcc.GetAddress(), accAddrs[4], balances)
require.Error(err)
// Send from mint module
err = suite.bankKeeper.SendCoins(ctx, mintAcc.GetAddress(), accAddrs[4], balances)
require.NoError(err)
// Check balances
acc4FooBalance := suite.bankKeeper.GetBalance(ctx, accAddrs[4], fooDenom)
require.Equal(acc4FooBalance.Amount, math.NewInt(100))
acc4BarBalance := suite.bankKeeper.GetBalance(ctx, accAddrs[4], barDenom)
require.Equal(acc4BarBalance.Amount, math.NewInt(50))
mintFooBalance := suite.bankKeeper.GetBalance(ctx, mintAcc.GetAddress(), fooDenom)
require.Equal(mintFooBalance.Amount, math.NewInt(0))
mintBarBalance := suite.bankKeeper.GetBalance(ctx, mintAcc.GetAddress(), barDenom)
require.Equal(mintBarBalance.Amount, math.NewInt(0))
}
func (suite *KeeperTestSuite) TestSendCoins_Module_To_Module() {
ctx := suite.ctx
require := suite.Require()
balances := sdk.NewCoins(newFooCoin(100), newBarCoin(50))
require.NoError(suite.bankKeeper.MintCoins(ctx, mintAcc.GetAddress(), balances))
// Try send from burner module
err := suite.bankKeeper.SendCoins(ctx, burnerAcc.GetAddress(), mintAcc.GetAddress(), sdk.NewCoins(newFooCoin(100), newBarCoin(50)))
require.Error(err)
// Send from mint module to burn module
err = suite.bankKeeper.SendCoins(ctx, mintAcc.GetAddress(), burnerAcc.GetAddress(), sdk.NewCoins(newFooCoin(100), newBarCoin(50)))
require.NoError(err)
// Check balances
burnerFooBalance := suite.bankKeeper.GetBalance(ctx, burnerAcc.GetAddress(), fooDenom)
require.Equal(burnerFooBalance.Amount, math.NewInt(100))
burnerBarBalance := suite.bankKeeper.GetBalance(ctx, burnerAcc.GetAddress(), barDenom)
require.Equal(burnerBarBalance.Amount, math.NewInt(50))
mintFooBalance := suite.bankKeeper.GetBalance(ctx, mintAcc.GetAddress(), fooDenom)
require.Equal(mintFooBalance.Amount, math.NewInt(0))
mintBarBalance := suite.bankKeeper.GetBalance(ctx, mintAcc.GetAddress(), barDenom)
require.Equal(mintBarBalance.Amount, math.NewInt(0))
}

View File

@ -0,0 +1,218 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: x/bank/types/expected_keepers.go
// Package testutil is a generated GoMock package.
package testutil
import (
context "context"
reflect "reflect"
address "cosmossdk.io/core/address"
types "github.com/cosmos/cosmos-sdk/types"
types0 "github.com/cosmos/cosmos-sdk/x/auth/types"
gomock "github.com/golang/mock/gomock"
)
// MockAccountKeeper is a mock of AccountKeeper interface.
type MockAccountKeeper struct {
ctrl *gomock.Controller
recorder *MockAccountKeeperMockRecorder
}
// MockAccountKeeperMockRecorder is the mock recorder for MockAccountKeeper.
type MockAccountKeeperMockRecorder struct {
mock *MockAccountKeeper
}
// NewMockAccountKeeper creates a new mock instance.
func NewMockAccountKeeper(ctrl *gomock.Controller) *MockAccountKeeper {
mock := &MockAccountKeeper{ctrl: ctrl}
mock.recorder = &MockAccountKeeperMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockAccountKeeper) EXPECT() *MockAccountKeeperMockRecorder {
return m.recorder
}
// AddressCodec mocks base method.
func (m *MockAccountKeeper) AddressCodec() address.Codec {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddressCodec")
ret0, _ := ret[0].(address.Codec)
return ret0
}
// AddressCodec indicates an expected call of AddressCodec.
func (mr *MockAccountKeeperMockRecorder) AddressCodec() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddressCodec", reflect.TypeOf((*MockAccountKeeper)(nil).AddressCodec))
}
// GetAccount mocks base method.
func (m *MockAccountKeeper) GetAccount(ctx context.Context, addr types.AccAddress) types.AccountI {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetAccount", ctx, addr)
ret0, _ := ret[0].(types.AccountI)
return ret0
}
// GetAccount indicates an expected call of GetAccount.
func (mr *MockAccountKeeperMockRecorder) GetAccount(ctx, addr interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccount", reflect.TypeOf((*MockAccountKeeper)(nil).GetAccount), ctx, addr)
}
// GetModuleAccount mocks base method.
func (m *MockAccountKeeper) GetModuleAccount(ctx context.Context, moduleName string) types.ModuleAccountI {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetModuleAccount", ctx, moduleName)
ret0, _ := ret[0].(types.ModuleAccountI)
return ret0
}
// GetModuleAccount indicates an expected call of GetModuleAccount.
func (mr *MockAccountKeeperMockRecorder) GetModuleAccount(ctx, moduleName interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetModuleAccount", reflect.TypeOf((*MockAccountKeeper)(nil).GetModuleAccount), ctx, moduleName)
}
// GetModuleAccountAndPermissions mocks base method.
func (m *MockAccountKeeper) GetModuleAccountAndPermissions(ctx context.Context, moduleName string) (types.ModuleAccountI, []string) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetModuleAccountAndPermissions", ctx, moduleName)
ret0, _ := ret[0].(types.ModuleAccountI)
ret1, _ := ret[1].([]string)
return ret0, ret1
}
// GetModuleAccountAndPermissions indicates an expected call of GetModuleAccountAndPermissions.
func (mr *MockAccountKeeperMockRecorder) GetModuleAccountAndPermissions(ctx, moduleName interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetModuleAccountAndPermissions", reflect.TypeOf((*MockAccountKeeper)(nil).GetModuleAccountAndPermissions), ctx, moduleName)
}
// GetModuleAddress mocks base method.
func (m *MockAccountKeeper) GetModuleAddress(moduleName string) types.AccAddress {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetModuleAddress", moduleName)
ret0, _ := ret[0].(types.AccAddress)
return ret0
}
// GetModuleAddress indicates an expected call of GetModuleAddress.
func (mr *MockAccountKeeperMockRecorder) GetModuleAddress(moduleName interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetModuleAddress", reflect.TypeOf((*MockAccountKeeper)(nil).GetModuleAddress), moduleName)
}
// GetModuleAddressAndPermissions mocks base method.
func (m *MockAccountKeeper) GetModuleAddressAndPermissions(moduleName string) (types.AccAddress, []string) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetModuleAddressAndPermissions", moduleName)
ret0, _ := ret[0].(types.AccAddress)
ret1, _ := ret[1].([]string)
return ret0, ret1
}
// GetModuleAddressAndPermissions indicates an expected call of GetModuleAddressAndPermissions.
func (mr *MockAccountKeeperMockRecorder) GetModuleAddressAndPermissions(moduleName interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetModuleAddressAndPermissions", reflect.TypeOf((*MockAccountKeeper)(nil).GetModuleAddressAndPermissions), moduleName)
}
// GetModulePermissions mocks base method.
func (m *MockAccountKeeper) GetModulePermissions() map[string]types0.PermissionsForAddress {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetModulePermissions")
ret0, _ := ret[0].(map[string]types0.PermissionsForAddress)
return ret0
}
// GetModulePermissions indicates an expected call of GetModulePermissions.
func (mr *MockAccountKeeperMockRecorder) GetModulePermissions() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetModulePermissions", reflect.TypeOf((*MockAccountKeeper)(nil).GetModulePermissions))
}
// HasAccount mocks base method.
func (m *MockAccountKeeper) HasAccount(ctx context.Context, addr types.AccAddress) bool {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "HasAccount", ctx, addr)
ret0, _ := ret[0].(bool)
return ret0
}
// HasAccount indicates an expected call of HasAccount.
func (mr *MockAccountKeeperMockRecorder) HasAccount(ctx, addr interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasAccount", reflect.TypeOf((*MockAccountKeeper)(nil).HasAccount), ctx, addr)
}
// NewAccount mocks base method.
func (m *MockAccountKeeper) NewAccount(arg0 context.Context, arg1 types.AccountI) types.AccountI {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "NewAccount", arg0, arg1)
ret0, _ := ret[0].(types.AccountI)
return ret0
}
// NewAccount indicates an expected call of NewAccount.
func (mr *MockAccountKeeperMockRecorder) NewAccount(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewAccount", reflect.TypeOf((*MockAccountKeeper)(nil).NewAccount), arg0, arg1)
}
// NewAccountWithAddress mocks base method.
func (m *MockAccountKeeper) NewAccountWithAddress(ctx context.Context, addr types.AccAddress) types.AccountI {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "NewAccountWithAddress", ctx, addr)
ret0, _ := ret[0].(types.AccountI)
return ret0
}
// NewAccountWithAddress indicates an expected call of NewAccountWithAddress.
func (mr *MockAccountKeeperMockRecorder) NewAccountWithAddress(ctx, addr interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewAccountWithAddress", reflect.TypeOf((*MockAccountKeeper)(nil).NewAccountWithAddress), ctx, addr)
}
// SetAccount mocks base method.
func (m *MockAccountKeeper) SetAccount(ctx context.Context, acc types.AccountI) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "SetAccount", ctx, acc)
}
// SetAccount indicates an expected call of SetAccount.
func (mr *MockAccountKeeperMockRecorder) SetAccount(ctx, acc interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAccount", reflect.TypeOf((*MockAccountKeeper)(nil).SetAccount), ctx, acc)
}
// SetModuleAccount mocks base method.
func (m *MockAccountKeeper) SetModuleAccount(ctx context.Context, macc types.ModuleAccountI) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "SetModuleAccount", ctx, macc)
}
// SetModuleAccount indicates an expected call of SetModuleAccount.
func (mr *MockAccountKeeperMockRecorder) SetModuleAccount(ctx, macc interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetModuleAccount", reflect.TypeOf((*MockAccountKeeper)(nil).SetModuleAccount), ctx, macc)
}
// ValidatePermissions mocks base method.
func (m *MockAccountKeeper) ValidatePermissions(macc types.ModuleAccountI) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ValidatePermissions", macc)
ret0, _ := ret[0].(error)
return ret0
}
// ValidatePermissions indicates an expected call of ValidatePermissions.
func (mr *MockAccountKeeperMockRecorder) ValidatePermissions(macc interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidatePermissions", reflect.TypeOf((*MockAccountKeeper)(nil).ValidatePermissions), macc)
}

View File

@ -0,0 +1,16 @@
package testutil
import (
"context"
bankkeeper "cosmossdk.io/x/bank/v2/keeper"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// FundAccount is a utility function that funds an account by minting and
// sending the coins to the address. This should be used for testing purposes
// only!
func FundAccount(ctx context.Context, bankKeeper bankkeeper.Keeper, addr []byte, amounts sdk.Coins) error {
return bankKeeper.MintCoins(ctx, addr, amounts)
}

24
x/bank/v2/types/events.go Normal file
View File

@ -0,0 +1,24 @@
package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// bank module event types
const (
EventTypeTransfer = "transfer"
AttributeKeyRecipient = "recipient"
AttributeKeySender = sdk.AttributeKeySender
// supply and balance tracking events name and attributes
EventTypeCoinSpent = "coin_spent"
EventTypeCoinReceived = "coin_received"
EventTypeCoinMint = "coinbase" // NOTE(fdymylja): using mint clashes with mint module event
EventTypeCoinBurn = "burn"
AttributeKeySpender = "spender"
AttributeKeyReceiver = "receiver"
AttributeKeyMinter = "minter"
AttributeKeyBurner = "burner"
)

View File

@ -0,0 +1 @@
package types

View File

@ -1,14 +1,34 @@
package types
import "cosmossdk.io/collections"
import (
"cosmossdk.io/collections"
)
const (
// ModuleName is the name of the module
ModuleName = "bankv2"
// StoreKey defines the primary module store key
StoreKey = ModuleName
// GovModuleName duplicates the gov module's name to avoid a dependency with x/gov.
GovModuleName = "gov"
// MintModuleName duplicates the mint module's name to avoid a cyclic dependency with x/mint.
// It should be synced with the mint module's name if it is ever changed.
// See: https://github.com/cosmos/cosmos-sdk/blob/0e34478eb7420b69869ed50f129fc274a97a9b06/x/mint/types/keys.go#L13
MintModuleName = "mint"
)
// ParamsKey is the prefix for x/bank/v2 parameters
var ParamsKey = collections.NewPrefix(2)
var (
// ParamsKey is the prefix for x/bank/v2 parameters
ParamsKey = collections.NewPrefix(2)
// BalancesPrefix is the prefix for the account balances store. We use a byte
// (instead of `[]byte("balances")` to save some disk space).
BalancesPrefix = collections.NewPrefix(3)
DenomAddressPrefix = collections.NewPrefix(4)
SupplyKey = collections.NewPrefix(5)
)