mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-24 15:25:18 +00:00
Hard Audit: add minimum borrow USD value (#822)
* add module param MinimumBorrowUSDValue * borrow/repay min limit restrictions * add borrow/repay test cases * update tests with new module params * update timelock test with param * update withdraw LTV test * remove unused GetCurrentBorrowUSDValue method * commit to prompt CircleCI run
This commit is contained in:
parent
cd7a227030
commit
fe2a131b31
@ -208,6 +208,12 @@ func (k Keeper) ValidateBorrow(ctx sdk.Context, borrower sdk.AccAddress, amount
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Borrow's updated total USD value must be greater than the minimum global USD borrow limit
|
||||||
|
totalBorrowUSDValue := proprosedBorrowUSDValue.Add(existingBorrowUSDValue)
|
||||||
|
if totalBorrowUSDValue.LT(k.GetMinimumBorrowUSDValue(ctx)) {
|
||||||
|
return sdkerrors.Wrapf(types.ErrBelowMinimumBorrowValue, "the proposed borrow's USD value $%s is below the minimum borrow limit $%s", totalBorrowUSDValue, k.GetMinimumBorrowUSDValue(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
// Validate that the proposed borrow's USD value is within user's borrowable limit
|
// Validate that the proposed borrow's USD value is within user's borrowable limit
|
||||||
if proprosedBorrowUSDValue.GT(totalBorrowableAmount.Sub(existingBorrowUSDValue)) {
|
if proprosedBorrowUSDValue.GT(totalBorrowableAmount.Sub(existingBorrowUSDValue)) {
|
||||||
return sdkerrors.Wrapf(types.ErrInsufficientLoanToValue, "requested borrow %s exceeds the allowable amount as determined by the collateralization ratio", amount)
|
return sdkerrors.Wrapf(types.ErrInsufficientLoanToValue, "requested borrow %s exceeds the allowable amount as determined by the collateralization ratio", amount)
|
||||||
|
@ -245,6 +245,50 @@ func (suite *KeeperTestSuite) TestBorrow() {
|
|||||||
contains: "fails global asset borrow limit validation",
|
contains: "fails global asset borrow limit validation",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"invalid: borrowing an individual coin type results in a borrow that's under the minimum USD borrow limit",
|
||||||
|
args{
|
||||||
|
usdxBorrowLimit: sdk.MustNewDecFromStr("20000000"),
|
||||||
|
priceKAVA: sdk.MustNewDecFromStr("2.00"),
|
||||||
|
loanToValueKAVA: sdk.MustNewDecFromStr("0.8"),
|
||||||
|
priceBTCB: sdk.MustNewDecFromStr("0.00"),
|
||||||
|
loanToValueBTCB: sdk.MustNewDecFromStr("0.01"),
|
||||||
|
priceBNB: sdk.MustNewDecFromStr("0.00"),
|
||||||
|
loanToValueBNB: sdk.MustNewDecFromStr("0.01"),
|
||||||
|
borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
||||||
|
depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(50*KAVA_CF))),
|
||||||
|
previousBorrowCoins: sdk.NewCoins(),
|
||||||
|
borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(5*USDX_CF))),
|
||||||
|
expectedAccountBalance: sdk.NewCoins(),
|
||||||
|
expectedModAccountBalance: sdk.NewCoins(),
|
||||||
|
},
|
||||||
|
errArgs{
|
||||||
|
expectPass: false,
|
||||||
|
contains: "below the minimum borrow limit",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"invalid: borrowing multiple coins results in a borrow that's under the minimum USD borrow limit",
|
||||||
|
args{
|
||||||
|
usdxBorrowLimit: sdk.MustNewDecFromStr("20000000"),
|
||||||
|
priceKAVA: sdk.MustNewDecFromStr("2.00"),
|
||||||
|
loanToValueKAVA: sdk.MustNewDecFromStr("0.8"),
|
||||||
|
priceBTCB: sdk.MustNewDecFromStr("0.00"),
|
||||||
|
loanToValueBTCB: sdk.MustNewDecFromStr("0.01"),
|
||||||
|
priceBNB: sdk.MustNewDecFromStr("0.00"),
|
||||||
|
loanToValueBNB: sdk.MustNewDecFromStr("0.01"),
|
||||||
|
borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
||||||
|
depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(50*KAVA_CF))),
|
||||||
|
previousBorrowCoins: sdk.NewCoins(),
|
||||||
|
borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(5*USDX_CF)), sdk.NewCoin("ukava", sdk.NewInt(2*USDX_CF))),
|
||||||
|
expectedAccountBalance: sdk.NewCoins(),
|
||||||
|
expectedModAccountBalance: sdk.NewCoins(),
|
||||||
|
},
|
||||||
|
errArgs{
|
||||||
|
expectPass: false,
|
||||||
|
contains: "below the minimum borrow limit",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
suite.Run(tc.name, func() {
|
suite.Run(tc.name, func() {
|
||||||
@ -269,6 +313,7 @@ func (suite *KeeperTestSuite) TestBorrow() {
|
|||||||
types.NewMoneyMarket("bnb", types.NewBorrowLimit(false, sdk.NewDec(100000000*BNB_CF), tc.args.loanToValueBNB), "bnb:usd", sdk.NewInt(BNB_CF), 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(100000000*BNB_CF), tc.args.loanToValueBNB), "bnb:usd", sdk.NewInt(BNB_CF), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
types.NewMoneyMarket("xyz", types.NewBorrowLimit(false, sdk.NewDec(1), tc.args.loanToValueBNB), "xyz:usd", 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()),
|
types.NewMoneyMarket("xyz", types.NewBorrowLimit(false, sdk.NewDec(1), tc.args.loanToValueBNB), "xyz:usd", 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()),
|
||||||
},
|
},
|
||||||
|
sdk.NewDec(10),
|
||||||
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
|
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
|
||||||
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
|
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
|
||||||
)
|
)
|
||||||
|
@ -111,6 +111,7 @@ func (suite *KeeperTestSuite) TestDeposit() {
|
|||||||
types.NewMoneyMarket("bnb", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "bnb:usd", sdk.NewInt(1000000), 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(1000000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
types.NewMoneyMarket("btcb", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "btcb:usd", sdk.NewInt(1000000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
types.NewMoneyMarket("btcb", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "btcb:usd", sdk.NewInt(1000000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
},
|
},
|
||||||
|
sdk.NewDec(10),
|
||||||
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
|
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
|
||||||
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
|
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
|
||||||
)
|
)
|
||||||
|
@ -796,6 +796,7 @@ func (suite *KeeperTestSuite) TestBorrowInterest() {
|
|||||||
tc.args.reserveFactor, // Reserve Factor
|
tc.args.reserveFactor, // Reserve Factor
|
||||||
sdk.ZeroDec()), // Keeper Reward Percentage
|
sdk.ZeroDec()), // Keeper Reward Percentage
|
||||||
},
|
},
|
||||||
|
sdk.NewDec(10),
|
||||||
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
|
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
|
||||||
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
|
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
|
||||||
)
|
)
|
||||||
@ -1209,6 +1210,7 @@ func (suite *KeeperTestSuite) TestSupplyInterest() {
|
|||||||
tc.args.reserveFactor, // Reserve Factor
|
tc.args.reserveFactor, // Reserve Factor
|
||||||
sdk.ZeroDec()), // Keeper Reward Percentage
|
sdk.ZeroDec()), // Keeper Reward Percentage
|
||||||
},
|
},
|
||||||
|
sdk.NewDec(10),
|
||||||
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
|
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
|
||||||
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
|
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
|
||||||
)
|
)
|
||||||
|
@ -511,6 +511,7 @@ func (suite *KeeperTestSuite) TestKeeperLiquidation() {
|
|||||||
reserveFactor, // Reserve Factor
|
reserveFactor, // Reserve Factor
|
||||||
tc.args.keeperRewardPercent), // Keeper Reward Percent
|
tc.args.keeperRewardPercent), // Keeper Reward Percent
|
||||||
},
|
},
|
||||||
|
sdk.NewDec(10),
|
||||||
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
|
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
|
||||||
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
|
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
|
||||||
)
|
)
|
||||||
|
@ -28,3 +28,9 @@ func (k Keeper) GetMoneyMarketParam(ctx sdk.Context, denom string) (types.MoneyM
|
|||||||
}
|
}
|
||||||
return types.MoneyMarket{}, false
|
return types.MoneyMarket{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetMinimumBorrowUSDValue returns the minimum borrow USD value
|
||||||
|
func (k Keeper) GetMinimumBorrowUSDValue(ctx sdk.Context) sdk.Dec {
|
||||||
|
params := k.GetParams(ctx)
|
||||||
|
return params.MinimumBorrowUSDValue
|
||||||
|
}
|
||||||
|
@ -21,7 +21,7 @@ func (k Keeper) Repay(ctx sdk.Context, sender, owner sdk.AccAddress, coins sdk.C
|
|||||||
k.SyncBorrowInterest(ctx, owner)
|
k.SyncBorrowInterest(ctx, owner)
|
||||||
|
|
||||||
// Validate that sender holds coins for repayment
|
// Validate that sender holds coins for repayment
|
||||||
err := k.ValidateRepay(ctx, sender, coins)
|
err := k.ValidateRepay(ctx, sender, owner, coins)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -78,14 +78,80 @@ func (k Keeper) Repay(ctx sdk.Context, sender, owner sdk.AccAddress, coins sdk.C
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ValidateRepay validates a requested loan repay
|
// ValidateRepay validates a requested loan repay
|
||||||
func (k Keeper) ValidateRepay(ctx sdk.Context, sender sdk.AccAddress, coins sdk.Coins) error {
|
func (k Keeper) ValidateRepay(ctx sdk.Context, sender, owner sdk.AccAddress, coins sdk.Coins) error {
|
||||||
|
moneyMarketCache := map[string]types.MoneyMarket{}
|
||||||
|
assetPriceCache := map[string]sdk.Dec{}
|
||||||
|
|
||||||
|
// Get the total USD value of user's existing borrows
|
||||||
|
existingBorrowUSDValue := sdk.ZeroDec()
|
||||||
|
existingBorrow, found := k.GetBorrow(ctx, owner)
|
||||||
|
if found {
|
||||||
|
for _, borrowedCoin := range existingBorrow.Amount {
|
||||||
|
moneyMarket, ok := moneyMarketCache[borrowedCoin.Denom]
|
||||||
|
if !ok { // Fetch money market and store in local cache
|
||||||
|
newMoneyMarket, found := k.GetMoneyMarketParam(ctx, borrowedCoin.Denom)
|
||||||
|
if !found {
|
||||||
|
return sdkerrors.Wrapf(types.ErrMarketNotFound, "no market found for denom %s", borrowedCoin.Denom)
|
||||||
|
}
|
||||||
|
moneyMarketCache[borrowedCoin.Denom] = newMoneyMarket
|
||||||
|
moneyMarket = newMoneyMarket
|
||||||
|
}
|
||||||
|
|
||||||
|
assetPrice, ok := assetPriceCache[borrowedCoin.Denom]
|
||||||
|
if !ok { // Fetch current asset price and store in local cache
|
||||||
|
assetPriceInfo, err := k.pricefeedKeeper.GetCurrentPrice(ctx, moneyMarket.SpotMarketID)
|
||||||
|
if err != nil {
|
||||||
|
return sdkerrors.Wrapf(types.ErrPriceNotFound, "no price found for market %s", moneyMarket.SpotMarketID)
|
||||||
|
}
|
||||||
|
assetPriceCache[borrowedCoin.Denom] = assetPriceInfo.Price
|
||||||
|
assetPrice = assetPriceInfo.Price
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate this borrow coin's USD value and add it to the total previous borrowed USD value
|
||||||
|
coinUSDValue := sdk.NewDecFromInt(borrowedCoin.Amount).Quo(sdk.NewDecFromInt(moneyMarket.ConversionFactor)).Mul(assetPrice)
|
||||||
|
existingBorrowUSDValue = existingBorrowUSDValue.Add(coinUSDValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
senderAcc := k.accountKeeper.GetAccount(ctx, sender)
|
senderAcc := k.accountKeeper.GetAccount(ctx, sender)
|
||||||
senderCoins := senderAcc.SpendableCoins(ctx.BlockTime())
|
senderCoins := senderAcc.SpendableCoins(ctx.BlockTime())
|
||||||
|
repayTotalUSDValue := sdk.ZeroDec()
|
||||||
for _, coin := range coins {
|
for _, repayCoin := range coins {
|
||||||
if senderCoins.AmountOf(coin.Denom).LT(coin.Amount) {
|
// Check that sender holds enough tokens to make the proposed payment
|
||||||
return sdkerrors.Wrapf(types.ErrInsufficientBalanceForRepay, "account can only repay up to %s%s", senderCoins.AmountOf(coin.Denom), coin.Denom)
|
if senderCoins.AmountOf(repayCoin.Denom).LT(repayCoin.Amount) {
|
||||||
|
return sdkerrors.Wrapf(types.ErrInsufficientBalanceForRepay, "account can only repay up to %s%s", senderCoins.AmountOf(repayCoin.Denom), repayCoin.Denom)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
moneyMarket, ok := moneyMarketCache[repayCoin.Denom]
|
||||||
|
if !ok { // Fetch money market and store in local cache
|
||||||
|
newMoneyMarket, found := k.GetMoneyMarketParam(ctx, repayCoin.Denom)
|
||||||
|
if !found {
|
||||||
|
return sdkerrors.Wrapf(types.ErrMarketNotFound, "no market found for denom %s", repayCoin.Denom)
|
||||||
|
}
|
||||||
|
moneyMarketCache[repayCoin.Denom] = newMoneyMarket
|
||||||
|
moneyMarket = newMoneyMarket
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate this coin's USD value and add it to the repay's total USD value
|
||||||
|
assetPrice, ok := assetPriceCache[repayCoin.Denom]
|
||||||
|
if !ok { // Fetch current asset price and store in local cache
|
||||||
|
assetPriceInfo, err := k.pricefeedKeeper.GetCurrentPrice(ctx, moneyMarket.SpotMarketID)
|
||||||
|
if err != nil {
|
||||||
|
return sdkerrors.Wrapf(types.ErrPriceNotFound, "no price found for market %s", moneyMarket.SpotMarketID)
|
||||||
|
}
|
||||||
|
assetPriceCache[repayCoin.Denom] = assetPriceInfo.Price
|
||||||
|
assetPrice = assetPriceInfo.Price
|
||||||
|
}
|
||||||
|
coinUSDValue := sdk.NewDecFromInt(repayCoin.Amount).Quo(sdk.NewDecFromInt(moneyMarket.ConversionFactor)).Mul(assetPrice)
|
||||||
|
repayTotalUSDValue = repayTotalUSDValue.Add(coinUSDValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the proposed repayment would results in a borrowed USD value below the minimum borrow USD value, reject it.
|
||||||
|
// User can overpay their loan to close it out, but underpaying by such a margin that the USD value is in an
|
||||||
|
// invalid range is not allowed
|
||||||
|
proposedBorrowNewUSDValue := existingBorrowUSDValue.Sub(repayTotalUSDValue)
|
||||||
|
if proposedBorrowNewUSDValue.IsPositive() && proposedBorrowNewUSDValue.LT(k.GetMinimumBorrowUSDValue(ctx)) {
|
||||||
|
return sdkerrors.Wrapf(types.ErrBelowMinimumBorrowValue, "the proposed borrow's USD value $%s is below the minimum borrow limit $%s", proposedBorrowNewUSDValue, k.GetMinimumBorrowUSDValue(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -122,6 +122,38 @@ func (suite *KeeperTestSuite) TestRepay() {
|
|||||||
contains: "account can only repay up to 50000000ukava",
|
contains: "account can only repay up to 50000000ukava",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"invalid: repaying a single coin type results in borrow position below the minimum USD value",
|
||||||
|
args{
|
||||||
|
borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
||||||
|
initialBorrowerCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(100*USDX_CF))),
|
||||||
|
initialModuleCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("usdx", sdk.NewInt(1000*USDX_CF))),
|
||||||
|
depositCoins: []sdk.Coin{sdk.NewCoin("usdx", sdk.NewInt(100*USDX_CF))},
|
||||||
|
borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(50*USDX_CF))),
|
||||||
|
repayCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(45*USDX_CF))),
|
||||||
|
},
|
||||||
|
errArgs{
|
||||||
|
expectPass: false,
|
||||||
|
expectDelete: false,
|
||||||
|
contains: "proposed borrow's USD value $5.000000000000000000 is below the minimum borrow limit",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"invalid: repaying multiple coin types results in borrow position below the minimum USD value",
|
||||||
|
args{
|
||||||
|
borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
||||||
|
initialBorrowerCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(100*USDX_CF))),
|
||||||
|
initialModuleCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("usdx", sdk.NewInt(1000*USDX_CF))),
|
||||||
|
depositCoins: []sdk.Coin{sdk.NewCoin("usdx", sdk.NewInt(100*USDX_CF))},
|
||||||
|
borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(50*USDX_CF)), sdk.NewCoin("ukava", sdk.NewInt(10*KAVA_CF))), // (50*$1)+(10*$2) = $70
|
||||||
|
repayCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(45*USDX_CF)), sdk.NewCoin("ukava", sdk.NewInt(8*KAVA_CF))), // (45*$1)+(8*2) = $61
|
||||||
|
},
|
||||||
|
errArgs{
|
||||||
|
expectPass: false,
|
||||||
|
expectDelete: false,
|
||||||
|
contains: "proposed borrow's USD value $9.000000000000000000 is below the minimum borrow limit",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
@ -153,6 +185,7 @@ func (suite *KeeperTestSuite) TestRepay() {
|
|||||||
sdk.MustNewDecFromStr("0.05"), // Reserve Factor
|
sdk.MustNewDecFromStr("0.05"), // Reserve Factor
|
||||||
sdk.MustNewDecFromStr("0.05")), // Keeper Reward Percent
|
sdk.MustNewDecFromStr("0.05")), // Keeper Reward Percent
|
||||||
},
|
},
|
||||||
|
sdk.NewDec(10),
|
||||||
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
|
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
|
||||||
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
|
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
|
||||||
)
|
)
|
||||||
|
@ -285,6 +285,7 @@ func (suite *KeeperTestSuite) TestSendTimeLockedCoinsToAccount() {
|
|||||||
types.NewMoneyMarket("usdx", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "usdx:usd", sdk.NewInt(1000000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
types.NewMoneyMarket("usdx", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "usdx:usd", sdk.NewInt(1000000), 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), 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), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
},
|
},
|
||||||
|
sdk.NewDec(10),
|
||||||
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
|
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
|
||||||
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
|
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
|
||||||
)
|
)
|
||||||
|
@ -129,6 +129,7 @@ func (suite *KeeperTestSuite) TestWithdraw() {
|
|||||||
types.NewMoneyMarket("ukava", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "kava:usd", sdk.NewInt(1000000), 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), 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), 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), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
},
|
},
|
||||||
|
sdk.NewDec(10),
|
||||||
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
|
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
|
||||||
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
|
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
|
||||||
)
|
)
|
||||||
@ -212,6 +213,7 @@ func (suite *KeeperTestSuite) TestLtvWithdraw() {
|
|||||||
initialBorrowerCoins sdk.Coins
|
initialBorrowerCoins sdk.Coins
|
||||||
depositCoins sdk.Coins
|
depositCoins sdk.Coins
|
||||||
borrowCoins sdk.Coins
|
borrowCoins sdk.Coins
|
||||||
|
repayCoins sdk.Coins
|
||||||
futureTime int64
|
futureTime int64
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,8 +241,9 @@ func (suite *KeeperTestSuite) TestLtvWithdraw() {
|
|||||||
borrower: borrower,
|
borrower: borrower,
|
||||||
initialModuleCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF))),
|
initialModuleCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF))),
|
||||||
initialBorrowerCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF)), sdk.NewCoin("usdx", sdk.NewInt(100*KAVA_CF))),
|
initialBorrowerCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF)), sdk.NewCoin("usdx", sdk.NewInt(100*KAVA_CF))),
|
||||||
depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(10*KAVA_CF))), // 10 * 2 = $20
|
depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF))), // 100 * 2 = $200
|
||||||
borrowCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(8*KAVA_CF))), // 8 * 2 = $16
|
borrowCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(80*KAVA_CF))), // 80 * 2 = $160
|
||||||
|
repayCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(60*KAVA_CF))), // 60 * 2 = $120
|
||||||
futureTime: oneMonthInSeconds,
|
futureTime: oneMonthInSeconds,
|
||||||
},
|
},
|
||||||
errArgs{
|
errArgs{
|
||||||
@ -280,6 +283,7 @@ func (suite *KeeperTestSuite) TestLtvWithdraw() {
|
|||||||
reserveFactor, // Reserve Factor
|
reserveFactor, // Reserve Factor
|
||||||
sdk.MustNewDecFromStr("0.05")), // Keeper Reward Percent
|
sdk.MustNewDecFromStr("0.05")), // Keeper Reward Percent
|
||||||
},
|
},
|
||||||
|
sdk.NewDec(10),
|
||||||
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
|
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
|
||||||
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
|
types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves,
|
||||||
)
|
)
|
||||||
@ -353,8 +357,8 @@ func (suite *KeeperTestSuite) TestLtvWithdraw() {
|
|||||||
suite.Require().Error(err)
|
suite.Require().Error(err)
|
||||||
suite.Require().True(strings.Contains(err.Error(), tc.errArgs.contains))
|
suite.Require().True(strings.Contains(err.Error(), tc.errArgs.contains))
|
||||||
|
|
||||||
// Repay the initial principal
|
// Repay the initial principal. Over pay the position so the borrow is closed.
|
||||||
err = suite.keeper.Repay(suite.ctx, tc.args.borrower, tc.args.borrower, tc.args.borrowCoins)
|
err = suite.keeper.Repay(suite.ctx, tc.args.borrower, tc.args.borrower, tc.args.repayCoins)
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
// Attempted withdraw of all deposited coins fails as user hasn't repaid interest debt
|
// Attempted withdraw of all deposited coins fails as user hasn't repaid interest debt
|
||||||
@ -362,8 +366,8 @@ func (suite *KeeperTestSuite) TestLtvWithdraw() {
|
|||||||
suite.Require().Error(err)
|
suite.Require().Error(err)
|
||||||
suite.Require().True(strings.Contains(err.Error(), tc.errArgs.contains))
|
suite.Require().True(strings.Contains(err.Error(), tc.errArgs.contains))
|
||||||
|
|
||||||
// Withdrawing half the coins should succeed
|
// Withdrawing 10% of the coins should succeed
|
||||||
withdrawCoins := sdk.NewCoins(sdk.NewCoin("ukava", tc.args.depositCoins[0].Amount.Quo(sdk.NewInt(2))))
|
withdrawCoins := sdk.NewCoins(sdk.NewCoin("ukava", tc.args.depositCoins[0].Amount.Quo(sdk.NewInt(10))))
|
||||||
err = suite.keeper.Withdraw(suite.ctx, tc.args.borrower, withdrawCoins)
|
err = suite.keeper.Withdraw(suite.ctx, tc.args.borrower, withdrawCoins)
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
})
|
})
|
||||||
|
@ -63,4 +63,6 @@ var (
|
|||||||
ErrInvalidRepaymentDenom = sdkerrors.Register(ModuleName, 28, "no coins of this type borrowed")
|
ErrInvalidRepaymentDenom = sdkerrors.Register(ModuleName, 28, "no coins of this type borrowed")
|
||||||
// ErrInvalidIndexFactorDenom error for when index factor denom cannot be found
|
// ErrInvalidIndexFactorDenom error for when index factor denom cannot be found
|
||||||
ErrInvalidIndexFactorDenom = sdkerrors.Register(ModuleName, 29, "no index factor found for denom")
|
ErrInvalidIndexFactorDenom = sdkerrors.Register(ModuleName, 29, "no index factor found for denom")
|
||||||
|
// ErrBelowMinimumBorrowValue error for when a proposed borrow position is less than the minimum USD value
|
||||||
|
ErrBelowMinimumBorrowValue = sdkerrors.Register(ModuleName, 30, "invalid proposed borrow value")
|
||||||
)
|
)
|
||||||
|
@ -61,6 +61,7 @@ func (suite *GenesisTestSuite) TestGenesisValidation() {
|
|||||||
types.MoneyMarkets{
|
types.MoneyMarkets{
|
||||||
types.NewMoneyMarket("usdx", types.NewBorrowLimit(true, sdk.MustNewDecFromStr("100000000000"), sdk.MustNewDecFromStr("1")), "usdx:usd", sdk.NewInt(USDX_CF), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
types.NewMoneyMarket("usdx", types.NewBorrowLimit(true, sdk.MustNewDecFromStr("100000000000"), sdk.MustNewDecFromStr("1")), "usdx:usd", sdk.NewInt(USDX_CF), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
},
|
},
|
||||||
|
sdk.MustNewDecFromStr("10"),
|
||||||
),
|
),
|
||||||
gats: types.GenesisAccumulationTimes{
|
gats: types.GenesisAccumulationTimes{
|
||||||
types.NewGenesisAccumulationTime("usdx", time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), sdk.OneDec(), sdk.OneDec()),
|
types.NewGenesisAccumulationTime("usdx", time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), sdk.OneDec(), sdk.OneDec()),
|
||||||
|
@ -11,20 +11,23 @@ import (
|
|||||||
|
|
||||||
// Parameter keys and default values
|
// Parameter keys and default values
|
||||||
var (
|
var (
|
||||||
KeyMoneyMarkets = []byte("MoneyMarkets")
|
KeyMoneyMarkets = []byte("MoneyMarkets")
|
||||||
DefaultMoneyMarkets = MoneyMarkets{}
|
KeyMinimumBorrowUSDValue = []byte("MinimumBorrowUSDValue")
|
||||||
GovDenom = cdptypes.DefaultGovDenom
|
DefaultMoneyMarkets = MoneyMarkets{}
|
||||||
DefaultAccumulationTimes = GenesisAccumulationTimes{}
|
DefaultMinimumBorrowUSDValue = sdk.NewDec(10) // $10 USD minimum borrow value
|
||||||
DefaultTotalSupplied = sdk.Coins{}
|
GovDenom = cdptypes.DefaultGovDenom
|
||||||
DefaultTotalBorrowed = sdk.Coins{}
|
DefaultAccumulationTimes = GenesisAccumulationTimes{}
|
||||||
DefaultTotalReserves = sdk.Coins{}
|
DefaultTotalSupplied = sdk.Coins{}
|
||||||
DefaultDeposits = Deposits{}
|
DefaultTotalBorrowed = sdk.Coins{}
|
||||||
DefaultBorrows = Borrows{}
|
DefaultTotalReserves = sdk.Coins{}
|
||||||
|
DefaultDeposits = Deposits{}
|
||||||
|
DefaultBorrows = Borrows{}
|
||||||
)
|
)
|
||||||
|
|
||||||
// Params governance parameters for hard module
|
// Params governance parameters for hard module
|
||||||
type Params struct {
|
type Params struct {
|
||||||
MoneyMarkets MoneyMarkets `json:"money_markets" yaml:"money_markets"`
|
MoneyMarkets MoneyMarkets `json:"money_markets" yaml:"money_markets"`
|
||||||
|
MinimumBorrowUSDValue sdk.Dec `json:"minimum_borrow_usd_value" yaml:"minimum_borrow_usd_value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// BorrowLimit enforces restrictions on a money market
|
// BorrowLimit enforces restrictions on a money market
|
||||||
@ -220,22 +223,24 @@ func (irm InterestRateModel) Equal(irmCompareTo InterestRateModel) bool {
|
|||||||
type InterestRateModels []InterestRateModel
|
type InterestRateModels []InterestRateModel
|
||||||
|
|
||||||
// NewParams returns a new params object
|
// NewParams returns a new params object
|
||||||
func NewParams(moneyMarkets MoneyMarkets) Params {
|
func NewParams(moneyMarkets MoneyMarkets, minimumBorrowUSDValue sdk.Dec) Params {
|
||||||
return Params{
|
return Params{
|
||||||
MoneyMarkets: moneyMarkets,
|
MoneyMarkets: moneyMarkets,
|
||||||
|
MinimumBorrowUSDValue: minimumBorrowUSDValue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultParams returns default params for hard module
|
// DefaultParams returns default params for hard module
|
||||||
func DefaultParams() Params {
|
func DefaultParams() Params {
|
||||||
return NewParams(DefaultMoneyMarkets)
|
return NewParams(DefaultMoneyMarkets, DefaultMinimumBorrowUSDValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements fmt.Stringer
|
// String implements fmt.Stringer
|
||||||
func (p Params) String() string {
|
func (p Params) String() string {
|
||||||
return fmt.Sprintf(`Params:
|
return fmt.Sprintf(`Params:
|
||||||
Money Markets %v`,
|
Minimum Borrow USD Value: %v
|
||||||
p.MoneyMarkets)
|
Money Markets: %v`,
|
||||||
|
p.MinimumBorrowUSDValue, p.MoneyMarkets)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParamKeyTable Key declaration for parameters
|
// ParamKeyTable Key declaration for parameters
|
||||||
@ -247,14 +252,32 @@ func ParamKeyTable() params.KeyTable {
|
|||||||
func (p *Params) ParamSetPairs() params.ParamSetPairs {
|
func (p *Params) ParamSetPairs() params.ParamSetPairs {
|
||||||
return params.ParamSetPairs{
|
return params.ParamSetPairs{
|
||||||
params.NewParamSetPair(KeyMoneyMarkets, &p.MoneyMarkets, validateMoneyMarketParams),
|
params.NewParamSetPair(KeyMoneyMarkets, &p.MoneyMarkets, validateMoneyMarketParams),
|
||||||
|
params.NewParamSetPair(KeyMinimumBorrowUSDValue, &p.MinimumBorrowUSDValue, validateMinimumBorrowUSDValue),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate checks that the parameters have valid values.
|
// Validate checks that the parameters have valid values.
|
||||||
func (p Params) Validate() error {
|
func (p Params) Validate() error {
|
||||||
|
if err := validateMinimumBorrowUSDValue(p.MinimumBorrowUSDValue); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return validateMoneyMarketParams(p.MoneyMarkets)
|
return validateMoneyMarketParams(p.MoneyMarkets)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateMinimumBorrowUSDValue(i interface{}) error {
|
||||||
|
minBorrowVal, ok := i.(sdk.Dec)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("invalid parameter type: %T", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
if minBorrowVal.IsNegative() {
|
||||||
|
return fmt.Errorf("Minimum borrow USD value cannot be negative")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func validateMoneyMarketParams(i interface{}) error {
|
func validateMoneyMarketParams(i interface{}) error {
|
||||||
mm, ok := i.(MoneyMarkets)
|
mm, ok := i.(MoneyMarkets)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
"github.com/kava-labs/kava/x/hard/types"
|
"github.com/kava-labs/kava/x/hard/types"
|
||||||
@ -15,7 +16,8 @@ type ParamTestSuite struct {
|
|||||||
|
|
||||||
func (suite *ParamTestSuite) TestParamValidation() {
|
func (suite *ParamTestSuite) TestParamValidation() {
|
||||||
type args struct {
|
type args struct {
|
||||||
mms types.MoneyMarkets
|
minBorrowVal sdk.Dec
|
||||||
|
mms types.MoneyMarkets
|
||||||
}
|
}
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
@ -26,7 +28,8 @@ func (suite *ParamTestSuite) TestParamValidation() {
|
|||||||
{
|
{
|
||||||
name: "default",
|
name: "default",
|
||||||
args: args{
|
args: args{
|
||||||
mms: types.DefaultMoneyMarkets,
|
minBorrowVal: types.DefaultMinimumBorrowUSDValue,
|
||||||
|
mms: types.DefaultMoneyMarkets,
|
||||||
},
|
},
|
||||||
expectPass: true,
|
expectPass: true,
|
||||||
expectedErr: "",
|
expectedErr: "",
|
||||||
@ -34,7 +37,7 @@ func (suite *ParamTestSuite) TestParamValidation() {
|
|||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
suite.Run(tc.name, func() {
|
suite.Run(tc.name, func() {
|
||||||
params := types.NewParams(tc.args.mms)
|
params := types.NewParams(tc.args.mms, tc.args.minBorrowVal)
|
||||||
err := params.Validate()
|
err := params.Validate()
|
||||||
if tc.expectPass {
|
if tc.expectPass {
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
@ -159,6 +159,7 @@ func NewHardGenStateMulti() app.GenesisState {
|
|||||||
hard.NewMoneyMarket("btcb", hard.NewBorrowLimit(false, borrowLimit, loanToValue), "btc:usd", sdk.NewInt(1000000), hard.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
hard.NewMoneyMarket("btcb", hard.NewBorrowLimit(false, borrowLimit, loanToValue), "btc:usd", sdk.NewInt(1000000), hard.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
hard.NewMoneyMarket("xrp", hard.NewBorrowLimit(false, borrowLimit, loanToValue), "xrp:usd", sdk.NewInt(1000000), hard.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
hard.NewMoneyMarket("xrp", hard.NewBorrowLimit(false, borrowLimit, loanToValue), "xrp:usd", sdk.NewInt(1000000), hard.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
},
|
},
|
||||||
|
sdk.NewDec(10),
|
||||||
), hard.DefaultAccumulationTimes, hard.DefaultDeposits, hard.DefaultBorrows,
|
), hard.DefaultAccumulationTimes, hard.DefaultDeposits, hard.DefaultBorrows,
|
||||||
hard.DefaultTotalSupplied, hard.DefaultTotalBorrowed, hard.DefaultTotalReserves,
|
hard.DefaultTotalSupplied, hard.DefaultTotalBorrowed, hard.DefaultTotalReserves,
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user