2021-07-15 14:05:54 +00:00
|
|
|
package testutil
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
|
|
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
|
|
|
"github.com/cosmos/cosmos-sdk/x/auth/vesting"
|
2021-07-26 19:07:24 +00:00
|
|
|
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
|
2021-07-15 14:05:54 +00:00
|
|
|
"github.com/cosmos/cosmos-sdk/x/staking"
|
|
|
|
supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported"
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
abci "github.com/tendermint/tendermint/abci/types"
|
|
|
|
"github.com/tendermint/tendermint/crypto/ed25519"
|
|
|
|
|
|
|
|
"github.com/kava-labs/kava/app"
|
|
|
|
"github.com/kava-labs/kava/x/cdp"
|
2021-07-26 19:07:24 +00:00
|
|
|
"github.com/kava-labs/kava/x/committee"
|
2021-07-15 14:05:54 +00:00
|
|
|
"github.com/kava-labs/kava/x/hard"
|
|
|
|
"github.com/kava-labs/kava/x/incentive"
|
|
|
|
"github.com/kava-labs/kava/x/swap"
|
|
|
|
)
|
|
|
|
|
|
|
|
type IntegrationTester struct {
|
|
|
|
suite.Suite
|
|
|
|
App app.TestApp
|
|
|
|
Ctx sdk.Context
|
|
|
|
}
|
|
|
|
|
2021-07-26 19:07:24 +00:00
|
|
|
func (suite *IntegrationTester) SetupSuite() {
|
|
|
|
config := sdk.GetConfig()
|
|
|
|
app.SetBech32AddressPrefixes(config)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTester) StartChain(genesisTime time.Time, genesisStates ...app.GenesisState) {
|
|
|
|
suite.App = app.NewTestApp()
|
|
|
|
|
|
|
|
suite.App.InitializeFromGenesisStatesWithTime(
|
|
|
|
genesisTime,
|
|
|
|
genesisStates...,
|
|
|
|
)
|
|
|
|
|
|
|
|
suite.Ctx = suite.App.NewContext(false, abci.Header{Height: 1, Time: genesisTime})
|
|
|
|
}
|
|
|
|
|
2021-07-15 14:05:54 +00:00
|
|
|
func (suite *IntegrationTester) NextBlockAt(blockTime time.Time) {
|
|
|
|
if !suite.Ctx.BlockTime().Before(blockTime) {
|
|
|
|
panic(fmt.Sprintf("new block time %s must be after current %s", blockTime, suite.Ctx.BlockTime()))
|
|
|
|
}
|
|
|
|
blockHeight := suite.Ctx.BlockHeight() + 1
|
|
|
|
|
|
|
|
_ = suite.App.EndBlocker(suite.Ctx, abci.RequestEndBlock{})
|
|
|
|
|
|
|
|
suite.Ctx = suite.Ctx.WithBlockTime(blockTime).WithBlockHeight(blockHeight)
|
|
|
|
|
|
|
|
_ = suite.App.BeginBlocker(suite.Ctx, abci.RequestBeginBlock{}) // height and time in RequestBeginBlock are ignored by module begin blockers
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTester) NextBlockAfter(blockDuration time.Duration) {
|
|
|
|
suite.NextBlockAt(suite.Ctx.BlockTime().Add(blockDuration))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTester) DeliverIncentiveMsg(msg sdk.Msg) error {
|
|
|
|
handler := incentive.NewHandler(suite.App.GetIncentiveKeeper())
|
|
|
|
_, err := handler(suite.Ctx, msg)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTester) DeliverMsgCreateValidator(address sdk.ValAddress, selfDelegation sdk.Coin) error {
|
|
|
|
msg := staking.NewMsgCreateValidator(
|
|
|
|
address,
|
|
|
|
ed25519.GenPrivKey().PubKey(),
|
|
|
|
selfDelegation,
|
|
|
|
staking.Description{},
|
|
|
|
staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
|
|
|
|
sdk.NewInt(1_000_000),
|
|
|
|
)
|
|
|
|
handler := staking.NewHandler(suite.App.GetStakingKeeper())
|
|
|
|
_, err := handler(suite.Ctx, msg)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTester) DeliverMsgDelegate(delegator sdk.AccAddress, validator sdk.ValAddress, amount sdk.Coin) error {
|
|
|
|
msg := staking.NewMsgDelegate(
|
|
|
|
delegator,
|
|
|
|
validator,
|
|
|
|
amount,
|
|
|
|
)
|
|
|
|
handleStakingMsg := staking.NewHandler(suite.App.GetStakingKeeper())
|
|
|
|
_, err := handleStakingMsg(suite.Ctx, msg)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTester) DeliverSwapMsgDeposit(depositor sdk.AccAddress, tokenA, tokenB sdk.Coin, slippage sdk.Dec) error {
|
|
|
|
msg := swap.NewMsgDeposit(
|
|
|
|
depositor,
|
|
|
|
tokenA,
|
|
|
|
tokenB,
|
|
|
|
slippage,
|
|
|
|
suite.Ctx.BlockTime().Add(time.Hour).Unix(), // ensure msg will not fail due to short deadline
|
|
|
|
)
|
|
|
|
_, err := swap.NewHandler(suite.App.GetSwapKeeper())(suite.Ctx, msg)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-07-26 19:07:24 +00:00
|
|
|
func (suite *IntegrationTester) DeliverHardMsgDeposit(owner sdk.AccAddress, deposit sdk.Coins) error {
|
|
|
|
msg := hard.NewMsgDeposit(owner, deposit)
|
|
|
|
_, err := hard.NewHandler(suite.App.GetHardKeeper())(suite.Ctx, msg)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTester) DeliverHardMsgBorrow(owner sdk.AccAddress, borrow sdk.Coins) error {
|
|
|
|
msg := hard.NewMsgBorrow(owner, borrow)
|
2021-07-15 14:05:54 +00:00
|
|
|
_, err := hard.NewHandler(suite.App.GetHardKeeper())(suite.Ctx, msg)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-07-26 19:07:24 +00:00
|
|
|
func (suite *IntegrationTester) DeliverHardMsgRepay(owner sdk.AccAddress, repay sdk.Coins) error {
|
|
|
|
msg := hard.NewMsgRepay(owner, owner, repay)
|
|
|
|
_, err := hard.NewHandler(suite.App.GetHardKeeper())(suite.Ctx, msg)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTester) DeliverHardMsgWithdraw(owner sdk.AccAddress, withdraw sdk.Coins) error {
|
|
|
|
msg := hard.NewMsgRepay(owner, owner, withdraw)
|
2021-07-15 14:05:54 +00:00
|
|
|
_, err := hard.NewHandler(suite.App.GetHardKeeper())(suite.Ctx, msg)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTester) DeliverMsgCreateCDP(owner sdk.AccAddress, collateral, principal sdk.Coin, collateralType string) error {
|
|
|
|
msg := cdp.NewMsgCreateCDP(owner, collateral, principal, collateralType)
|
|
|
|
_, err := cdp.NewHandler(suite.App.GetCDPKeeper())(suite.Ctx, msg)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-07-26 19:07:24 +00:00
|
|
|
func (suite *IntegrationTester) DeliverCDPMsgRepay(owner sdk.AccAddress, collateralType string, payment sdk.Coin) error {
|
|
|
|
msg := cdp.NewMsgRepayDebt(owner, collateralType, payment)
|
|
|
|
_, err := cdp.NewHandler(suite.App.GetCDPKeeper())(suite.Ctx, msg)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTester) DeliverCDPMsgBorrow(owner sdk.AccAddress, collateralType string, draw sdk.Coin) error {
|
|
|
|
msg := cdp.NewMsgDrawDebt(owner, collateralType, draw)
|
|
|
|
_, err := cdp.NewHandler(suite.App.GetCDPKeeper())(suite.Ctx, msg)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTester) ProposeAndVoteOnNewParams(voter sdk.AccAddress, committeeID uint64, changes []paramtypes.ParamChange) {
|
|
|
|
|
|
|
|
propose := committee.NewMsgSubmitProposal(
|
|
|
|
paramtypes.NewParameterChangeProposal(
|
|
|
|
"test title",
|
|
|
|
"test description",
|
|
|
|
changes,
|
|
|
|
),
|
|
|
|
voter,
|
|
|
|
committeeID,
|
|
|
|
)
|
|
|
|
|
|
|
|
handleMsg := committee.NewHandler(suite.App.GetCommitteeKeeper())
|
|
|
|
|
|
|
|
res, err := handleMsg(suite.Ctx, propose)
|
|
|
|
suite.NoError(err)
|
|
|
|
|
|
|
|
proposalID := committee.Uint64FromBytes(res.Data)
|
|
|
|
vote := committee.NewMsgVote(voter, proposalID, committee.Yes)
|
|
|
|
|
|
|
|
_, err = handleMsg(suite.Ctx, vote)
|
|
|
|
suite.NoError(err)
|
|
|
|
}
|
|
|
|
|
2021-07-15 14:05:54 +00:00
|
|
|
func (suite *IntegrationTester) GetAccount(addr sdk.AccAddress) authexported.Account {
|
|
|
|
ak := suite.App.GetAccountKeeper()
|
|
|
|
return ak.GetAccount(suite.Ctx, addr)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTester) GetModuleAccount(name string) supplyexported.ModuleAccountI {
|
|
|
|
sk := suite.App.GetSupplyKeeper()
|
|
|
|
return sk.GetModuleAccount(suite.Ctx, name)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTester) GetBalance(address sdk.AccAddress) sdk.Coins {
|
|
|
|
acc := suite.App.GetAccountKeeper().GetAccount(suite.Ctx, address)
|
|
|
|
if acc != nil {
|
|
|
|
return acc.GetCoins()
|
|
|
|
} else {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTester) ErrorIs(err, target error) bool {
|
|
|
|
return suite.Truef(errors.Is(err, target), "err didn't match: %s, it was: %s", target, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTester) BalanceEquals(address sdk.AccAddress, expected sdk.Coins) {
|
|
|
|
acc := suite.App.GetAccountKeeper().GetAccount(suite.Ctx, address)
|
|
|
|
suite.Require().NotNil(acc, "expected account to not be nil")
|
|
|
|
suite.Equalf(expected, acc.GetCoins(), "expected account balance to equal coins %s, but got %s", expected, acc.GetCoins())
|
|
|
|
}
|
|
|
|
|
2021-07-26 19:07:24 +00:00
|
|
|
func (suite *IntegrationTester) BalanceInEpsilon(address sdk.AccAddress, expected sdk.Coins, epsilon float64) {
|
|
|
|
actual := suite.GetBalance(address)
|
|
|
|
|
|
|
|
allDenoms := expected.Add(actual...)
|
|
|
|
for _, coin := range allDenoms {
|
|
|
|
suite.InEpsilonf(
|
|
|
|
expected.AmountOf(coin.Denom).Int64(),
|
|
|
|
actual.AmountOf(coin.Denom).Int64(),
|
|
|
|
epsilon,
|
|
|
|
"expected balance to be within %f%% of coins %s, but got %s", epsilon*100, expected, actual,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-15 14:05:54 +00:00
|
|
|
func (suite *IntegrationTester) VestingPeriodsEqual(address sdk.AccAddress, expectedPeriods vesting.Periods) {
|
|
|
|
acc := suite.App.GetAccountKeeper().GetAccount(suite.Ctx, address)
|
|
|
|
suite.Require().NotNil(acc, "expected vesting account not to be nil")
|
|
|
|
vacc, ok := acc.(*vesting.PeriodicVestingAccount)
|
|
|
|
suite.Require().True(ok, "expected vesting account to be type PeriodicVestingAccount")
|
|
|
|
suite.Equal(expectedPeriods, vacc.VestingPeriods)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTester) SwapRewardEquals(owner sdk.AccAddress, expected sdk.Coins) {
|
|
|
|
claim, found := suite.App.GetIncentiveKeeper().GetSwapClaim(suite.Ctx, owner)
|
|
|
|
suite.Require().Truef(found, "expected swap claim to be found for %s", owner)
|
|
|
|
suite.Equalf(expected, claim.Reward, "expected swap claim reward to be %s, but got %s", expected, claim.Reward)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTester) DelegatorRewardEquals(owner sdk.AccAddress, expected sdk.Coins) {
|
|
|
|
claim, found := suite.App.GetIncentiveKeeper().GetDelegatorClaim(suite.Ctx, owner)
|
|
|
|
suite.Require().Truef(found, "expected delegator claim to be found for %s", owner)
|
|
|
|
suite.Equalf(expected, claim.Reward, "expected delegator claim reward to be %s, but got %s", expected, claim.Reward)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTester) HardRewardEquals(owner sdk.AccAddress, expected sdk.Coins) {
|
|
|
|
claim, found := suite.App.GetIncentiveKeeper().GetHardLiquidityProviderClaim(suite.Ctx, owner)
|
|
|
|
suite.Require().Truef(found, "expected delegator claim to be found for %s", owner)
|
|
|
|
suite.Equalf(expected, claim.Reward, "expected delegator claim reward to be %s, but got %s", expected, claim.Reward)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTester) USDXRewardEquals(owner sdk.AccAddress, expected sdk.Coin) {
|
|
|
|
claim, found := suite.App.GetIncentiveKeeper().GetUSDXMintingClaim(suite.Ctx, owner)
|
|
|
|
suite.Require().Truef(found, "expected delegator claim to be found for %s", owner)
|
|
|
|
suite.Equalf(expected, claim.Reward, "expected delegator claim reward to be %s, but got %s", expected, claim.Reward)
|
|
|
|
}
|