mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-26 00:05: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
47
app/app.go
47
app/app.go
@ -4,6 +4,10 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"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"
|
validatorvesting "github.com/kava-labs/kava/x/validator-vesting"
|
||||||
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
@ -55,6 +59,10 @@ var (
|
|||||||
crisis.AppModuleBasic{},
|
crisis.AppModuleBasic{},
|
||||||
slashing.AppModuleBasic{},
|
slashing.AppModuleBasic{},
|
||||||
supply.AppModuleBasic{},
|
supply.AppModuleBasic{},
|
||||||
|
auction.AppModuleBasic{},
|
||||||
|
cdp.AppModuleBasic{},
|
||||||
|
liquidator.AppModuleBasic{},
|
||||||
|
pricefeed.AppModuleBasic{},
|
||||||
)
|
)
|
||||||
|
|
||||||
// module account permissions
|
// module account permissions
|
||||||
@ -92,6 +100,10 @@ type App struct {
|
|||||||
crisisKeeper crisis.Keeper
|
crisisKeeper crisis.Keeper
|
||||||
paramsKeeper params.Keeper
|
paramsKeeper params.Keeper
|
||||||
vvKeeper validatorvesting.Keeper
|
vvKeeper validatorvesting.Keeper
|
||||||
|
auctionKeeper auction.Keeper
|
||||||
|
cdpKeeper cdp.Keeper
|
||||||
|
liquidatorKeeper liquidator.Keeper
|
||||||
|
pricefeedKeeper pricefeed.Keeper
|
||||||
|
|
||||||
// the module manager
|
// the module manager
|
||||||
mm *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,
|
bam.MainStoreKey, auth.StoreKey, staking.StoreKey,
|
||||||
supply.StoreKey, mint.StoreKey, distr.StoreKey, slashing.StoreKey,
|
supply.StoreKey, mint.StoreKey, distr.StoreKey, slashing.StoreKey,
|
||||||
gov.StoreKey, params.StoreKey, validatorvesting.StoreKey,
|
gov.StoreKey, params.StoreKey, validatorvesting.StoreKey,
|
||||||
|
auction.StoreKey, cdp.StoreKey, liquidator.StoreKey, pricefeed.StoreKey,
|
||||||
)
|
)
|
||||||
tkeys := sdk.NewTransientStoreKeys(params.TStoreKey)
|
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)
|
slashingSubspace := app.paramsKeeper.Subspace(slashing.DefaultParamspace)
|
||||||
govSubspace := app.paramsKeeper.Subspace(gov.DefaultParamspace).WithKeyTable(gov.ParamKeyTable())
|
govSubspace := app.paramsKeeper.Subspace(gov.DefaultParamspace).WithKeyTable(gov.ParamKeyTable())
|
||||||
crisisSubspace := app.paramsKeeper.Subspace(crisis.DefaultParamspace)
|
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
|
// add keepers
|
||||||
app.accountKeeper = auth.NewAccountKeeper(
|
app.accountKeeper = auth.NewAccountKeeper(
|
||||||
@ -207,6 +224,29 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
|
|||||||
app.bankKeeper,
|
app.bankKeeper,
|
||||||
app.supplyKeeper,
|
app.supplyKeeper,
|
||||||
&stakingKeeper)
|
&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
|
// register the staking hooks
|
||||||
// NOTE: stakingKeeper above is passed by reference, so that it will contain these 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),
|
slashing.NewAppModule(app.slashingKeeper, app.stakingKeeper),
|
||||||
staking.NewAppModule(app.stakingKeeper, app.accountKeeper, app.supplyKeeper),
|
staking.NewAppModule(app.stakingKeeper, app.accountKeeper, app.supplyKeeper),
|
||||||
validatorvesting.NewAppModule(app.vvKeeper, app.accountKeeper),
|
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
|
// 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.
|
// CanWithdrawInvariant invariant.
|
||||||
app.mm.SetOrderBeginBlockers(mint.ModuleName, distr.ModuleName, slashing.ModuleName, validatorvesting.ModuleName)
|
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
|
// Note: genutils must occur after staking so that pools are properly
|
||||||
// initialized with tokens from genesis accounts.
|
// 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,
|
auth.ModuleName, validatorvesting.ModuleName, distr.ModuleName,
|
||||||
staking.ModuleName, bank.ModuleName, slashing.ModuleName,
|
staking.ModuleName, bank.ModuleName, slashing.ModuleName,
|
||||||
gov.ModuleName, mint.ModuleName, supply.ModuleName, crisis.ModuleName, genutil.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)
|
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 (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
@ -6,23 +6,43 @@ import (
|
|||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
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) {
|
func TestKeeper_EndBlocker(t *testing.T) {
|
||||||
// setup keeper and auction
|
// Setup
|
||||||
mapp, keeper, addresses, _ := setUpMockApp()
|
_, addrs := app.GeneratePrivKeyAddressPairs(1)
|
||||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
seller := addrs[0]
|
||||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
|
||||||
ctx := mapp.BaseApp.NewContext(false, header)
|
|
||||||
|
|
||||||
seller := addresses[0]
|
tApp := app.NewTestApp()
|
||||||
keeper.StartForwardAuction(ctx, seller, sdk.NewInt64Coin("token1", 20), sdk.NewInt64Coin("token2", 0))
|
tApp.InitializeFromGenesisStates(
|
||||||
|
app.NewAuthGenState(addrs, []sdk.Coins{cs(c("token1", 100), c("token2", 100))}),
|
||||||
|
)
|
||||||
|
|
||||||
// run the endblocker, simulating a block height after auction expiry
|
ctx := tApp.NewContext(true, abci.Header{})
|
||||||
expiryBlock := ctx.BlockHeight() + int64(DefaultMaxAuctionDuration)
|
keeper := tApp.GetAuctionKeeper()
|
||||||
EndBlocker(ctx.WithBlockHeight(expiryBlock), keeper)
|
|
||||||
|
|
||||||
// check auction has been closed
|
auctionID, err := keeper.StartForwardAuction(ctx, seller, c("token1", 20), c("token2", 0))
|
||||||
_, found := keeper.GetAuction(ctx, 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)
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete auction from store (and queue)
|
// Delete auction from store (and queue)
|
||||||
k.deleteAuction(ctx, auctionID)
|
k.DeleteAuction(ctx, auctionID)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -204,7 +204,7 @@ func (k Keeper) SetAuction(ctx sdk.Context, auction types.Auction) {
|
|||||||
store.Set(k.getAuctionKey(auction.GetID()), bz)
|
store.Set(k.getAuctionKey(auction.GetID()), bz)
|
||||||
|
|
||||||
// add to the queue
|
// 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
|
// 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
|
return auction, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// deleteAuction removes an auction from the store without any validation
|
// DeleteAuction removes an auction from the store without any validation
|
||||||
func (k Keeper) deleteAuction(ctx sdk.Context, auctionID types.ID) {
|
func (k Keeper) DeleteAuction(ctx sdk.Context, auctionID types.ID) {
|
||||||
// remove from queue
|
// remove from queue
|
||||||
auction, found := k.GetAuction(ctx, auctionID)
|
auction, found := k.GetAuction(ctx, auctionID)
|
||||||
if found {
|
if found {
|
||||||
@ -245,7 +245,7 @@ func (k Keeper) getAuctionKey(auctionID types.ID) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Inserts a AuctionID into the queue at endTime
|
// 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
|
// get the store
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
// marshal thing to be inserted
|
// marshal thing to be inserted
|
||||||
|
@ -1,21 +1,129 @@
|
|||||||
package keeper
|
package keeper_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/kava-labs/kava/x/auction/types"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
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) {
|
func TestKeeper_SetGetDeleteAuction(t *testing.T) {
|
||||||
// setup keeper, create auction
|
// setup keeper, create auction
|
||||||
mapp, keeper, addresses, _ := setUpMockApp()
|
_, addrs := app.GeneratePrivKeyAddressPairs(1)
|
||||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
tApp := app.NewTestApp()
|
||||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header}) // Without this it panics about "invalid memory address or nil pointer dereference"
|
keeper := tApp.GetAuctionKeeper()
|
||||||
ctx := mapp.BaseApp.NewContext(false, header)
|
ctx := tApp.NewContext(true, abci.Header{})
|
||||||
auction, _ := types.NewForwardAuction(addresses[0], sdk.NewInt64Coin("usdx", 100), sdk.NewInt64Coin("kava", 0), types.EndTime(1000))
|
auction, _ := types.NewForwardAuction(addrs[0], c("usdx", 100), c("kava", 0), types.EndTime(1000))
|
||||||
id := types.ID(5)
|
id := types.ID(5)
|
||||||
auction.SetID(id)
|
auction.SetID(id)
|
||||||
|
|
||||||
@ -26,15 +134,13 @@ func TestKeeper_SetGetDeleteAuction(t *testing.T) {
|
|||||||
// check before and after match
|
// check before and after match
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
require.Equal(t, &auction, readAuction)
|
require.Equal(t, &auction, readAuction)
|
||||||
t.Log(auction)
|
|
||||||
t.Log(readAuction.GetID())
|
|
||||||
// check auction is in queue
|
// check auction is in queue
|
||||||
iter := keeper.GetQueueIterator(ctx, 100000)
|
iter := keeper.GetQueueIterator(ctx, 100000)
|
||||||
require.Equal(t, 1, len(convertIteratorToSlice(keeper, iter)))
|
require.Equal(t, 1, len(convertIteratorToSlice(keeper, iter)))
|
||||||
iter.Close()
|
iter.Close()
|
||||||
|
|
||||||
// delete auction
|
// delete auction
|
||||||
keeper.deleteAuction(ctx, id)
|
keeper.DeleteAuction(ctx, id)
|
||||||
|
|
||||||
// check auction does not exist
|
// check auction does not exist
|
||||||
_, found = keeper.GetAuction(ctx, id)
|
_, 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
|
// TODO convert to table driven test with more test cases
|
||||||
func TestKeeper_ExpiredAuctionQueue(t *testing.T) {
|
func TestKeeper_ExpiredAuctionQueue(t *testing.T) {
|
||||||
// setup keeper
|
// setup keeper
|
||||||
mapp, keeper, _, _ := setUpMockApp()
|
tApp := app.NewTestApp()
|
||||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
keeper := tApp.GetAuctionKeeper()
|
||||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
ctx := tApp.NewContext(true, abci.Header{})
|
||||||
ctx := mapp.BaseApp.NewContext(false, header)
|
|
||||||
// create an example queue
|
// create an example queue
|
||||||
type queue []struct {
|
type queue []struct {
|
||||||
endTime types.EndTime
|
endTime types.EndTime
|
||||||
@ -62,7 +168,7 @@ func TestKeeper_ExpiredAuctionQueue(t *testing.T) {
|
|||||||
|
|
||||||
// write and read queue
|
// write and read queue
|
||||||
for _, v := range q {
|
for _, v := range q {
|
||||||
keeper.insertIntoQueue(ctx, v.endTime, v.auctionID)
|
keeper.InsertIntoQueue(ctx, v.endTime, v.auctionID)
|
||||||
}
|
}
|
||||||
iter := keeper.GetQueueIterator(ctx, 1000)
|
iter := keeper.GetQueueIterator(ctx, 1000)
|
||||||
|
|
||||||
@ -70,19 +176,22 @@ func TestKeeper_ExpiredAuctionQueue(t *testing.T) {
|
|||||||
i := 0
|
i := 0
|
||||||
for ; iter.Valid(); iter.Next() {
|
for ; iter.Valid(); iter.Next() {
|
||||||
var auctionID types.ID
|
var auctionID types.ID
|
||||||
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &auctionID)
|
tApp.Codec().MustUnmarshalBinaryLengthPrefixed(iter.Value(), &auctionID)
|
||||||
require.Equal(t, q[i].auctionID, auctionID)
|
require.Equal(t, q[i].auctionID, auctionID)
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertIteratorToSlice(keeper Keeper, iterator sdk.Iterator) []types.ID {
|
func convertIteratorToSlice(keeper keeper.Keeper, iterator sdk.Iterator) []types.ID {
|
||||||
var queue []types.ID
|
var queue []types.ID
|
||||||
for ; iterator.Valid(); iterator.Next() {
|
for ; iterator.Valid(); iterator.Next() {
|
||||||
var auctionID types.ID
|
var auctionID types.ID
|
||||||
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &auctionID)
|
types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &auctionID)
|
||||||
queue = append(queue, auctionID)
|
queue = append(queue, auctionID)
|
||||||
}
|
}
|
||||||
return queue
|
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 (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/simapp"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
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) {
|
func TestApp_CreateModifyDeleteCDP(t *testing.T) {
|
||||||
// Setup
|
// Setup
|
||||||
mapp, keeper, pfKeeper := setUpMockAppWithoutGenesis()
|
tApp := app.NewTestApp()
|
||||||
genAccs, addrs, _, privKeys := mock.CreateGenAccounts(1, cs(c("xrp", 100)))
|
privKeys, addrs := app.GeneratePrivKeyAddressPairs(1)
|
||||||
testAddr := addrs[0]
|
testAddr := addrs[0]
|
||||||
testPrivKey := privKeys[0]
|
testPrivKey := privKeys[0]
|
||||||
mock.SetGenesis(mapp, genAccs)
|
tApp.InitializeFromGenesisStates(
|
||||||
mock.CheckBalance(t, mapp, testAddr, cs(c("xrp", 100)))
|
app.NewAuthGenState(addrs, []sdk.Coins{cs(c("xrp", 100))}),
|
||||||
// setup pricefeed, TODO can this be shortened a bit?
|
NewPFGenState("xrp", d("1.00")),
|
||||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1, Time: tmtime.Now()}
|
NewCDPGenState("xrp", d("1.5")),
|
||||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
)
|
||||||
ctx := mapp.BaseApp.NewContext(false, header)
|
// check balance
|
||||||
params := CdpParams{
|
ctx := tApp.NewContext(false, abci.Header{})
|
||||||
GlobalDebtLimit: sdk.NewInt(100000),
|
tApp.CheckBalance(t, ctx, testAddr, cs(c("xrp", 100)))
|
||||||
CollateralParams: []CollateralParams{
|
|
||||||
{
|
tApp.EndBlock(abci.RequestEndBlock{})
|
||||||
Denom: "xrp",
|
tApp.Commit()
|
||||||
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()
|
|
||||||
|
|
||||||
// Create CDP
|
// Create CDP
|
||||||
msgs := []sdk.Msg{NewMsgCreateOrModifyCDP(testAddr, "xrp", i(10), i(5))}
|
msgs := []sdk.Msg{cdp.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)
|
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
|
// Modify CDP
|
||||||
msgs = []sdk.Msg{NewMsgCreateOrModifyCDP(testAddr, "xrp", i(40), i(5))}
|
msgs = []sdk.Msg{cdp.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)
|
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
|
// Delete CDP
|
||||||
msgs = []sdk.Msg{NewMsgCreateOrModifyCDP(testAddr, "xrp", i(-50), i(-10))}
|
msgs = []sdk.Msg{cdp.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)
|
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 (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
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"
|
"github.com/stretchr/testify/require"
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
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
|
// Test the bank functionality of the CDP keeper
|
||||||
func TestKeeper_AddSubtractGetCoins(t *testing.T) {
|
func TestKeeper_AddSubtractGetCoins(t *testing.T) {
|
||||||
_, addrs := mock.GeneratePrivKeyAddressPairs(1)
|
_, addrs := app.GeneratePrivKeyAddressPairs(1)
|
||||||
normalAddr := addrs[0]
|
normalAddr := addrs[0]
|
||||||
|
|
||||||
tests := []struct {
|
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))},
|
{"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))},
|
{"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))},
|
{"addLiquidatorStable", keep.LiquidatorAccountAddress, true, cs(c("usdx", 53)), cs(c("usdx", 153))},
|
||||||
{"subLiquidatorStable", LiquidatorAccountAddress, false, cs(c("usdx", 53)), cs(c("usdx", 47))},
|
{"subLiquidatorStable", keep.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
|
{"addLiquidatorGov", keep.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
|
{"subLiquidatorGov", keep.LiquidatorAccountAddress, false, cs(c("kava", 53)), cs(c("usdx", 100))}, // no change to balance
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
// setup keeper
|
// setup app with an account
|
||||||
mapp, keeper, _, _ := setUpMockAppWithoutGenesis()
|
tApp := app.NewTestApp()
|
||||||
// initialize an account with coins
|
tApp.InitializeFromGenesisStates(
|
||||||
genAcc := auth.BaseAccount{
|
app.NewAuthGenState([]sdk.AccAddress{normalAddr}, []sdk.Coins{cs(c("usdx", 100), c("kava", 100))}),
|
||||||
Address: normalAddr,
|
)
|
||||||
Coins: cs(c("usdx", 100), c("kava", 100)),
|
|
||||||
}
|
|
||||||
mock.SetGenesis(mapp, []authexported.Account{&genAcc})
|
|
||||||
|
|
||||||
// create a new context and setup the liquidator account
|
// create a new context and setup the liquidator account
|
||||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
ctx := tApp.NewContext(false, abci.Header{})
|
||||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
keeper := tApp.GetCDPKeeper()
|
||||||
ctx := mapp.BaseApp.NewContext(false, header)
|
keeper.SetLiquidatorModuleAccount(ctx, keep.LiquidatorModuleAccount{cs(c("usdx", 100))}) // set gov coin "balance" to zero
|
||||||
keeper.setLiquidatorModuleAccount(ctx, LiquidatorModuleAccount{cs(c("usdx", 100))}) // set gov coin "balance" to zero
|
|
||||||
|
|
||||||
// perform the test action
|
// perform the test action
|
||||||
var err sdk.Error
|
var err sdk.Error
|
||||||
@ -56,9 +52,6 @@ func TestKeeper_AddSubtractGetCoins(t *testing.T) {
|
|||||||
_, err = keeper.SubtractCoins(ctx, tc.address, tc.amount)
|
_, err = keeper.SubtractCoins(ctx, tc.address, tc.amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
mapp.EndBlock(abci.RequestEndBlock{})
|
|
||||||
mapp.Commit()
|
|
||||||
|
|
||||||
// check balances are as expected
|
// check balances are as expected
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, tc.expectedCoins, keeper.GetCoins(ctx, tc.address))
|
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
|
// Set CDP
|
||||||
if cdp.CollateralAmount.IsZero() && cdp.Debt.IsZero() { // TODO maybe abstract this logic into SetCDP
|
if cdp.CollateralAmount.IsZero() && cdp.Debt.IsZero() { // TODO maybe abstract this logic into SetCDP
|
||||||
k.deleteCDP(ctx, cdp)
|
k.DeleteCDP(ctx, cdp)
|
||||||
} else {
|
} else {
|
||||||
k.SetCDP(ctx, cdp)
|
k.SetCDP(ctx, cdp)
|
||||||
}
|
}
|
||||||
// set total debts
|
// set total debts
|
||||||
k.SetGlobalDebt(ctx, gDebt)
|
k.SetGlobalDebt(ctx, gDebt)
|
||||||
k.setCollateralState(ctx, collateralState)
|
k.SetCollateralState(ctx, collateralState)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -195,11 +195,11 @@ func (k Keeper) PartialSeizeCDP(ctx sdk.Context, owner sdk.AccAddress, collatera
|
|||||||
|
|
||||||
// Store updated state
|
// Store updated state
|
||||||
if cdp.CollateralAmount.IsZero() && cdp.Debt.IsZero() { // TODO maybe abstract this logic into SetCDP
|
if cdp.CollateralAmount.IsZero() && cdp.Debt.IsZero() { // TODO maybe abstract this logic into SetCDP
|
||||||
k.deleteCDP(ctx, cdp)
|
k.DeleteCDP(ctx, cdp)
|
||||||
} else {
|
} else {
|
||||||
k.SetCDP(ctx, cdp)
|
k.SetCDP(ctx, cdp)
|
||||||
}
|
}
|
||||||
k.setCollateralState(ctx, collateralState)
|
k.SetCollateralState(ctx, collateralState)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,7 +264,7 @@ func (k Keeper) SetCDP(ctx sdk.Context, cdp types.CDP) {
|
|||||||
bz := k.cdc.MustMarshalBinaryLengthPrefixed(cdp)
|
bz := k.cdc.MustMarshalBinaryLengthPrefixed(cdp)
|
||||||
store.Set(k.getCDPKey(cdp.Owner, cdp.CollateralDenom), bz)
|
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
|
// get store
|
||||||
store := ctx.KVStore(k.key)
|
store := ctx.KVStore(k.key)
|
||||||
// delete key
|
// delete key
|
||||||
@ -354,7 +354,7 @@ func (k Keeper) GetCollateralState(ctx sdk.Context, collateralDenom string) (typ
|
|||||||
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &collateralState)
|
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &collateralState)
|
||||||
return collateralState, true
|
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
|
// get store
|
||||||
store := ctx.KVStore(k.key)
|
store := ctx.KVStore(k.key)
|
||||||
// marshal and set
|
// 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))
|
return amount, sdk.ErrInsufficientCoins(fmt.Sprintf("insufficient account funds; %s < %s", lma.Coins, amount))
|
||||||
}
|
}
|
||||||
lma.Coins = updatedCoins
|
lma.Coins = updatedCoins
|
||||||
k.setLiquidatorModuleAccount(ctx, lma)
|
k.SetLiquidatorModuleAccount(ctx, lma)
|
||||||
return updatedCoins, nil
|
return updatedCoins, nil
|
||||||
} else {
|
} else {
|
||||||
return k.bankKeeper.AddCoins(ctx, address, amount)
|
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))
|
return amount, sdk.ErrInsufficientCoins(fmt.Sprintf("insufficient account funds; %s < %s", lma.Coins, amount))
|
||||||
}
|
}
|
||||||
lma.Coins = updatedCoins
|
lma.Coins = updatedCoins
|
||||||
k.setLiquidatorModuleAccount(ctx, lma)
|
k.SetLiquidatorModuleAccount(ctx, lma)
|
||||||
return updatedCoins, nil
|
return updatedCoins, nil
|
||||||
} else {
|
} else {
|
||||||
return k.bankKeeper.SubtractCoins(ctx, address, amount)
|
return k.bankKeeper.SubtractCoins(ctx, address, amount)
|
||||||
@ -483,7 +483,7 @@ func (k Keeper) getLiquidatorModuleAccount(ctx sdk.Context) LiquidatorModuleAcco
|
|||||||
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &lma)
|
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &lma)
|
||||||
return 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)
|
store := ctx.KVStore(k.key)
|
||||||
bz := k.cdc.MustMarshalBinaryLengthPrefixed(lma)
|
bz := k.cdc.MustMarshalBinaryLengthPrefixed(lma)
|
||||||
store.Set(liquidatorAccountKey, bz)
|
store.Set(liquidatorAccountKey, bz)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package keeper
|
package keeper_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -6,24 +6,21 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
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"
|
"github.com/stretchr/testify/require"
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
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?
|
// 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.
|
// 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) {
|
func TestKeeper_ModifyCDP(t *testing.T) {
|
||||||
_, addrs := mock.GeneratePrivKeyAddressPairs(1)
|
_, addrs := app.GeneratePrivKeyAddressPairs(1)
|
||||||
ownerAddr := addrs[0]
|
ownerAddr := addrs[0]
|
||||||
|
|
||||||
type state struct { // TODO this allows invalid state to be set up, should it?
|
type state struct {
|
||||||
CDP types.CDP
|
CDP types.CDP
|
||||||
OwnerCoins sdk.Coins
|
OwnerCoins sdk.Coins
|
||||||
GlobalDebt sdk.Int
|
GlobalDebt sdk.Int
|
||||||
@ -96,59 +93,32 @@ func TestKeeper_ModifyCDP(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
// setup keeper
|
// setup test app
|
||||||
mapp, keeper, _, _ := setUpMockAppWithoutGenesis()
|
tApp := app.NewTestApp()
|
||||||
// initialize cdp owner account with coins
|
// initialize cdp owner account with coins, and collateral with price and params
|
||||||
genAcc := auth.BaseAccount{
|
tApp.InitializeFromGenesisStates(
|
||||||
Address: ownerAddr,
|
app.NewAuthGenState([]sdk.AccAddress{ownerAddr}, []sdk.Coins{tc.priorState.OwnerCoins}),
|
||||||
Coins: tc.priorState.OwnerCoins,
|
NewPricefeedGenState("xrp", d(tc.price)),
|
||||||
}
|
NewCDPGenState("xrp", d("2.0")),
|
||||||
mock.SetGenesis(mapp, []authexported.Account{&genAcc})
|
)
|
||||||
// create a new context
|
// create a context for db access
|
||||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1, Time: tmtime.Now()}
|
ctx := tApp.NewContext(false, abci.Header{})
|
||||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
|
||||||
ctx := mapp.BaseApp.NewContext(false, header)
|
|
||||||
keeper.SetParams(ctx, defaultParamsSingle())
|
|
||||||
// setup store state
|
// setup store state
|
||||||
ap := pricefeed.Params{
|
keeper := tApp.GetCDPKeeper()
|
||||||
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)
|
|
||||||
}
|
|
||||||
if tc.priorState.CDP.CollateralDenom != "" { // check if the prior CDP should be created or not (see if an empty one was specified)
|
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.SetCDP(ctx, tc.priorState.CDP)
|
||||||
}
|
}
|
||||||
keeper.SetGlobalDebt(ctx, tc.priorState.GlobalDebt)
|
keeper.SetGlobalDebt(ctx, tc.priorState.GlobalDebt)
|
||||||
if tc.priorState.CollateralState.Denom != "" {
|
if tc.priorState.CollateralState.Denom != "" {
|
||||||
keeper.setCollateralState(ctx, tc.priorState.CollateralState)
|
keeper.SetCollateralState(ctx, tc.priorState.CollateralState)
|
||||||
}
|
}
|
||||||
|
|
||||||
// call func under test
|
// call func under test
|
||||||
err = keeper.ModifyCDP(ctx, tc.args.owner, tc.args.collateralDenom, tc.args.changeInCollateral, tc.args.changeInDebt)
|
err := keeper.ModifyCDP(ctx, tc.args.owner, tc.args.collateralDenom, tc.args.changeInCollateral, tc.args.changeInDebt)
|
||||||
mapp.EndBlock(abci.RequestEndBlock{})
|
|
||||||
mapp.Commit()
|
|
||||||
|
|
||||||
// get new state for verification
|
// get new state for verification
|
||||||
actualCDP, found := keeper.GetCDP(ctx, tc.args.owner, tc.args.collateralDenom)
|
actualCDP, found := keeper.GetCDP(ctx, tc.args.owner, tc.args.collateralDenom)
|
||||||
|
|
||||||
// check for err
|
// check for err
|
||||||
if tc.expectPass {
|
if tc.expectPass {
|
||||||
require.NoError(t, err, fmt.Sprint(err))
|
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.GlobalDebt, actualGDebt)
|
||||||
require.Equal(t, tc.expectedState.CollateralState, actualCstate)
|
require.Equal(t, tc.expectedState.CollateralState, actualCstate)
|
||||||
// check owner balance
|
// 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) {
|
func TestKeeper_PartialSeizeCDP(t *testing.T) {
|
||||||
// Setup
|
// Setup
|
||||||
const collateral = "xrp"
|
const collateral = "xrp"
|
||||||
mapp, keeper, _, _ := setUpMockAppWithoutGenesis()
|
_, addrs := app.GeneratePrivKeyAddressPairs(1)
|
||||||
genAccs, addrs, _, _ := mock.CreateGenAccounts(1, cs(c(collateral, 100)))
|
|
||||||
testAddr := addrs[0]
|
testAddr := addrs[0]
|
||||||
mock.SetGenesis(mapp, genAccs)
|
|
||||||
// setup pricefeed
|
tApp := app.NewTestApp()
|
||||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1, Time: tmtime.Now()}
|
tApp.InitializeFromGenesisStates(
|
||||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
app.NewAuthGenState(addrs, []sdk.Coins{cs(c(collateral, 100))}),
|
||||||
ctx := mapp.BaseApp.NewContext(false, header)
|
NewPricefeedGenState(collateral, d("1.00")),
|
||||||
keeper.SetParams(ctx, defaultParamsSingle())
|
NewCDPGenState(collateral, d("2.00")),
|
||||||
ap := pricefeed.Params{
|
)
|
||||||
Markets: []pricefeed.Market{
|
|
||||||
pricefeed.Market{
|
ctx := tApp.NewContext(false, abci.Header{})
|
||||||
MarketID: "xrp", BaseAsset: "xrp",
|
keeper := tApp.GetCDPKeeper()
|
||||||
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)
|
|
||||||
// Create CDP
|
// Create CDP
|
||||||
keeper.SetGlobalDebt(ctx, i(0))
|
|
||||||
err := keeper.ModifyCDP(ctx, testAddr, collateral, i(10), i(5))
|
err := keeper.ModifyCDP(ctx, testAddr, collateral, i(10), i(5))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
// Reduce price
|
// Reduce price
|
||||||
keeper.pricefeedKeeper.SetPrice(
|
tApp.GetPriceFeedKeeper().SetPrice(
|
||||||
ctx, sdk.AccAddress{}, collateral,
|
ctx, sdk.AccAddress{}, collateral,
|
||||||
sdk.MustNewDecFromStr("0.90"),
|
d("0.90"), time.Now().Add(1*time.Hour))
|
||||||
header.Time.Add(time.Hour*1))
|
tApp.GetPriceFeedKeeper().SetCurrentPrices(ctx, collateral)
|
||||||
keeper.pricefeedKeeper.SetCurrentPrices(ctx, collateral)
|
|
||||||
|
|
||||||
// Seize entire CDP
|
// Seize entire CDP
|
||||||
err = keeper.PartialSeizeCDP(ctx, testAddr, collateral, i(10), i(5))
|
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) {
|
func TestKeeper_GetCDPs(t *testing.T) {
|
||||||
// setup keeper
|
// setup test app
|
||||||
mapp, keeper, _, _ := setUpMockAppWithoutGenesis()
|
tApp := app.NewTestApp().InitializeFromGenesisStates(
|
||||||
mock.SetGenesis(mapp, []authexported.Account(nil))
|
NewPricefeedGenStateMulti(), // collateral needs to be in pricefeed for cdp InitGenesis to validate
|
||||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
NewCDPGenStateMulti(),
|
||||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
)
|
||||||
ctx := mapp.BaseApp.NewContext(false, header)
|
ctx := tApp.NewContext(true, abci.Header{})
|
||||||
keeper.SetParams(ctx, defaultParamsMulti())
|
keeper := tApp.GetCDPKeeper()
|
||||||
|
|
||||||
// setup CDPs
|
// setup CDPs
|
||||||
_, addrs := mock.GeneratePrivKeyAddressPairs(2)
|
_, addrs := app.GeneratePrivKeyAddressPairs(2)
|
||||||
cdps := types.CDPs{
|
cdps := types.CDPs{
|
||||||
{addrs[0], "xrp", i(4000), i(5)},
|
{addrs[0], "xrp", i(4000), i(5)},
|
||||||
{addrs[1], "xrp", i(4000), i(2000)},
|
{addrs[1], "xrp", i(4000), i(2000)},
|
||||||
@ -288,7 +247,7 @@ func TestKeeper_GetCDPs(t *testing.T) {
|
|||||||
_, err = keeper.GetCDPs(ctx, "", d("0.34023"))
|
_, err = keeper.GetCDPs(ctx, "", d("0.34023"))
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
// Check deleting a CDP removes it
|
// Check deleting a CDP removes it
|
||||||
keeper.deleteCDP(ctx, cdps[0])
|
keeper.DeleteCDP(ctx, cdps[0])
|
||||||
returnedCdps, err = keeper.GetCDPs(ctx, "", sdk.Dec{})
|
returnedCdps, err = keeper.GetCDPs(ctx, "", sdk.Dec{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t,
|
require.Equal(t,
|
||||||
@ -298,14 +257,14 @@ func TestKeeper_GetCDPs(t *testing.T) {
|
|||||||
returnedCdps,
|
returnedCdps,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKeeper_GetSetDeleteCDP(t *testing.T) {
|
func TestKeeper_GetSetDeleteCDP(t *testing.T) {
|
||||||
// setup keeper, create CDP
|
// setup keeper, create CDP
|
||||||
mapp, keeper, _, _ := setUpMockAppWithoutGenesis()
|
tApp := app.NewTestApp()
|
||||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
ctx := tApp.NewContext(true, abci.Header{})
|
||||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
keeper := tApp.GetCDPKeeper()
|
||||||
ctx := mapp.BaseApp.NewContext(false, header)
|
|
||||||
keeper.SetParams(ctx, defaultParamsSingle())
|
_, addrs := app.GeneratePrivKeyAddressPairs(1)
|
||||||
_, addrs := mock.GeneratePrivKeyAddressPairs(1)
|
|
||||||
cdp := types.CDP{addrs[0], "xrp", i(412), i(56)}
|
cdp := types.CDP{addrs[0], "xrp", i(412), i(56)}
|
||||||
|
|
||||||
// write and read from store
|
// write and read from store
|
||||||
@ -317,7 +276,7 @@ func TestKeeper_GetSetDeleteCDP(t *testing.T) {
|
|||||||
require.Equal(t, cdp, readCDP)
|
require.Equal(t, cdp, readCDP)
|
||||||
|
|
||||||
// delete auction
|
// delete auction
|
||||||
keeper.deleteCDP(ctx, cdp)
|
keeper.DeleteCDP(ctx, cdp)
|
||||||
|
|
||||||
// check auction does not exist
|
// check auction does not exist
|
||||||
_, found = keeper.GetCDP(ctx, cdp.Owner, cdp.CollateralDenom)
|
_, found = keeper.GetCDP(ctx, cdp.Owner, cdp.CollateralDenom)
|
||||||
@ -325,11 +284,10 @@ func TestKeeper_GetSetDeleteCDP(t *testing.T) {
|
|||||||
}
|
}
|
||||||
func TestKeeper_GetSetGDebt(t *testing.T) {
|
func TestKeeper_GetSetGDebt(t *testing.T) {
|
||||||
// setup keeper, create GDebt
|
// setup keeper, create GDebt
|
||||||
mapp, keeper, _, _ := setUpMockAppWithoutGenesis()
|
tApp := app.NewTestApp()
|
||||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
ctx := tApp.NewContext(true, abci.Header{})
|
||||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
keeper := tApp.GetCDPKeeper()
|
||||||
ctx := mapp.BaseApp.NewContext(false, header)
|
|
||||||
keeper.SetParams(ctx, defaultParamsSingle())
|
|
||||||
gDebt := i(4120000)
|
gDebt := i(4120000)
|
||||||
|
|
||||||
// write and read from store
|
// write and read from store
|
||||||
@ -342,15 +300,14 @@ func TestKeeper_GetSetGDebt(t *testing.T) {
|
|||||||
|
|
||||||
func TestKeeper_GetSetCollateralState(t *testing.T) {
|
func TestKeeper_GetSetCollateralState(t *testing.T) {
|
||||||
// setup keeper, create CState
|
// setup keeper, create CState
|
||||||
mapp, keeper, _, _ := setUpMockAppWithoutGenesis()
|
tApp := app.NewTestApp()
|
||||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
ctx := tApp.NewContext(true, abci.Header{})
|
||||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
keeper := tApp.GetCDPKeeper()
|
||||||
ctx := mapp.BaseApp.NewContext(false, header)
|
|
||||||
keeper.SetParams(ctx, defaultParamsSingle())
|
|
||||||
collateralState := types.CollateralState{"xrp", i(15400)}
|
collateralState := types.CollateralState{"xrp", i(15400)}
|
||||||
|
|
||||||
// write and read from store
|
// write and read from store
|
||||||
keeper.setCollateralState(ctx, collateralState)
|
keeper.SetCollateralState(ctx, collateralState)
|
||||||
readCState, found := keeper.GetCollateralState(ctx, collateralState.Denom)
|
readCState, found := keeper.GetCollateralState(ctx, collateralState.Denom)
|
||||||
|
|
||||||
// check before and after match
|
// 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()
|
stableToRaise := sdk.NewDecFromInt(collateralToSell).Quo(sdk.NewDecFromInt(cdp.CollateralAmount)).Mul(sdk.NewDecFromInt(cdp.Debt)).RoundInt()
|
||||||
|
|
||||||
// Seize the collateral and debt from the CDP
|
// 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 {
|
if err != nil {
|
||||||
return 0, err
|
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
|
// 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)
|
seizedDebt.SentToAuction = seizedDebt.SentToAuction.Add(params.DebtAuctionSize)
|
||||||
k.setSeizedDebt(ctx, seizedDebt)
|
k.SetSeizedDebt(ctx, seizedDebt)
|
||||||
return auctionID, nil
|
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.
|
// 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.
|
// Seize debt and collateral in the cdp module. This also validates the inputs.
|
||||||
err := k.cdpKeeper.PartialSeizeCDP(ctx, owner, collateralDenom, collateralToSeize, debtToSeize)
|
err := k.cdpKeeper.PartialSeizeCDP(ctx, owner, collateralDenom, collateralToSeize, debtToSeize)
|
||||||
if err != nil {
|
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
|
// increment the total seized debt (Awe) by cdp.debt
|
||||||
seizedDebt := k.GetSeizedDebt(ctx)
|
seizedDebt := k.GetSeizedDebt(ctx)
|
||||||
seizedDebt.Total = seizedDebt.Total.Add(debtToSeize)
|
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)
|
// 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))
|
coins := sdk.NewCoins(sdk.NewCoin(collateralDenom, collateralToSeize))
|
||||||
@ -172,7 +172,7 @@ func (k Keeper) SettleDebt(ctx sdk.Context) sdk.Error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err // this should not error in this context
|
return err // this should not error in this context
|
||||||
}
|
}
|
||||||
k.setSeizedDebt(ctx, updatedDebt)
|
k.SetSeizedDebt(ctx, updatedDebt)
|
||||||
|
|
||||||
// Subtract stable coin from moduleAccout
|
// Subtract stable coin from moduleAccout
|
||||||
k.bankKeeper.SubtractCoins(ctx, k.cdpKeeper.GetLiquidatorAccountAddress(), sdk.Coins{sdk.NewCoin(k.cdpKeeper.GetStableDenom(), settleAmount)})
|
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)
|
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &seizedDebt)
|
||||||
return 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)
|
store := ctx.KVStore(k.key)
|
||||||
bz := k.cdc.MustMarshalBinaryLengthPrefixed(debt)
|
bz := k.cdc.MustMarshalBinaryLengthPrefixed(debt)
|
||||||
store.Set(k.getSeizedDebtKey(), bz)
|
store.Set(k.getSeizedDebtKey(), bz)
|
||||||
|
@ -1,124 +1,103 @@
|
|||||||
package keeper
|
package keeper_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
tmtime "github.com/tendermint/tendermint/types/time"
|
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/liquidator/types"
|
||||||
"github.com/kava-labs/kava/x/pricefeed"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestKeeper_SeizeAndStartCollateralAuction(t *testing.T) {
|
func TestKeeper_SeizeAndStartCollateralAuction(t *testing.T) {
|
||||||
// Setup
|
// 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())
|
require.NoError(t, 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")
|
|
||||||
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)))
|
|
||||||
|
|
||||||
k.cdpKeeper.ModifyCDP(ctx, addrs[0], "btc", i(3), i(16000))
|
_, err := tApp.GetPriceFeedKeeper().SetPrice(ctx, addrs[0], "btc", d("7999.99"), time.Now().Add(1*time.Hour))
|
||||||
|
require.NoError(t, err)
|
||||||
k.pricefeedKeeper.SetPrice(ctx, addrs[0], "btc", sdk.MustNewDecFromStr("7999.99"), tmtime.Now().Add(time.Hour*1))
|
require.NoError(t, tApp.GetPriceFeedKeeper().SetCurrentPrices(ctx, "btc"))
|
||||||
k.pricefeedKeeper.SetCurrentPrices(ctx, "btc")
|
|
||||||
|
|
||||||
// Run test function
|
// Run test function
|
||||||
auctionID, err := k.liquidatorKeeper.SeizeAndStartCollateralAuction(ctx, addrs[0], "btc")
|
auctionID, err := tApp.GetLiquidatorKeeper().SeizeAndStartCollateralAuction(ctx, addrs[0], "btc")
|
||||||
|
|
||||||
// Check CDP
|
// Check CDP
|
||||||
require.NoError(t, err)
|
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.True(t, found)
|
||||||
require.Equal(t, cdp.CollateralAmount, i(2)) // original amount - params.CollateralAuctionSize
|
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
|
require.Equal(t, cdp.Debt, i(10667)) // original debt scaled by amount of collateral removed
|
||||||
// Check auction exists
|
// Check auction exists
|
||||||
_, found = k.auctionKeeper.GetAuction(ctx, auctionID)
|
_, found = tApp.GetAuctionKeeper().GetAuction(ctx, auctionID)
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
// TODO check auction values are correct?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKeeper_StartDebtAuction(t *testing.T) {
|
func TestKeeper_StartDebtAuction(t *testing.T) {
|
||||||
// Setup
|
// Setup
|
||||||
ctx, k := setupTestKeepers()
|
tApp := app.NewTestApp()
|
||||||
k.liquidatorKeeper.SetParams(ctx, defaultParams())
|
tApp.InitializeFromGenesisStates(
|
||||||
|
NewLiquidatorGenState(),
|
||||||
|
)
|
||||||
|
keeper := tApp.GetLiquidatorKeeper()
|
||||||
|
ctx := tApp.NewContext(false, abci.Header{})
|
||||||
|
|
||||||
initSDebt := types.SeizedDebt{i(2000), i(0)}
|
initSDebt := types.SeizedDebt{i(2000), i(0)}
|
||||||
k.liquidatorKeeper.setSeizedDebt(ctx, initSDebt)
|
keeper.SetSeizedDebt(ctx, initSDebt)
|
||||||
|
|
||||||
// Execute
|
// Execute
|
||||||
auctionID, err := k.liquidatorKeeper.StartDebtAuction(ctx)
|
auctionID, err := keeper.StartDebtAuction(ctx)
|
||||||
|
|
||||||
// Check
|
// Check
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t,
|
require.Equal(t,
|
||||||
types.SeizedDebt{
|
types.SeizedDebt{
|
||||||
initSDebt.Total,
|
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)
|
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) {
|
func TestKeeper_partialSeizeCDP(t *testing.T) {
|
||||||
// Setup
|
// 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))
|
tApp.GetPriceFeedKeeper().SetPrice(ctx, addrs[0], "btc", d("7999.99"), tmtime.Now().Add(time.Hour*1))
|
||||||
k.pricefeedKeeper.SetCurrentPrices(ctx, "btc")
|
tApp.GetPriceFeedKeeper().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")
|
|
||||||
|
|
||||||
// Run test function
|
// 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
|
// Check
|
||||||
require.NoError(t, err)
|
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.True(t, found)
|
||||||
require.Equal(t, i(1), cdp.CollateralAmount)
|
require.Equal(t, i(1), cdp.CollateralAmount)
|
||||||
require.Equal(t, i(6000), cdp.Debt)
|
require.Equal(t, i(6000), cdp.Debt)
|
||||||
@ -126,12 +105,13 @@ func TestKeeper_partialSeizeCDP(t *testing.T) {
|
|||||||
|
|
||||||
func TestKeeper_GetSetSeizedDebt(t *testing.T) {
|
func TestKeeper_GetSetSeizedDebt(t *testing.T) {
|
||||||
// Setup
|
// Setup
|
||||||
ctx, k := setupTestKeepers()
|
tApp := app.NewTestApp()
|
||||||
|
ctx := tApp.NewContext(true, abci.Header{})
|
||||||
debt := types.SeizedDebt{i(234247645), i(2343)}
|
debt := types.SeizedDebt{i(234247645), i(2343)}
|
||||||
|
|
||||||
// Run test function
|
// Run test function
|
||||||
k.liquidatorKeeper.setSeizedDebt(ctx, debt)
|
tApp.GetLiquidatorKeeper().SetSeizedDebt(ctx, debt)
|
||||||
readDebt := k.liquidatorKeeper.GetSeizedDebt(ctx)
|
readDebt := tApp.GetLiquidatorKeeper().GetSeizedDebt(ctx)
|
||||||
|
|
||||||
// Check
|
// Check
|
||||||
require.Equal(t, debt, readDebt)
|
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
|
// Set the current price (if any) based on what's now in the store
|
||||||
for _, a := range data.Params.Markets {
|
for _, a := range data.Params.Markets {
|
||||||
if a.Active {
|
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 oracles
|
||||||
// - adding/removing assets from the pricefeed
|
// - adding/removing assets from the pricefeed
|
||||||
func NewKeeper(
|
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 {
|
) Keeper {
|
||||||
return Keeper{
|
return Keeper{
|
||||||
paramstore: paramstore.WithKeyTable(types.ParamKeyTable()),
|
paramstore: paramstore.WithKeyTable(types.ParamKeyTable()),
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package keeper
|
package keeper_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
@ -7,31 +7,28 @@ import (
|
|||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
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"
|
"github.com/kava-labs/kava/x/pricefeed/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestKeeper_SetGetMarket tests adding markets to the pricefeed, getting markets from the store
|
// TestKeeper_SetGetMarket tests adding markets to the pricefeed, getting markets from the store
|
||||||
func TestKeeper_SetGetMarket(t *testing.T) {
|
func TestKeeper_SetGetMarket(t *testing.T) {
|
||||||
helper := getMockApp(t, 0, types.GenesisState{}, nil)
|
tApp := app.NewTestApp()
|
||||||
header := abci.Header{
|
ctx := tApp.NewContext(true, abci.Header{})
|
||||||
Height: helper.mApp.LastBlockHeight() + 1,
|
keeper := tApp.GetPriceFeedKeeper()
|
||||||
Time: tmtime.Now()}
|
|
||||||
helper.mApp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
|
||||||
ctx := helper.mApp.BaseApp.NewContext(false, header)
|
|
||||||
|
|
||||||
mp := types.Params{
|
mp := types.Params{
|
||||||
Markets: types.Markets{
|
Markets: types.Markets{
|
||||||
types.Market{MarketID: "tstusd", BaseAsset: "tst", QuoteAsset: "usd", Oracles: types.Oracles{}, Active: true},
|
types.Market{MarketID: "tstusd", BaseAsset: "tst", QuoteAsset: "usd", Oracles: types.Oracles{}, Active: true},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
helper.keeper.SetParams(ctx, mp)
|
keeper.SetParams(ctx, mp)
|
||||||
markets := helper.keeper.GetMarketParams(ctx)
|
markets := keeper.GetMarketParams(ctx)
|
||||||
require.Equal(t, len(markets), 1)
|
require.Equal(t, len(markets), 1)
|
||||||
require.Equal(t, markets[0].MarketID, "tstusd")
|
require.Equal(t, markets[0].MarketID, "tstusd")
|
||||||
|
|
||||||
_, found := helper.keeper.GetMarket(ctx, "tstusd")
|
_, found := keeper.GetMarket(ctx, "tstusd")
|
||||||
require.Equal(t, found, true)
|
require.Equal(t, found, true)
|
||||||
|
|
||||||
mp = types.Params{
|
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},
|
types.Market{MarketID: "tst2usd", BaseAsset: "tst2", QuoteAsset: "usd", Oracles: types.Oracles{}, Active: true},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
helper.keeper.SetParams(ctx, mp)
|
keeper.SetParams(ctx, mp)
|
||||||
markets = helper.keeper.GetMarketParams(ctx)
|
markets = keeper.GetMarketParams(ctx)
|
||||||
require.Equal(t, len(markets), 2)
|
require.Equal(t, len(markets), 2)
|
||||||
require.Equal(t, markets[0].MarketID, "tstusd")
|
require.Equal(t, markets[0].MarketID, "tstusd")
|
||||||
require.Equal(t, markets[1].MarketID, "tst2usd")
|
require.Equal(t, markets[1].MarketID, "tst2usd")
|
||||||
|
|
||||||
_, found = helper.keeper.GetMarket(ctx, "nan")
|
_, found = keeper.GetMarket(ctx, "nan")
|
||||||
require.Equal(t, found, false)
|
require.Equal(t, found, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestKeeper_GetSetPrice Test Posting the price by an oracle
|
// TestKeeper_GetSetPrice Test Posting the price by an oracle
|
||||||
func TestKeeper_GetSetPrice(t *testing.T) {
|
func TestKeeper_GetSetPrice(t *testing.T) {
|
||||||
helper := getMockApp(t, 2, types.GenesisState{}, nil)
|
_, addrs := app.GeneratePrivKeyAddressPairs(2)
|
||||||
header := abci.Header{
|
tApp := app.NewTestApp()
|
||||||
Height: helper.mApp.LastBlockHeight() + 1,
|
ctx := tApp.NewContext(true, abci.Header{})
|
||||||
Time: tmtime.Now()}
|
keeper := tApp.GetPriceFeedKeeper()
|
||||||
helper.mApp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
|
||||||
ctx := helper.mApp.BaseApp.NewContext(false, header)
|
|
||||||
mp := types.Params{
|
mp := types.Params{
|
||||||
Markets: types.Markets{
|
Markets: types.Markets{
|
||||||
types.Market{MarketID: "tstusd", BaseAsset: "tst", QuoteAsset: "usd", Oracles: types.Oracles{}, Active: true},
|
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
|
// Set price by oracle 1
|
||||||
_, err := helper.keeper.SetPrice(
|
_, err := keeper.SetPrice(
|
||||||
ctx, helper.addrs[0], "tstusd",
|
ctx, addrs[0], "tstusd",
|
||||||
sdk.MustNewDecFromStr("0.33"),
|
sdk.MustNewDecFromStr("0.33"),
|
||||||
header.Time.Add(1*time.Hour))
|
time.Now().Add(1*time.Hour))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
// Get raw prices
|
// Get raw prices
|
||||||
rawPrices := helper.keeper.GetRawPrices(ctx, "tstusd")
|
rawPrices := keeper.GetRawPrices(ctx, "tstusd")
|
||||||
require.Equal(t, len(rawPrices), 1)
|
require.Equal(t, len(rawPrices), 1)
|
||||||
require.Equal(t, rawPrices[0].Price.Equal(sdk.MustNewDecFromStr("0.33")), true)
|
require.Equal(t, rawPrices[0].Price.Equal(sdk.MustNewDecFromStr("0.33")), true)
|
||||||
// Set price by oracle 2
|
// Set price by oracle 2
|
||||||
_, err = helper.keeper.SetPrice(
|
_, err = keeper.SetPrice(
|
||||||
ctx, helper.addrs[1], "tstusd",
|
ctx, addrs[1], "tstusd",
|
||||||
sdk.MustNewDecFromStr("0.35"),
|
sdk.MustNewDecFromStr("0.35"),
|
||||||
header.Time.Add(time.Hour*1))
|
time.Now().Add(time.Hour*1))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
rawPrices = helper.keeper.GetRawPrices(ctx, "tstusd")
|
rawPrices = keeper.GetRawPrices(ctx, "tstusd")
|
||||||
require.Equal(t, len(rawPrices), 2)
|
require.Equal(t, len(rawPrices), 2)
|
||||||
require.Equal(t, rawPrices[1].Price.Equal(sdk.MustNewDecFromStr("0.35")), true)
|
require.Equal(t, rawPrices[1].Price.Equal(sdk.MustNewDecFromStr("0.35")), true)
|
||||||
|
|
||||||
// Update Price by Oracle 1
|
// Update Price by Oracle 1
|
||||||
_, err = helper.keeper.SetPrice(
|
_, err = keeper.SetPrice(
|
||||||
ctx, helper.addrs[0], "tstusd",
|
ctx, addrs[0], "tstusd",
|
||||||
sdk.MustNewDecFromStr("0.37"),
|
sdk.MustNewDecFromStr("0.37"),
|
||||||
header.Time.Add(time.Hour*1))
|
time.Now().Add(time.Hour*1))
|
||||||
require.NoError(t, err)
|
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)
|
require.Equal(t, rawPrices[0].Price.Equal(sdk.MustNewDecFromStr("0.37")), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestKeeper_GetSetCurrentPrice Test Setting the median price of an Asset
|
// TestKeeper_GetSetCurrentPrice Test Setting the median price of an Asset
|
||||||
func TestKeeper_GetSetCurrentPrice(t *testing.T) {
|
func TestKeeper_GetSetCurrentPrice(t *testing.T) {
|
||||||
helper := getMockApp(t, 4, types.GenesisState{}, nil)
|
_, addrs := app.GeneratePrivKeyAddressPairs(4)
|
||||||
header := abci.Header{
|
tApp := app.NewTestApp()
|
||||||
Height: helper.mApp.LastBlockHeight() + 1,
|
ctx := tApp.NewContext(true, abci.Header{})
|
||||||
Time: tmtime.Now()}
|
keeper := tApp.GetPriceFeedKeeper()
|
||||||
helper.mApp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
|
||||||
ctx := helper.mApp.BaseApp.NewContext(false, header)
|
|
||||||
mp := types.Params{
|
mp := types.Params{
|
||||||
Markets: types.Markets{
|
Markets: types.Markets{
|
||||||
types.Market{MarketID: "tstusd", BaseAsset: "tst", QuoteAsset: "usd", Oracles: types.Oracles{}, Active: true},
|
types.Market{MarketID: "tstusd", BaseAsset: "tst", QuoteAsset: "usd", Oracles: types.Oracles{}, Active: true},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
helper.keeper.SetParams(ctx, mp)
|
keeper.SetParams(ctx, mp)
|
||||||
helper.keeper.SetPrice(
|
keeper.SetPrice(
|
||||||
ctx, helper.addrs[0], "tstusd",
|
ctx, addrs[0], "tstusd",
|
||||||
sdk.MustNewDecFromStr("0.33"),
|
sdk.MustNewDecFromStr("0.33"),
|
||||||
header.Time.Add(time.Hour*1))
|
time.Now().Add(time.Hour*1))
|
||||||
helper.keeper.SetPrice(
|
keeper.SetPrice(
|
||||||
ctx, helper.addrs[1], "tstusd",
|
ctx, addrs[1], "tstusd",
|
||||||
sdk.MustNewDecFromStr("0.35"),
|
sdk.MustNewDecFromStr("0.35"),
|
||||||
header.Time.Add(time.Hour*1))
|
time.Now().Add(time.Hour*1))
|
||||||
helper.keeper.SetPrice(
|
keeper.SetPrice(
|
||||||
ctx, helper.addrs[2], "tstusd",
|
ctx, addrs[2], "tstusd",
|
||||||
sdk.MustNewDecFromStr("0.34"),
|
sdk.MustNewDecFromStr("0.34"),
|
||||||
header.Time.Add(time.Hour*1))
|
time.Now().Add(time.Hour*1))
|
||||||
// Set current price
|
// Set current price
|
||||||
err := helper.keeper.SetCurrentPrices(ctx, "tstusd")
|
err := keeper.SetCurrentPrices(ctx, "tstusd")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
// Get Current price
|
// 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)
|
require.Equal(t, price.Price.Equal(sdk.MustNewDecFromStr("0.34")), true)
|
||||||
|
|
||||||
// Even number of oracles
|
// Even number of oracles
|
||||||
helper.keeper.SetPrice(
|
keeper.SetPrice(
|
||||||
ctx, helper.addrs[3], "tstusd",
|
ctx, addrs[3], "tstusd",
|
||||||
sdk.MustNewDecFromStr("0.36"),
|
sdk.MustNewDecFromStr("0.36"),
|
||||||
header.Time.Add(time.Hour*1))
|
time.Now().Add(time.Hour*1))
|
||||||
err = helper.keeper.SetCurrentPrices(ctx, "tstusd")
|
err = keeper.SetCurrentPrices(ctx, "tstusd")
|
||||||
require.NoError(t, err)
|
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)
|
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