github.com/Finschia/finschia-sdk@v0.48.1/simapp/test_helpers.go (about)

     1  package simapp
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/hex"
     6  	"encoding/json"
     7  	"fmt"
     8  	"math/rand"
     9  	"os"
    10  	"path/filepath"
    11  	"sort"
    12  	"strconv"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/stretchr/testify/require"
    17  	abci "github.com/tendermint/tendermint/abci/types"
    18  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
    19  	dbm "github.com/tendermint/tm-db"
    20  
    21  	ocabci "github.com/Finschia/ostracon/abci/types"
    22  	"github.com/Finschia/ostracon/libs/log"
    23  	octypes "github.com/Finschia/ostracon/types"
    24  
    25  	bam "github.com/Finschia/finschia-sdk/baseapp"
    26  	"github.com/Finschia/finschia-sdk/client"
    27  	"github.com/Finschia/finschia-sdk/crypto/keys/ed25519"
    28  	cryptotypes "github.com/Finschia/finschia-sdk/crypto/types"
    29  	"github.com/Finschia/finschia-sdk/simapp/helpers"
    30  	"github.com/Finschia/finschia-sdk/snapshots"
    31  	sdk "github.com/Finschia/finschia-sdk/types"
    32  	"github.com/Finschia/finschia-sdk/types/errors"
    33  	authtypes "github.com/Finschia/finschia-sdk/x/auth/types"
    34  	banktypes "github.com/Finschia/finschia-sdk/x/bank/types"
    35  	minttypes "github.com/Finschia/finschia-sdk/x/mint/types"
    36  )
    37  
    38  // DefaultConsensusParams defines the default Tendermint consensus params used in
    39  // SimApp testing.
    40  var DefaultConsensusParams = &abci.ConsensusParams{
    41  	Block: &abci.BlockParams{
    42  		MaxBytes: 200000,
    43  		MaxGas:   2000000,
    44  	},
    45  	Evidence: &tmproto.EvidenceParams{
    46  		MaxAgeNumBlocks: 302400,
    47  		MaxAgeDuration:  504 * time.Hour, // 3 weeks is the max duration
    48  		MaxBytes:        10000,
    49  	},
    50  	Validator: &tmproto.ValidatorParams{
    51  		PubKeyTypes: []string{
    52  			octypes.ABCIPubKeyTypeEd25519,
    53  		},
    54  	},
    55  }
    56  
    57  func setup(withGenesis bool, invCheckPeriod uint) (*SimApp, GenesisState) {
    58  	randDir, _ := os.MkdirTemp(DefaultNodeHome, "")
    59  	snapshotDir := filepath.Join(randDir, "data", "snapshots")
    60  	snapshotDB := dbm.NewMemDB()
    61  
    62  	snapshotStore, _ := snapshots.NewStore(snapshotDB, snapshotDir)
    63  	baseAppOpts := []func(*bam.BaseApp){bam.SetSnapshotStore(snapshotStore), bam.SetSnapshotKeepRecent(2)}
    64  
    65  	db := dbm.NewMemDB()
    66  	encCdc := MakeTestEncodingConfig()
    67  	app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, invCheckPeriod, encCdc, EmptyAppOptions{}, baseAppOpts...)
    68  	if withGenesis {
    69  		return app, NewDefaultGenesisState(encCdc.Marshaler)
    70  	}
    71  	return app, GenesisState{}
    72  }
    73  
    74  // Setup initializes a new SimApp. A Nop logger is set in SimApp.
    75  func Setup(isCheckTx bool) *SimApp {
    76  	app, genesisState := setup(!isCheckTx, 5)
    77  	if !isCheckTx {
    78  		// init chain must be called to stop deliverState from being nil
    79  		stateBytes, err := json.MarshalIndent(genesisState, "", " ")
    80  		if err != nil {
    81  			panic(err)
    82  		}
    83  
    84  		// Initialize the chain
    85  		app.InitChain(
    86  			abci.RequestInitChain{
    87  				Validators:      []abci.ValidatorUpdate{},
    88  				ConsensusParams: DefaultConsensusParams,
    89  				AppStateBytes:   stateBytes,
    90  			},
    91  		)
    92  	}
    93  
    94  	return app
    95  }
    96  
    97  // SetupWithGenesisValSet initializes a new SimApp with a validator set and genesis accounts
    98  // that also act as delegators. For simplicity, each validator is bonded with a delegation
    99  // of one consensus engine unit (10^6) in the default token of the simapp from first genesis
   100  // account. A Nop logger is set in SimApp.
   101  //func SetupWithGenesisValSet(t *testing.T, valSet *octypes.ValidatorSet, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *SimApp {
   102  //	app, genesisState := setup(true, 5)
   103  //	// set genesis accounts
   104  //	authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs)
   105  //	genesisState[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(authGenesis)
   106  //
   107  //	validators := make([]stakingtypes.Validator, 0, len(valSet.Validators))
   108  //	delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators))
   109  //
   110  //	bondAmt := sdk.NewInt(1000000)
   111  //
   112  //	for _, val := range valSet.Validators {
   113  //		pk, err := cryptocodec.FromOcPubKeyInterface(val.PubKey)
   114  //		require.NoError(t, err)
   115  //		pkAny, err := codectypes.NewAnyWithValue(pk)
   116  //		require.NoError(t, err)
   117  //		validator := stakingtypes.Validator{
   118  //			OperatorAddress:   sdk.ValAddress(val.Address).String(),
   119  //			ConsensusPubkey:   pkAny,
   120  //			Jailed:            false,
   121  //			Status:            stakingtypes.Bonded,
   122  //			Tokens:            bondAmt,
   123  //			DelegatorShares:   sdk.OneDec(),
   124  //			Description:       stakingtypes.Description{},
   125  //			UnbondingHeight:   int64(0),
   126  //			UnbondingTime:     time.Unix(0, 0).UTC(),
   127  //			Commission:        stakingtypes.NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
   128  //			MinSelfDelegation: sdk.ZeroInt(),
   129  //		}
   130  //		validators = append(validators, validator)
   131  //		delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec()))
   132  //
   133  //	}
   134  //	// set validators and delegations
   135  //	stakingGenesis := stakingtypes.NewGenesisState(stakingtypes.DefaultParams(), validators, delegations)
   136  //	genesisState[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(stakingGenesis)
   137  //
   138  //	totalSupply := sdk.NewCoins()
   139  //	for _, b := range balances {
   140  //		// add genesis acc tokens and delegated tokens to total supply
   141  //		totalSupply = totalSupply.Add(b.Coins.Add(sdk.NewCoin(sdk.DefaultBondDenom, bondAmt))...)
   142  //	}
   143  //
   144  //	// add bonded amount to bonded pool module account
   145  //	balances = append(balances, banktypes.Balance{
   146  //		Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(),
   147  //		Coins:   sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)},
   148  //	})
   149  //
   150  //	// update total supply
   151  //	bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{})
   152  //	genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis)
   153  //
   154  //	stateBytes, err := json.MarshalIndent(genesisState, "", " ")
   155  //	require.NoError(t, err)
   156  //
   157  //	// init chain will set the validator set and initialize the genesis accounts
   158  //	app.InitChain(
   159  //		abci.RequestInitChain{
   160  //			Validators:      []abci.ValidatorUpdate{},
   161  //			ConsensusParams: DefaultConsensusParams,
   162  //			AppStateBytes:   stateBytes,
   163  //		},
   164  //	)
   165  //
   166  //	// commit genesis changes
   167  //	app.Commit()
   168  //	app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{
   169  //		Height:             app.LastBlockHeight() + 1,
   170  //		AppHash:            app.LastCommitID().Hash,
   171  //		ValidatorsHash:     valSet.Hash(),
   172  //		NextValidatorsHash: valSet.Hash(),
   173  //	}})
   174  //
   175  //	return app
   176  //}
   177  
   178  // SetupWithGenesisAccounts initializes a new SimApp with the provided genesis
   179  // accounts and possible balances.
   180  func SetupWithGenesisAccounts(genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *SimApp {
   181  	app, genesisState := setup(true, 0)
   182  	authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs)
   183  	genesisState[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(authGenesis)
   184  
   185  	totalSupply := sdk.NewCoins()
   186  	for _, b := range balances {
   187  		totalSupply = totalSupply.Add(b.Coins...)
   188  	}
   189  
   190  	bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{})
   191  	genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis)
   192  
   193  	stateBytes, err := json.MarshalIndent(genesisState, "", " ")
   194  	if err != nil {
   195  		panic(err)
   196  	}
   197  
   198  	app.InitChain(
   199  		abci.RequestInitChain{
   200  			Validators:      []abci.ValidatorUpdate{},
   201  			ConsensusParams: DefaultConsensusParams,
   202  			AppStateBytes:   stateBytes,
   203  		},
   204  	)
   205  
   206  	app.Commit()
   207  	app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1}})
   208  
   209  	return app
   210  }
   211  
   212  type GenerateAccountStrategy func(int) []sdk.AccAddress
   213  
   214  // createRandomAccounts is a strategy used by addTestAddrs() in order to generated addresses in random order.
   215  func createRandomAccounts(accNum int) []sdk.AccAddress {
   216  	testAddrs := make([]sdk.AccAddress, accNum)
   217  	for i := 0; i < accNum; i++ {
   218  		pk := ed25519.GenPrivKey().PubKey()
   219  		testAddrs[i] = sdk.AccAddress(pk.Address())
   220  	}
   221  
   222  	return testAddrs
   223  }
   224  
   225  // createIncrementalAccounts is a strategy used by addTestAddrs() in order to generated addresses in ascending order.
   226  func createIncrementalAccounts(accNum int) []sdk.AccAddress {
   227  	var addresses []sdk.AccAddress
   228  	var buffer bytes.Buffer
   229  
   230  	// start at 100 so we can make up to 999 test addresses with valid test addresses
   231  	for i := 100; i < (accNum + 100); i++ {
   232  		numString := strconv.Itoa(i)
   233  		buffer.WriteString("A58856F0FD53BF058B4909A21AEC019107BA6") // base address string
   234  
   235  		buffer.WriteString(numString) // adding on final two digits to make addresses unique
   236  		res, _ := sdk.AccAddressFromHex(buffer.String())
   237  		bech := res.String()
   238  		addr, _ := TestAddr(buffer.String(), bech)
   239  
   240  		addresses = append(addresses, addr)
   241  		buffer.Reset()
   242  	}
   243  
   244  	return addresses
   245  }
   246  
   247  // AddTestAddrsFromPubKeys adds the addresses into the SimApp providing only the public keys.
   248  func AddTestAddrsFromPubKeys(app *SimApp, ctx sdk.Context, pubKeys []cryptotypes.PubKey, accAmt sdk.Int) {
   249  	initCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt))
   250  
   251  	// fill all the addresses with some coins, set the loose pool tokens simultaneously
   252  	for _, pk := range pubKeys {
   253  		initAccountWithCoins(app, ctx, sdk.AccAddress(pk.Address()), initCoins)
   254  	}
   255  }
   256  
   257  // SortAddresses - Sorts Addresses
   258  func SortAddresses(addrs []sdk.AccAddress) {
   259  	byteAddrs := make([][]byte, len(addrs))
   260  
   261  	for i, addr := range addrs {
   262  		byteAddrs[i] = addr.Bytes()
   263  	}
   264  
   265  	SortByteArrays(byteAddrs)
   266  
   267  	for i, byteAddr := range byteAddrs {
   268  		addrs[i] = sdk.AccAddress(byteAddr)
   269  	}
   270  }
   271  
   272  // implement `Interface` in sort package.
   273  type sortByteArrays [][]byte
   274  
   275  func (b sortByteArrays) Len() int {
   276  	return len(b)
   277  }
   278  
   279  func (b sortByteArrays) Less(i, j int) bool {
   280  	// bytes package already implements Comparable for []byte.
   281  	switch bytes.Compare(b[i], b[j]) {
   282  	case -1:
   283  		return true
   284  	case 0, 1:
   285  		return false
   286  	default:
   287  		panic("not fail-able with `bytes.Comparable` bounded [-1, 1].")
   288  	}
   289  }
   290  
   291  func (b sortByteArrays) Swap(i, j int) {
   292  	b[j], b[i] = b[i], b[j]
   293  }
   294  
   295  // SortByteArrays - sorts the provided byte array
   296  func SortByteArrays(src [][]byte) [][]byte {
   297  	sorted := sortByteArrays(src)
   298  	sort.Sort(sorted)
   299  	return sorted
   300  }
   301  
   302  // AddTestAddrs constructs and returns accNum amount of accounts with an
   303  // initial balance of accAmt in random order
   304  func AddTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sdk.AccAddress {
   305  	return addTestAddrs(app, ctx, accNum, accAmt, createRandomAccounts)
   306  }
   307  
   308  // AddTestAddrs constructs and returns accNum amount of accounts with an
   309  // initial balance of accAmt in random order
   310  func AddTestAddrsIncremental(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sdk.AccAddress {
   311  	return addTestAddrs(app, ctx, accNum, accAmt, createIncrementalAccounts)
   312  }
   313  
   314  func addTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int, strategy GenerateAccountStrategy) []sdk.AccAddress {
   315  	testAddrs := strategy(accNum)
   316  
   317  	initCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt))
   318  
   319  	for _, addr := range testAddrs {
   320  		initAccountWithCoins(app, ctx, addr, initCoins)
   321  	}
   322  
   323  	SortAddresses(testAddrs)
   324  	return testAddrs
   325  }
   326  
   327  func initAccountWithCoins(app *SimApp, ctx sdk.Context, addr sdk.AccAddress, coins sdk.Coins) {
   328  	err := app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, coins)
   329  	if err != nil {
   330  		panic(err)
   331  	}
   332  
   333  	err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr, coins)
   334  	if err != nil {
   335  		panic(err)
   336  	}
   337  }
   338  
   339  // ConvertAddrsToValAddrs converts the provided addresses to ValAddress.
   340  func ConvertAddrsToValAddrs(addrs []sdk.AccAddress) []sdk.ValAddress {
   341  	valAddrs := make([]sdk.ValAddress, len(addrs))
   342  
   343  	for i, addr := range addrs {
   344  		valAddrs[i] = sdk.ValAddress(addr)
   345  	}
   346  
   347  	return valAddrs
   348  }
   349  
   350  func TestAddr(addr string, bech string) (sdk.AccAddress, error) {
   351  	res, err := sdk.AccAddressFromHex(addr)
   352  	if err != nil {
   353  		return nil, err
   354  	}
   355  	bechexpected := res.String()
   356  	if bech != bechexpected {
   357  		return nil, fmt.Errorf("bech encoding doesn't match reference")
   358  	}
   359  
   360  	bechres, err := sdk.AccAddressFromBech32(bech)
   361  	if err != nil {
   362  		return nil, err
   363  	}
   364  	if !bytes.Equal(bechres, res) {
   365  		return nil, err
   366  	}
   367  
   368  	return res, nil
   369  }
   370  
   371  // CheckBalance checks the balance of an account.
   372  func CheckBalance(t *testing.T, app *SimApp, addr sdk.AccAddress, balances sdk.Coins) {
   373  	ctxCheck := app.BaseApp.NewContext(true, tmproto.Header{})
   374  	require.True(t, balances.IsEqual(app.BankKeeper.GetAllBalances(ctxCheck, addr)))
   375  }
   376  
   377  // SignCheckDeliver checks a generated signed transaction and simulates a
   378  // block commitment with the given transaction. A test assertion is made using
   379  // the parameter 'expPass' against the result. A corresponding result is
   380  // returned.
   381  func SignCheckDeliver(
   382  	t *testing.T, txCfg client.TxConfig, app *bam.BaseApp, header tmproto.Header, msgs []sdk.Msg,
   383  	chainID string, accNums, accSeqs []uint64, expSimPass, expPass bool, priv ...cryptotypes.PrivKey,
   384  ) (sdk.GasInfo, *sdk.Result, error) {
   385  	tx, err := helpers.GenSignedMockTx(
   386  		rand.New(rand.NewSource(time.Now().UnixNano())),
   387  		txCfg,
   388  		msgs,
   389  		sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)},
   390  		helpers.DefaultGenTxGas,
   391  		chainID,
   392  		accNums,
   393  		accSeqs,
   394  		priv...,
   395  	)
   396  	require.NoError(t, err)
   397  	txBytes, err := txCfg.TxEncoder()(tx)
   398  	require.Nil(t, err)
   399  
   400  	// Must simulate now as CheckTx doesn't run Msgs anymore
   401  	_, res, err := app.Simulate(txBytes)
   402  
   403  	if expSimPass {
   404  		require.NoError(t, err)
   405  		require.NotNil(t, res)
   406  	} else {
   407  		require.Error(t, err)
   408  		require.Nil(t, res)
   409  	}
   410  
   411  	// Simulate a sending a transaction and committing a block and recheck
   412  	app.BeginBlock(ocabci.RequestBeginBlock{Header: header})
   413  	gInfo, res, err := app.Deliver(txCfg.TxEncoder(), tx)
   414  
   415  	if expPass {
   416  		require.NoError(t, err)
   417  		require.NotNil(t, res)
   418  	} else {
   419  		require.Error(t, err)
   420  		require.Nil(t, res)
   421  	}
   422  
   423  	app.EndBlock(abci.RequestEndBlock{})
   424  	app.Commit()
   425  
   426  	app.BeginRecheckTx(ocabci.RequestBeginRecheckTx{Header: header})
   427  	app.EndRecheckTx(ocabci.RequestEndRecheckTx{})
   428  
   429  	return gInfo, res, err
   430  }
   431  
   432  // SignAndDeliver signs and delivers a transaction. No simulation occurs as the
   433  // ibc testing package causes checkState and deliverState to diverge in block time.
   434  func SignAndDeliver(
   435  	t *testing.T, txCfg client.TxConfig, app *bam.BaseApp, header tmproto.Header, msgs []sdk.Msg,
   436  	chainID string, accNums, accSeqs []uint64, expSimPass, expPass bool, priv ...cryptotypes.PrivKey,
   437  ) (sdk.GasInfo, *sdk.Result, error) {
   438  	tx, err := helpers.GenTx(
   439  		txCfg,
   440  		msgs,
   441  		sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)},
   442  		2*helpers.DefaultGenTxGas,
   443  		chainID,
   444  		accNums,
   445  		accSeqs,
   446  		priv...,
   447  	)
   448  	require.NoError(t, err)
   449  
   450  	// Simulate a sending a transaction and committing a block
   451  	app.BeginBlock(ocabci.RequestBeginBlock{Header: header})
   452  	gInfo, res, err := app.Deliver(txCfg.TxEncoder(), tx)
   453  
   454  	if expPass {
   455  		require.NoError(t, err)
   456  		require.NotNil(t, res)
   457  	} else {
   458  		require.Error(t, err)
   459  		require.Nil(t, res)
   460  	}
   461  
   462  	app.EndBlock(abci.RequestEndBlock{})
   463  	app.Commit()
   464  
   465  	return gInfo, res, err
   466  }
   467  
   468  // GenSequenceOfTxs generates a set of signed transactions of messages, such
   469  // that they differ only by having the sequence numbers incremented between
   470  // every transaction.
   471  func GenSequenceOfTxs(txGen client.TxConfig, msgs []sdk.Msg, accNums []uint64, initSeqNums []uint64, numToGenerate int, priv ...cryptotypes.PrivKey) ([]sdk.Tx, error) {
   472  	txs := make([]sdk.Tx, numToGenerate)
   473  	var err error
   474  	for i := 0; i < numToGenerate; i++ {
   475  		txs[i], err = helpers.GenSignedMockTx(
   476  			rand.New(rand.NewSource(time.Now().UnixNano())),
   477  			txGen,
   478  			msgs,
   479  			sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)},
   480  			helpers.DefaultGenTxGas,
   481  			"",
   482  			accNums,
   483  			initSeqNums,
   484  			priv...,
   485  		)
   486  		if err != nil {
   487  			break
   488  		}
   489  		incrementAllSequenceNumbers(initSeqNums)
   490  	}
   491  
   492  	return txs, err
   493  }
   494  
   495  func incrementAllSequenceNumbers(initSeqNums []uint64) {
   496  	for i := 0; i < len(initSeqNums); i++ {
   497  		initSeqNums[i]++
   498  	}
   499  }
   500  
   501  // CreateTestPubKeys returns a total of numPubKeys public keys in ascending order.
   502  func CreateTestPubKeys(numPubKeys int) []cryptotypes.PubKey {
   503  	var publicKeys []cryptotypes.PubKey
   504  	var buffer bytes.Buffer
   505  
   506  	// start at 10 to avoid changing 1 to 01, 2 to 02, etc
   507  	for i := 100; i < (numPubKeys + 100); i++ {
   508  		numString := strconv.Itoa(i)
   509  		buffer.WriteString("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AF") // base pubkey string
   510  		buffer.WriteString(numString)                                                       // adding on final two digits to make pubkeys unique
   511  		publicKeys = append(publicKeys, NewPubKeyFromHex(buffer.String()))
   512  		buffer.Reset()
   513  	}
   514  
   515  	return publicKeys
   516  }
   517  
   518  // NewPubKeyFromHex returns a PubKey from a hex string.
   519  func NewPubKeyFromHex(pk string) (res cryptotypes.PubKey) {
   520  	pkBytes, err := hex.DecodeString(pk)
   521  	if err != nil {
   522  		panic(err)
   523  	}
   524  	if len(pkBytes) != ed25519.PubKeySize {
   525  		panic(errors.Wrap(errors.ErrInvalidPubKey, "invalid pubkey size"))
   526  	}
   527  	return &ed25519.PubKey{Key: pkBytes}
   528  }
   529  
   530  // EmptyAppOptions is a stub implementing AppOptions
   531  type EmptyAppOptions struct{}
   532  
   533  // Get implements AppOptions
   534  func (ao EmptyAppOptions) Get(o string) interface{} {
   535  	return nil
   536  }
   537  
   538  // FundAccount is a utility function that funds an account by minting and
   539  // sending the coins to the address. This should be used for testing purposes
   540  // only!
   541  //
   542  // TODO: Instead of using the mint module account, which has the
   543  // permission of minting, create a "faucet" account. (@fdymylja)
   544  func FundAccount(app *SimApp, ctx sdk.Context, addr sdk.AccAddress, amounts sdk.Coins) error {
   545  	if err := app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, amounts); err != nil {
   546  		return err
   547  	}
   548  
   549  	return app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr, amounts)
   550  }
   551  
   552  // FundModuleAccount is a utility function that funds a module account by
   553  // minting and sending the coins to the address. This should be used for testing
   554  // purposes only!
   555  //
   556  // TODO: Instead of using the mint module account, which has the
   557  // permission of minting, create a "faucet" account. (@fdymylja)
   558  func FundModuleAccount(app *SimApp, ctx sdk.Context, recipientMod string, amounts sdk.Coins) error {
   559  	if err := app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, amounts); err != nil {
   560  		return err
   561  	}
   562  
   563  	return app.BankKeeper.SendCoinsFromModuleToModule(ctx, minttypes.ModuleName, recipientMod, amounts)
   564  }