mirror of
				https://github.com/0glabs/0g-chain.git
				synced 2025-11-04 12:17:28 +00:00 
			
		
		
		
	Merge pull request #273 from Kava-Labs/ro-remove-mock-from-tests
Tests Refactor v1: remove mock
This commit is contained in:
		
						commit
						c5db0ff680
					
				
							
								
								
									
										69
									
								
								app/app.go
									
									
									
									
									
								
							
							
						
						
									
										69
									
								
								app/app.go
									
									
									
									
									
								
							@ -4,6 +4,10 @@ import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"github.com/kava-labs/kava/x/auction"
 | 
			
		||||
	"github.com/kava-labs/kava/x/cdp"
 | 
			
		||||
	"github.com/kava-labs/kava/x/liquidator"
 | 
			
		||||
	"github.com/kava-labs/kava/x/pricefeed"
 | 
			
		||||
	validatorvesting "github.com/kava-labs/kava/x/validator-vesting"
 | 
			
		||||
 | 
			
		||||
	abci "github.com/tendermint/tendermint/abci/types"
 | 
			
		||||
@ -55,6 +59,10 @@ var (
 | 
			
		||||
		crisis.AppModuleBasic{},
 | 
			
		||||
		slashing.AppModuleBasic{},
 | 
			
		||||
		supply.AppModuleBasic{},
 | 
			
		||||
		auction.AppModuleBasic{},
 | 
			
		||||
		cdp.AppModuleBasic{},
 | 
			
		||||
		liquidator.AppModuleBasic{},
 | 
			
		||||
		pricefeed.AppModuleBasic{},
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// module account permissions
 | 
			
		||||
@ -81,17 +89,21 @@ type App struct {
 | 
			
		||||
	tkeys map[string]*sdk.TransientStoreKey
 | 
			
		||||
 | 
			
		||||
	// keepers from all the modules
 | 
			
		||||
	accountKeeper  auth.AccountKeeper
 | 
			
		||||
	bankKeeper     bank.Keeper
 | 
			
		||||
	supplyKeeper   supply.Keeper
 | 
			
		||||
	stakingKeeper  staking.Keeper
 | 
			
		||||
	slashingKeeper slashing.Keeper
 | 
			
		||||
	mintKeeper     mint.Keeper
 | 
			
		||||
	distrKeeper    distr.Keeper
 | 
			
		||||
	govKeeper      gov.Keeper
 | 
			
		||||
	crisisKeeper   crisis.Keeper
 | 
			
		||||
	paramsKeeper   params.Keeper
 | 
			
		||||
	vvKeeper       validatorvesting.Keeper
 | 
			
		||||
	accountKeeper    auth.AccountKeeper
 | 
			
		||||
	bankKeeper       bank.Keeper
 | 
			
		||||
	supplyKeeper     supply.Keeper
 | 
			
		||||
	stakingKeeper    staking.Keeper
 | 
			
		||||
	slashingKeeper   slashing.Keeper
 | 
			
		||||
	mintKeeper       mint.Keeper
 | 
			
		||||
	distrKeeper      distr.Keeper
 | 
			
		||||
	govKeeper        gov.Keeper
 | 
			
		||||
	crisisKeeper     crisis.Keeper
 | 
			
		||||
	paramsKeeper     params.Keeper
 | 
			
		||||
	vvKeeper         validatorvesting.Keeper
 | 
			
		||||
	auctionKeeper    auction.Keeper
 | 
			
		||||
	cdpKeeper        cdp.Keeper
 | 
			
		||||
	liquidatorKeeper liquidator.Keeper
 | 
			
		||||
	pricefeedKeeper  pricefeed.Keeper
 | 
			
		||||
 | 
			
		||||
	// the module manager
 | 
			
		||||
	mm *module.Manager
 | 
			
		||||
@ -115,6 +127,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
 | 
			
		||||
		bam.MainStoreKey, auth.StoreKey, staking.StoreKey,
 | 
			
		||||
		supply.StoreKey, mint.StoreKey, distr.StoreKey, slashing.StoreKey,
 | 
			
		||||
		gov.StoreKey, params.StoreKey, validatorvesting.StoreKey,
 | 
			
		||||
		auction.StoreKey, cdp.StoreKey, liquidator.StoreKey, pricefeed.StoreKey,
 | 
			
		||||
	)
 | 
			
		||||
	tkeys := sdk.NewTransientStoreKeys(params.TStoreKey)
 | 
			
		||||
 | 
			
		||||
@ -136,6 +149,10 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
 | 
			
		||||
	slashingSubspace := app.paramsKeeper.Subspace(slashing.DefaultParamspace)
 | 
			
		||||
	govSubspace := app.paramsKeeper.Subspace(gov.DefaultParamspace).WithKeyTable(gov.ParamKeyTable())
 | 
			
		||||
	crisisSubspace := app.paramsKeeper.Subspace(crisis.DefaultParamspace)
 | 
			
		||||
	auctionSubspace := app.paramsKeeper.Subspace(auction.DefaultParamspace)
 | 
			
		||||
	cdpSubspace := app.paramsKeeper.Subspace(cdp.DefaultParamspace)
 | 
			
		||||
	liquidatorSubspace := app.paramsKeeper.Subspace(liquidator.DefaultParamspace)
 | 
			
		||||
	pricefeedSubspace := app.paramsKeeper.Subspace(pricefeed.DefaultParamspace)
 | 
			
		||||
 | 
			
		||||
	// add keepers
 | 
			
		||||
	app.accountKeeper = auth.NewAccountKeeper(
 | 
			
		||||
@ -207,6 +224,29 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
 | 
			
		||||
		app.bankKeeper,
 | 
			
		||||
		app.supplyKeeper,
 | 
			
		||||
		&stakingKeeper)
 | 
			
		||||
	app.pricefeedKeeper = pricefeed.NewKeeper(
 | 
			
		||||
		app.cdc,
 | 
			
		||||
		keys[pricefeed.StoreKey],
 | 
			
		||||
		pricefeedSubspace,
 | 
			
		||||
		pricefeed.DefaultCodespace)
 | 
			
		||||
	app.cdpKeeper = cdp.NewKeeper(
 | 
			
		||||
		app.cdc,
 | 
			
		||||
		keys[cdp.StoreKey],
 | 
			
		||||
		cdpSubspace,
 | 
			
		||||
		app.pricefeedKeeper,
 | 
			
		||||
		app.bankKeeper)
 | 
			
		||||
	app.auctionKeeper = auction.NewKeeper(
 | 
			
		||||
		app.cdc,
 | 
			
		||||
		app.cdpKeeper, // CDP keeper standing in for bank
 | 
			
		||||
		keys[auction.StoreKey],
 | 
			
		||||
		auctionSubspace)
 | 
			
		||||
	app.liquidatorKeeper = liquidator.NewKeeper(
 | 
			
		||||
		app.cdc,
 | 
			
		||||
		keys[liquidator.StoreKey],
 | 
			
		||||
		liquidatorSubspace,
 | 
			
		||||
		app.cdpKeeper,
 | 
			
		||||
		app.auctionKeeper,
 | 
			
		||||
		app.cdpKeeper) // CDP keeper standing in for bank
 | 
			
		||||
 | 
			
		||||
	// register the staking hooks
 | 
			
		||||
	// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
 | 
			
		||||
@ -227,6 +267,10 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
 | 
			
		||||
		slashing.NewAppModule(app.slashingKeeper, app.stakingKeeper),
 | 
			
		||||
		staking.NewAppModule(app.stakingKeeper, app.accountKeeper, app.supplyKeeper),
 | 
			
		||||
		validatorvesting.NewAppModule(app.vvKeeper, app.accountKeeper),
 | 
			
		||||
		auction.NewAppModule(app.auctionKeeper),
 | 
			
		||||
		cdp.NewAppModule(app.cdpKeeper, app.pricefeedKeeper),
 | 
			
		||||
		liquidator.NewAppModule(app.liquidatorKeeper),
 | 
			
		||||
		pricefeed.NewAppModule(app.pricefeedKeeper),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// During begin block slashing happens after distr.BeginBlocker so that
 | 
			
		||||
@ -234,7 +278,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
 | 
			
		||||
	// CanWithdrawInvariant invariant.
 | 
			
		||||
	app.mm.SetOrderBeginBlockers(mint.ModuleName, distr.ModuleName, slashing.ModuleName, validatorvesting.ModuleName)
 | 
			
		||||
 | 
			
		||||
	app.mm.SetOrderEndBlockers(crisis.ModuleName, gov.ModuleName, staking.ModuleName)
 | 
			
		||||
	app.mm.SetOrderEndBlockers(crisis.ModuleName, gov.ModuleName, staking.ModuleName, pricefeed.ModuleName, auction.ModuleName) // TODO is this correct order?
 | 
			
		||||
 | 
			
		||||
	// Note: genutils must occur after staking so that pools are properly
 | 
			
		||||
	// initialized with tokens from genesis accounts.
 | 
			
		||||
@ -245,6 +289,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
 | 
			
		||||
		auth.ModuleName, validatorvesting.ModuleName, distr.ModuleName,
 | 
			
		||||
		staking.ModuleName, bank.ModuleName, slashing.ModuleName,
 | 
			
		||||
		gov.ModuleName, mint.ModuleName, supply.ModuleName, crisis.ModuleName, genutil.ModuleName,
 | 
			
		||||
		pricefeed.ModuleName, cdp.ModuleName, auction.ModuleName, liquidator.ModuleName, // TODO is this order ok?
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	app.mm.RegisterInvariants(&app.crisisKeeper)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										136
									
								
								app/test_common.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								app/test_common.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,136 @@
 | 
			
		||||
package app
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"math/rand"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/require"
 | 
			
		||||
 | 
			
		||||
	abci "github.com/tendermint/tendermint/abci/types"
 | 
			
		||||
	"github.com/tendermint/tendermint/crypto"
 | 
			
		||||
	"github.com/tendermint/tendermint/crypto/ed25519"
 | 
			
		||||
	"github.com/tendermint/tendermint/crypto/secp256k1"
 | 
			
		||||
	"github.com/tendermint/tendermint/libs/log"
 | 
			
		||||
	tmdb "github.com/tendermint/tm-db"
 | 
			
		||||
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/codec"
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/auth"
 | 
			
		||||
	authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/bank"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/crisis"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/distribution"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/gov"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/mint"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/params"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/slashing"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/staking"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/supply"
 | 
			
		||||
 | 
			
		||||
	"github.com/kava-labs/kava/x/auction"
 | 
			
		||||
	"github.com/kava-labs/kava/x/cdp"
 | 
			
		||||
	"github.com/kava-labs/kava/x/liquidator"
 | 
			
		||||
	"github.com/kava-labs/kava/x/pricefeed"
 | 
			
		||||
	validatorvesting "github.com/kava-labs/kava/x/validator-vesting"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TestApp is a simple wrapper around an App. It exposes internal keepers for use in integration tests.
 | 
			
		||||
// This file also contains test helpers. Ideally they would be in separate package.
 | 
			
		||||
// Basic Usage:
 | 
			
		||||
// 	Create a test app with NewTestApp, then all keepers and their methods can be accessed for test setup and execution.
 | 
			
		||||
// Advanced Usage:
 | 
			
		||||
// 	Some tests call for an app to be initialized with some state. This can be achieved through keeper method calls (ie keeper.SetParams(...)).
 | 
			
		||||
// 	However this leads to a lot of duplicated logic similar to InitGenesis methods.
 | 
			
		||||
// 	So TestApp.InitializeFromGenesisStates() will call InitGenesis with the default genesis state.
 | 
			
		||||
//	and TestApp.InitializeFromGenesisStates(authState, cdpState) will do the same but overwrite the auth and cdp sections of the default genesis state
 | 
			
		||||
// 	Creating the genesis states can be combersome, but helper methods can make it easier such as NewAuthGenStateFromAccounts below.
 | 
			
		||||
type TestApp struct {
 | 
			
		||||
	App
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewTestApp() TestApp {
 | 
			
		||||
	db := tmdb.NewMemDB()
 | 
			
		||||
	app := NewApp(log.NewNopLogger(), db, nil, true, 0)
 | 
			
		||||
	return TestApp{App: *app}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tApp TestApp) GetAccountKeeper() auth.AccountKeeper   { return tApp.accountKeeper }
 | 
			
		||||
func (tApp TestApp) GetBankKeeper() bank.Keeper             { return tApp.bankKeeper }
 | 
			
		||||
func (tApp TestApp) GetSupplyKeeper() supply.Keeper         { return tApp.supplyKeeper }
 | 
			
		||||
func (tApp TestApp) GetStakingKeeper() staking.Keeper       { return tApp.stakingKeeper }
 | 
			
		||||
func (tApp TestApp) GetSlashingKeeper() slashing.Keeper     { return tApp.slashingKeeper }
 | 
			
		||||
func (tApp TestApp) GetMintKeeper() mint.Keeper             { return tApp.mintKeeper }
 | 
			
		||||
func (tApp TestApp) GetDistrKeeper() distribution.Keeper    { return tApp.distrKeeper }
 | 
			
		||||
func (tApp TestApp) GetGovKeeper() gov.Keeper               { return tApp.govKeeper }
 | 
			
		||||
func (tApp TestApp) GetCrisisKeeper() crisis.Keeper         { return tApp.crisisKeeper }
 | 
			
		||||
func (tApp TestApp) GetParamsKeeper() params.Keeper         { return tApp.paramsKeeper }
 | 
			
		||||
func (tApp TestApp) GetVVKeeper() validatorvesting.Keeper   { return tApp.vvKeeper }
 | 
			
		||||
func (tApp TestApp) GetAuctionKeeper() auction.Keeper       { return tApp.auctionKeeper }
 | 
			
		||||
func (tApp TestApp) GetCDPKeeper() cdp.Keeper               { return tApp.cdpKeeper }
 | 
			
		||||
func (tApp TestApp) GetLiquidatorKeeper() liquidator.Keeper { return tApp.liquidatorKeeper }
 | 
			
		||||
func (tApp TestApp) GetPriceFeedKeeper() pricefeed.Keeper   { return tApp.pricefeedKeeper }
 | 
			
		||||
 | 
			
		||||
// This calls InitChain on the app using the default genesis state, overwitten with any passed in genesis states
 | 
			
		||||
func (tApp TestApp) InitializeFromGenesisStates(genesisStates ...GenesisState) TestApp {
 | 
			
		||||
	// Create a default genesis state and overwrite with provided values
 | 
			
		||||
	genesisState := NewDefaultGenesisState()
 | 
			
		||||
	for _, state := range genesisStates {
 | 
			
		||||
		for k, v := range state {
 | 
			
		||||
			genesisState[k] = v
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Initialize the chain
 | 
			
		||||
	stateBytes, err := codec.MarshalJSONIndent(tApp.cdc, genesisState)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	tApp.InitChain(
 | 
			
		||||
		abci.RequestInitChain{
 | 
			
		||||
			Validators:    []abci.ValidatorUpdate{},
 | 
			
		||||
			AppStateBytes: stateBytes,
 | 
			
		||||
		},
 | 
			
		||||
	)
 | 
			
		||||
	tApp.Commit()
 | 
			
		||||
	tApp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: tApp.LastBlockHeight() + 1}})
 | 
			
		||||
	return tApp
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tApp TestApp) CheckBalance(t *testing.T, ctx sdk.Context, owner sdk.AccAddress, expectedCoins sdk.Coins) {
 | 
			
		||||
	actualCoins := tApp.GetAccountKeeper().GetAccount(ctx, owner).GetCoins()
 | 
			
		||||
	require.Equal(t, expectedCoins, actualCoins)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Create a new auth genesis state from some addresses and coins. The state is returned marshalled into a map.
 | 
			
		||||
func NewAuthGenState(addresses []sdk.AccAddress, coins []sdk.Coins) GenesisState {
 | 
			
		||||
	// Create GenAccounts
 | 
			
		||||
	accounts := authexported.GenesisAccounts{}
 | 
			
		||||
	for i := range addresses {
 | 
			
		||||
		accounts = append(accounts, auth.NewBaseAccount(addresses[i], coins[i], nil, 0, 0))
 | 
			
		||||
	}
 | 
			
		||||
	// Create the auth genesis state
 | 
			
		||||
	authGenesis := auth.NewGenesisState(auth.DefaultParams(), accounts)
 | 
			
		||||
	return GenesisState{auth.ModuleName: auth.ModuleCdc.MustMarshalJSON(authGenesis)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GeneratePrivKeyAddressPairsFromRand generates (deterministically) a total of n private keys and addresses.
 | 
			
		||||
// TODO only generate secp256 keys?
 | 
			
		||||
func GeneratePrivKeyAddressPairs(n int) (keys []crypto.PrivKey, addrs []sdk.AccAddress) {
 | 
			
		||||
	r := rand.New(rand.NewSource(12345)) // make the generation deterministic
 | 
			
		||||
	keys = make([]crypto.PrivKey, n)
 | 
			
		||||
	addrs = make([]sdk.AccAddress, n)
 | 
			
		||||
	for i := 0; i < n; i++ {
 | 
			
		||||
		secret := make([]byte, 32)
 | 
			
		||||
		_, err := r.Read(secret)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			panic("Could not read randomness")
 | 
			
		||||
		}
 | 
			
		||||
		if r.Int63()%2 == 0 {
 | 
			
		||||
			keys[i] = secp256k1.GenPrivKeySecp256k1(secret)
 | 
			
		||||
		} else {
 | 
			
		||||
			keys[i] = ed25519.GenPrivKeyFromSecret(secret)
 | 
			
		||||
		}
 | 
			
		||||
		addrs[i] = sdk.AccAddress(keys[i].PubKey().Address())
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
package auction
 | 
			
		||||
package auction_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
@ -6,23 +6,43 @@ import (
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
	"github.com/stretchr/testify/require"
 | 
			
		||||
	abci "github.com/tendermint/tendermint/abci/types"
 | 
			
		||||
 | 
			
		||||
	"github.com/kava-labs/kava/app"
 | 
			
		||||
	"github.com/kava-labs/kava/x/auction"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestKeeper_EndBlocker(t *testing.T) {
 | 
			
		||||
	// setup keeper and auction
 | 
			
		||||
	mapp, keeper, addresses, _ := setUpMockApp()
 | 
			
		||||
	header := abci.Header{Height: mapp.LastBlockHeight() + 1}
 | 
			
		||||
	mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
 | 
			
		||||
	ctx := mapp.BaseApp.NewContext(false, header)
 | 
			
		||||
	// Setup
 | 
			
		||||
	_, addrs := app.GeneratePrivKeyAddressPairs(1)
 | 
			
		||||
	seller := addrs[0]
 | 
			
		||||
 | 
			
		||||
	seller := addresses[0]
 | 
			
		||||
	keeper.StartForwardAuction(ctx, seller, sdk.NewInt64Coin("token1", 20), sdk.NewInt64Coin("token2", 0))
 | 
			
		||||
	tApp := app.NewTestApp()
 | 
			
		||||
	tApp.InitializeFromGenesisStates(
 | 
			
		||||
		app.NewAuthGenState(addrs, []sdk.Coins{cs(c("token1", 100), c("token2", 100))}),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// run the endblocker, simulating a block height after auction expiry
 | 
			
		||||
	expiryBlock := ctx.BlockHeight() + int64(DefaultMaxAuctionDuration)
 | 
			
		||||
	EndBlocker(ctx.WithBlockHeight(expiryBlock), keeper)
 | 
			
		||||
	ctx := tApp.NewContext(true, abci.Header{})
 | 
			
		||||
	keeper := tApp.GetAuctionKeeper()
 | 
			
		||||
 | 
			
		||||
	// check auction has been closed
 | 
			
		||||
	_, found := keeper.GetAuction(ctx, 0)
 | 
			
		||||
	auctionID, err := keeper.StartForwardAuction(ctx, seller, c("token1", 20), c("token2", 0))
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
	// Run the endblocker, simulating a block height just before auction expiry
 | 
			
		||||
	preExpiryHeight := ctx.BlockHeight() + int64(auction.DefaultMaxAuctionDuration) - 1
 | 
			
		||||
	auction.EndBlocker(ctx.WithBlockHeight(preExpiryHeight), keeper)
 | 
			
		||||
 | 
			
		||||
	// Check auction has not been closed yet
 | 
			
		||||
	_, found := keeper.GetAuction(ctx, auctionID)
 | 
			
		||||
	require.True(t, found)
 | 
			
		||||
 | 
			
		||||
	// Run the endblocker, simulating a block height just after auction expiry
 | 
			
		||||
	expiryHeight := preExpiryHeight + 1
 | 
			
		||||
	auction.EndBlocker(ctx.WithBlockHeight(expiryHeight), keeper)
 | 
			
		||||
 | 
			
		||||
	// Check auction has been closed
 | 
			
		||||
	_, found = keeper.GetAuction(ctx, auctionID)
 | 
			
		||||
	require.False(t, found)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) }
 | 
			
		||||
func cs(coins ...sdk.Coin) sdk.Coins        { return sdk.NewCoins(coins...) }
 | 
			
		||||
 | 
			
		||||
@ -1,171 +0,0 @@
 | 
			
		||||
package auction
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/bank"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/mock"
 | 
			
		||||
	abci "github.com/tendermint/tendermint/abci/types"
 | 
			
		||||
	"github.com/tendermint/tendermint/crypto"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TestApp contans several basic integration tests of creating an auction, placing a bid, and the auction closing.
 | 
			
		||||
 | 
			
		||||
func TestApp_ForwardAuction(t *testing.T) {
 | 
			
		||||
	// Setup
 | 
			
		||||
	mapp, keeper, addresses, privKeys := setUpMockApp()
 | 
			
		||||
	seller := addresses[0]
 | 
			
		||||
	//sellerKey := privKeys[0]
 | 
			
		||||
	buyer := addresses[1]
 | 
			
		||||
	buyerKey := privKeys[1]
 | 
			
		||||
 | 
			
		||||
	// Create a block where an auction is started (lot: 20 t1, initialBid: 0 t2)
 | 
			
		||||
	header := abci.Header{Height: mapp.LastBlockHeight() + 1}
 | 
			
		||||
	mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
 | 
			
		||||
	ctx := mapp.BaseApp.NewContext(false, header)                                                          // make sure first arg is false, otherwise no db writes
 | 
			
		||||
	keeper.StartForwardAuction(ctx, seller, sdk.NewInt64Coin("token1", 20), sdk.NewInt64Coin("token2", 0)) // lot, initialBid
 | 
			
		||||
	mapp.EndBlock(abci.RequestEndBlock{})
 | 
			
		||||
	mapp.Commit()
 | 
			
		||||
 | 
			
		||||
	// Check seller's coins have decreased
 | 
			
		||||
	mock.CheckBalance(t, mapp, seller, sdk.NewCoins(sdk.NewInt64Coin("token1", 80), sdk.NewInt64Coin("token2", 100)))
 | 
			
		||||
 | 
			
		||||
	// Deliver a block that contains a PlaceBid tx (bid: 10 t2, lot: same as starting)
 | 
			
		||||
	msgs := []sdk.Msg{NewMsgPlaceBid(0, buyer, sdk.NewInt64Coin("token2", 10), sdk.NewInt64Coin("token1", 20))} // bid, lot
 | 
			
		||||
	header = abci.Header{Height: mapp.LastBlockHeight() + 1}
 | 
			
		||||
	mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, msgs, []uint64{1}, []uint64{0}, true, true, buyerKey) // account number for the buyer account is 1
 | 
			
		||||
 | 
			
		||||
	// Check buyer's coins have decreased
 | 
			
		||||
	mock.CheckBalance(t, mapp, buyer, sdk.NewCoins(sdk.NewInt64Coin("token1", 100), sdk.NewInt64Coin("token2", 90)))
 | 
			
		||||
	// Check seller's coins have increased
 | 
			
		||||
	mock.CheckBalance(t, mapp, seller, sdk.NewCoins(sdk.NewInt64Coin("token1", 80), sdk.NewInt64Coin("token2", 110)))
 | 
			
		||||
 | 
			
		||||
	// Deliver empty blocks until the auction should be closed (bid placed on block 3)
 | 
			
		||||
	// TODO is there a way of skipping ahead? This takes a while and prints a lot.
 | 
			
		||||
	for h := mapp.LastBlockHeight() + 1; h < int64(DefaultMaxBidDuration)+4; h++ {
 | 
			
		||||
		mapp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: h}})
 | 
			
		||||
		mapp.EndBlock(abci.RequestEndBlock{Height: h})
 | 
			
		||||
		mapp.Commit()
 | 
			
		||||
	}
 | 
			
		||||
	// Check buyer's coins increased
 | 
			
		||||
	mock.CheckBalance(t, mapp, buyer, sdk.NewCoins(sdk.NewInt64Coin("token1", 120), sdk.NewInt64Coin("token2", 90)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestApp_ReverseAuction(t *testing.T) {
 | 
			
		||||
	// Setup
 | 
			
		||||
	mapp, keeper, addresses, privKeys := setUpMockApp()
 | 
			
		||||
	seller := addresses[0]
 | 
			
		||||
	sellerKey := privKeys[0]
 | 
			
		||||
	buyer := addresses[1]
 | 
			
		||||
	//buyerKey := privKeys[1]
 | 
			
		||||
 | 
			
		||||
	// Create a block where an auction is started
 | 
			
		||||
	header := abci.Header{Height: mapp.LastBlockHeight() + 1}
 | 
			
		||||
	mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
 | 
			
		||||
	ctx := mapp.BaseApp.NewContext(false, header)
 | 
			
		||||
	keeper.StartReverseAuction(ctx, buyer, sdk.NewInt64Coin("token1", 20), sdk.NewInt64Coin("token2", 99)) // buyer, bid, initialLot
 | 
			
		||||
	mapp.EndBlock(abci.RequestEndBlock{})
 | 
			
		||||
	mapp.Commit()
 | 
			
		||||
 | 
			
		||||
	// Check buyer's coins have decreased
 | 
			
		||||
	mock.CheckBalance(t, mapp, buyer, sdk.NewCoins(sdk.NewInt64Coin("token1", 100), sdk.NewInt64Coin("token2", 1)))
 | 
			
		||||
 | 
			
		||||
	// Deliver a block that contains a PlaceBid tx
 | 
			
		||||
	msgs := []sdk.Msg{NewMsgPlaceBid(0, seller, sdk.NewInt64Coin("token1", 20), sdk.NewInt64Coin("token2", 10))} // bid, lot
 | 
			
		||||
	header = abci.Header{Height: mapp.LastBlockHeight() + 1}
 | 
			
		||||
	mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, msgs, []uint64{0}, []uint64{0}, true, true, sellerKey)
 | 
			
		||||
 | 
			
		||||
	// Check seller's coins have decreased
 | 
			
		||||
	mock.CheckBalance(t, mapp, seller, sdk.NewCoins(sdk.NewInt64Coin("token1", 80), sdk.NewInt64Coin("token2", 100)))
 | 
			
		||||
	// Check buyer's coins have increased
 | 
			
		||||
	mock.CheckBalance(t, mapp, buyer, sdk.NewCoins(sdk.NewInt64Coin("token1", 120), sdk.NewInt64Coin("token2", 90)))
 | 
			
		||||
 | 
			
		||||
	// Deliver empty blocks until the auction should be closed (bid placed on block 3)
 | 
			
		||||
	for h := mapp.LastBlockHeight() + 1; h < int64(DefaultMaxBidDuration)+4; h++ {
 | 
			
		||||
		mapp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: h}})
 | 
			
		||||
		mapp.EndBlock(abci.RequestEndBlock{Height: h})
 | 
			
		||||
		mapp.Commit()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check seller's coins increased
 | 
			
		||||
	mock.CheckBalance(t, mapp, seller, sdk.NewCoins(sdk.NewInt64Coin("token1", 80), sdk.NewInt64Coin("token2", 110)))
 | 
			
		||||
}
 | 
			
		||||
func TestApp_ForwardReverseAuction(t *testing.T) {
 | 
			
		||||
	// Setup
 | 
			
		||||
	mapp, keeper, addresses, privKeys := setUpMockApp()
 | 
			
		||||
	seller := addresses[0]
 | 
			
		||||
	//sellerKey := privKeys[0]
 | 
			
		||||
	buyer := addresses[1]
 | 
			
		||||
	buyerKey := privKeys[1]
 | 
			
		||||
	recipient := addresses[2]
 | 
			
		||||
 | 
			
		||||
	// Create a block where an auction is started
 | 
			
		||||
	header := abci.Header{Height: mapp.LastBlockHeight() + 1}
 | 
			
		||||
	mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
 | 
			
		||||
	ctx := mapp.BaseApp.NewContext(false, header)
 | 
			
		||||
	keeper.StartForwardReverseAuction(ctx, seller, sdk.NewInt64Coin("token1", 20), sdk.NewInt64Coin("token2", 50), recipient) // seller, lot, maxBid, otherPerson
 | 
			
		||||
	mapp.EndBlock(abci.RequestEndBlock{})
 | 
			
		||||
	mapp.Commit()
 | 
			
		||||
 | 
			
		||||
	// Check seller's coins have decreased
 | 
			
		||||
	mock.CheckBalance(t, mapp, seller, sdk.NewCoins(sdk.NewInt64Coin("token1", 80), sdk.NewInt64Coin("token2", 100)))
 | 
			
		||||
 | 
			
		||||
	// Deliver a block that contains a PlaceBid tx
 | 
			
		||||
	msgs := []sdk.Msg{NewMsgPlaceBid(0, buyer, sdk.NewInt64Coin("token2", 50), sdk.NewInt64Coin("token1", 15))} // bid, lot
 | 
			
		||||
	header = abci.Header{Height: mapp.LastBlockHeight() + 1}
 | 
			
		||||
	mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, msgs, []uint64{1}, []uint64{0}, true, true, buyerKey)
 | 
			
		||||
 | 
			
		||||
	// Check bidder's coins have decreased
 | 
			
		||||
	mock.CheckBalance(t, mapp, buyer, sdk.NewCoins(sdk.NewInt64Coin("token1", 100), sdk.NewInt64Coin("token2", 50)))
 | 
			
		||||
	// Check seller's coins have increased
 | 
			
		||||
	mock.CheckBalance(t, mapp, seller, sdk.NewCoins(sdk.NewInt64Coin("token1", 80), sdk.NewInt64Coin("token2", 150)))
 | 
			
		||||
	// Check "recipient" has received coins
 | 
			
		||||
	mock.CheckBalance(t, mapp, recipient, sdk.NewCoins(sdk.NewInt64Coin("token1", 105), sdk.NewInt64Coin("token2", 100)))
 | 
			
		||||
 | 
			
		||||
	// Deliver empty blocks until the auction should be closed (bid placed on block 3)
 | 
			
		||||
	for h := mapp.LastBlockHeight() + 1; h < int64(DefaultMaxBidDuration)+4; h++ {
 | 
			
		||||
		mapp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: h}})
 | 
			
		||||
		mapp.EndBlock(abci.RequestEndBlock{Height: h})
 | 
			
		||||
		mapp.Commit()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check buyer's coins increased
 | 
			
		||||
	mock.CheckBalance(t, mapp, buyer, sdk.NewCoins(sdk.NewInt64Coin("token1", 115), sdk.NewInt64Coin("token2", 50)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func setUpMockApp() (*mock.App, Keeper, []sdk.AccAddress, []crypto.PrivKey) {
 | 
			
		||||
	// Create uninitialized mock app
 | 
			
		||||
	mapp := mock.NewApp()
 | 
			
		||||
 | 
			
		||||
	// Register codecs
 | 
			
		||||
	RegisterCodec(mapp.Cdc)
 | 
			
		||||
 | 
			
		||||
	// Create keepers
 | 
			
		||||
	keyAuction := sdk.NewKVStoreKey("auction")
 | 
			
		||||
	blacklistedAddrs := make(map[string]bool)
 | 
			
		||||
	bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper, mapp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, blacklistedAddrs)
 | 
			
		||||
	auctionKeeper := NewKeeper(mapp.Cdc, bankKeeper, keyAuction, mapp.ParamsKeeper.Subspace(DefaultParamspace))
 | 
			
		||||
 | 
			
		||||
	// Register routes
 | 
			
		||||
	mapp.Router().AddRoute("auction", NewHandler(auctionKeeper))
 | 
			
		||||
 | 
			
		||||
	// Add endblocker
 | 
			
		||||
	mapp.SetEndBlocker(
 | 
			
		||||
		func(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
 | 
			
		||||
			EndBlocker(ctx, auctionKeeper)
 | 
			
		||||
			return abci.ResponseEndBlock{}
 | 
			
		||||
		},
 | 
			
		||||
	)
 | 
			
		||||
	// Mount and load the stores
 | 
			
		||||
	err := mapp.CompleteSetup(keyAuction)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic("mock app setup failed")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Create a bunch (ie 10) of pre-funded accounts to use for tests
 | 
			
		||||
	genAccs, addrs, _, privKeys := mock.CreateGenAccounts(10, sdk.NewCoins(sdk.NewInt64Coin("token1", 100), sdk.NewInt64Coin("token2", 100)))
 | 
			
		||||
	mock.SetGenesis(mapp, genAccs)
 | 
			
		||||
 | 
			
		||||
	return mapp, auctionKeeper, addrs, privKeys
 | 
			
		||||
}
 | 
			
		||||
@ -144,8 +144,8 @@ func (k Keeper) CloseAuction(ctx sdk.Context, auctionID types.ID) sdk.Error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// delete auction from store (and queue)
 | 
			
		||||
	k.deleteAuction(ctx, auctionID)
 | 
			
		||||
	// Delete auction from store (and queue)
 | 
			
		||||
	k.DeleteAuction(ctx, auctionID)
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
@ -204,7 +204,7 @@ func (k Keeper) SetAuction(ctx sdk.Context, auction types.Auction) {
 | 
			
		||||
	store.Set(k.getAuctionKey(auction.GetID()), bz)
 | 
			
		||||
 | 
			
		||||
	// add to the queue
 | 
			
		||||
	k.insertIntoQueue(ctx, auction.GetEndTime(), auction.GetID())
 | 
			
		||||
	k.InsertIntoQueue(ctx, auction.GetEndTime(), auction.GetID())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getAuction gets an auction from the store by auctionID
 | 
			
		||||
@ -221,8 +221,8 @@ func (k Keeper) GetAuction(ctx sdk.Context, auctionID types.ID) (types.Auction,
 | 
			
		||||
	return auction, true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// deleteAuction removes an auction from the store without any validation
 | 
			
		||||
func (k Keeper) deleteAuction(ctx sdk.Context, auctionID types.ID) {
 | 
			
		||||
// DeleteAuction removes an auction from the store without any validation
 | 
			
		||||
func (k Keeper) DeleteAuction(ctx sdk.Context, auctionID types.ID) {
 | 
			
		||||
	// remove from queue
 | 
			
		||||
	auction, found := k.GetAuction(ctx, auctionID)
 | 
			
		||||
	if found {
 | 
			
		||||
@ -245,7 +245,7 @@ func (k Keeper) getAuctionKey(auctionID types.ID) []byte {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Inserts a AuctionID into the queue at endTime
 | 
			
		||||
func (k Keeper) insertIntoQueue(ctx sdk.Context, endTime types.EndTime, auctionID types.ID) {
 | 
			
		||||
func (k Keeper) InsertIntoQueue(ctx sdk.Context, endTime types.EndTime, auctionID types.ID) {
 | 
			
		||||
	// get the store
 | 
			
		||||
	store := ctx.KVStore(k.storeKey)
 | 
			
		||||
	// marshal thing to be inserted
 | 
			
		||||
 | 
			
		||||
@ -1,21 +1,129 @@
 | 
			
		||||
package keeper
 | 
			
		||||
package keeper_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
	"github.com/kava-labs/kava/x/auction/types"
 | 
			
		||||
	"github.com/stretchr/testify/require"
 | 
			
		||||
	abci "github.com/tendermint/tendermint/abci/types"
 | 
			
		||||
 | 
			
		||||
	"github.com/kava-labs/kava/app"
 | 
			
		||||
	"github.com/kava-labs/kava/x/auction/keeper"
 | 
			
		||||
	"github.com/kava-labs/kava/x/auction/types"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestKeeper_ForwardAuction(t *testing.T) {
 | 
			
		||||
	// Setup
 | 
			
		||||
	_, addrs := app.GeneratePrivKeyAddressPairs(2)
 | 
			
		||||
	seller := addrs[0]
 | 
			
		||||
	buyer := addrs[1]
 | 
			
		||||
 | 
			
		||||
	tApp := app.NewTestApp()
 | 
			
		||||
	tApp.InitializeFromGenesisStates(
 | 
			
		||||
		app.NewAuthGenState(addrs, []sdk.Coins{cs(c("token1", 100), c("token2", 100)), cs(c("token1", 100), c("token2", 100))}),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	ctx := tApp.NewContext(false, abci.Header{})
 | 
			
		||||
	keeper := tApp.GetAuctionKeeper()
 | 
			
		||||
 | 
			
		||||
	// Create an auction (lot: 20 t1, initialBid: 0 t2)
 | 
			
		||||
	auctionID, err := keeper.StartForwardAuction(ctx, seller, c("token1", 20), c("token2", 0)) // lot, initialBid
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	// Check seller's coins have decreased
 | 
			
		||||
	tApp.CheckBalance(t, ctx, seller, cs(c("token1", 80), c("token2", 100)))
 | 
			
		||||
 | 
			
		||||
	// PlaceBid (bid: 10 t2, lot: same as starting)
 | 
			
		||||
	require.NoError(t, keeper.PlaceBid(ctx, 0, buyer, c("token2", 10), c("token1", 20))) // bid, lot
 | 
			
		||||
	// Check buyer's coins have decreased
 | 
			
		||||
	tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 100), c("token2", 90)))
 | 
			
		||||
	// Check seller's coins have increased
 | 
			
		||||
	tApp.CheckBalance(t, ctx, seller, cs(c("token1", 80), c("token2", 110)))
 | 
			
		||||
 | 
			
		||||
	// Close auction at just after auction expiry
 | 
			
		||||
	ctx = ctx.WithBlockHeight(int64(types.DefaultMaxBidDuration))
 | 
			
		||||
	require.NoError(t, keeper.CloseAuction(ctx, auctionID))
 | 
			
		||||
	// Check buyer's coins increased
 | 
			
		||||
	tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 120), c("token2", 90)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestKeeper_ReverseAuction(t *testing.T) {
 | 
			
		||||
	// Setup
 | 
			
		||||
	_, addrs := app.GeneratePrivKeyAddressPairs(2)
 | 
			
		||||
	seller := addrs[0]
 | 
			
		||||
	buyer := addrs[1]
 | 
			
		||||
 | 
			
		||||
	tApp := app.NewTestApp()
 | 
			
		||||
	tApp.InitializeFromGenesisStates(
 | 
			
		||||
		app.NewAuthGenState(addrs, []sdk.Coins{cs(c("token1", 100), c("token2", 100)), cs(c("token1", 100), c("token2", 100))}),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	ctx := tApp.NewContext(false, abci.Header{})
 | 
			
		||||
	keeper := tApp.GetAuctionKeeper()
 | 
			
		||||
 | 
			
		||||
	// Start auction
 | 
			
		||||
	auctionID, err := keeper.StartReverseAuction(ctx, buyer, c("token1", 20), c("token2", 99)) // buyer, bid, initialLot
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	// Check buyer's coins have decreased
 | 
			
		||||
	tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 100), c("token2", 1)))
 | 
			
		||||
 | 
			
		||||
	// Place a bid
 | 
			
		||||
	require.NoError(t, keeper.PlaceBid(ctx, 0, seller, c("token1", 20), c("token2", 10))) // bid, lot
 | 
			
		||||
	// Check seller's coins have decreased
 | 
			
		||||
	tApp.CheckBalance(t, ctx, seller, cs(c("token1", 80), c("token2", 100)))
 | 
			
		||||
	// Check buyer's coins have increased
 | 
			
		||||
	tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 120), c("token2", 90)))
 | 
			
		||||
 | 
			
		||||
	// Close auction at just after auction expiry
 | 
			
		||||
	ctx = ctx.WithBlockHeight(int64(types.DefaultMaxBidDuration))
 | 
			
		||||
	require.NoError(t, keeper.CloseAuction(ctx, auctionID))
 | 
			
		||||
	// Check seller's coins increased
 | 
			
		||||
	tApp.CheckBalance(t, ctx, seller, cs(c("token1", 80), c("token2", 110)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestKeeper_ForwardReverseAuction(t *testing.T) {
 | 
			
		||||
	// Setup
 | 
			
		||||
	_, addrs := app.GeneratePrivKeyAddressPairs(3)
 | 
			
		||||
	seller := addrs[0]
 | 
			
		||||
	buyer := addrs[1]
 | 
			
		||||
	recipient := addrs[2]
 | 
			
		||||
 | 
			
		||||
	tApp := app.NewTestApp()
 | 
			
		||||
	tApp.InitializeFromGenesisStates(
 | 
			
		||||
		app.NewAuthGenState(addrs, []sdk.Coins{cs(c("token1", 100), c("token2", 100)), cs(c("token1", 100), c("token2", 100)), cs(c("token1", 100), c("token2", 100))}),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	ctx := tApp.NewContext(false, abci.Header{})
 | 
			
		||||
	keeper := tApp.GetAuctionKeeper()
 | 
			
		||||
 | 
			
		||||
	// Start auction
 | 
			
		||||
	auctionID, err := keeper.StartForwardReverseAuction(ctx, seller, c("token1", 20), c("token2", 50), recipient) // seller, lot, maxBid, otherPerson
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	// Check seller's coins have decreased
 | 
			
		||||
	tApp.CheckBalance(t, ctx, seller, cs(c("token1", 80), c("token2", 100)))
 | 
			
		||||
 | 
			
		||||
	// Place a bid
 | 
			
		||||
	require.NoError(t, keeper.PlaceBid(ctx, 0, buyer, c("token2", 50), c("token1", 15))) // bid, lot
 | 
			
		||||
	// Check bidder's coins have decreased
 | 
			
		||||
	tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 100), c("token2", 50)))
 | 
			
		||||
	// Check seller's coins have increased
 | 
			
		||||
	tApp.CheckBalance(t, ctx, seller, cs(c("token1", 80), c("token2", 150)))
 | 
			
		||||
	// Check "recipient" has received coins
 | 
			
		||||
	tApp.CheckBalance(t, ctx, recipient, cs(c("token1", 105), c("token2", 100)))
 | 
			
		||||
 | 
			
		||||
	// Close auction at just after auction expiry
 | 
			
		||||
	ctx = ctx.WithBlockHeight(int64(types.DefaultMaxBidDuration))
 | 
			
		||||
	require.NoError(t, keeper.CloseAuction(ctx, auctionID))
 | 
			
		||||
	// Check buyer's coins increased
 | 
			
		||||
	tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 115), c("token2", 50)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestKeeper_SetGetDeleteAuction(t *testing.T) {
 | 
			
		||||
	// setup keeper, create auction
 | 
			
		||||
	mapp, keeper, addresses, _ := setUpMockApp()
 | 
			
		||||
	header := abci.Header{Height: mapp.LastBlockHeight() + 1}
 | 
			
		||||
	mapp.BeginBlock(abci.RequestBeginBlock{Header: header}) // Without this it panics about "invalid memory address or nil pointer dereference"
 | 
			
		||||
	ctx := mapp.BaseApp.NewContext(false, header)
 | 
			
		||||
	auction, _ := types.NewForwardAuction(addresses[0], sdk.NewInt64Coin("usdx", 100), sdk.NewInt64Coin("kava", 0), types.EndTime(1000))
 | 
			
		||||
	_, addrs := app.GeneratePrivKeyAddressPairs(1)
 | 
			
		||||
	tApp := app.NewTestApp()
 | 
			
		||||
	keeper := tApp.GetAuctionKeeper()
 | 
			
		||||
	ctx := tApp.NewContext(true, abci.Header{})
 | 
			
		||||
	auction, _ := types.NewForwardAuction(addrs[0], c("usdx", 100), c("kava", 0), types.EndTime(1000))
 | 
			
		||||
	id := types.ID(5)
 | 
			
		||||
	auction.SetID(id)
 | 
			
		||||
 | 
			
		||||
@ -26,15 +134,13 @@ func TestKeeper_SetGetDeleteAuction(t *testing.T) {
 | 
			
		||||
	// check before and after match
 | 
			
		||||
	require.True(t, found)
 | 
			
		||||
	require.Equal(t, &auction, readAuction)
 | 
			
		||||
	t.Log(auction)
 | 
			
		||||
	t.Log(readAuction.GetID())
 | 
			
		||||
	// check auction is in queue
 | 
			
		||||
	iter := keeper.GetQueueIterator(ctx, 100000)
 | 
			
		||||
	require.Equal(t, 1, len(convertIteratorToSlice(keeper, iter)))
 | 
			
		||||
	iter.Close()
 | 
			
		||||
 | 
			
		||||
	// delete auction
 | 
			
		||||
	keeper.deleteAuction(ctx, id)
 | 
			
		||||
	keeper.DeleteAuction(ctx, id)
 | 
			
		||||
 | 
			
		||||
	// check auction does not exist
 | 
			
		||||
	_, found = keeper.GetAuction(ctx, id)
 | 
			
		||||
@ -49,10 +155,10 @@ func TestKeeper_SetGetDeleteAuction(t *testing.T) {
 | 
			
		||||
// TODO convert to table driven test with more test cases
 | 
			
		||||
func TestKeeper_ExpiredAuctionQueue(t *testing.T) {
 | 
			
		||||
	// setup keeper
 | 
			
		||||
	mapp, keeper, _, _ := setUpMockApp()
 | 
			
		||||
	header := abci.Header{Height: mapp.LastBlockHeight() + 1}
 | 
			
		||||
	mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
 | 
			
		||||
	ctx := mapp.BaseApp.NewContext(false, header)
 | 
			
		||||
	tApp := app.NewTestApp()
 | 
			
		||||
	keeper := tApp.GetAuctionKeeper()
 | 
			
		||||
	ctx := tApp.NewContext(true, abci.Header{})
 | 
			
		||||
 | 
			
		||||
	// create an example queue
 | 
			
		||||
	type queue []struct {
 | 
			
		||||
		endTime   types.EndTime
 | 
			
		||||
@ -62,7 +168,7 @@ func TestKeeper_ExpiredAuctionQueue(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	// write and read queue
 | 
			
		||||
	for _, v := range q {
 | 
			
		||||
		keeper.insertIntoQueue(ctx, v.endTime, v.auctionID)
 | 
			
		||||
		keeper.InsertIntoQueue(ctx, v.endTime, v.auctionID)
 | 
			
		||||
	}
 | 
			
		||||
	iter := keeper.GetQueueIterator(ctx, 1000)
 | 
			
		||||
 | 
			
		||||
@ -70,19 +176,22 @@ func TestKeeper_ExpiredAuctionQueue(t *testing.T) {
 | 
			
		||||
	i := 0
 | 
			
		||||
	for ; iter.Valid(); iter.Next() {
 | 
			
		||||
		var auctionID types.ID
 | 
			
		||||
		keeper.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &auctionID)
 | 
			
		||||
		tApp.Codec().MustUnmarshalBinaryLengthPrefixed(iter.Value(), &auctionID)
 | 
			
		||||
		require.Equal(t, q[i].auctionID, auctionID)
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertIteratorToSlice(keeper Keeper, iterator sdk.Iterator) []types.ID {
 | 
			
		||||
func convertIteratorToSlice(keeper keeper.Keeper, iterator sdk.Iterator) []types.ID {
 | 
			
		||||
	var queue []types.ID
 | 
			
		||||
	for ; iterator.Valid(); iterator.Next() {
 | 
			
		||||
		var auctionID types.ID
 | 
			
		||||
		keeper.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &auctionID)
 | 
			
		||||
		types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &auctionID)
 | 
			
		||||
		queue = append(queue, auctionID)
 | 
			
		||||
	}
 | 
			
		||||
	return queue
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) }
 | 
			
		||||
func cs(coins ...sdk.Coin) sdk.Coins        { return sdk.NewCoins(coins...) }
 | 
			
		||||
 | 
			
		||||
@ -1,35 +0,0 @@
 | 
			
		||||
package keeper
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/bank"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/mock"
 | 
			
		||||
	"github.com/kava-labs/kava/x/auction/types"
 | 
			
		||||
	"github.com/tendermint/tendermint/crypto"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func setUpMockApp() (*mock.App, Keeper, []sdk.AccAddress, []crypto.PrivKey) {
 | 
			
		||||
	// Create uninitialized mock app
 | 
			
		||||
	mapp := mock.NewApp()
 | 
			
		||||
 | 
			
		||||
	// Register codecs
 | 
			
		||||
	types.RegisterCodec(mapp.Cdc)
 | 
			
		||||
 | 
			
		||||
	// Create keepers
 | 
			
		||||
	keyAuction := sdk.NewKVStoreKey("auction")
 | 
			
		||||
	blacklistedAddrs := make(map[string]bool)
 | 
			
		||||
	bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper, mapp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, blacklistedAddrs)
 | 
			
		||||
	auctionKeeper := NewKeeper(mapp.Cdc, bankKeeper, keyAuction, mapp.ParamsKeeper.Subspace(types.DefaultParamspace))
 | 
			
		||||
 | 
			
		||||
	// Mount and load the stores
 | 
			
		||||
	err := mapp.CompleteSetup(keyAuction)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic("mock app setup failed")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Create a bunch (ie 10) of pre-funded accounts to use for tests
 | 
			
		||||
	genAccs, addrs, _, privKeys := mock.CreateGenAccounts(10, sdk.NewCoins(sdk.NewInt64Coin("token1", 100), sdk.NewInt64Coin("token2", 100)))
 | 
			
		||||
	mock.SetGenesis(mapp, genAccs)
 | 
			
		||||
 | 
			
		||||
	return mapp, auctionKeeper, addrs, privKeys
 | 
			
		||||
}
 | 
			
		||||
@ -1,73 +1,55 @@
 | 
			
		||||
package cdp
 | 
			
		||||
package cdp_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/simapp"
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/mock"
 | 
			
		||||
	abci "github.com/tendermint/tendermint/abci/types"
 | 
			
		||||
	tmtime "github.com/tendermint/tendermint/types/time"
 | 
			
		||||
 | 
			
		||||
	"github.com/kava-labs/kava/x/pricefeed"
 | 
			
		||||
	"github.com/kava-labs/kava/app"
 | 
			
		||||
	"github.com/kava-labs/kava/x/cdp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestApp_CreateModifyDeleteCDP(t *testing.T) {
 | 
			
		||||
	// Setup
 | 
			
		||||
	mapp, keeper, pfKeeper := setUpMockAppWithoutGenesis()
 | 
			
		||||
	genAccs, addrs, _, privKeys := mock.CreateGenAccounts(1, cs(c("xrp", 100)))
 | 
			
		||||
	tApp := app.NewTestApp()
 | 
			
		||||
	privKeys, addrs := app.GeneratePrivKeyAddressPairs(1)
 | 
			
		||||
	testAddr := addrs[0]
 | 
			
		||||
	testPrivKey := privKeys[0]
 | 
			
		||||
	mock.SetGenesis(mapp, genAccs)
 | 
			
		||||
	mock.CheckBalance(t, mapp, testAddr, cs(c("xrp", 100)))
 | 
			
		||||
	// setup pricefeed, TODO can this be shortened a bit?
 | 
			
		||||
	header := abci.Header{Height: mapp.LastBlockHeight() + 1, Time: tmtime.Now()}
 | 
			
		||||
	mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
 | 
			
		||||
	ctx := mapp.BaseApp.NewContext(false, header)
 | 
			
		||||
	params := CdpParams{
 | 
			
		||||
		GlobalDebtLimit: sdk.NewInt(100000),
 | 
			
		||||
		CollateralParams: []CollateralParams{
 | 
			
		||||
			{
 | 
			
		||||
				Denom:            "xrp",
 | 
			
		||||
				LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
 | 
			
		||||
				DebtLimit:        sdk.NewInt(10000),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		StableDenoms: []string{"usdx"},
 | 
			
		||||
	}
 | 
			
		||||
	keeper.SetParams(ctx, params)
 | 
			
		||||
	keeper.SetGlobalDebt(ctx, sdk.NewInt(0))
 | 
			
		||||
	ap := pricefeed.Params{
 | 
			
		||||
		Markets: []pricefeed.Market{
 | 
			
		||||
			pricefeed.Market{
 | 
			
		||||
				MarketID: "xrp", BaseAsset: "xrp",
 | 
			
		||||
				QuoteAsset: "usd", Oracles: pricefeed.Oracles{}, Active: true},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	pfKeeper.SetParams(ctx, ap)
 | 
			
		||||
	pfKeeper.SetPrice(
 | 
			
		||||
		ctx, sdk.AccAddress{}, "xrp",
 | 
			
		||||
		sdk.MustNewDecFromStr("1.00"),
 | 
			
		||||
		header.Time.Add(time.Hour*1))
 | 
			
		||||
	pfKeeper.SetCurrentPrices(ctx, "xrp")
 | 
			
		||||
	mapp.EndBlock(abci.RequestEndBlock{})
 | 
			
		||||
	mapp.Commit()
 | 
			
		||||
	tApp.InitializeFromGenesisStates(
 | 
			
		||||
		app.NewAuthGenState(addrs, []sdk.Coins{cs(c("xrp", 100))}),
 | 
			
		||||
		NewPFGenState("xrp", d("1.00")),
 | 
			
		||||
		NewCDPGenState("xrp", d("1.5")),
 | 
			
		||||
	)
 | 
			
		||||
	// check balance
 | 
			
		||||
	ctx := tApp.NewContext(false, abci.Header{})
 | 
			
		||||
	tApp.CheckBalance(t, ctx, testAddr, cs(c("xrp", 100)))
 | 
			
		||||
 | 
			
		||||
	tApp.EndBlock(abci.RequestEndBlock{})
 | 
			
		||||
	tApp.Commit()
 | 
			
		||||
 | 
			
		||||
	// Create CDP
 | 
			
		||||
	msgs := []sdk.Msg{NewMsgCreateOrModifyCDP(testAddr, "xrp", i(10), i(5))}
 | 
			
		||||
	mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, abci.Header{Height: mapp.LastBlockHeight() + 1}, msgs, []uint64{0}, []uint64{0}, true, true, testPrivKey)
 | 
			
		||||
	msgs := []sdk.Msg{cdp.NewMsgCreateOrModifyCDP(testAddr, "xrp", i(10), i(5))}
 | 
			
		||||
	simapp.SignCheckDeliver(t, tApp.Codec(), tApp.BaseApp, abci.Header{Height: tApp.LastBlockHeight() + 1}, msgs, []uint64{0}, []uint64{0}, true, true, testPrivKey)
 | 
			
		||||
 | 
			
		||||
	mock.CheckBalance(t, mapp, testAddr, cs(c("usdx", 5), c("xrp", 90)))
 | 
			
		||||
	// check balance
 | 
			
		||||
	ctx = tApp.NewContext(true, abci.Header{})
 | 
			
		||||
	tApp.CheckBalance(t, ctx, testAddr, cs(c("usdx", 5), c("xrp", 90)))
 | 
			
		||||
 | 
			
		||||
	// Modify CDP
 | 
			
		||||
	msgs = []sdk.Msg{NewMsgCreateOrModifyCDP(testAddr, "xrp", i(40), i(5))}
 | 
			
		||||
	mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, abci.Header{Height: mapp.LastBlockHeight() + 1}, msgs, []uint64{0}, []uint64{1}, true, true, testPrivKey)
 | 
			
		||||
	msgs = []sdk.Msg{cdp.NewMsgCreateOrModifyCDP(testAddr, "xrp", i(40), i(5))}
 | 
			
		||||
	simapp.SignCheckDeliver(t, tApp.Codec(), tApp.BaseApp, abci.Header{Height: tApp.LastBlockHeight() + 1}, msgs, []uint64{0}, []uint64{1}, true, true, testPrivKey)
 | 
			
		||||
 | 
			
		||||
	mock.CheckBalance(t, mapp, testAddr, cs(c("usdx", 10), c("xrp", 50)))
 | 
			
		||||
	// check balance
 | 
			
		||||
	ctx = tApp.NewContext(true, abci.Header{})
 | 
			
		||||
	tApp.CheckBalance(t, ctx, testAddr, cs(c("usdx", 10), c("xrp", 50)))
 | 
			
		||||
 | 
			
		||||
	// Delete CDP
 | 
			
		||||
	msgs = []sdk.Msg{NewMsgCreateOrModifyCDP(testAddr, "xrp", i(-50), i(-10))}
 | 
			
		||||
	mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, abci.Header{Height: mapp.LastBlockHeight() + 1}, msgs, []uint64{0}, []uint64{2}, true, true, testPrivKey)
 | 
			
		||||
	msgs = []sdk.Msg{cdp.NewMsgCreateOrModifyCDP(testAddr, "xrp", i(-50), i(-10))}
 | 
			
		||||
	simapp.SignCheckDeliver(t, tApp.Codec(), tApp.BaseApp, abci.Header{Height: tApp.LastBlockHeight() + 1}, msgs, []uint64{0}, []uint64{2}, true, true, testPrivKey)
 | 
			
		||||
 | 
			
		||||
	mock.CheckBalance(t, mapp, testAddr, cs(c("xrp", 100)))
 | 
			
		||||
	// check balance
 | 
			
		||||
	ctx = tApp.NewContext(true, abci.Header{})
 | 
			
		||||
	tApp.CheckBalance(t, ctx, testAddr, cs(c("xrp", 100)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										56
									
								
								x/cdp/integration_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								x/cdp/integration_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,56 @@
 | 
			
		||||
package cdp_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
 | 
			
		||||
	"github.com/kava-labs/kava/app"
 | 
			
		||||
	"github.com/kava-labs/kava/x/cdp"
 | 
			
		||||
	"github.com/kava-labs/kava/x/pricefeed"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Avoid cluttering test cases with long function name
 | 
			
		||||
func i(in int64) sdk.Int                    { return sdk.NewInt(in) }
 | 
			
		||||
func d(str string) sdk.Dec                  { return sdk.MustNewDecFromStr(str) }
 | 
			
		||||
func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) }
 | 
			
		||||
func cs(coins ...sdk.Coin) sdk.Coins        { return sdk.NewCoins(coins...) }
 | 
			
		||||
 | 
			
		||||
func NewPFGenState(asset string, price sdk.Dec) app.GenesisState {
 | 
			
		||||
	quote := "usd"
 | 
			
		||||
	ap := pricefeed.Params{
 | 
			
		||||
		Markets: []pricefeed.Market{
 | 
			
		||||
			pricefeed.Market{MarketID: asset, BaseAsset: asset, QuoteAsset: quote, Oracles: pricefeed.Oracles{}, Active: true},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	pfGenesis := pricefeed.GenesisState{
 | 
			
		||||
		Params: ap,
 | 
			
		||||
		PostedPrices: []pricefeed.PostedPrice{
 | 
			
		||||
			pricefeed.PostedPrice{
 | 
			
		||||
				MarketID:      asset,
 | 
			
		||||
				OracleAddress: sdk.AccAddress{},
 | 
			
		||||
				Price:         price,
 | 
			
		||||
				Expiry:        time.Now().Add(1 * time.Hour),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	return app.GenesisState{pricefeed.ModuleName: pricefeed.ModuleCdc.MustMarshalJSON(pfGenesis)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewCDPGenState(asset string, liquidationRatio sdk.Dec) app.GenesisState {
 | 
			
		||||
	cdpGenesis := cdp.GenesisState{
 | 
			
		||||
		Params: cdp.CdpParams{
 | 
			
		||||
			GlobalDebtLimit: sdk.NewInt(1000000),
 | 
			
		||||
			CollateralParams: []cdp.CollateralParams{
 | 
			
		||||
				{
 | 
			
		||||
					Denom:            asset,
 | 
			
		||||
					LiquidationRatio: liquidationRatio,
 | 
			
		||||
					DebtLimit:        sdk.NewInt(500000),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		GlobalDebt: sdk.ZeroInt(),
 | 
			
		||||
		CDPs:       cdp.CDPs{},
 | 
			
		||||
	}
 | 
			
		||||
	return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)}
 | 
			
		||||
}
 | 
			
		||||
@ -1,19 +1,19 @@
 | 
			
		||||
package keeper
 | 
			
		||||
package keeper_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/auth"
 | 
			
		||||
	authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/mock"
 | 
			
		||||
	"github.com/stretchr/testify/require"
 | 
			
		||||
	abci "github.com/tendermint/tendermint/abci/types"
 | 
			
		||||
 | 
			
		||||
	"github.com/kava-labs/kava/app"
 | 
			
		||||
	keep "github.com/kava-labs/kava/x/cdp/keeper"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Test the bank functionality of the CDP keeper
 | 
			
		||||
func TestKeeper_AddSubtractGetCoins(t *testing.T) {
 | 
			
		||||
	_, addrs := mock.GeneratePrivKeyAddressPairs(1)
 | 
			
		||||
	_, addrs := app.GeneratePrivKeyAddressPairs(1)
 | 
			
		||||
	normalAddr := addrs[0]
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
@ -25,28 +25,24 @@ func TestKeeper_AddSubtractGetCoins(t *testing.T) {
 | 
			
		||||
	}{
 | 
			
		||||
		{"addNormalAddress", normalAddr, true, cs(c("usdx", 53)), cs(c("usdx", 153), c("kava", 100))},
 | 
			
		||||
		{"subNormalAddress", normalAddr, false, cs(c("usdx", 53)), cs(c("usdx", 47), c("kava", 100))},
 | 
			
		||||
		{"addLiquidatorStable", LiquidatorAccountAddress, true, cs(c("usdx", 53)), cs(c("usdx", 153))},
 | 
			
		||||
		{"subLiquidatorStable", LiquidatorAccountAddress, false, cs(c("usdx", 53)), cs(c("usdx", 47))},
 | 
			
		||||
		{"addLiquidatorGov", LiquidatorAccountAddress, true, cs(c("kava", 53)), cs(c("usdx", 100))},  // no change to balance
 | 
			
		||||
		{"subLiquidatorGov", LiquidatorAccountAddress, false, cs(c("kava", 53)), cs(c("usdx", 100))}, // no change to balance
 | 
			
		||||
		{"addLiquidatorStable", keep.LiquidatorAccountAddress, true, cs(c("usdx", 53)), cs(c("usdx", 153))},
 | 
			
		||||
		{"subLiquidatorStable", keep.LiquidatorAccountAddress, false, cs(c("usdx", 53)), cs(c("usdx", 47))},
 | 
			
		||||
		{"addLiquidatorGov", keep.LiquidatorAccountAddress, true, cs(c("kava", 53)), cs(c("usdx", 100))},  // no change to balance
 | 
			
		||||
		{"subLiquidatorGov", keep.LiquidatorAccountAddress, false, cs(c("kava", 53)), cs(c("usdx", 100))}, // no change to balance
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tc := range tests {
 | 
			
		||||
		t.Run(tc.name, func(t *testing.T) {
 | 
			
		||||
			// setup keeper
 | 
			
		||||
			mapp, keeper, _, _ := setUpMockAppWithoutGenesis()
 | 
			
		||||
			// initialize an account with coins
 | 
			
		||||
			genAcc := auth.BaseAccount{
 | 
			
		||||
				Address: normalAddr,
 | 
			
		||||
				Coins:   cs(c("usdx", 100), c("kava", 100)),
 | 
			
		||||
			}
 | 
			
		||||
			mock.SetGenesis(mapp, []authexported.Account{&genAcc})
 | 
			
		||||
			// setup app with an account
 | 
			
		||||
			tApp := app.NewTestApp()
 | 
			
		||||
			tApp.InitializeFromGenesisStates(
 | 
			
		||||
				app.NewAuthGenState([]sdk.AccAddress{normalAddr}, []sdk.Coins{cs(c("usdx", 100), c("kava", 100))}),
 | 
			
		||||
			)
 | 
			
		||||
 | 
			
		||||
			// create a new context and setup the liquidator account
 | 
			
		||||
			header := abci.Header{Height: mapp.LastBlockHeight() + 1}
 | 
			
		||||
			mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
 | 
			
		||||
			ctx := mapp.BaseApp.NewContext(false, header)
 | 
			
		||||
			keeper.setLiquidatorModuleAccount(ctx, LiquidatorModuleAccount{cs(c("usdx", 100))}) // set gov coin "balance" to zero
 | 
			
		||||
			ctx := tApp.NewContext(false, abci.Header{})
 | 
			
		||||
			keeper := tApp.GetCDPKeeper()
 | 
			
		||||
			keeper.SetLiquidatorModuleAccount(ctx, keep.LiquidatorModuleAccount{cs(c("usdx", 100))}) // set gov coin "balance" to zero
 | 
			
		||||
 | 
			
		||||
			// perform the test action
 | 
			
		||||
			var err sdk.Error
 | 
			
		||||
@ -56,9 +52,6 @@ func TestKeeper_AddSubtractGetCoins(t *testing.T) {
 | 
			
		||||
				_, err = keeper.SubtractCoins(ctx, tc.address, tc.amount)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			mapp.EndBlock(abci.RequestEndBlock{})
 | 
			
		||||
			mapp.Commit()
 | 
			
		||||
 | 
			
		||||
			// check balances are as expected
 | 
			
		||||
			require.NoError(t, err)
 | 
			
		||||
			require.Equal(t, tc.expectedCoins, keeper.GetCoins(ctx, tc.address))
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										103
									
								
								x/cdp/keeper/integration_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								x/cdp/keeper/integration_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,103 @@
 | 
			
		||||
package keeper_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
 | 
			
		||||
	"github.com/kava-labs/kava/app"
 | 
			
		||||
	"github.com/kava-labs/kava/x/cdp"
 | 
			
		||||
	"github.com/kava-labs/kava/x/cdp/types"
 | 
			
		||||
	"github.com/kava-labs/kava/x/pricefeed"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Avoid cluttering test cases with long function name
 | 
			
		||||
func i(in int64) sdk.Int                    { return sdk.NewInt(in) }
 | 
			
		||||
func d(str string) sdk.Dec                  { return sdk.MustNewDecFromStr(str) }
 | 
			
		||||
func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) }
 | 
			
		||||
func cs(coins ...sdk.Coin) sdk.Coins        { return sdk.NewCoins(coins...) }
 | 
			
		||||
 | 
			
		||||
func NewPricefeedGenState(asset string, price sdk.Dec) app.GenesisState {
 | 
			
		||||
	pfGenesis := pricefeed.GenesisState{
 | 
			
		||||
		Params: pricefeed.Params{
 | 
			
		||||
			Markets: []pricefeed.Market{
 | 
			
		||||
				pricefeed.Market{MarketID: asset, BaseAsset: asset, QuoteAsset: "usd", Oracles: pricefeed.Oracles{}, Active: true},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		PostedPrices: []pricefeed.PostedPrice{
 | 
			
		||||
			pricefeed.PostedPrice{
 | 
			
		||||
				MarketID:      asset,
 | 
			
		||||
				OracleAddress: sdk.AccAddress{},
 | 
			
		||||
				Price:         price,
 | 
			
		||||
				Expiry:        time.Now().Add(1 * time.Hour),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	return app.GenesisState{pricefeed.ModuleName: pricefeed.ModuleCdc.MustMarshalJSON(pfGenesis)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewCDPGenState(asset string, liquidationRatio sdk.Dec) app.GenesisState {
 | 
			
		||||
	cdpGenesis := cdp.GenesisState{
 | 
			
		||||
		Params: cdp.CdpParams{
 | 
			
		||||
			GlobalDebtLimit: sdk.NewInt(1000000),
 | 
			
		||||
			CollateralParams: []cdp.CollateralParams{
 | 
			
		||||
				{
 | 
			
		||||
					Denom:            asset,
 | 
			
		||||
					LiquidationRatio: liquidationRatio,
 | 
			
		||||
					DebtLimit:        sdk.NewInt(500000),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		GlobalDebt: sdk.ZeroInt(),
 | 
			
		||||
		CDPs:       cdp.CDPs{},
 | 
			
		||||
	}
 | 
			
		||||
	return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewPricefeedGenStateMulti() app.GenesisState {
 | 
			
		||||
	pfGenesis := pricefeed.GenesisState{
 | 
			
		||||
		Params: pricefeed.Params{
 | 
			
		||||
			Markets: []pricefeed.Market{
 | 
			
		||||
				pricefeed.Market{MarketID: "btc", BaseAsset: "btc", QuoteAsset: "usd", Oracles: pricefeed.Oracles{}, Active: true},
 | 
			
		||||
				pricefeed.Market{MarketID: "xrp", BaseAsset: "xrp", QuoteAsset: "usd", Oracles: pricefeed.Oracles{}, Active: true},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		PostedPrices: []pricefeed.PostedPrice{
 | 
			
		||||
			pricefeed.PostedPrice{
 | 
			
		||||
				MarketID:      "btc",
 | 
			
		||||
				OracleAddress: sdk.AccAddress{},
 | 
			
		||||
				Price:         sdk.MustNewDecFromStr("8000.00"),
 | 
			
		||||
				Expiry:        time.Now().Add(1 * time.Hour),
 | 
			
		||||
			},
 | 
			
		||||
			pricefeed.PostedPrice{
 | 
			
		||||
				MarketID:      "xrp",
 | 
			
		||||
				OracleAddress: sdk.AccAddress{},
 | 
			
		||||
				Price:         sdk.MustNewDecFromStr("0.25"),
 | 
			
		||||
				Expiry:        time.Now().Add(1 * time.Hour),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	return app.GenesisState{pricefeed.ModuleName: pricefeed.ModuleCdc.MustMarshalJSON(pfGenesis)}
 | 
			
		||||
}
 | 
			
		||||
func NewCDPGenStateMulti() app.GenesisState {
 | 
			
		||||
	cdpGenesis := cdp.GenesisState{
 | 
			
		||||
		Params: cdp.CdpParams{
 | 
			
		||||
			GlobalDebtLimit: sdk.NewInt(1000000),
 | 
			
		||||
			CollateralParams: []types.CollateralParams{
 | 
			
		||||
				{
 | 
			
		||||
					Denom:            "btc",
 | 
			
		||||
					LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
 | 
			
		||||
					DebtLimit:        sdk.NewInt(500000),
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					Denom:            "xrp",
 | 
			
		||||
					LiquidationRatio: sdk.MustNewDecFromStr("2.0"),
 | 
			
		||||
					DebtLimit:        sdk.NewInt(500000),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		GlobalDebt: sdk.ZeroInt(),
 | 
			
		||||
		CDPs:       cdp.CDPs{},
 | 
			
		||||
	}
 | 
			
		||||
	return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)}
 | 
			
		||||
}
 | 
			
		||||
@ -126,13 +126,13 @@ func (k Keeper) ModifyCDP(ctx sdk.Context, owner sdk.AccAddress, collateralDenom
 | 
			
		||||
	}
 | 
			
		||||
	// Set CDP
 | 
			
		||||
	if cdp.CollateralAmount.IsZero() && cdp.Debt.IsZero() { // TODO maybe abstract this logic into SetCDP
 | 
			
		||||
		k.deleteCDP(ctx, cdp)
 | 
			
		||||
		k.DeleteCDP(ctx, cdp)
 | 
			
		||||
	} else {
 | 
			
		||||
		k.SetCDP(ctx, cdp)
 | 
			
		||||
	}
 | 
			
		||||
	// set total debts
 | 
			
		||||
	k.SetGlobalDebt(ctx, gDebt)
 | 
			
		||||
	k.setCollateralState(ctx, collateralState)
 | 
			
		||||
	k.SetCollateralState(ctx, collateralState)
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
@ -195,11 +195,11 @@ func (k Keeper) PartialSeizeCDP(ctx sdk.Context, owner sdk.AccAddress, collatera
 | 
			
		||||
 | 
			
		||||
	// Store updated state
 | 
			
		||||
	if cdp.CollateralAmount.IsZero() && cdp.Debt.IsZero() { // TODO maybe abstract this logic into SetCDP
 | 
			
		||||
		k.deleteCDP(ctx, cdp)
 | 
			
		||||
		k.DeleteCDP(ctx, cdp)
 | 
			
		||||
	} else {
 | 
			
		||||
		k.SetCDP(ctx, cdp)
 | 
			
		||||
	}
 | 
			
		||||
	k.setCollateralState(ctx, collateralState)
 | 
			
		||||
	k.SetCollateralState(ctx, collateralState)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -264,7 +264,7 @@ func (k Keeper) SetCDP(ctx sdk.Context, cdp types.CDP) {
 | 
			
		||||
	bz := k.cdc.MustMarshalBinaryLengthPrefixed(cdp)
 | 
			
		||||
	store.Set(k.getCDPKey(cdp.Owner, cdp.CollateralDenom), bz)
 | 
			
		||||
}
 | 
			
		||||
func (k Keeper) deleteCDP(ctx sdk.Context, cdp types.CDP) { // TODO should this id the cdp by passing in owner,collateralDenom pair?
 | 
			
		||||
func (k Keeper) DeleteCDP(ctx sdk.Context, cdp types.CDP) { // TODO should this id the cdp by passing in owner,collateralDenom pair?
 | 
			
		||||
	// get store
 | 
			
		||||
	store := ctx.KVStore(k.key)
 | 
			
		||||
	// delete key
 | 
			
		||||
@ -354,7 +354,7 @@ func (k Keeper) GetCollateralState(ctx sdk.Context, collateralDenom string) (typ
 | 
			
		||||
	k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &collateralState)
 | 
			
		||||
	return collateralState, true
 | 
			
		||||
}
 | 
			
		||||
func (k Keeper) setCollateralState(ctx sdk.Context, collateralstate types.CollateralState) {
 | 
			
		||||
func (k Keeper) SetCollateralState(ctx sdk.Context, collateralstate types.CollateralState) {
 | 
			
		||||
	// get store
 | 
			
		||||
	store := ctx.KVStore(k.key)
 | 
			
		||||
	// marshal and set
 | 
			
		||||
@ -422,7 +422,7 @@ func (k Keeper) AddCoins(ctx sdk.Context, address sdk.AccAddress, amount sdk.Coi
 | 
			
		||||
			return amount, sdk.ErrInsufficientCoins(fmt.Sprintf("insufficient account funds; %s < %s", lma.Coins, amount))
 | 
			
		||||
		}
 | 
			
		||||
		lma.Coins = updatedCoins
 | 
			
		||||
		k.setLiquidatorModuleAccount(ctx, lma)
 | 
			
		||||
		k.SetLiquidatorModuleAccount(ctx, lma)
 | 
			
		||||
		return updatedCoins, nil
 | 
			
		||||
	} else {
 | 
			
		||||
		return k.bankKeeper.AddCoins(ctx, address, amount)
 | 
			
		||||
@ -445,7 +445,7 @@ func (k Keeper) SubtractCoins(ctx sdk.Context, address sdk.AccAddress, amount sd
 | 
			
		||||
			return amount, sdk.ErrInsufficientCoins(fmt.Sprintf("insufficient account funds; %s < %s", lma.Coins, amount))
 | 
			
		||||
		}
 | 
			
		||||
		lma.Coins = updatedCoins
 | 
			
		||||
		k.setLiquidatorModuleAccount(ctx, lma)
 | 
			
		||||
		k.SetLiquidatorModuleAccount(ctx, lma)
 | 
			
		||||
		return updatedCoins, nil
 | 
			
		||||
	} else {
 | 
			
		||||
		return k.bankKeeper.SubtractCoins(ctx, address, amount)
 | 
			
		||||
@ -483,7 +483,7 @@ func (k Keeper) getLiquidatorModuleAccount(ctx sdk.Context) LiquidatorModuleAcco
 | 
			
		||||
	k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &lma)
 | 
			
		||||
	return lma
 | 
			
		||||
}
 | 
			
		||||
func (k Keeper) setLiquidatorModuleAccount(ctx sdk.Context, lma LiquidatorModuleAccount) {
 | 
			
		||||
func (k Keeper) SetLiquidatorModuleAccount(ctx sdk.Context, lma LiquidatorModuleAccount) {
 | 
			
		||||
	store := ctx.KVStore(k.key)
 | 
			
		||||
	bz := k.cdc.MustMarshalBinaryLengthPrefixed(lma)
 | 
			
		||||
	store.Set(liquidatorAccountKey, bz)
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
package keeper
 | 
			
		||||
package keeper_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
@ -6,24 +6,21 @@ import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/auth"
 | 
			
		||||
	authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/mock"
 | 
			
		||||
	"github.com/kava-labs/kava/x/cdp/types"
 | 
			
		||||
	"github.com/kava-labs/kava/x/pricefeed"
 | 
			
		||||
	"github.com/stretchr/testify/require"
 | 
			
		||||
	abci "github.com/tendermint/tendermint/abci/types"
 | 
			
		||||
	tmtime "github.com/tendermint/tendermint/types/time"
 | 
			
		||||
 | 
			
		||||
	"github.com/kava-labs/kava/app"
 | 
			
		||||
	"github.com/kava-labs/kava/x/cdp/types"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// How could one reduce the number of params in the test cases. Create a table driven test for each of the 4 add/withdraw collateral/debt?
 | 
			
		||||
 | 
			
		||||
// These are more like app level tests - I think this is a symptom of having 'ModifyCDP' do a lot. Could be easier for testing purposes to break it down.
 | 
			
		||||
func TestKeeper_ModifyCDP(t *testing.T) {
 | 
			
		||||
	_, addrs := mock.GeneratePrivKeyAddressPairs(1)
 | 
			
		||||
	_, addrs := app.GeneratePrivKeyAddressPairs(1)
 | 
			
		||||
	ownerAddr := addrs[0]
 | 
			
		||||
 | 
			
		||||
	type state struct { // TODO this allows invalid state to be set up, should it?
 | 
			
		||||
	type state struct {
 | 
			
		||||
		CDP             types.CDP
 | 
			
		||||
		OwnerCoins      sdk.Coins
 | 
			
		||||
		GlobalDebt      sdk.Int
 | 
			
		||||
@ -96,59 +93,32 @@ func TestKeeper_ModifyCDP(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
	for _, tc := range tests {
 | 
			
		||||
		t.Run(tc.name, func(t *testing.T) {
 | 
			
		||||
			// setup keeper
 | 
			
		||||
			mapp, keeper, _, _ := setUpMockAppWithoutGenesis()
 | 
			
		||||
			// initialize cdp owner account with coins
 | 
			
		||||
			genAcc := auth.BaseAccount{
 | 
			
		||||
				Address: ownerAddr,
 | 
			
		||||
				Coins:   tc.priorState.OwnerCoins,
 | 
			
		||||
			}
 | 
			
		||||
			mock.SetGenesis(mapp, []authexported.Account{&genAcc})
 | 
			
		||||
			// create a new context
 | 
			
		||||
			header := abci.Header{Height: mapp.LastBlockHeight() + 1, Time: tmtime.Now()}
 | 
			
		||||
			mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
 | 
			
		||||
			ctx := mapp.BaseApp.NewContext(false, header)
 | 
			
		||||
			keeper.SetParams(ctx, defaultParamsSingle())
 | 
			
		||||
			// setup test app
 | 
			
		||||
			tApp := app.NewTestApp()
 | 
			
		||||
			// initialize cdp owner account with coins, and collateral with price and params
 | 
			
		||||
			tApp.InitializeFromGenesisStates(
 | 
			
		||||
				app.NewAuthGenState([]sdk.AccAddress{ownerAddr}, []sdk.Coins{tc.priorState.OwnerCoins}),
 | 
			
		||||
				NewPricefeedGenState("xrp", d(tc.price)),
 | 
			
		||||
				NewCDPGenState("xrp", d("2.0")),
 | 
			
		||||
			)
 | 
			
		||||
			// create a context for db access
 | 
			
		||||
			ctx := tApp.NewContext(false, abci.Header{})
 | 
			
		||||
 | 
			
		||||
			// setup store state
 | 
			
		||||
			ap := pricefeed.Params{
 | 
			
		||||
				Markets: []pricefeed.Market{
 | 
			
		||||
					pricefeed.Market{
 | 
			
		||||
						MarketID: "xrp", BaseAsset: "xrp",
 | 
			
		||||
						QuoteAsset: "usd", Oracles: pricefeed.Oracles{}, Active: true},
 | 
			
		||||
				},
 | 
			
		||||
			}
 | 
			
		||||
			keeper.pricefeedKeeper.SetParams(ctx, ap)
 | 
			
		||||
			_, err := keeper.pricefeedKeeper.SetPrice(
 | 
			
		||||
				ctx, ownerAddr, "xrp",
 | 
			
		||||
				sdk.MustNewDecFromStr(tc.price),
 | 
			
		||||
				header.Time.Add(time.Hour*1))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				t.Log("test context height", ctx.BlockHeight())
 | 
			
		||||
				t.Log(err)
 | 
			
		||||
				t.Log(tc.name)
 | 
			
		||||
			}
 | 
			
		||||
			err = keeper.pricefeedKeeper.SetCurrentPrices(ctx, "xrp")
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				t.Log("test context height", ctx.BlockHeight())
 | 
			
		||||
				t.Log(err)
 | 
			
		||||
				t.Log(tc.name)
 | 
			
		||||
			}
 | 
			
		||||
			keeper := tApp.GetCDPKeeper()
 | 
			
		||||
			if tc.priorState.CDP.CollateralDenom != "" { // check if the prior CDP should be created or not (see if an empty one was specified)
 | 
			
		||||
				keeper.SetCDP(ctx, tc.priorState.CDP)
 | 
			
		||||
			}
 | 
			
		||||
			keeper.SetGlobalDebt(ctx, tc.priorState.GlobalDebt)
 | 
			
		||||
			if tc.priorState.CollateralState.Denom != "" {
 | 
			
		||||
				keeper.setCollateralState(ctx, tc.priorState.CollateralState)
 | 
			
		||||
				keeper.SetCollateralState(ctx, tc.priorState.CollateralState)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// call func under test
 | 
			
		||||
			err = keeper.ModifyCDP(ctx, tc.args.owner, tc.args.collateralDenom, tc.args.changeInCollateral, tc.args.changeInDebt)
 | 
			
		||||
			mapp.EndBlock(abci.RequestEndBlock{})
 | 
			
		||||
			mapp.Commit()
 | 
			
		||||
			err := keeper.ModifyCDP(ctx, tc.args.owner, tc.args.collateralDenom, tc.args.changeInCollateral, tc.args.changeInDebt)
 | 
			
		||||
 | 
			
		||||
			// get new state for verification
 | 
			
		||||
			actualCDP, found := keeper.GetCDP(ctx, tc.args.owner, tc.args.collateralDenom)
 | 
			
		||||
 | 
			
		||||
			// check for err
 | 
			
		||||
			if tc.expectPass {
 | 
			
		||||
				require.NoError(t, err, fmt.Sprint(err))
 | 
			
		||||
@ -167,47 +137,35 @@ func TestKeeper_ModifyCDP(t *testing.T) {
 | 
			
		||||
			require.Equal(t, tc.expectedState.GlobalDebt, actualGDebt)
 | 
			
		||||
			require.Equal(t, tc.expectedState.CollateralState, actualCstate)
 | 
			
		||||
			// check owner balance
 | 
			
		||||
			mock.CheckBalance(t, mapp, ownerAddr, tc.expectedState.OwnerCoins)
 | 
			
		||||
			tApp.CheckBalance(t, ctx, ownerAddr, tc.expectedState.OwnerCoins)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO change to table driven test to test more test cases
 | 
			
		||||
func TestKeeper_PartialSeizeCDP(t *testing.T) {
 | 
			
		||||
	// Setup
 | 
			
		||||
	const collateral = "xrp"
 | 
			
		||||
	mapp, keeper, _, _ := setUpMockAppWithoutGenesis()
 | 
			
		||||
	genAccs, addrs, _, _ := mock.CreateGenAccounts(1, cs(c(collateral, 100)))
 | 
			
		||||
	_, addrs := app.GeneratePrivKeyAddressPairs(1)
 | 
			
		||||
	testAddr := addrs[0]
 | 
			
		||||
	mock.SetGenesis(mapp, genAccs)
 | 
			
		||||
	// setup pricefeed
 | 
			
		||||
	header := abci.Header{Height: mapp.LastBlockHeight() + 1, Time: tmtime.Now()}
 | 
			
		||||
	mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
 | 
			
		||||
	ctx := mapp.BaseApp.NewContext(false, header)
 | 
			
		||||
	keeper.SetParams(ctx, defaultParamsSingle())
 | 
			
		||||
	ap := pricefeed.Params{
 | 
			
		||||
		Markets: []pricefeed.Market{
 | 
			
		||||
			pricefeed.Market{
 | 
			
		||||
				MarketID: "xrp", BaseAsset: "xrp",
 | 
			
		||||
				QuoteAsset: "usd", Oracles: pricefeed.Oracles{}, Active: true},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	keeper.pricefeedKeeper.SetParams(ctx, ap)
 | 
			
		||||
	keeper.pricefeedKeeper.SetPrice(
 | 
			
		||||
		ctx, sdk.AccAddress{}, collateral,
 | 
			
		||||
		sdk.MustNewDecFromStr("1.00"),
 | 
			
		||||
		header.Time.Add(time.Hour*1))
 | 
			
		||||
	keeper.pricefeedKeeper.SetCurrentPrices(ctx, collateral)
 | 
			
		||||
 | 
			
		||||
	tApp := app.NewTestApp()
 | 
			
		||||
	tApp.InitializeFromGenesisStates(
 | 
			
		||||
		app.NewAuthGenState(addrs, []sdk.Coins{cs(c(collateral, 100))}),
 | 
			
		||||
		NewPricefeedGenState(collateral, d("1.00")),
 | 
			
		||||
		NewCDPGenState(collateral, d("2.00")),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	ctx := tApp.NewContext(false, abci.Header{})
 | 
			
		||||
	keeper := tApp.GetCDPKeeper()
 | 
			
		||||
 | 
			
		||||
	// Create CDP
 | 
			
		||||
	keeper.SetGlobalDebt(ctx, i(0))
 | 
			
		||||
	err := keeper.ModifyCDP(ctx, testAddr, collateral, i(10), i(5))
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	// Reduce price
 | 
			
		||||
	keeper.pricefeedKeeper.SetPrice(
 | 
			
		||||
	tApp.GetPriceFeedKeeper().SetPrice(
 | 
			
		||||
		ctx, sdk.AccAddress{}, collateral,
 | 
			
		||||
		sdk.MustNewDecFromStr("0.90"),
 | 
			
		||||
		header.Time.Add(time.Hour*1))
 | 
			
		||||
	keeper.pricefeedKeeper.SetCurrentPrices(ctx, collateral)
 | 
			
		||||
		d("0.90"), time.Now().Add(1*time.Hour))
 | 
			
		||||
	tApp.GetPriceFeedKeeper().SetCurrentPrices(ctx, collateral)
 | 
			
		||||
 | 
			
		||||
	// Seize entire CDP
 | 
			
		||||
	err = keeper.PartialSeizeCDP(ctx, testAddr, collateral, i(10), i(5))
 | 
			
		||||
@ -222,15 +180,16 @@ func TestKeeper_PartialSeizeCDP(t *testing.T) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestKeeper_GetCDPs(t *testing.T) {
 | 
			
		||||
	// setup keeper
 | 
			
		||||
	mapp, keeper, _, _ := setUpMockAppWithoutGenesis()
 | 
			
		||||
	mock.SetGenesis(mapp, []authexported.Account(nil))
 | 
			
		||||
	header := abci.Header{Height: mapp.LastBlockHeight() + 1}
 | 
			
		||||
	mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
 | 
			
		||||
	ctx := mapp.BaseApp.NewContext(false, header)
 | 
			
		||||
	keeper.SetParams(ctx, defaultParamsMulti())
 | 
			
		||||
	// setup test app
 | 
			
		||||
	tApp := app.NewTestApp().InitializeFromGenesisStates(
 | 
			
		||||
		NewPricefeedGenStateMulti(), // collateral needs to be in pricefeed for cdp InitGenesis to validate
 | 
			
		||||
		NewCDPGenStateMulti(),
 | 
			
		||||
	)
 | 
			
		||||
	ctx := tApp.NewContext(true, abci.Header{})
 | 
			
		||||
	keeper := tApp.GetCDPKeeper()
 | 
			
		||||
 | 
			
		||||
	// setup CDPs
 | 
			
		||||
	_, addrs := mock.GeneratePrivKeyAddressPairs(2)
 | 
			
		||||
	_, addrs := app.GeneratePrivKeyAddressPairs(2)
 | 
			
		||||
	cdps := types.CDPs{
 | 
			
		||||
		{addrs[0], "xrp", i(4000), i(5)},
 | 
			
		||||
		{addrs[1], "xrp", i(4000), i(2000)},
 | 
			
		||||
@ -288,7 +247,7 @@ func TestKeeper_GetCDPs(t *testing.T) {
 | 
			
		||||
	_, err = keeper.GetCDPs(ctx, "", d("0.34023"))
 | 
			
		||||
	require.Error(t, err)
 | 
			
		||||
	// Check deleting a CDP removes it
 | 
			
		||||
	keeper.deleteCDP(ctx, cdps[0])
 | 
			
		||||
	keeper.DeleteCDP(ctx, cdps[0])
 | 
			
		||||
	returnedCdps, err = keeper.GetCDPs(ctx, "", sdk.Dec{})
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	require.Equal(t,
 | 
			
		||||
@ -298,14 +257,14 @@ func TestKeeper_GetCDPs(t *testing.T) {
 | 
			
		||||
		returnedCdps,
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestKeeper_GetSetDeleteCDP(t *testing.T) {
 | 
			
		||||
	// setup keeper, create CDP
 | 
			
		||||
	mapp, keeper, _, _ := setUpMockAppWithoutGenesis()
 | 
			
		||||
	header := abci.Header{Height: mapp.LastBlockHeight() + 1}
 | 
			
		||||
	mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
 | 
			
		||||
	ctx := mapp.BaseApp.NewContext(false, header)
 | 
			
		||||
	keeper.SetParams(ctx, defaultParamsSingle())
 | 
			
		||||
	_, addrs := mock.GeneratePrivKeyAddressPairs(1)
 | 
			
		||||
	tApp := app.NewTestApp()
 | 
			
		||||
	ctx := tApp.NewContext(true, abci.Header{})
 | 
			
		||||
	keeper := tApp.GetCDPKeeper()
 | 
			
		||||
 | 
			
		||||
	_, addrs := app.GeneratePrivKeyAddressPairs(1)
 | 
			
		||||
	cdp := types.CDP{addrs[0], "xrp", i(412), i(56)}
 | 
			
		||||
 | 
			
		||||
	// write and read from store
 | 
			
		||||
@ -317,7 +276,7 @@ func TestKeeper_GetSetDeleteCDP(t *testing.T) {
 | 
			
		||||
	require.Equal(t, cdp, readCDP)
 | 
			
		||||
 | 
			
		||||
	// delete auction
 | 
			
		||||
	keeper.deleteCDP(ctx, cdp)
 | 
			
		||||
	keeper.DeleteCDP(ctx, cdp)
 | 
			
		||||
 | 
			
		||||
	// check auction does not exist
 | 
			
		||||
	_, found = keeper.GetCDP(ctx, cdp.Owner, cdp.CollateralDenom)
 | 
			
		||||
@ -325,11 +284,10 @@ func TestKeeper_GetSetDeleteCDP(t *testing.T) {
 | 
			
		||||
}
 | 
			
		||||
func TestKeeper_GetSetGDebt(t *testing.T) {
 | 
			
		||||
	// setup keeper, create GDebt
 | 
			
		||||
	mapp, keeper, _, _ := setUpMockAppWithoutGenesis()
 | 
			
		||||
	header := abci.Header{Height: mapp.LastBlockHeight() + 1}
 | 
			
		||||
	mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
 | 
			
		||||
	ctx := mapp.BaseApp.NewContext(false, header)
 | 
			
		||||
	keeper.SetParams(ctx, defaultParamsSingle())
 | 
			
		||||
	tApp := app.NewTestApp()
 | 
			
		||||
	ctx := tApp.NewContext(true, abci.Header{})
 | 
			
		||||
	keeper := tApp.GetCDPKeeper()
 | 
			
		||||
 | 
			
		||||
	gDebt := i(4120000)
 | 
			
		||||
 | 
			
		||||
	// write and read from store
 | 
			
		||||
@ -342,15 +300,14 @@ func TestKeeper_GetSetGDebt(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
func TestKeeper_GetSetCollateralState(t *testing.T) {
 | 
			
		||||
	// setup keeper, create CState
 | 
			
		||||
	mapp, keeper, _, _ := setUpMockAppWithoutGenesis()
 | 
			
		||||
	header := abci.Header{Height: mapp.LastBlockHeight() + 1}
 | 
			
		||||
	mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
 | 
			
		||||
	ctx := mapp.BaseApp.NewContext(false, header)
 | 
			
		||||
	keeper.SetParams(ctx, defaultParamsSingle())
 | 
			
		||||
	tApp := app.NewTestApp()
 | 
			
		||||
	ctx := tApp.NewContext(true, abci.Header{})
 | 
			
		||||
	keeper := tApp.GetCDPKeeper()
 | 
			
		||||
 | 
			
		||||
	collateralState := types.CollateralState{"xrp", i(15400)}
 | 
			
		||||
 | 
			
		||||
	// write and read from store
 | 
			
		||||
	keeper.setCollateralState(ctx, collateralState)
 | 
			
		||||
	keeper.SetCollateralState(ctx, collateralState)
 | 
			
		||||
	readCState, found := keeper.GetCollateralState(ctx, collateralState.Denom)
 | 
			
		||||
 | 
			
		||||
	// check before and after match
 | 
			
		||||
 | 
			
		||||
@ -1,88 +0,0 @@
 | 
			
		||||
package keeper
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/bank"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/mock"
 | 
			
		||||
 | 
			
		||||
	"github.com/kava-labs/kava/x/cdp/types"
 | 
			
		||||
	"github.com/kava-labs/kava/x/pricefeed"
 | 
			
		||||
	"github.com/tendermint/tendermint/crypto"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Mock app is an ABCI app with an in memory database.
 | 
			
		||||
// This function creates an app, setting up the keepers, routes, begin and end blockers.
 | 
			
		||||
// But leaves it to the tests to call InitChain (done by calling mock.SetGenesis)
 | 
			
		||||
// The app works by submitting ABCI messages.
 | 
			
		||||
//  - InitChain sets up the app db from genesis.
 | 
			
		||||
//  - BeginBlock starts the delivery of a new block
 | 
			
		||||
//  - DeliverTx delivers a tx
 | 
			
		||||
//  - EndBlock signals the end of a block
 | 
			
		||||
//  - Commit ?
 | 
			
		||||
func setUpMockAppWithoutGenesis() (*mock.App, Keeper, []sdk.AccAddress, []crypto.PrivKey) {
 | 
			
		||||
	// Create uninitialized mock app
 | 
			
		||||
	mapp := mock.NewApp()
 | 
			
		||||
 | 
			
		||||
	// Register codecs
 | 
			
		||||
	types.RegisterCodec(mapp.Cdc)
 | 
			
		||||
 | 
			
		||||
	// Create keepers
 | 
			
		||||
	keyCDP := sdk.NewKVStoreKey("cdp")
 | 
			
		||||
	keyPriceFeed := sdk.NewKVStoreKey(pricefeed.StoreKey)
 | 
			
		||||
	pk := mapp.ParamsKeeper
 | 
			
		||||
	priceFeedKeeper := pricefeed.NewKeeper(keyPriceFeed, mapp.Cdc, pk.Subspace(pricefeed.DefaultParamspace), pricefeed.DefaultCodespace)
 | 
			
		||||
	blacklistedAddrs := make(map[string]bool)
 | 
			
		||||
	bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, blacklistedAddrs)
 | 
			
		||||
	cdpKeeper := NewKeeper(mapp.Cdc, keyCDP, pk.Subspace(types.DefaultParamspace), priceFeedKeeper, bankKeeper)
 | 
			
		||||
 | 
			
		||||
	// Mount and load the stores
 | 
			
		||||
	err := mapp.CompleteSetup(keyPriceFeed, keyCDP)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic("mock app setup failed")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Create a bunch (ie 10) of pre-funded accounts to use for tests
 | 
			
		||||
	genAccs, addrs, _, privKeys := mock.CreateGenAccounts(10, sdk.NewCoins(sdk.NewInt64Coin("token1", 100), sdk.NewInt64Coin("token2", 100)))
 | 
			
		||||
	mock.SetGenesis(mapp, genAccs)
 | 
			
		||||
 | 
			
		||||
	return mapp, cdpKeeper, addrs, privKeys
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Avoid cluttering test cases with long function name
 | 
			
		||||
func i(in int64) sdk.Int                    { return sdk.NewInt(in) }
 | 
			
		||||
func d(str string) sdk.Dec                  { return sdk.MustNewDecFromStr(str) }
 | 
			
		||||
func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) }
 | 
			
		||||
func cs(coins ...sdk.Coin) sdk.Coins        { return sdk.NewCoins(coins...) }
 | 
			
		||||
 | 
			
		||||
func defaultParamsMulti() types.CdpParams {
 | 
			
		||||
	return types.CdpParams{
 | 
			
		||||
		GlobalDebtLimit: sdk.NewInt(1000000),
 | 
			
		||||
		CollateralParams: []types.CollateralParams{
 | 
			
		||||
			{
 | 
			
		||||
				Denom:            "btc",
 | 
			
		||||
				LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
 | 
			
		||||
				DebtLimit:        sdk.NewInt(500000),
 | 
			
		||||
			},
 | 
			
		||||
			{
 | 
			
		||||
				Denom:            "xrp",
 | 
			
		||||
				LiquidationRatio: sdk.MustNewDecFromStr("2.0"),
 | 
			
		||||
				DebtLimit:        sdk.NewInt(500000),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		StableDenoms: []string{"usdx"},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func defaultParamsSingle() types.CdpParams {
 | 
			
		||||
	return types.CdpParams{
 | 
			
		||||
		GlobalDebtLimit: sdk.NewInt(1000000),
 | 
			
		||||
		CollateralParams: []types.CollateralParams{
 | 
			
		||||
			{
 | 
			
		||||
				Denom:            "xrp",
 | 
			
		||||
				LiquidationRatio: sdk.MustNewDecFromStr("2.0"),
 | 
			
		||||
				DebtLimit:        sdk.NewInt(500000),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		StableDenoms: []string{"usdx"},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -1,52 +0,0 @@
 | 
			
		||||
package cdp
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/bank"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/mock"
 | 
			
		||||
 | 
			
		||||
	"github.com/kava-labs/kava/x/pricefeed"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Mock app is an ABCI app with an in memory database.
 | 
			
		||||
// This function creates an app, setting up the keepers, routes, begin and end blockers.
 | 
			
		||||
// But leaves it to the tests to call InitChain (done by calling mock.SetGenesis)
 | 
			
		||||
// The app works by submitting ABCI messages.
 | 
			
		||||
//  - InitChain sets up the app db from genesis.
 | 
			
		||||
//  - BeginBlock starts the delivery of a new block
 | 
			
		||||
//  - DeliverTx delivers a tx
 | 
			
		||||
//  - EndBlock signals the end of a block
 | 
			
		||||
//  - Commit ?
 | 
			
		||||
func setUpMockAppWithoutGenesis() (*mock.App, Keeper, PricefeedKeeper) {
 | 
			
		||||
	// Create uninitialized mock app
 | 
			
		||||
	mapp := mock.NewApp()
 | 
			
		||||
 | 
			
		||||
	// Register codecs
 | 
			
		||||
	RegisterCodec(mapp.Cdc)
 | 
			
		||||
 | 
			
		||||
	// Create keepers
 | 
			
		||||
	keyCDP := sdk.NewKVStoreKey("cdp")
 | 
			
		||||
	keyPriceFeed := sdk.NewKVStoreKey(pricefeed.StoreKey)
 | 
			
		||||
	pk := mapp.ParamsKeeper
 | 
			
		||||
	priceFeedKeeper := pricefeed.NewKeeper(keyPriceFeed, mapp.Cdc, pk.Subspace(pricefeed.DefaultParamspace), pricefeed.DefaultCodespace)
 | 
			
		||||
	blacklistedAddrs := make(map[string]bool)
 | 
			
		||||
	bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, blacklistedAddrs)
 | 
			
		||||
	cdpKeeper := NewKeeper(mapp.Cdc, keyCDP, pk.Subspace(DefaultParamspace), priceFeedKeeper, bankKeeper)
 | 
			
		||||
 | 
			
		||||
	// Register routes
 | 
			
		||||
	mapp.Router().AddRoute("cdp", NewHandler(cdpKeeper))
 | 
			
		||||
 | 
			
		||||
	// Mount and load the stores
 | 
			
		||||
	err := mapp.CompleteSetup(keyPriceFeed, keyCDP)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic("mock app setup failed")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return mapp, cdpKeeper, priceFeedKeeper
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Avoid cluttering test cases with long function name
 | 
			
		||||
func i(in int64) sdk.Int                    { return sdk.NewInt(in) }
 | 
			
		||||
func d(str string) sdk.Dec                  { return sdk.MustNewDecFromStr(str) }
 | 
			
		||||
func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) }
 | 
			
		||||
func cs(coins ...sdk.Coin) sdk.Coins        { return sdk.NewCoins(coins...) }
 | 
			
		||||
							
								
								
									
										72
									
								
								x/liquidator/keeper/integration_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								x/liquidator/keeper/integration_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,72 @@
 | 
			
		||||
package keeper_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
 | 
			
		||||
	"github.com/kava-labs/kava/app"
 | 
			
		||||
	"github.com/kava-labs/kava/x/cdp"
 | 
			
		||||
	"github.com/kava-labs/kava/x/liquidator"
 | 
			
		||||
	"github.com/kava-labs/kava/x/liquidator/types"
 | 
			
		||||
	"github.com/kava-labs/kava/x/pricefeed"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Avoid cluttering test cases with long function name
 | 
			
		||||
func i(in int64) sdk.Int                    { return sdk.NewInt(in) }
 | 
			
		||||
func d(str string) sdk.Dec                  { return sdk.MustNewDecFromStr(str) }
 | 
			
		||||
func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) }
 | 
			
		||||
func cs(coins ...sdk.Coin) sdk.Coins        { return sdk.NewCoins(coins...) }
 | 
			
		||||
 | 
			
		||||
// Genesis states to initialize test apps
 | 
			
		||||
 | 
			
		||||
func NewPricefeedGenState(asset string, price sdk.Dec) app.GenesisState {
 | 
			
		||||
	pfGenesis := pricefeed.GenesisState{
 | 
			
		||||
		Params: pricefeed.Params{
 | 
			
		||||
			Markets: []pricefeed.Market{
 | 
			
		||||
				pricefeed.Market{MarketID: asset, BaseAsset: asset, QuoteAsset: "usd", Oracles: pricefeed.Oracles{}, Active: true}},
 | 
			
		||||
		},
 | 
			
		||||
		PostedPrices: []pricefeed.PostedPrice{
 | 
			
		||||
			pricefeed.PostedPrice{
 | 
			
		||||
				MarketID:      asset,
 | 
			
		||||
				OracleAddress: sdk.AccAddress{},
 | 
			
		||||
				Price:         price,
 | 
			
		||||
				Expiry:        time.Now().Add(1 * time.Hour),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	return app.GenesisState{pricefeed.ModuleName: pricefeed.ModuleCdc.MustMarshalJSON(pfGenesis)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewCDPGenState() app.GenesisState {
 | 
			
		||||
	cdpGenesis := cdp.GenesisState{
 | 
			
		||||
		Params: cdp.CdpParams{
 | 
			
		||||
			GlobalDebtLimit: sdk.NewInt(1000000),
 | 
			
		||||
			CollateralParams: []cdp.CollateralParams{
 | 
			
		||||
				{
 | 
			
		||||
					Denom:            "btc",
 | 
			
		||||
					LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
 | 
			
		||||
					DebtLimit:        sdk.NewInt(500000),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		GlobalDebt: sdk.ZeroInt(),
 | 
			
		||||
		CDPs:       cdp.CDPs{},
 | 
			
		||||
	}
 | 
			
		||||
	return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewLiquidatorGenState() app.GenesisState {
 | 
			
		||||
	liquidatorGenesis := types.GenesisState{
 | 
			
		||||
		Params: types.LiquidatorParams{
 | 
			
		||||
			DebtAuctionSize: sdk.NewInt(1000),
 | 
			
		||||
			CollateralParams: []types.CollateralParams{
 | 
			
		||||
				{
 | 
			
		||||
					Denom:       "btc",
 | 
			
		||||
					AuctionSize: sdk.NewInt(1),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	return app.GenesisState{liquidator.ModuleName: liquidator.ModuleCdc.MustMarshalJSON(liquidatorGenesis)}
 | 
			
		||||
}
 | 
			
		||||
@ -55,7 +55,7 @@ func (k Keeper) SeizeAndStartCollateralAuction(ctx sdk.Context, owner sdk.AccAdd
 | 
			
		||||
	stableToRaise := sdk.NewDecFromInt(collateralToSell).Quo(sdk.NewDecFromInt(cdp.CollateralAmount)).Mul(sdk.NewDecFromInt(cdp.Debt)).RoundInt()
 | 
			
		||||
 | 
			
		||||
	// Seize the collateral and debt from the CDP
 | 
			
		||||
	err := k.partialSeizeCDP(ctx, owner, collateralDenom, collateralToSell, stableToRaise)
 | 
			
		||||
	err := k.PartialSeizeCDP(ctx, owner, collateralDenom, collateralToSell, stableToRaise)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
@ -99,7 +99,7 @@ func (k Keeper) StartDebtAuction(ctx sdk.Context) (auction.ID, sdk.Error) {
 | 
			
		||||
	}
 | 
			
		||||
	// Record amount of debt sent for auction. Debt can only be reduced in lock step with reducing stable coin
 | 
			
		||||
	seizedDebt.SentToAuction = seizedDebt.SentToAuction.Add(params.DebtAuctionSize)
 | 
			
		||||
	k.setSeizedDebt(ctx, seizedDebt)
 | 
			
		||||
	k.SetSeizedDebt(ctx, seizedDebt)
 | 
			
		||||
	return auctionID, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -131,7 +131,7 @@ func (k Keeper) StartDebtAuction(ctx sdk.Context) (auction.ID, sdk.Error) {
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// PartialSeizeCDP seizes some collateral and debt from an under-collateralized CDP.
 | 
			
		||||
func (k Keeper) partialSeizeCDP(ctx sdk.Context, owner sdk.AccAddress, collateralDenom string, collateralToSeize sdk.Int, debtToSeize sdk.Int) sdk.Error { // aka Cat.bite
 | 
			
		||||
func (k Keeper) PartialSeizeCDP(ctx sdk.Context, owner sdk.AccAddress, collateralDenom string, collateralToSeize sdk.Int, debtToSeize sdk.Int) sdk.Error { // aka Cat.bite
 | 
			
		||||
	// Seize debt and collateral in the cdp module. This also validates the inputs.
 | 
			
		||||
	err := k.cdpKeeper.PartialSeizeCDP(ctx, owner, collateralDenom, collateralToSeize, debtToSeize)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@ -141,7 +141,7 @@ func (k Keeper) partialSeizeCDP(ctx sdk.Context, owner sdk.AccAddress, collatera
 | 
			
		||||
	// increment the total seized debt (Awe) by cdp.debt
 | 
			
		||||
	seizedDebt := k.GetSeizedDebt(ctx)
 | 
			
		||||
	seizedDebt.Total = seizedDebt.Total.Add(debtToSeize)
 | 
			
		||||
	k.setSeizedDebt(ctx, seizedDebt)
 | 
			
		||||
	k.SetSeizedDebt(ctx, seizedDebt)
 | 
			
		||||
 | 
			
		||||
	// add cdp.collateral amount of coins to the moduleAccount (so they can be transferred to the auction later)
 | 
			
		||||
	coins := sdk.NewCoins(sdk.NewCoin(collateralDenom, collateralToSeize))
 | 
			
		||||
@ -172,7 +172,7 @@ func (k Keeper) SettleDebt(ctx sdk.Context) sdk.Error {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err // this should not error in this context
 | 
			
		||||
	}
 | 
			
		||||
	k.setSeizedDebt(ctx, updatedDebt)
 | 
			
		||||
	k.SetSeizedDebt(ctx, updatedDebt)
 | 
			
		||||
 | 
			
		||||
	// Subtract stable coin from moduleAccout
 | 
			
		||||
	k.bankKeeper.SubtractCoins(ctx, k.cdpKeeper.GetLiquidatorAccountAddress(), sdk.Coins{sdk.NewCoin(k.cdpKeeper.GetStableDenom(), settleAmount)})
 | 
			
		||||
@ -197,7 +197,7 @@ func (k Keeper) GetSeizedDebt(ctx sdk.Context) types.SeizedDebt {
 | 
			
		||||
	k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &seizedDebt)
 | 
			
		||||
	return seizedDebt
 | 
			
		||||
}
 | 
			
		||||
func (k Keeper) setSeizedDebt(ctx sdk.Context, debt types.SeizedDebt) {
 | 
			
		||||
func (k Keeper) SetSeizedDebt(ctx sdk.Context, debt types.SeizedDebt) {
 | 
			
		||||
	store := ctx.KVStore(k.key)
 | 
			
		||||
	bz := k.cdc.MustMarshalBinaryLengthPrefixed(debt)
 | 
			
		||||
	store.Set(k.getSeizedDebtKey(), bz)
 | 
			
		||||
 | 
			
		||||
@ -1,124 +1,103 @@
 | 
			
		||||
package keeper
 | 
			
		||||
package keeper_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/mock"
 | 
			
		||||
	"github.com/stretchr/testify/require"
 | 
			
		||||
	abci "github.com/tendermint/tendermint/abci/types"
 | 
			
		||||
	tmtime "github.com/tendermint/tendermint/types/time"
 | 
			
		||||
 | 
			
		||||
	"github.com/kava-labs/kava/x/cdp"
 | 
			
		||||
	"github.com/kava-labs/kava/app"
 | 
			
		||||
	"github.com/kava-labs/kava/x/liquidator/types"
 | 
			
		||||
	"github.com/kava-labs/kava/x/pricefeed"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestKeeper_SeizeAndStartCollateralAuction(t *testing.T) {
 | 
			
		||||
	// Setup
 | 
			
		||||
	ctx, k := setupTestKeepers()
 | 
			
		||||
	_, addrs := app.GeneratePrivKeyAddressPairs(1)
 | 
			
		||||
 | 
			
		||||
	_, addrs := mock.GeneratePrivKeyAddressPairs(1)
 | 
			
		||||
	tApp := app.NewTestApp()
 | 
			
		||||
	tApp.InitializeFromGenesisStates(
 | 
			
		||||
		app.NewAuthGenState(addrs, []sdk.Coins{cs(c("btc", 100))}),
 | 
			
		||||
		NewPricefeedGenState("btc", d("8000.00")),
 | 
			
		||||
		NewCDPGenState(),
 | 
			
		||||
		NewLiquidatorGenState(),
 | 
			
		||||
	)
 | 
			
		||||
	ctx := tApp.NewContext(false, abci.Header{})
 | 
			
		||||
 | 
			
		||||
	pricefeed.InitGenesis(ctx, k.pricefeedKeeper, pricefeedGenesis())
 | 
			
		||||
	k.pricefeedKeeper.SetPrice(ctx, addrs[0], "btc", sdk.MustNewDecFromStr("8000.00"), tmtime.Now().Add(time.Hour*1))
 | 
			
		||||
	k.pricefeedKeeper.SetCurrentPrices(ctx, "btc")
 | 
			
		||||
	cdp.InitGenesis(ctx, k.cdpKeeper, k.pricefeedKeeper, cdpDefaultGenesis())
 | 
			
		||||
	dp := defaultParams()
 | 
			
		||||
	k.liquidatorKeeper.SetParams(ctx, dp)
 | 
			
		||||
	k.bankKeeper.AddCoins(ctx, addrs[0], cs(c("btc", 100)))
 | 
			
		||||
	require.NoError(t, tApp.GetCDPKeeper().ModifyCDP(ctx, addrs[0], "btc", i(3), i(16000)))
 | 
			
		||||
 | 
			
		||||
	k.cdpKeeper.ModifyCDP(ctx, addrs[0], "btc", i(3), i(16000))
 | 
			
		||||
 | 
			
		||||
	k.pricefeedKeeper.SetPrice(ctx, addrs[0], "btc", sdk.MustNewDecFromStr("7999.99"), tmtime.Now().Add(time.Hour*1))
 | 
			
		||||
	k.pricefeedKeeper.SetCurrentPrices(ctx, "btc")
 | 
			
		||||
	_, err := tApp.GetPriceFeedKeeper().SetPrice(ctx, addrs[0], "btc", d("7999.99"), time.Now().Add(1*time.Hour))
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	require.NoError(t, tApp.GetPriceFeedKeeper().SetCurrentPrices(ctx, "btc"))
 | 
			
		||||
 | 
			
		||||
	// Run test function
 | 
			
		||||
	auctionID, err := k.liquidatorKeeper.SeizeAndStartCollateralAuction(ctx, addrs[0], "btc")
 | 
			
		||||
	auctionID, err := tApp.GetLiquidatorKeeper().SeizeAndStartCollateralAuction(ctx, addrs[0], "btc")
 | 
			
		||||
 | 
			
		||||
	// Check CDP
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	cdp, found := k.cdpKeeper.GetCDP(ctx, addrs[0], "btc")
 | 
			
		||||
	cdp, found := tApp.GetCDPKeeper().GetCDP(ctx, addrs[0], "btc")
 | 
			
		||||
	require.True(t, found)
 | 
			
		||||
	require.Equal(t, cdp.CollateralAmount, i(2)) // original amount - params.CollateralAuctionSize
 | 
			
		||||
	require.Equal(t, cdp.Debt, i(10667))         // original debt scaled by amount of collateral removed
 | 
			
		||||
	// Check auction exists
 | 
			
		||||
	_, found = k.auctionKeeper.GetAuction(ctx, auctionID)
 | 
			
		||||
	_, found = tApp.GetAuctionKeeper().GetAuction(ctx, auctionID)
 | 
			
		||||
	require.True(t, found)
 | 
			
		||||
	// TODO check auction values are correct?
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestKeeper_StartDebtAuction(t *testing.T) {
 | 
			
		||||
	// Setup
 | 
			
		||||
	ctx, k := setupTestKeepers()
 | 
			
		||||
	k.liquidatorKeeper.SetParams(ctx, defaultParams())
 | 
			
		||||
	tApp := app.NewTestApp()
 | 
			
		||||
	tApp.InitializeFromGenesisStates(
 | 
			
		||||
		NewLiquidatorGenState(),
 | 
			
		||||
	)
 | 
			
		||||
	keeper := tApp.GetLiquidatorKeeper()
 | 
			
		||||
	ctx := tApp.NewContext(false, abci.Header{})
 | 
			
		||||
 | 
			
		||||
	initSDebt := types.SeizedDebt{i(2000), i(0)}
 | 
			
		||||
	k.liquidatorKeeper.setSeizedDebt(ctx, initSDebt)
 | 
			
		||||
	keeper.SetSeizedDebt(ctx, initSDebt)
 | 
			
		||||
 | 
			
		||||
	// Execute
 | 
			
		||||
	auctionID, err := k.liquidatorKeeper.StartDebtAuction(ctx)
 | 
			
		||||
	auctionID, err := keeper.StartDebtAuction(ctx)
 | 
			
		||||
 | 
			
		||||
	// Check
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	require.Equal(t,
 | 
			
		||||
		types.SeizedDebt{
 | 
			
		||||
			initSDebt.Total,
 | 
			
		||||
			initSDebt.SentToAuction.Add(k.liquidatorKeeper.GetParams(ctx).DebtAuctionSize),
 | 
			
		||||
			initSDebt.SentToAuction.Add(keeper.GetParams(ctx).DebtAuctionSize),
 | 
			
		||||
		},
 | 
			
		||||
		k.liquidatorKeeper.GetSeizedDebt(ctx),
 | 
			
		||||
		keeper.GetSeizedDebt(ctx),
 | 
			
		||||
	)
 | 
			
		||||
	_, found := k.auctionKeeper.GetAuction(ctx, auctionID)
 | 
			
		||||
	_, found := tApp.GetAuctionKeeper().GetAuction(ctx, auctionID)
 | 
			
		||||
	require.True(t, found)
 | 
			
		||||
	// TODO check auction values are correct?
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// func TestKeeper_StartSurplusAuction(t *testing.T) {
 | 
			
		||||
// 	// Setup
 | 
			
		||||
// 	ctx, k := setupTestKeepers()
 | 
			
		||||
// 	initSurplus := i(2000)
 | 
			
		||||
// 	k.liquidatorKeeper.bankKeeper.AddCoins(ctx, k.cdpKeeper.GetLiquidatorAccountAddress(), cs(sdk.NewCoin(k.cdpKeeper.GetStableDenom(), initSurplus)))
 | 
			
		||||
// 	k.liquidatorKeeper.setSeizedDebt(ctx, i(0))
 | 
			
		||||
 | 
			
		||||
// 	// Execute
 | 
			
		||||
// 	auctionID, err := k.liquidatorKeeper.StartSurplusAuction(ctx)
 | 
			
		||||
 | 
			
		||||
// 	// Check
 | 
			
		||||
// 	require.NoError(t, err)
 | 
			
		||||
// 	require.Equal(t,
 | 
			
		||||
// 		initSurplus.Sub(SurplusAuctionSize),
 | 
			
		||||
// 		k.liquidatorKeeper.bankKeeper.GetCoins(ctx,
 | 
			
		||||
// 			k.cdpKeeper.GetLiquidatorAccountAddress(),
 | 
			
		||||
// 		).AmountOf(k.cdpKeeper.GetStableDenom()),
 | 
			
		||||
// 	)
 | 
			
		||||
// 	_, found := k.auctionKeeper.GetAuction(ctx, auctionID)
 | 
			
		||||
// 	require.True(t, found)
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
func TestKeeper_partialSeizeCDP(t *testing.T) {
 | 
			
		||||
	// Setup
 | 
			
		||||
	ctx, k := setupTestKeepers()
 | 
			
		||||
	_, addrs := app.GeneratePrivKeyAddressPairs(1)
 | 
			
		||||
 | 
			
		||||
	_, addrs := mock.GeneratePrivKeyAddressPairs(1)
 | 
			
		||||
	tApp := app.NewTestApp()
 | 
			
		||||
	tApp.InitializeFromGenesisStates(
 | 
			
		||||
		app.NewAuthGenState(addrs, []sdk.Coins{cs(c("btc", 100))}),
 | 
			
		||||
		NewPricefeedGenState("btc", d("8000.00")),
 | 
			
		||||
		NewCDPGenState(),
 | 
			
		||||
		NewLiquidatorGenState(),
 | 
			
		||||
	)
 | 
			
		||||
	ctx := tApp.NewContext(false, abci.Header{})
 | 
			
		||||
 | 
			
		||||
	pricefeed.InitGenesis(ctx, k.pricefeedKeeper, pricefeedGenesis())
 | 
			
		||||
	tApp.GetCDPKeeper().ModifyCDP(ctx, addrs[0], "btc", i(3), i(16000))
 | 
			
		||||
 | 
			
		||||
	k.pricefeedKeeper.SetPrice(ctx, addrs[0], "btc", sdk.MustNewDecFromStr("8000.00"), tmtime.Now().Add(time.Hour*1))
 | 
			
		||||
	k.pricefeedKeeper.SetCurrentPrices(ctx, "btc")
 | 
			
		||||
	k.bankKeeper.AddCoins(ctx, addrs[0], cs(c("btc", 100)))
 | 
			
		||||
	cdp.InitGenesis(ctx, k.cdpKeeper, k.pricefeedKeeper, cdpDefaultGenesis())
 | 
			
		||||
	k.liquidatorKeeper.SetParams(ctx, defaultParams())
 | 
			
		||||
 | 
			
		||||
	k.cdpKeeper.ModifyCDP(ctx, addrs[0], "btc", i(3), i(16000))
 | 
			
		||||
 | 
			
		||||
	k.pricefeedKeeper.SetPrice(ctx, addrs[0], "btc", sdk.MustNewDecFromStr("7999.99"), tmtime.Now().Add(time.Hour*1))
 | 
			
		||||
	k.pricefeedKeeper.SetCurrentPrices(ctx, "btc")
 | 
			
		||||
	tApp.GetPriceFeedKeeper().SetPrice(ctx, addrs[0], "btc", d("7999.99"), tmtime.Now().Add(time.Hour*1))
 | 
			
		||||
	tApp.GetPriceFeedKeeper().SetCurrentPrices(ctx, "btc")
 | 
			
		||||
 | 
			
		||||
	// Run test function
 | 
			
		||||
	err := k.liquidatorKeeper.partialSeizeCDP(ctx, addrs[0], "btc", i(2), i(10000))
 | 
			
		||||
	err := tApp.GetLiquidatorKeeper().PartialSeizeCDP(ctx, addrs[0], "btc", i(2), i(10000))
 | 
			
		||||
 | 
			
		||||
	// Check
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	cdp, found := k.cdpKeeper.GetCDP(ctx, addrs[0], "btc")
 | 
			
		||||
	cdp, found := tApp.GetCDPKeeper().GetCDP(ctx, addrs[0], "btc")
 | 
			
		||||
	require.True(t, found)
 | 
			
		||||
	require.Equal(t, i(1), cdp.CollateralAmount)
 | 
			
		||||
	require.Equal(t, i(6000), cdp.Debt)
 | 
			
		||||
@ -126,12 +105,13 @@ func TestKeeper_partialSeizeCDP(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
func TestKeeper_GetSetSeizedDebt(t *testing.T) {
 | 
			
		||||
	// Setup
 | 
			
		||||
	ctx, k := setupTestKeepers()
 | 
			
		||||
	tApp := app.NewTestApp()
 | 
			
		||||
	ctx := tApp.NewContext(true, abci.Header{})
 | 
			
		||||
	debt := types.SeizedDebt{i(234247645), i(2343)}
 | 
			
		||||
 | 
			
		||||
	// Run test function
 | 
			
		||||
	k.liquidatorKeeper.setSeizedDebt(ctx, debt)
 | 
			
		||||
	readDebt := k.liquidatorKeeper.GetSeizedDebt(ctx)
 | 
			
		||||
	tApp.GetLiquidatorKeeper().SetSeizedDebt(ctx, debt)
 | 
			
		||||
	readDebt := tApp.GetLiquidatorKeeper().GetSeizedDebt(ctx)
 | 
			
		||||
 | 
			
		||||
	// Check
 | 
			
		||||
	require.Equal(t, debt, readDebt)
 | 
			
		||||
 | 
			
		||||
@ -1,171 +0,0 @@
 | 
			
		||||
package keeper
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/codec"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/store"
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/auth"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/bank"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/params"
 | 
			
		||||
	abci "github.com/tendermint/tendermint/abci/types"
 | 
			
		||||
	"github.com/tendermint/tendermint/libs/log"
 | 
			
		||||
	tmtime "github.com/tendermint/tendermint/types/time"
 | 
			
		||||
	dbm "github.com/tendermint/tm-db"
 | 
			
		||||
 | 
			
		||||
	"github.com/kava-labs/kava/x/auction"
 | 
			
		||||
	"github.com/kava-labs/kava/x/cdp"
 | 
			
		||||
	"github.com/kava-labs/kava/x/liquidator/types"
 | 
			
		||||
	"github.com/kava-labs/kava/x/pricefeed"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Avoid cluttering test cases with long function name
 | 
			
		||||
func i(in int64) sdk.Int                    { return sdk.NewInt(in) }
 | 
			
		||||
func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) }
 | 
			
		||||
func cs(coins ...sdk.Coin) sdk.Coins        { return sdk.NewCoins(coins...) }
 | 
			
		||||
 | 
			
		||||
type keepers struct {
 | 
			
		||||
	paramsKeeper     params.Keeper
 | 
			
		||||
	accountKeeper    auth.AccountKeeper
 | 
			
		||||
	bankKeeper       bank.Keeper
 | 
			
		||||
	pricefeedKeeper  pricefeed.Keeper
 | 
			
		||||
	auctionKeeper    auction.Keeper
 | 
			
		||||
	cdpKeeper        cdp.Keeper
 | 
			
		||||
	liquidatorKeeper Keeper
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func setupTestKeepers() (sdk.Context, keepers) {
 | 
			
		||||
 | 
			
		||||
	// Setup in memory database
 | 
			
		||||
	keyParams := sdk.NewKVStoreKey(params.StoreKey)
 | 
			
		||||
	tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey)
 | 
			
		||||
	keyAcc := sdk.NewKVStoreKey(auth.StoreKey)
 | 
			
		||||
	keyPriceFeed := sdk.NewKVStoreKey(pricefeed.StoreKey)
 | 
			
		||||
	keyCDP := sdk.NewKVStoreKey("cdp")
 | 
			
		||||
	keyAuction := sdk.NewKVStoreKey("auction")
 | 
			
		||||
	keyLiquidator := sdk.NewKVStoreKey("liquidator")
 | 
			
		||||
 | 
			
		||||
	db := dbm.NewMemDB()
 | 
			
		||||
	ms := store.NewCommitMultiStore(db)
 | 
			
		||||
	ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db)
 | 
			
		||||
	ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db)
 | 
			
		||||
	ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db)
 | 
			
		||||
	ms.MountStoreWithDB(keyPriceFeed, sdk.StoreTypeIAVL, db)
 | 
			
		||||
	ms.MountStoreWithDB(keyCDP, sdk.StoreTypeIAVL, db)
 | 
			
		||||
	ms.MountStoreWithDB(keyAuction, sdk.StoreTypeIAVL, db)
 | 
			
		||||
	ms.MountStoreWithDB(keyLiquidator, sdk.StoreTypeIAVL, db)
 | 
			
		||||
	err := ms.LoadLatestVersion()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Create Codec
 | 
			
		||||
	cdc := makeTestCodec()
 | 
			
		||||
 | 
			
		||||
	// Create Keepers
 | 
			
		||||
	paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams, params.DefaultCodespace)
 | 
			
		||||
	accountKeeper := auth.NewAccountKeeper(
 | 
			
		||||
		cdc,
 | 
			
		||||
		keyAcc,
 | 
			
		||||
		paramsKeeper.Subspace(auth.DefaultParamspace),
 | 
			
		||||
		auth.ProtoBaseAccount,
 | 
			
		||||
	)
 | 
			
		||||
	blacklistedAddrs := make(map[string]bool)
 | 
			
		||||
	bankKeeper := bank.NewBaseKeeper(
 | 
			
		||||
		accountKeeper,
 | 
			
		||||
		paramsKeeper.Subspace(bank.DefaultParamspace),
 | 
			
		||||
		bank.DefaultCodespace,
 | 
			
		||||
		blacklistedAddrs,
 | 
			
		||||
	)
 | 
			
		||||
	pricefeedKeeper := pricefeed.NewKeeper(keyPriceFeed, cdc, paramsKeeper.Subspace(pricefeed.DefaultParamspace), pricefeed.DefaultCodespace)
 | 
			
		||||
	cdpKeeper := cdp.NewKeeper(
 | 
			
		||||
		cdc,
 | 
			
		||||
		keyCDP,
 | 
			
		||||
		paramsKeeper.Subspace(cdp.DefaultParamspace),
 | 
			
		||||
		pricefeedKeeper,
 | 
			
		||||
		bankKeeper,
 | 
			
		||||
	)
 | 
			
		||||
	auctionKeeper := auction.NewKeeper(cdc, cdpKeeper, keyAuction, paramsKeeper.Subspace(auction.DefaultParamspace)) // Note: cdp keeper stands in for bank keeper
 | 
			
		||||
	liquidatorKeeper := NewKeeper(
 | 
			
		||||
		cdc,
 | 
			
		||||
		keyLiquidator,
 | 
			
		||||
		paramsKeeper.Subspace(types.DefaultParamspace),
 | 
			
		||||
		cdpKeeper,
 | 
			
		||||
		auctionKeeper,
 | 
			
		||||
		cdpKeeper,
 | 
			
		||||
	) // Note: cdp keeper stands in for bank keeper
 | 
			
		||||
 | 
			
		||||
	// Create context
 | 
			
		||||
	ctx := sdk.NewContext(ms, abci.Header{ChainID: "testchain"}, false, log.NewNopLogger())
 | 
			
		||||
 | 
			
		||||
	return ctx, keepers{
 | 
			
		||||
		paramsKeeper,
 | 
			
		||||
		accountKeeper,
 | 
			
		||||
		bankKeeper,
 | 
			
		||||
		pricefeedKeeper,
 | 
			
		||||
		auctionKeeper,
 | 
			
		||||
		cdpKeeper,
 | 
			
		||||
		liquidatorKeeper,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func makeTestCodec() *codec.Codec {
 | 
			
		||||
	var cdc = codec.New()
 | 
			
		||||
	auth.RegisterCodec(cdc)
 | 
			
		||||
	bank.RegisterCodec(cdc)
 | 
			
		||||
	pricefeed.RegisterCodec(cdc)
 | 
			
		||||
	auction.RegisterCodec(cdc)
 | 
			
		||||
	cdp.RegisterCodec(cdc)
 | 
			
		||||
	types.RegisterCodec(cdc)
 | 
			
		||||
	sdk.RegisterCodec(cdc)
 | 
			
		||||
	codec.RegisterCrypto(cdc)
 | 
			
		||||
	return cdc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func defaultParams() types.LiquidatorParams {
 | 
			
		||||
	return types.LiquidatorParams{
 | 
			
		||||
		DebtAuctionSize: sdk.NewInt(1000),
 | 
			
		||||
		CollateralParams: []types.CollateralParams{
 | 
			
		||||
			{
 | 
			
		||||
				Denom:       "btc",
 | 
			
		||||
				AuctionSize: sdk.NewInt(1),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cdpDefaultGenesis() cdp.GenesisState {
 | 
			
		||||
	return cdp.GenesisState{
 | 
			
		||||
		cdp.CdpParams{
 | 
			
		||||
			GlobalDebtLimit: sdk.NewInt(1000000),
 | 
			
		||||
			CollateralParams: []cdp.CollateralParams{
 | 
			
		||||
				{
 | 
			
		||||
					Denom:            "btc",
 | 
			
		||||
					LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
 | 
			
		||||
					DebtLimit:        sdk.NewInt(500000),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		sdk.ZeroInt(),
 | 
			
		||||
		cdp.CDPs{},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func pricefeedGenesis() pricefeed.GenesisState {
 | 
			
		||||
	ap := pricefeed.Params{
 | 
			
		||||
		Markets: []pricefeed.Market{
 | 
			
		||||
			pricefeed.Market{MarketID: "btc", BaseAsset: "btc", QuoteAsset: "usd", Oracles: pricefeed.Oracles{}, Active: true}},
 | 
			
		||||
	}
 | 
			
		||||
	return pricefeed.GenesisState{
 | 
			
		||||
		Params: ap,
 | 
			
		||||
		PostedPrices: []pricefeed.PostedPrice{
 | 
			
		||||
			pricefeed.PostedPrice{
 | 
			
		||||
				MarketID:      "btc",
 | 
			
		||||
				OracleAddress: sdk.AccAddress{},
 | 
			
		||||
				Price:         sdk.MustNewDecFromStr("8000.00"),
 | 
			
		||||
				Expiry:        tmtime.Now().Add(1 * time.Hour),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -21,7 +21,10 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState) {
 | 
			
		||||
	// Set the current price (if any) based on what's now in the store
 | 
			
		||||
	for _, a := range data.Params.Markets {
 | 
			
		||||
		if a.Active {
 | 
			
		||||
			_ = keeper.SetCurrentPrices(ctx, a.MarketID)
 | 
			
		||||
			err := keeper.SetCurrentPrices(ctx, a.MarketID)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				panic(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -27,7 +27,7 @@ type Keeper struct {
 | 
			
		||||
// - adding oracles
 | 
			
		||||
// - adding/removing assets from the pricefeed
 | 
			
		||||
func NewKeeper(
 | 
			
		||||
	storeKey sdk.StoreKey, cdc *codec.Codec, paramstore params.Subspace, codespace sdk.CodespaceType,
 | 
			
		||||
	cdc *codec.Codec, storeKey sdk.StoreKey, paramstore params.Subspace, codespace sdk.CodespaceType,
 | 
			
		||||
) Keeper {
 | 
			
		||||
	return Keeper{
 | 
			
		||||
		paramstore: paramstore.WithKeyTable(types.ParamKeyTable()),
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
package keeper
 | 
			
		||||
package keeper_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
@ -7,31 +7,28 @@ import (
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
	"github.com/stretchr/testify/require"
 | 
			
		||||
	abci "github.com/tendermint/tendermint/abci/types"
 | 
			
		||||
	tmtime "github.com/tendermint/tendermint/types/time"
 | 
			
		||||
 | 
			
		||||
	"github.com/kava-labs/kava/app"
 | 
			
		||||
	"github.com/kava-labs/kava/x/pricefeed/types"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TestKeeper_SetGetMarket tests adding markets to the pricefeed, getting markets from the store
 | 
			
		||||
func TestKeeper_SetGetMarket(t *testing.T) {
 | 
			
		||||
	helper := getMockApp(t, 0, types.GenesisState{}, nil)
 | 
			
		||||
	header := abci.Header{
 | 
			
		||||
		Height: helper.mApp.LastBlockHeight() + 1,
 | 
			
		||||
		Time:   tmtime.Now()}
 | 
			
		||||
	helper.mApp.BeginBlock(abci.RequestBeginBlock{Header: header})
 | 
			
		||||
	ctx := helper.mApp.BaseApp.NewContext(false, header)
 | 
			
		||||
	tApp := app.NewTestApp()
 | 
			
		||||
	ctx := tApp.NewContext(true, abci.Header{})
 | 
			
		||||
	keeper := tApp.GetPriceFeedKeeper()
 | 
			
		||||
 | 
			
		||||
	mp := types.Params{
 | 
			
		||||
		Markets: types.Markets{
 | 
			
		||||
			types.Market{MarketID: "tstusd", BaseAsset: "tst", QuoteAsset: "usd", Oracles: types.Oracles{}, Active: true},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	helper.keeper.SetParams(ctx, mp)
 | 
			
		||||
	markets := helper.keeper.GetMarketParams(ctx)
 | 
			
		||||
	keeper.SetParams(ctx, mp)
 | 
			
		||||
	markets := keeper.GetMarketParams(ctx)
 | 
			
		||||
	require.Equal(t, len(markets), 1)
 | 
			
		||||
	require.Equal(t, markets[0].MarketID, "tstusd")
 | 
			
		||||
 | 
			
		||||
	_, found := helper.keeper.GetMarket(ctx, "tstusd")
 | 
			
		||||
	_, found := keeper.GetMarket(ctx, "tstusd")
 | 
			
		||||
	require.Equal(t, found, true)
 | 
			
		||||
 | 
			
		||||
	mp = types.Params{
 | 
			
		||||
@ -40,102 +37,99 @@ func TestKeeper_SetGetMarket(t *testing.T) {
 | 
			
		||||
			types.Market{MarketID: "tst2usd", BaseAsset: "tst2", QuoteAsset: "usd", Oracles: types.Oracles{}, Active: true},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	helper.keeper.SetParams(ctx, mp)
 | 
			
		||||
	markets = helper.keeper.GetMarketParams(ctx)
 | 
			
		||||
	keeper.SetParams(ctx, mp)
 | 
			
		||||
	markets = keeper.GetMarketParams(ctx)
 | 
			
		||||
	require.Equal(t, len(markets), 2)
 | 
			
		||||
	require.Equal(t, markets[0].MarketID, "tstusd")
 | 
			
		||||
	require.Equal(t, markets[1].MarketID, "tst2usd")
 | 
			
		||||
 | 
			
		||||
	_, found = helper.keeper.GetMarket(ctx, "nan")
 | 
			
		||||
	_, found = keeper.GetMarket(ctx, "nan")
 | 
			
		||||
	require.Equal(t, found, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TestKeeper_GetSetPrice Test Posting the price by an oracle
 | 
			
		||||
func TestKeeper_GetSetPrice(t *testing.T) {
 | 
			
		||||
	helper := getMockApp(t, 2, types.GenesisState{}, nil)
 | 
			
		||||
	header := abci.Header{
 | 
			
		||||
		Height: helper.mApp.LastBlockHeight() + 1,
 | 
			
		||||
		Time:   tmtime.Now()}
 | 
			
		||||
	helper.mApp.BeginBlock(abci.RequestBeginBlock{Header: header})
 | 
			
		||||
	ctx := helper.mApp.BaseApp.NewContext(false, header)
 | 
			
		||||
	_, addrs := app.GeneratePrivKeyAddressPairs(2)
 | 
			
		||||
	tApp := app.NewTestApp()
 | 
			
		||||
	ctx := tApp.NewContext(true, abci.Header{})
 | 
			
		||||
	keeper := tApp.GetPriceFeedKeeper()
 | 
			
		||||
 | 
			
		||||
	mp := types.Params{
 | 
			
		||||
		Markets: types.Markets{
 | 
			
		||||
			types.Market{MarketID: "tstusd", BaseAsset: "tst", QuoteAsset: "usd", Oracles: types.Oracles{}, Active: true},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	helper.keeper.SetParams(ctx, mp)
 | 
			
		||||
	keeper.SetParams(ctx, mp)
 | 
			
		||||
	// Set price by oracle 1
 | 
			
		||||
	_, err := helper.keeper.SetPrice(
 | 
			
		||||
		ctx, helper.addrs[0], "tstusd",
 | 
			
		||||
	_, err := keeper.SetPrice(
 | 
			
		||||
		ctx, addrs[0], "tstusd",
 | 
			
		||||
		sdk.MustNewDecFromStr("0.33"),
 | 
			
		||||
		header.Time.Add(1*time.Hour))
 | 
			
		||||
		time.Now().Add(1*time.Hour))
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	// Get raw prices
 | 
			
		||||
	rawPrices := helper.keeper.GetRawPrices(ctx, "tstusd")
 | 
			
		||||
	rawPrices := keeper.GetRawPrices(ctx, "tstusd")
 | 
			
		||||
	require.Equal(t, len(rawPrices), 1)
 | 
			
		||||
	require.Equal(t, rawPrices[0].Price.Equal(sdk.MustNewDecFromStr("0.33")), true)
 | 
			
		||||
	// Set price by oracle 2
 | 
			
		||||
	_, err = helper.keeper.SetPrice(
 | 
			
		||||
		ctx, helper.addrs[1], "tstusd",
 | 
			
		||||
	_, err = keeper.SetPrice(
 | 
			
		||||
		ctx, addrs[1], "tstusd",
 | 
			
		||||
		sdk.MustNewDecFromStr("0.35"),
 | 
			
		||||
		header.Time.Add(time.Hour*1))
 | 
			
		||||
		time.Now().Add(time.Hour*1))
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
	rawPrices = helper.keeper.GetRawPrices(ctx, "tstusd")
 | 
			
		||||
	rawPrices = keeper.GetRawPrices(ctx, "tstusd")
 | 
			
		||||
	require.Equal(t, len(rawPrices), 2)
 | 
			
		||||
	require.Equal(t, rawPrices[1].Price.Equal(sdk.MustNewDecFromStr("0.35")), true)
 | 
			
		||||
 | 
			
		||||
	// Update Price by Oracle 1
 | 
			
		||||
	_, err = helper.keeper.SetPrice(
 | 
			
		||||
		ctx, helper.addrs[0], "tstusd",
 | 
			
		||||
	_, err = keeper.SetPrice(
 | 
			
		||||
		ctx, addrs[0], "tstusd",
 | 
			
		||||
		sdk.MustNewDecFromStr("0.37"),
 | 
			
		||||
		header.Time.Add(time.Hour*1))
 | 
			
		||||
		time.Now().Add(time.Hour*1))
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	rawPrices = helper.keeper.GetRawPrices(ctx, "tstusd")
 | 
			
		||||
	rawPrices = keeper.GetRawPrices(ctx, "tstusd")
 | 
			
		||||
	require.Equal(t, rawPrices[0].Price.Equal(sdk.MustNewDecFromStr("0.37")), true)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TestKeeper_GetSetCurrentPrice Test Setting the median price of an Asset
 | 
			
		||||
func TestKeeper_GetSetCurrentPrice(t *testing.T) {
 | 
			
		||||
	helper := getMockApp(t, 4, types.GenesisState{}, nil)
 | 
			
		||||
	header := abci.Header{
 | 
			
		||||
		Height: helper.mApp.LastBlockHeight() + 1,
 | 
			
		||||
		Time:   tmtime.Now()}
 | 
			
		||||
	helper.mApp.BeginBlock(abci.RequestBeginBlock{Header: header})
 | 
			
		||||
	ctx := helper.mApp.BaseApp.NewContext(false, header)
 | 
			
		||||
	_, addrs := app.GeneratePrivKeyAddressPairs(4)
 | 
			
		||||
	tApp := app.NewTestApp()
 | 
			
		||||
	ctx := tApp.NewContext(true, abci.Header{})
 | 
			
		||||
	keeper := tApp.GetPriceFeedKeeper()
 | 
			
		||||
 | 
			
		||||
	mp := types.Params{
 | 
			
		||||
		Markets: types.Markets{
 | 
			
		||||
			types.Market{MarketID: "tstusd", BaseAsset: "tst", QuoteAsset: "usd", Oracles: types.Oracles{}, Active: true},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	helper.keeper.SetParams(ctx, mp)
 | 
			
		||||
	helper.keeper.SetPrice(
 | 
			
		||||
		ctx, helper.addrs[0], "tstusd",
 | 
			
		||||
	keeper.SetParams(ctx, mp)
 | 
			
		||||
	keeper.SetPrice(
 | 
			
		||||
		ctx, addrs[0], "tstusd",
 | 
			
		||||
		sdk.MustNewDecFromStr("0.33"),
 | 
			
		||||
		header.Time.Add(time.Hour*1))
 | 
			
		||||
	helper.keeper.SetPrice(
 | 
			
		||||
		ctx, helper.addrs[1], "tstusd",
 | 
			
		||||
		time.Now().Add(time.Hour*1))
 | 
			
		||||
	keeper.SetPrice(
 | 
			
		||||
		ctx, addrs[1], "tstusd",
 | 
			
		||||
		sdk.MustNewDecFromStr("0.35"),
 | 
			
		||||
		header.Time.Add(time.Hour*1))
 | 
			
		||||
	helper.keeper.SetPrice(
 | 
			
		||||
		ctx, helper.addrs[2], "tstusd",
 | 
			
		||||
		time.Now().Add(time.Hour*1))
 | 
			
		||||
	keeper.SetPrice(
 | 
			
		||||
		ctx, addrs[2], "tstusd",
 | 
			
		||||
		sdk.MustNewDecFromStr("0.34"),
 | 
			
		||||
		header.Time.Add(time.Hour*1))
 | 
			
		||||
		time.Now().Add(time.Hour*1))
 | 
			
		||||
	// Set current price
 | 
			
		||||
	err := helper.keeper.SetCurrentPrices(ctx, "tstusd")
 | 
			
		||||
	err := keeper.SetCurrentPrices(ctx, "tstusd")
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	// Get Current price
 | 
			
		||||
	price := helper.keeper.GetCurrentPrice(ctx, "tstusd")
 | 
			
		||||
	price := keeper.GetCurrentPrice(ctx, "tstusd")
 | 
			
		||||
	require.Equal(t, price.Price.Equal(sdk.MustNewDecFromStr("0.34")), true)
 | 
			
		||||
 | 
			
		||||
	// Even number of oracles
 | 
			
		||||
	helper.keeper.SetPrice(
 | 
			
		||||
		ctx, helper.addrs[3], "tstusd",
 | 
			
		||||
	keeper.SetPrice(
 | 
			
		||||
		ctx, addrs[3], "tstusd",
 | 
			
		||||
		sdk.MustNewDecFromStr("0.36"),
 | 
			
		||||
		header.Time.Add(time.Hour*1))
 | 
			
		||||
	err = helper.keeper.SetCurrentPrices(ctx, "tstusd")
 | 
			
		||||
		time.Now().Add(time.Hour*1))
 | 
			
		||||
	err = keeper.SetCurrentPrices(ctx, "tstusd")
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	price = helper.keeper.GetCurrentPrice(ctx, "tstusd")
 | 
			
		||||
	price = keeper.GetCurrentPrice(ctx, "tstusd")
 | 
			
		||||
	require.Equal(t, price.Price.Equal(sdk.MustNewDecFromStr("0.345")), true)
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,46 +0,0 @@
 | 
			
		||||
package keeper
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
	authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
 | 
			
		||||
	"github.com/cosmos/cosmos-sdk/x/mock"
 | 
			
		||||
	"github.com/stretchr/testify/require"
 | 
			
		||||
	"github.com/tendermint/tendermint/crypto"
 | 
			
		||||
 | 
			
		||||
	"github.com/kava-labs/kava/x/pricefeed/types"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type testHelper struct {
 | 
			
		||||
	mApp     *mock.App
 | 
			
		||||
	keeper   Keeper
 | 
			
		||||
	addrs    []sdk.AccAddress
 | 
			
		||||
	pubKeys  []crypto.PubKey
 | 
			
		||||
	privKeys []crypto.PrivKey
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getMockApp(t *testing.T, numGenAccs int, genState types.GenesisState, genAccs []authexported.Account) testHelper {
 | 
			
		||||
	mApp := mock.NewApp()
 | 
			
		||||
	types.RegisterCodec(mApp.Cdc)
 | 
			
		||||
	keyPricefeed := sdk.NewKVStoreKey(types.StoreKey)
 | 
			
		||||
	pk := mApp.ParamsKeeper
 | 
			
		||||
	keeper := NewKeeper(keyPricefeed, mApp.Cdc, pk.Subspace(types.DefaultParamspace), types.DefaultCodespace)
 | 
			
		||||
 | 
			
		||||
	require.NoError(t, mApp.CompleteSetup(keyPricefeed))
 | 
			
		||||
 | 
			
		||||
	valTokens := sdk.TokensFromConsensusPower(42)
 | 
			
		||||
	var (
 | 
			
		||||
		addrs    []sdk.AccAddress
 | 
			
		||||
		pubKeys  []crypto.PubKey
 | 
			
		||||
		privKeys []crypto.PrivKey
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if genAccs == nil || len(genAccs) == 0 {
 | 
			
		||||
		genAccs, addrs, pubKeys, privKeys = mock.CreateGenAccounts(numGenAccs,
 | 
			
		||||
			sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, valTokens)))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mock.SetGenesis(mApp, genAccs)
 | 
			
		||||
	return testHelper{mApp, keeper, addrs, pubKeys, privKeys}
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user