Update hard genesis state (#777)

* feat: update hard genesis state and init/export methods

* address review comments
This commit is contained in:
Kevin Davis 2021-01-22 22:17:40 -07:00 committed by GitHub
parent f89b8797ed
commit dc330d02bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 533 additions and 137 deletions

View File

@ -9,86 +9,172 @@ import (
const (
AttributeKeyBlockHeight = types.AttributeKeyBlockHeight
AttributeKeyBorrow = types.AttributeKeyBorrow
AttributeKeyBorrowCoins = types.AttributeKeyBorrowCoins
AttributeKeyBorrower = types.AttributeKeyBorrower
AttributeKeyDeposit = types.AttributeKeyDeposit
AttributeKeyDepositCoins = types.AttributeKeyDepositCoins
AttributeKeyDepositDenom = types.AttributeKeyDepositDenom
AttributeKeyDepositor = types.AttributeKeyDepositor
AttributeKeyRepayCoins = types.AttributeKeyRepayCoins
AttributeKeyRewardsDistribution = types.AttributeKeyRewardsDistribution
AttributeKeySender = types.AttributeKeySender
AttributeValueCategory = types.AttributeValueCategory
DefaultParamspace = types.DefaultParamspace
DelegatorAccount = types.DelegatorAccount
EventTypeDeleteHardDeposit = types.EventTypeDeleteHardDeposit
EventTypeDepositLiquidation = types.EventTypeDepositLiquidation
EventTypeHardBorrow = types.EventTypeHardBorrow
EventTypeHardDelegatorDistribution = types.EventTypeHardDelegatorDistribution
EventTypeHardDeposit = types.EventTypeHardDeposit
EventTypeHardLPDistribution = types.EventTypeHardLPDistribution
EventTypeHardRepay = types.EventTypeHardRepay
EventTypeHardWithdrawal = types.EventTypeHardWithdrawal
LPAccount = types.LPAccount
LiquidatorAccount = types.LiquidatorAccount
ModuleAccountName = types.ModuleAccountName
ModuleName = types.ModuleName
QuerierRoute = types.QuerierRoute
QueryGetBorrows = types.QueryGetBorrows
QueryGetDeposits = types.QueryGetDeposits
QueryGetModuleAccounts = types.QueryGetModuleAccounts
QueryGetParams = types.QueryGetParams
QueryGetTotalBorrowed = types.QueryGetTotalBorrowed
QueryGetTotalDeposited = types.QueryGetTotalDeposited
RouterKey = types.RouterKey
StoreKey = types.StoreKey
)
var (
// function aliases
APYToSPY = keeper.APYToSPY
CalculateBorrowInterestFactor = keeper.CalculateBorrowInterestFactor
CalculateBorrowRate = keeper.CalculateBorrowRate
CalculateSupplyInterestFactor = keeper.CalculateSupplyInterestFactor
CalculateUtilizationRatio = keeper.CalculateUtilizationRatio
NewKeeper = keeper.NewKeeper
NewQuerier = keeper.NewQuerier
CalculateUtilizationRatio = keeper.CalculateUtilizationRatio
CalculateBorrowRate = keeper.CalculateBorrowRate
CalculateBorrowInterestFactor = keeper.CalculateBorrowInterestFactor
CalculateSupplyInterestFactor = keeper.CalculateSupplyInterestFactor
APYToSPY = keeper.APYToSPY
DefaultGenesisState = types.DefaultGenesisState
DefaultParams = types.DefaultParams
DepositTypeIteratorKey = types.DepositTypeIteratorKey
GetBorrowByLtvKey = types.GetBorrowByLtvKey
GetTotalVestingPeriodLength = types.GetTotalVestingPeriodLength
NewBorrow = types.NewBorrow
NewBorrowInterestFactor = types.NewBorrowInterestFactor
NewBorrowLimit = types.NewBorrowLimit
NewInterestRateModel = types.NewInterestRateModel
NewDeposit = types.NewDeposit
NewGenesisAccumulationTime = types.NewGenesisAccumulationTime
NewGenesisState = types.NewGenesisState
NewInterestRateModel = types.NewInterestRateModel
NewMoneyMarket = types.NewMoneyMarket
NewMsgBorrow = types.NewMsgBorrow
NewMsgDeposit = types.NewMsgDeposit
NewMsgLiquidate = types.NewMsgLiquidate
NewMsgRepay = types.NewMsgRepay
NewMsgWithdraw = types.NewMsgWithdraw
NewMultiHARDHooks = types.NewMultiHARDHooks
NewParams = types.NewParams
NewPeriod = types.NewPeriod
NewMoneyMarket = types.NewMoneyMarket
NewQueryAccountParams = types.NewQueryAccountParams
NewQueryBorrowsParams = types.NewQueryBorrowsParams
NewQueryDepositsParams = types.NewQueryDepositsParams
NewQueryTotalBorrowedParams = types.NewQueryTotalBorrowedParams
NewQueryTotalDepositedParams = types.NewQueryTotalDepositedParams
NewSupplyInterestFactor = types.NewSupplyInterestFactor
NewValuationMap = types.NewValuationMap
ParamKeyTable = types.ParamKeyTable
RegisterCodec = types.RegisterCodec
// variable aliases
BorrowInterestFactorPrefix = types.BorrowInterestFactorPrefix
BorrowedCoinsPrefix = types.BorrowedCoinsPrefix
BorrowsKeyPrefix = types.BorrowsKeyPrefix
DefaultActive = types.DefaultActive
DefaultAccumulationTimes = types.DefaultAccumulationTimes
DefaultBorrows = types.DefaultBorrows
DefaultCheckLtvIndexCount = types.DefaultCheckLtvIndexCount
DefaultDeposits = types.DefaultDeposits
DefaultMoneyMarkets = types.DefaultMoneyMarkets
DefaultPreviousBlockTime = types.DefaultPreviousBlockTime
DefaultTotalBorrowed = types.DefaultTotalBorrowed
DefaultTotalReserves = types.DefaultTotalReserves
DefaultTotalSupplied = types.DefaultTotalSupplied
DepositsKeyPrefix = types.DepositsKeyPrefix
ErrAccountNotFound = types.ErrAccountNotFound
ErrBorrowEmptyCoins = types.ErrBorrowEmptyCoins
ErrBorrowExceedsAvailableBalance = types.ErrBorrowExceedsAvailableBalance
ErrBorrowNotFound = types.ErrBorrowNotFound
ErrBorrowNotLiquidatable = types.ErrBorrowNotLiquidatable
ErrBorrowedCoinsNotFound = types.ErrBorrowedCoinsNotFound
ErrDepositNotFound = types.ErrDepositNotFound
ErrDepositsNotFound = types.ErrDepositsNotFound
ErrGreaterThanAssetBorrowLimit = types.ErrGreaterThanAssetBorrowLimit
ErrInsufficientBalanceForBorrow = types.ErrInsufficientBalanceForBorrow
ErrInsufficientBalanceForRepay = types.ErrInsufficientBalanceForRepay
ErrInsufficientCoins = types.ErrInsufficientCoins
ErrInsufficientLoanToValue = types.ErrInsufficientLoanToValue
ErrInsufficientModAccountBalance = types.ErrInsufficientModAccountBalance
ErrInvaliWithdrawAmount = types.ErrInvalidWithdrawAmount
ErrInvalidAccountType = types.ErrInvalidAccountType
ErrInvalidDepositDenom = types.ErrInvalidDepositDenom
ErrInvalidReceiver = types.ErrInvalidReceiver
ErrInvalidRepaymentDenom = types.ErrInvalidRepaymentDenom
ErrInvalidWithdrawAmount = types.ErrInvalidWithdrawAmount
ErrInvalidWithdrawDenom = types.ErrInvalidWithdrawDenom
ErrMarketNotFound = types.ErrMarketNotFound
ErrMoneyMarketNotFound = types.ErrMoneyMarketNotFound
ErrNegativeBorrowedCoins = types.ErrNegativeBorrowedCoins
ErrNegativeSuppliedCoins = types.ErrNegativeSuppliedCoins
ErrPreviousAccrualTimeNotFound = types.ErrPreviousAccrualTimeNotFound
ErrPriceNotFound = types.ErrPriceNotFound
ErrSuppliedCoinsNotFound = types.ErrSuppliedCoinsNotFound
GovDenom = types.GovDenom
KeyActive = types.KeyActive
KeyCheckLtvIndexCount = types.KeyCheckLtvIndexCount
KeyMoneyMarkets = types.KeyMoneyMarkets
LtvIndexPrefix = types.LtvIndexPrefix
ModuleCdc = types.ModuleCdc
MoneyMarketsPrefix = types.MoneyMarketsPrefix
PreviousAccrualTimePrefix = types.PreviousAccrualTimePrefix
PreviousBlockTimeKey = types.PreviousBlockTimeKey
SuppliedCoinsPrefix = types.SuppliedCoinsPrefix
SupplyInterestFactorPrefix = types.SupplyInterestFactorPrefix
TotalReservesPrefix = types.TotalReservesPrefix
)
type (
Keeper = keeper.Keeper
AccountKeeper = types.AccountKeeper
Borrow = types.Borrow
MoneyMarket = types.MoneyMarket
MoneyMarkets = types.MoneyMarkets
Deposit = types.Deposit
GenesisState = types.GenesisState
MsgDeposit = types.MsgDeposit
MsgWithdraw = types.MsgWithdraw
Params = types.Params
QueryAccountParams = types.QueryAccountParams
StakingKeeper = types.StakingKeeper
SupplyKeeper = types.SupplyKeeper
Keeper = keeper.Keeper
LiqData = keeper.LiqData
AccountKeeper = types.AccountKeeper
AuctionKeeper = types.AuctionKeeper
Borrow = types.Borrow
BorrowInterestFactor = types.BorrowInterestFactor
BorrowInterestFactors = types.BorrowInterestFactors
BorrowLimit = types.BorrowLimit
Borrows = types.Borrows
Deposit = types.Deposit
Deposits = types.Deposits
GenesisAccumulationTime = types.GenesisAccumulationTime
GenesisAccumulationTimes = types.GenesisAccumulationTimes
GenesisState = types.GenesisState
HARDHooks = types.HARDHooks
InterestRateModel = types.InterestRateModel
InterestRateModels = types.InterestRateModels
MoneyMarket = types.MoneyMarket
MoneyMarkets = types.MoneyMarkets
MsgBorrow = types.MsgBorrow
MsgDeposit = types.MsgDeposit
MsgLiquidate = types.MsgLiquidate
MsgRepay = types.MsgRepay
MsgWithdraw = types.MsgWithdraw
MultiHARDHooks = types.MultiHARDHooks
Params = types.Params
PricefeedKeeper = types.PricefeedKeeper
QueryAccountParams = types.QueryAccountParams
QueryBorrowsParams = types.QueryBorrowsParams
QueryDepositsParams = types.QueryDepositsParams
QueryTotalBorrowedParams = types.QueryTotalBorrowedParams
QueryTotalDepositedParams = types.QueryTotalDepositedParams
StakingKeeper = types.StakingKeeper
SupplyInterestFactor = types.SupplyInterestFactor
SupplyInterestFactors = types.SupplyInterestFactors
SupplyKeeper = types.SupplyKeeper
ValuationMap = types.ValuationMap
)

View File

@ -16,15 +16,28 @@ func InitGenesis(ctx sdk.Context, k Keeper, supplyKeeper types.SupplyKeeper, gs
k.SetParams(ctx, gs.Params)
// only set the previous block time if it's different than default
if !gs.PreviousBlockTime.Equal(DefaultPreviousBlockTime) {
k.SetPreviousBlockTime(ctx, gs.PreviousBlockTime)
}
for _, mm := range gs.Params.MoneyMarkets {
k.SetMoneyMarket(ctx, mm.Denom, mm)
}
for _, gat := range gs.PreviousAccumulationTimes {
k.SetPreviousAccrualTime(ctx, gat.CollateralType, gat.PreviousAccumulationTime)
k.SetSupplyInterestFactor(ctx, gat.CollateralType, gat.SupplyInterestFactor)
k.SetBorrowInterestFactor(ctx, gat.CollateralType, gat.BorrowInterestFactor)
}
for _, deposit := range gs.Deposits {
k.SetDeposit(ctx, deposit)
}
for _, borrow := range gs.Borrows {
k.SetBorrow(ctx, borrow)
}
k.SetSuppliedCoins(ctx, gs.TotalSupplied)
k.SetBorrowedCoins(ctx, gs.TotalBorrowed)
k.SetTotalReserves(ctx, gs.TotalReserves)
// check if the module account exists
LPModuleAcc := supplyKeeper.GetModuleAccount(ctx, LPAccount)
if LPModuleAcc == nil {
@ -54,9 +67,53 @@ func InitGenesis(ctx sdk.Context, k Keeper, supplyKeeper types.SupplyKeeper, gs
// ExportGenesis export genesis state for hard module
func ExportGenesis(ctx sdk.Context, k Keeper) GenesisState {
params := k.GetParams(ctx)
previousBlockTime, found := k.GetPreviousBlockTime(ctx)
gats := types.GenesisAccumulationTimes{}
deposits := types.Deposits{}
borrows := types.Borrows{}
k.IterateDeposits(ctx, func(d types.Deposit) bool {
deposits = append(deposits, d)
return false
})
k.IterateBorrows(ctx, func(b types.Borrow) bool {
borrows = append(borrows, b)
return false
})
totalSupplied, found := k.GetSuppliedCoins(ctx)
if !found {
previousBlockTime = DefaultPreviousBlockTime
totalSupplied = DefaultTotalSupplied
}
return NewGenesisState(params, previousBlockTime)
totalBorrowed, found := k.GetBorrowedCoins(ctx)
if !found {
totalBorrowed = DefaultTotalBorrowed
}
totalReserves, found := k.GetTotalReserves(ctx)
if !found {
totalReserves = DefaultTotalReserves
}
for _, mm := range params.MoneyMarkets {
supplyFactor, f := k.GetSupplyInterestFactor(ctx, mm.Denom)
if !f {
supplyFactor = sdk.ZeroDec()
}
borrowFactor, f := k.GetBorrowInterestFactor(ctx, mm.Denom)
if !f {
borrowFactor = sdk.ZeroDec()
}
previousAccrualTime, f := k.GetPreviousAccrualTime(ctx, mm.Denom)
if !f {
previousAccrualTime = ctx.BlockTime()
}
gat := types.NewGenesisAccumulationTime(mm.Denom, previousAccrualTime, supplyFactor, borrowFactor)
gats = append(gats, gat)
}
return NewGenesisState(
params, gats, deposits, borrows,
totalSupplied, totalBorrowed, totalReserves,
)
}

View File

@ -261,7 +261,6 @@ func (suite *KeeperTestSuite) TestBorrow() {
// hard module genesis state
hardGS := types.NewGenesisState(types.NewParams(
true,
types.MoneyMarkets{
types.NewMoneyMarket("usdx", types.NewBorrowLimit(true, tc.args.usdxBorrowLimit, sdk.MustNewDecFromStr("1")), "usdx:usd", sdk.NewInt(USDX_CF), sdk.NewInt(USDX_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
types.NewMoneyMarket("busd", types.NewBorrowLimit(false, sdk.NewDec(100000000*BUSD_CF), sdk.MustNewDecFromStr("1")), "busd:usd", sdk.NewInt(BUSD_CF), sdk.NewInt(BUSD_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
@ -271,7 +270,9 @@ func (suite *KeeperTestSuite) TestBorrow() {
types.NewMoneyMarket("xyz", types.NewBorrowLimit(false, sdk.NewDec(1), tc.args.loanToValueBNB), "xyz:usd", sdk.NewInt(1), sdk.NewInt(1), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
},
0, // LTV counter
), types.DefaultPreviousBlockTime)
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
)
// Pricefeed module genesis state
pricefeedGS := pricefeed.GenesisState{

View File

@ -105,7 +105,6 @@ func (suite *KeeperTestSuite) TestDeposit() {
authGS := app.NewAuthGenState([]sdk.AccAddress{tc.args.depositor}, []sdk.Coins{sdk.NewCoins(sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000)))})
loanToValue, _ := sdk.NewDecFromStr("0.6")
hardGS := types.NewGenesisState(types.NewParams(
true,
types.MoneyMarkets{
types.NewMoneyMarket("usdx", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "usdx:usd", sdk.NewInt(1000000), sdk.NewInt(USDX_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
types.NewMoneyMarket("ukava", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "kava:usd", sdk.NewInt(1000000), sdk.NewInt(KAVA_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
@ -113,7 +112,9 @@ func (suite *KeeperTestSuite) TestDeposit() {
types.NewMoneyMarket("btcb", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "btcb:usd", sdk.NewInt(1000000), sdk.NewInt(BTCB_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
},
0, // LTV counter
), types.DefaultPreviousBlockTime)
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
)
// Pricefeed module genesis state
pricefeedGS := pricefeed.GenesisState{

View File

@ -78,10 +78,10 @@ func (k Keeper) AccrueInterest(ctx sdk.Context, denom string) error {
borrowedPrior = sdk.NewCoin(denom, borrowedCoinsPrior.AmountOf(denom))
}
reservesPrior, foundReservesPrior := k.GetTotalReserves(ctx, denom)
reservesPrior, foundReservesPrior := k.GetTotalReserves(ctx)
if !foundReservesPrior {
newReservesPrior := sdk.NewCoin(denom, sdk.ZeroInt())
k.SetTotalReserves(ctx, denom, newReservesPrior)
newReservesPrior := sdk.NewCoins()
k.SetTotalReserves(ctx, newReservesPrior)
reservesPrior = newReservesPrior
}
@ -106,7 +106,7 @@ func (k Keeper) AccrueInterest(ctx sdk.Context, denom string) error {
}
// GetBorrowRate calculates the current interest rate based on utilization (the fraction of supply that has been borrowed)
borrowRateApy, err := CalculateBorrowRate(mm.InterestRateModel, sdk.NewDecFromInt(cashPrior), sdk.NewDecFromInt(borrowedPrior.Amount), sdk.NewDecFromInt(reservesPrior.Amount))
borrowRateApy, err := CalculateBorrowRate(mm.InterestRateModel, sdk.NewDecFromInt(cashPrior), sdk.NewDecFromInt(borrowedPrior.Amount), sdk.NewDecFromInt(reservesPrior.AmountOf(denom)))
if err != nil {
return err
}
@ -127,14 +127,14 @@ func (k Keeper) AccrueInterest(ctx sdk.Context, denom string) error {
// Calculate supply interest factor and update
supplyInterestNew := interestBorrowAccumulated.Sub(reservesNew)
supplyInterestFactor := CalculateSupplyInterestFactor(supplyInterestNew.ToDec(), cashPrior.ToDec(), borrowedPrior.Amount.ToDec(), reservesPrior.Amount.ToDec())
supplyInterestFactor := CalculateSupplyInterestFactor(supplyInterestNew.ToDec(), cashPrior.ToDec(), borrowedPrior.Amount.ToDec(), reservesPrior.AmountOf(denom).ToDec())
supplyInterestFactorNew := supplyInterestFactorPrior.Mul(supplyInterestFactor)
k.SetSupplyInterestFactor(ctx, denom, supplyInterestFactorNew)
// Update accural keys in store
k.IncrementBorrowedCoins(ctx, totalBorrowInterestAccumulated)
k.IncrementSuppliedCoins(ctx, sdk.NewCoins(sdk.NewCoin(denom, supplyInterestNew)))
k.SetTotalReserves(ctx, denom, reservesPrior.Add(sdk.NewCoin(mm.Denom, reservesNew)))
k.SetTotalReserves(ctx, reservesPrior.Add(sdk.NewCoin(denom, reservesNew)))
k.SetPreviousAccrualTime(ctx, denom, ctx.BlockTime())
return nil

View File

@ -711,7 +711,6 @@ func (suite *KeeperTestSuite) TestBorrowInterest() {
// Hard module genesis state
hardGS := types.NewGenesisState(types.NewParams(
true,
types.MoneyMarkets{
types.NewMoneyMarket("ukava",
types.NewBorrowLimit(false, sdk.NewDec(100000000*KAVA_CF), sdk.MustNewDecFromStr("0.8")), // Borrow Limit
@ -723,7 +722,9 @@ func (suite *KeeperTestSuite) TestBorrowInterest() {
sdk.ZeroDec()), // Keeper Reward Percentage
},
0, // LTV counter
), types.DefaultPreviousBlockTime)
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
)
// Pricefeed module genesis state
pricefeedGS := pricefeed.GenesisState{
@ -788,16 +789,16 @@ func (suite *KeeperTestSuite) TestBorrowInterest() {
suite.Require().True(borrowCoinsPriorFound)
borrowCoinPriorAmount := borrowCoinsPrior.AmountOf(tc.args.borrowCoinDenom)
reservesPrior, foundReservesPrior := suite.keeper.GetTotalReserves(prevCtx, tc.args.borrowCoinDenom)
reservesPrior, foundReservesPrior := suite.keeper.GetTotalReserves(prevCtx)
if !foundReservesPrior {
reservesPrior = sdk.NewCoin(tc.args.borrowCoinDenom, sdk.ZeroInt())
reservesPrior = sdk.NewCoins(sdk.NewCoin(tc.args.borrowCoinDenom, sdk.ZeroInt()))
}
interestFactorPrior, foundInterestFactorPrior := suite.keeper.GetBorrowInterestFactor(prevCtx, tc.args.borrowCoinDenom)
suite.Require().True(foundInterestFactorPrior)
// 2. Calculate expected interest owed
borrowRateApy, err := hard.CalculateBorrowRate(tc.args.interestRateModel, sdk.NewDecFromInt(cashPrior), sdk.NewDecFromInt(borrowCoinPriorAmount), sdk.NewDecFromInt(reservesPrior.Amount))
borrowRateApy, err := hard.CalculateBorrowRate(tc.args.interestRateModel, sdk.NewDecFromInt(cashPrior), sdk.NewDecFromInt(borrowCoinPriorAmount), sdk.NewDecFromInt(reservesPrior.AmountOf(tc.args.borrowCoinDenom)))
suite.Require().NoError(err)
// Convert from APY to SPY, expressed as (1 + borrow rate)
@ -821,7 +822,7 @@ func (suite *KeeperTestSuite) TestBorrowInterest() {
suite.Require().Equal(expectedBorrowedCoins, currBorrowedCoins.AmountOf(tc.args.borrowCoinDenom))
// Check that the total reserves have changed as expected
currTotalReserves, _ := suite.keeper.GetTotalReserves(snapshotCtx, tc.args.borrowCoinDenom)
currTotalReserves, _ := suite.keeper.GetTotalReserves(snapshotCtx)
suite.Require().Equal(expectedReserves, currTotalReserves)
// Check that the borrow index has increased as expected
@ -1118,7 +1119,6 @@ func (suite *KeeperTestSuite) TestSupplyInterest() {
// Hard module genesis state
hardGS := types.NewGenesisState(types.NewParams(
true,
types.MoneyMarkets{
types.NewMoneyMarket("ukava",
types.NewBorrowLimit(false, sdk.NewDec(100000000*KAVA_CF), sdk.MustNewDecFromStr("0.8")), // Borrow Limit
@ -1138,7 +1138,9 @@ func (suite *KeeperTestSuite) TestSupplyInterest() {
sdk.ZeroDec()), // Keeper Reward Percentage
},
0, // LTV counter
), types.DefaultPreviousBlockTime)
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
)
// Pricefeed module genesis state
pricefeedGS := pricefeed.GenesisState{
@ -1210,9 +1212,9 @@ func (suite *KeeperTestSuite) TestSupplyInterest() {
suite.Require().True(supplyCoinsPriorFound)
supplyCoinPriorAmount = supplyCoinsPrior.AmountOf(coinDenom)
reservesPrior, foundReservesPrior := suite.keeper.GetTotalReserves(prevCtx, coinDenom)
reservesPrior, foundReservesPrior := suite.keeper.GetTotalReserves(prevCtx)
if !foundReservesPrior {
reservesPrior = sdk.NewCoin(coinDenom, sdk.ZeroInt())
reservesPrior = sdk.NewCoins(sdk.NewCoin(coinDenom, sdk.ZeroInt()))
}
borrowInterestFactorPrior, foundBorrowInterestFactorPrior := suite.keeper.GetBorrowInterestFactor(prevCtx, coinDenom)
@ -1222,7 +1224,7 @@ func (suite *KeeperTestSuite) TestSupplyInterest() {
suite.Require().True(foundSupplyInterestFactorPrior)
// 2. Calculate expected borrow interest owed
borrowRateApy, err := hard.CalculateBorrowRate(tc.args.interestRateModel, sdk.NewDecFromInt(cashPrior), sdk.NewDecFromInt(borrowCoinPriorAmount), sdk.NewDecFromInt(reservesPrior.Amount))
borrowRateApy, err := hard.CalculateBorrowRate(tc.args.interestRateModel, sdk.NewDecFromInt(cashPrior), sdk.NewDecFromInt(borrowCoinPriorAmount), sdk.NewDecFromInt(reservesPrior.AmountOf(coinDenom)))
suite.Require().NoError(err)
// Convert from APY to SPY, expressed as (1 + borrow rate)
@ -1232,12 +1234,12 @@ func (suite *KeeperTestSuite) TestSupplyInterest() {
newBorrowInterestFactor := hard.CalculateBorrowInterestFactor(borrowRateSpy, sdk.NewInt(snapshot.elapsedTime))
expectedBorrowInterest := (newBorrowInterestFactor.Mul(sdk.NewDecFromInt(borrowCoinPriorAmount)).TruncateInt()).Sub(borrowCoinPriorAmount)
expectedReserves := reservesPrior.Add(sdk.NewCoin(coinDenom, sdk.NewDecFromInt(expectedBorrowInterest).Mul(tc.args.reserveFactor).TruncateInt())).Sub(reservesPrior)
expectedTotalReserves := expectedReserves.Add(reservesPrior)
expectedTotalReserves := expectedReserves.Add(reservesPrior...)
expectedBorrowInterestFactor := borrowInterestFactorPrior.Mul(newBorrowInterestFactor)
expectedSupplyInterest := expectedBorrowInterest.Sub(expectedReserves.Amount)
expectedSupplyInterest := expectedBorrowInterest.Sub(expectedReserves.AmountOf(coinDenom))
newSupplyInterestFactor := hard.CalculateSupplyInterestFactor(expectedSupplyInterest.ToDec(), sdk.NewDecFromInt(cashPrior), sdk.NewDecFromInt(borrowCoinPriorAmount), sdk.NewDecFromInt(reservesPrior.Amount))
newSupplyInterestFactor := hard.CalculateSupplyInterestFactor(expectedSupplyInterest.ToDec(), sdk.NewDecFromInt(cashPrior), sdk.NewDecFromInt(borrowCoinPriorAmount), sdk.NewDecFromInt(reservesPrior.AmountOf(coinDenom)))
expectedSupplyInterestFactor := supplyInterestFactorPrior.Mul(newSupplyInterestFactor)
// -------------------------------------------------------------------------------------
@ -1248,7 +1250,7 @@ func (suite *KeeperTestSuite) TestSupplyInterest() {
borrowInterestFactor, _ := suite.keeper.GetBorrowInterestFactor(ctx, coinDenom)
suite.Require().Equal(expectedBorrowInterestFactor, borrowInterestFactor)
suite.Require().Equal(expectedBorrowInterest, expectedSupplyInterest.Add(expectedReserves.Amount))
suite.Require().Equal(expectedBorrowInterest, expectedSupplyInterest.Add(expectedReserves.AmountOf(coinDenom)))
// Check that the total amount of borrowed coins has increased by expected borrow interest amount
borrowCoinsPost, _ := suite.keeper.GetBorrowedCoins(snapshotCtx)
@ -1261,8 +1263,11 @@ func (suite *KeeperTestSuite) TestSupplyInterest() {
suite.Require().Equal(supplyCoinPostAmount, supplyCoinPriorAmount.Add(expectedSupplyInterest))
// Check current total reserves
totalReserves, _ := suite.keeper.GetTotalReserves(snapshotCtx, coinDenom)
suite.Require().Equal(expectedTotalReserves, totalReserves)
totalReserves, _ := suite.keeper.GetTotalReserves(snapshotCtx)
suite.Require().Equal(
sdk.NewCoin(coinDenom, expectedTotalReserves.AmountOf(coinDenom)),
sdk.NewCoin(coinDenom, totalReserves.AmountOf(coinDenom)),
)
// Check that the supply index has increased as expected
currSupplyIndexPrior, _ := suite.keeper.GetSupplyInterestFactor(snapshotCtx, coinDenom)

View File

@ -272,22 +272,27 @@ func (k Keeper) SetPreviousAccrualTime(ctx sdk.Context, denom string, previousAc
}
// GetTotalReserves returns the total reserves for an individual market
func (k Keeper) GetTotalReserves(ctx sdk.Context, denom string) (sdk.Coin, bool) {
func (k Keeper) GetTotalReserves(ctx sdk.Context) (sdk.Coins, bool) {
store := prefix.NewStore(ctx.KVStore(k.key), types.TotalReservesPrefix)
bz := store.Get([]byte(denom))
bz := store.Get([]byte{})
if bz == nil {
return sdk.Coin{}, false
return sdk.Coins{}, false
}
var totalReserves sdk.Coin
var totalReserves sdk.Coins
k.cdc.MustUnmarshalBinaryBare(bz, &totalReserves)
return totalReserves, true
}
// SetTotalReserves sets the total reserves for an individual market
func (k Keeper) SetTotalReserves(ctx sdk.Context, denom string, coin sdk.Coin) {
func (k Keeper) SetTotalReserves(ctx sdk.Context, coins sdk.Coins) {
store := prefix.NewStore(ctx.KVStore(k.key), types.TotalReservesPrefix)
bz := k.cdc.MustMarshalBinaryBare(coin)
store.Set([]byte(denom), bz)
if coins.Empty() {
store.Set([]byte{}, []byte{})
return
}
bz := k.cdc.MustMarshalBinaryBare(coins)
store.Set([]byte{}, bz)
}
// GetBorrowInterestFactor returns the current borrow interest factor for an individual market

View File

@ -122,7 +122,6 @@ func (suite *KeeperTestSuite) TestIndexLiquidation() {
// Hard module genesis state
hardGS := types.NewGenesisState(types.NewParams(
true,
types.MoneyMarkets{
types.NewMoneyMarket("usdx",
types.NewBorrowLimit(false, sdk.NewDec(100000000*KAVA_CF), sdk.MustNewDecFromStr("0.9")), // Borrow Limit
@ -182,7 +181,9 @@ func (suite *KeeperTestSuite) TestIndexLiquidation() {
sdk.MustNewDecFromStr("0.05")), // Keeper Reward Percent
},
tc.args.ltvIndexCount, // LTV counter
), types.DefaultPreviousBlockTime)
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
)
// Pricefeed module genesis state
pricefeedGS := pricefeed.GenesisState{
@ -534,7 +535,6 @@ func (suite *KeeperTestSuite) TestFullIndexLiquidation() {
// Hard module genesis state
hardGS := types.NewGenesisState(types.NewParams(
true,
types.MoneyMarkets{
types.NewMoneyMarket("usdx",
types.NewBorrowLimit(false, sdk.NewDec(100000000*KAVA_CF), sdk.MustNewDecFromStr("0.9")), // Borrow Limit
@ -554,7 +554,9 @@ func (suite *KeeperTestSuite) TestFullIndexLiquidation() {
sdk.MustNewDecFromStr("0.05")), // Keeper Reward Percent
},
tc.args.ltvIndexCount, // LTV counter
), types.DefaultPreviousBlockTime)
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
)
// Pricefeed module genesis state
pricefeedGS := pricefeed.GenesisState{
@ -1157,7 +1159,6 @@ func (suite *KeeperTestSuite) TestKeeperLiquidation() {
// Hard module genesis state
hardGS := types.NewGenesisState(types.NewParams(
true,
types.MoneyMarkets{
types.NewMoneyMarket("usdx",
types.NewBorrowLimit(false, sdk.NewDec(100000000*KAVA_CF), sdk.MustNewDecFromStr("0.9")), // Borrow Limit
@ -1217,7 +1218,9 @@ func (suite *KeeperTestSuite) TestKeeperLiquidation() {
tc.args.keeperRewardPercent), // Keeper Reward Percent
},
0, // LTV counter
), types.DefaultPreviousBlockTime)
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
)
// Pricefeed module genesis state
pricefeedGS := pricefeed.GenesisState{

View File

@ -137,7 +137,6 @@ func (suite *KeeperTestSuite) TestRepay() {
// Hard module genesis state
hardGS := types.NewGenesisState(types.NewParams(
true,
types.MoneyMarkets{
types.NewMoneyMarket("usdx",
types.NewBorrowLimit(false, sdk.NewDec(100000000*USDX_CF), sdk.MustNewDecFromStr("1")), // Borrow Limit
@ -157,7 +156,9 @@ func (suite *KeeperTestSuite) TestRepay() {
sdk.MustNewDecFromStr("0.05")), // Keeper Reward Percent
},
0, // LTV counter
), types.DefaultPreviousBlockTime)
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
)
// Pricefeed module genesis state
pricefeedGS := pricefeed.GenesisState{

View File

@ -281,13 +281,14 @@ func (suite *KeeperTestSuite) TestSendTimeLockedCoinsToAccount() {
authGS := app.NewAuthGenState([]sdk.AccAddress{tc.args.accArgs.addr}, []sdk.Coins{tc.args.accArgs.coins})
loanToValue := sdk.MustNewDecFromStr("0.6")
hardGS := types.NewGenesisState(types.NewParams(
true,
types.MoneyMarkets{
types.NewMoneyMarket("usdx", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "usdx:usd", sdk.NewInt(1000000), sdk.NewInt(USDX_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
types.NewMoneyMarket("ukava", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "kava:usd", sdk.NewInt(1000000), sdk.NewInt(KAVA_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
},
0, // LTV counter
), types.DefaultPreviousBlockTime)
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
)
tApp.InitializeFromGenesisStates(authGS, app.GenesisState{types.ModuleName: types.ModuleCdc.MustMarshalJSON(hardGS)})
if tc.args.accArgs.vestingAccountBefore {
ak := tApp.GetAccountKeeper()

View File

@ -124,14 +124,15 @@ func (suite *KeeperTestSuite) TestWithdraw() {
loanToValue := sdk.MustNewDecFromStr("0.6")
hardGS := types.NewGenesisState(types.NewParams(
true,
types.MoneyMarkets{
types.NewMoneyMarket("usdx", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "usdx:usd", sdk.NewInt(1000000), sdk.NewInt(USDX_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
types.NewMoneyMarket("ukava", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "kava:usd", sdk.NewInt(1000000), sdk.NewInt(KAVA_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
types.NewMoneyMarket("bnb", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "bnb:usd", sdk.NewInt(100000000), sdk.NewInt(BNB_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
},
0, // LTV counter
), types.DefaultPreviousBlockTime)
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
)
// Pricefeed module genesis state
pricefeedGS := pricefeed.GenesisState{
@ -264,7 +265,6 @@ func (suite *KeeperTestSuite) TestLtvWithdraw() {
// Harvest module genesis state
harvestGS := types.NewGenesisState(types.NewParams(
true,
types.MoneyMarkets{
types.NewMoneyMarket("ukava",
types.NewBorrowLimit(false, sdk.NewDec(100000000*KAVA_CF), sdk.MustNewDecFromStr("0.8")), // Borrow Limit
@ -284,7 +284,9 @@ func (suite *KeeperTestSuite) TestLtvWithdraw() {
sdk.MustNewDecFromStr("0.05")), // Keeper Reward Percent
},
0, // LTV counter
), types.DefaultPreviousBlockTime)
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
)
// Pricefeed module genesis state
pricefeedGS := pricefeed.GenesisState{

View File

@ -1,6 +1,9 @@
package types
import (
"fmt"
"strings"
sdk "github.com/cosmos/cosmos-sdk/types"
)
@ -20,9 +23,49 @@ func NewBorrow(borrower sdk.AccAddress, amount sdk.Coins, index BorrowInterestFa
}
}
// Validate deposit validation
func (b Borrow) Validate() error {
if b.Borrower.Empty() {
return fmt.Errorf("Depositor cannot be empty")
}
if !b.Amount.IsValid() {
return fmt.Errorf("Invalid deposit coins: %s", b.Amount)
}
if err := b.Index.Validate(); err != nil {
return err
}
return nil
}
func (b Borrow) String() string {
return fmt.Sprintf(`Deposit:
Borrower: %s
Amount: %s
Index: %s
`, b.Borrower, b.Amount, b.Index)
}
// Borrows is a slice of Borrow
type Borrows []Borrow
// Validate validates Borrows
func (bs Borrows) Validate() error {
borrowDupMap := make(map[string]Borrow)
for _, b := range bs {
if err := b.Validate(); err != nil {
return err
}
dup, ok := borrowDupMap[b.Borrower.String()]
if ok {
return fmt.Errorf("duplicate borrower: %s\n%s", b, dup)
}
borrowDupMap[b.Borrower.String()] = b
}
return nil
}
// BorrowInterestFactor defines an individual borrow interest factor
type BorrowInterestFactor struct {
Denom string `json:"denom" yaml:"denom"`
@ -37,5 +80,40 @@ func NewBorrowInterestFactor(denom string, value sdk.Dec) BorrowInterestFactor {
}
}
// Validate validates BorrowInterestFactor values
func (bif BorrowInterestFactor) Validate() error {
if strings.TrimSpace(bif.Denom) == "" {
return fmt.Errorf("borrow interest factor denom cannot be empty")
}
if bif.Value.IsNegative() {
return fmt.Errorf("borrow interest factor value cannot be negative: %s", bif)
}
return nil
}
func (bif BorrowInterestFactor) String() string {
return fmt.Sprintf(`[%s,%s]
`, bif.Denom, bif.Value)
}
// BorrowInterestFactors is a slice of BorrowInterestFactor, because Amino won't marshal maps
type BorrowInterestFactors []BorrowInterestFactor
// Validate validates BorrowInterestFactors
func (bifs BorrowInterestFactors) Validate() error {
for _, bif := range bifs {
if err := bif.Validate(); err != nil {
return err
}
}
return nil
}
func (bifs BorrowInterestFactors) String() string {
out := ""
for _, bif := range bifs {
out += bif.String()
}
return out
}

View File

@ -1,6 +1,9 @@
package types
import (
"fmt"
"strings"
sdk "github.com/cosmos/cosmos-sdk/types"
)
@ -20,9 +23,49 @@ func NewDeposit(depositor sdk.AccAddress, amount sdk.Coins, indexes SupplyIntere
}
}
// Validate deposit validation
func (d Deposit) Validate() error {
if d.Depositor.Empty() {
return fmt.Errorf("Depositor cannot be empty")
}
if !d.Amount.IsValid() {
return fmt.Errorf("Invalid deposit coins: %s", d.Amount)
}
if err := d.Index.Validate(); err != nil {
return err
}
return nil
}
func (d Deposit) String() string {
return fmt.Sprintf(`Deposit:
Depositor: %s
Amount: %s
Index: %s
`, d.Depositor, d.Amount, d.Index)
}
// Deposits is a slice of Deposit
type Deposits []Deposit
// Validate validates Deposits
func (ds Deposits) Validate() error {
depositDupMap := make(map[string]Deposit)
for _, d := range ds {
if err := d.Validate(); err != nil {
return err
}
dup, ok := depositDupMap[d.Depositor.String()]
if ok {
return fmt.Errorf("duplicate depositor: %s\n%s", d, dup)
}
depositDupMap[d.Depositor.String()] = d
}
return nil
}
// SupplyInterestFactor defines an individual borrow interest factor
type SupplyInterestFactor struct {
Denom string `json:"denom" yaml:"denom"`
@ -37,5 +80,40 @@ func NewSupplyInterestFactor(denom string, value sdk.Dec) SupplyInterestFactor {
}
}
// Validate validates SupplyInterestFactor values
func (sif SupplyInterestFactor) Validate() error {
if strings.TrimSpace(sif.Denom) == "" {
return fmt.Errorf("supply interest factor denom cannot be empty")
}
if sif.Value.IsNegative() {
return fmt.Errorf("supply interest factor value cannot be negative: %s", sif)
}
return nil
}
func (sif SupplyInterestFactor) String() string {
return fmt.Sprintf(`[%s,%s]
`, sif.Denom, sif.Value)
}
// SupplyInterestFactors is a slice of SupplyInterestFactor, because Amino won't marshal maps
type SupplyInterestFactors []SupplyInterestFactor
// Validate validates SupplyInterestFactors
func (sifs SupplyInterestFactors) Validate() error {
for _, sif := range sifs {
if err := sif.Validate(); err != nil {
return err
}
}
return nil
}
func (sifs SupplyInterestFactors) String() string {
out := ""
for _, sif := range sifs {
out += sif.String()
}
return out
}

View File

@ -5,6 +5,7 @@ import (
"fmt"
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
tmtime "github.com/tendermint/tendermint/types/time"
)
@ -15,23 +16,40 @@ var (
// GenesisState is the state that must be provided at genesis.
type GenesisState struct {
Params Params `json:"params" yaml:"params"`
PreviousBlockTime time.Time `json:"previous_block_time" yaml:"previous_block_time"`
Params Params `json:"params" yaml:"params"`
PreviousAccumulationTimes GenesisAccumulationTimes `json:"previous_accumulation_times" yaml:"previous_accumulation_times"`
Deposits Deposits `json:"deposits" yaml:"deposits"`
Borrows Borrows `json:"borrows" yaml:"borrows"`
TotalSupplied sdk.Coins `json:"total_supplied" yaml:"total_supplied"`
TotalBorrowed sdk.Coins `json:"total_borrowed" yaml:"total_borrowed"`
TotalReserves sdk.Coins `json:"total_reserves" yaml:"total_reserves"`
}
// NewGenesisState returns a new genesis state
func NewGenesisState(params Params, previousBlockTime time.Time) GenesisState {
func NewGenesisState(
params Params, prevAccumulationTimes GenesisAccumulationTimes, deposits Deposits,
borrows Borrows, totalSupplied, totalBorrowed, totalReserves sdk.Coins) GenesisState {
return GenesisState{
Params: params,
PreviousBlockTime: previousBlockTime,
Params: params,
PreviousAccumulationTimes: prevAccumulationTimes,
Deposits: deposits,
Borrows: borrows,
TotalSupplied: totalSupplied,
TotalBorrowed: totalBorrowed,
TotalReserves: totalReserves,
}
}
// DefaultGenesisState returns a default genesis state
func DefaultGenesisState() GenesisState {
return GenesisState{
Params: DefaultParams(),
PreviousBlockTime: DefaultPreviousBlockTime,
Params: DefaultParams(),
PreviousAccumulationTimes: DefaultAccumulationTimes,
Deposits: DefaultDeposits,
Borrows: DefaultBorrows,
TotalSupplied: DefaultTotalSupplied,
TotalBorrowed: DefaultTotalBorrowed,
TotalReserves: DefaultTotalReserves,
}
}
@ -42,8 +60,24 @@ func (gs GenesisState) Validate() error {
if err := gs.Params.Validate(); err != nil {
return err
}
if gs.PreviousBlockTime.Equal(time.Time{}) {
return fmt.Errorf("previous block time not set")
if err := gs.PreviousAccumulationTimes.Validate(); err != nil {
return err
}
if err := gs.Deposits.Validate(); err != nil {
return err
}
if err := gs.Borrows.Validate(); err != nil {
return err
}
if !gs.TotalSupplied.IsValid() {
return fmt.Errorf("invalid total supplied coins: %s", gs.TotalSupplied)
}
if !gs.TotalBorrowed.IsValid() {
return fmt.Errorf("invalid total borrowed coins: %s", gs.TotalBorrowed)
}
if !gs.TotalReserves.IsValid() {
return fmt.Errorf("invalid total reserves coins: %s", gs.TotalReserves)
}
return nil
}
@ -59,3 +93,45 @@ func (gs GenesisState) Equal(gs2 GenesisState) bool {
func (gs GenesisState) IsEmpty() bool {
return gs.Equal(GenesisState{})
}
// GenesisAccumulationTime stores the previous distribution time and its corresponding denom
type GenesisAccumulationTime struct {
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
PreviousAccumulationTime time.Time `json:"previous_accumulation_time" yaml:"previous_accumulation_time"`
SupplyInterestFactor sdk.Dec `json:"supply_interest_factor" yaml:"supply_interest_factor"`
BorrowInterestFactor sdk.Dec `json:"borrow_interest_factor" yaml:"borrow_interest_factor"`
}
// NewGenesisAccumulationTime returns a new GenesisAccumulationTime
func NewGenesisAccumulationTime(ctype string, prevTime time.Time, supplyFactor, borrowFactor sdk.Dec) GenesisAccumulationTime {
return GenesisAccumulationTime{
CollateralType: ctype,
PreviousAccumulationTime: prevTime,
SupplyInterestFactor: supplyFactor,
BorrowInterestFactor: borrowFactor,
}
}
// GenesisAccumulationTimes slice of GenesisAccumulationTime
type GenesisAccumulationTimes []GenesisAccumulationTime
// Validate performs validation of GenesisAccumulationTimes
func (gats GenesisAccumulationTimes) Validate() error {
for _, gat := range gats {
if err := gat.Validate(); err != nil {
return err
}
}
return nil
}
// Validate performs validation of GenesisAccumulationTime
func (gat GenesisAccumulationTime) Validate() error {
if gat.SupplyInterestFactor.LT(sdk.OneDec()) {
return fmt.Errorf("supply interest factor should be ≥ 1.0, is %s for %s", gat.SupplyInterestFactor, gat.CollateralType)
}
if gat.BorrowInterestFactor.LT(sdk.OneDec()) {
return fmt.Errorf("borrow interest factor should be ≥ 1.0, is %s for %s", gat.BorrowInterestFactor, gat.CollateralType)
}
return nil
}

View File

@ -7,9 +7,19 @@ import (
"github.com/stretchr/testify/suite"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/x/hard/types"
)
const (
USDX_CF = 1000000
KAVA_CF = 1000000
BTCB_CF = 100000000
BNB_CF = 100000000
BUSD_CF = 100000000
)
type GenesisTestSuite struct {
suite.Suite
}
@ -17,7 +27,12 @@ type GenesisTestSuite struct {
func (suite *GenesisTestSuite) TestGenesisValidation() {
type args struct {
params types.Params
pbt time.Time
gats types.GenesisAccumulationTimes
deps types.Deposits
brws types.Borrows
ts sdk.Coins
tb sdk.Coins
tr sdk.Coins
}
testCases := []struct {
name string
@ -29,7 +44,12 @@ func (suite *GenesisTestSuite) TestGenesisValidation() {
name: "default",
args: args{
params: types.DefaultParams(),
pbt: types.DefaultPreviousBlockTime,
gats: types.DefaultAccumulationTimes,
deps: types.DefaultDeposits,
brws: types.DefaultBorrows,
ts: types.DefaultTotalSupplied,
tb: types.DefaultTotalBorrowed,
tr: types.DefaultTotalReserves,
},
expectPass: true,
expectedErr: "",
@ -37,25 +57,28 @@ func (suite *GenesisTestSuite) TestGenesisValidation() {
{
name: "valid",
args: args{
params: types.NewParams(true, types.DefaultMoneyMarkets, types.DefaultCheckLtvIndexCount),
pbt: time.Date(2020, 10, 8, 12, 0, 0, 0, time.UTC),
params: types.NewParams(
types.MoneyMarkets{
types.NewMoneyMarket("usdx", types.NewBorrowLimit(true, sdk.MustNewDecFromStr("100000000000"), sdk.MustNewDecFromStr("1")), "usdx:usd", sdk.NewInt(USDX_CF), sdk.NewInt(USDX_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
},
10,
),
gats: types.GenesisAccumulationTimes{
types.NewGenesisAccumulationTime("usdx", time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), sdk.OneDec(), sdk.OneDec()),
},
deps: types.DefaultDeposits,
brws: types.DefaultBorrows,
ts: sdk.Coins{},
tb: sdk.Coins{},
tr: sdk.Coins{},
},
expectPass: true,
expectedErr: "",
},
{
name: "invalid previous blocktime",
args: args{
params: types.NewParams(true, types.DefaultMoneyMarkets, types.DefaultCheckLtvIndexCount),
pbt: time.Time{},
},
expectPass: false,
expectedErr: "previous block time not set",
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
gs := types.NewGenesisState(tc.args.params, tc.args.pbt)
gs := types.NewGenesisState(tc.args.params, tc.args.gats, tc.args.deps, tc.args.brws, tc.args.ts, tc.args.tb, tc.args.tr)
err := gs.Validate()
if tc.expectPass {
suite.NoError(err)

View File

@ -11,18 +11,21 @@ import (
// Parameter keys and default values
var (
KeyActive = []byte("Active")
KeyMoneyMarkets = []byte("MoneyMarkets")
KeyCheckLtvIndexCount = []byte("CheckLtvIndexCount")
DefaultActive = true
DefaultMoneyMarkets = MoneyMarkets{}
DefaultCheckLtvIndexCount = 10
GovDenom = cdptypes.DefaultGovDenom
DefaultAccumulationTimes = GenesisAccumulationTimes{}
DefaultTotalSupplied = sdk.Coins{}
DefaultTotalBorrowed = sdk.Coins{}
DefaultTotalReserves = sdk.Coins{}
DefaultDeposits = Deposits{}
DefaultBorrows = Borrows{}
)
// Params governance parameters for hard module
type Params struct {
Active bool `json:"active" yaml:"active"`
MoneyMarkets MoneyMarkets `json:"money_markets" yaml:"money_markets"`
CheckLtvIndexCount int `json:"check_ltv_index_count" yaml:"check_ltv_index_count"`
}
@ -229,9 +232,8 @@ func (irm InterestRateModel) Equal(irmCompareTo InterestRateModel) bool {
type InterestRateModels []InterestRateModel
// NewParams returns a new params object
func NewParams(active bool, moneyMarkets MoneyMarkets, checkLtvIndexCount int) Params {
func NewParams(moneyMarkets MoneyMarkets, checkLtvIndexCount int) Params {
return Params{
Active: active,
MoneyMarkets: moneyMarkets,
CheckLtvIndexCount: checkLtvIndexCount,
}
@ -239,16 +241,15 @@ func NewParams(active bool, moneyMarkets MoneyMarkets, checkLtvIndexCount int) P
// DefaultParams returns default params for hard module
func DefaultParams() Params {
return NewParams(DefaultActive, DefaultMoneyMarkets, DefaultCheckLtvIndexCount)
return NewParams(DefaultMoneyMarkets, DefaultCheckLtvIndexCount)
}
// String implements fmt.Stringer
func (p Params) String() string {
return fmt.Sprintf(`Params:
Active: %t
Money Markets %v
Check LTV Index Count: %v`,
p.Active, p.MoneyMarkets, p.CheckLtvIndexCount)
p.MoneyMarkets, p.CheckLtvIndexCount)
}
// ParamKeyTable Key declaration for parameters
@ -259,7 +260,6 @@ func ParamKeyTable() params.KeyTable {
// ParamSetPairs implements the ParamSet interface and returns all the key/value pairs
func (p *Params) ParamSetPairs() params.ParamSetPairs {
return params.ParamSetPairs{
params.NewParamSetPair(KeyActive, &p.Active, validateActiveParam),
params.NewParamSetPair(KeyMoneyMarkets, &p.MoneyMarkets, validateMoneyMarketParams),
params.NewParamSetPair(KeyCheckLtvIndexCount, &p.CheckLtvIndexCount, validateCheckLtvIndexCount),
}
@ -267,9 +267,6 @@ func (p *Params) ParamSetPairs() params.ParamSetPairs {
// Validate checks that the parameters have valid values.
func (p Params) Validate() error {
if err := validateActiveParam(p.Active); err != nil {
return err
}
if err := validateMoneyMarketParams(p.MoneyMarkets); err != nil {
return err
@ -278,15 +275,6 @@ func (p Params) Validate() error {
return validateCheckLtvIndexCount(p.CheckLtvIndexCount)
}
func validateActiveParam(i interface{}) error {
_, ok := i.(bool)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
return nil
}
func validateMoneyMarketParams(i interface{}) error {
mm, ok := i.(MoneyMarkets)
if !ok {

View File

@ -17,7 +17,6 @@ func (suite *ParamTestSuite) TestParamValidation() {
type args struct {
mms types.MoneyMarkets
ltvCounter int
active bool
}
testCases := []struct {
name string
@ -27,18 +26,9 @@ func (suite *ParamTestSuite) TestParamValidation() {
}{
{
name: "default",
args: args{
active: types.DefaultActive,
},
expectPass: true,
expectedErr: "",
},
{
name: "valid",
args: args{
mms: types.DefaultMoneyMarkets,
ltvCounter: 10,
active: true,
ltvCounter: types.DefaultCheckLtvIndexCount,
},
expectPass: true,
expectedErr: "",
@ -46,7 +36,7 @@ func (suite *ParamTestSuite) TestParamValidation() {
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
params := types.NewParams(tc.args.active, tc.args.mms, tc.args.ltvCounter)
params := types.NewParams(tc.args.mms, tc.args.ltvCounter)
err := params.Validate()
if tc.expectPass {
suite.NoError(err)

View File

@ -157,7 +157,6 @@ func NewHardGenStateMulti() app.GenesisState {
borrowLimit := sdk.NewDec(1000000000000000)
hardGS := hard.NewGenesisState(hard.NewParams(
true,
hard.MoneyMarkets{
hard.NewMoneyMarket("usdx", hard.NewBorrowLimit(false, borrowLimit, loanToValue), "usdx:usd", sdk.NewInt(1000000), sdk.NewInt(USDX_CF*1000), hard.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
hard.NewMoneyMarket("ukava", hard.NewBorrowLimit(false, borrowLimit, loanToValue), "kava:usd", sdk.NewInt(1000000), sdk.NewInt(KAVA_CF*1000), hard.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
@ -166,7 +165,9 @@ func NewHardGenStateMulti() app.GenesisState {
hard.NewMoneyMarket("xrp", hard.NewBorrowLimit(false, borrowLimit, loanToValue), "xrp:usd", sdk.NewInt(1000000), sdk.NewInt(BTCB_CF*1000), hard.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
},
0, // LTV counter
), hard.DefaultPreviousBlockTime)
), hard.DefaultAccumulationTimes, hard.DefaultDeposits, hard.DefaultBorrows,
hard.DefaultTotalSupplied, hard.DefaultTotalBorrowed, hard.DefaultTotalReserves,
)
return app.GenesisState{hard.ModuleName: hard.ModuleCdc.MustMarshalJSON(hardGS)}
}