mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-25 07:45:18 +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