test(insolvency): add tests for Kava lend insolvency check (#1981)

* add additional tests that attempt to borrow funds from the insolvent market(should fail), and attempt to borrow funds from the not insolvent market (it will fail, but shouldn't). The not insolvent market should continue to processs borrows

* remove unused code

* make tests less specific for string contains

* change the structure for new and old tests and add more verbosity for other tests

* remove print

* remove unneeded code

* add paren

* remove duplicate test case with invalid test name, and update to use error contains in places where it was validating if true for strings contains

---------

Co-authored-by: Sam Sheffield <sam.sheffield@kavalabs.io>
This commit is contained in:
sesheffield 2024-07-29 20:51:08 -04:00 committed by GitHub
parent b4c04656ab
commit 916ec6d30c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 494 additions and 251 deletions

View File

@ -7,7 +7,6 @@ import (
sdkmath "cosmossdk.io/math" sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/kava-labs/kava/x/hard/types" "github.com/kava-labs/kava/x/hard/types"
) )

View File

@ -1,7 +1,6 @@
package keeper_test package keeper_test
import ( import (
"strings"
"time" "time"
sdkmath "cosmossdk.io/math" sdkmath "cosmossdk.io/math"
@ -9,7 +8,6 @@ import (
tmproto "github.com/cometbft/cometbft/proto/tendermint/types" tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
tmtime "github.com/cometbft/cometbft/types/time" tmtime "github.com/cometbft/cometbft/types/time"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/app" "github.com/kava-labs/kava/app"
"github.com/kava-labs/kava/x/hard" "github.com/kava-labs/kava/x/hard"
"github.com/kava-labs/kava/x/hard/types" "github.com/kava-labs/kava/x/hard/types"
@ -25,7 +23,7 @@ const (
) )
func (suite *KeeperTestSuite) TestBorrow() { func (suite *KeeperTestSuite) TestBorrow() {
type args struct { type setupArgs struct {
usdxBorrowLimit sdk.Dec usdxBorrowLimit sdk.Dec
priceKAVA sdk.Dec priceKAVA sdk.Dec
loanToValueKAVA sdk.Dec loanToValueKAVA sdk.Dec
@ -35,24 +33,32 @@ func (suite *KeeperTestSuite) TestBorrow() {
loanToValueBNB sdk.Dec loanToValueBNB sdk.Dec
borrower sdk.AccAddress borrower sdk.AccAddress
depositCoins []sdk.Coin depositCoins []sdk.Coin
previousBorrowCoins sdk.Coins initialBorrowCoins sdk.Coins
}
type borrowArgs struct {
borrowCoins sdk.Coins borrowCoins sdk.Coins
wantErr string
}
type expected struct {
expectedAccountBalance sdk.Coins expectedAccountBalance sdk.Coins
expectedModAccountBalance sdk.Coins expectedModAccountBalance sdk.Coins
}
type errArgs struct {
expectPass bool expectPass bool
contains string contains string
} }
type borrowTest struct { type borrowTest struct {
name string name string
args args setup setupArgs
errArgs errArgs borrows []borrowArgs
expected []expected
} }
testCases := []borrowTest{ testCases := []borrowTest{
{ {
"valid", name: "valid",
args{ setup: setupArgs{
usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"), usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"),
priceKAVA: sdk.MustNewDecFromStr("5.00"), priceKAVA: sdk.MustNewDecFromStr("5.00"),
loanToValueKAVA: sdk.MustNewDecFromStr("0.6"), loanToValueKAVA: sdk.MustNewDecFromStr("0.6"),
@ -62,19 +68,26 @@ func (suite *KeeperTestSuite) TestBorrow() {
loanToValueBNB: sdk.MustNewDecFromStr("0.01"), loanToValueBNB: sdk.MustNewDecFromStr("0.01"),
borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))), borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
depositCoins: []sdk.Coin{sdk.NewCoin("ukava", sdkmath.NewInt(100*KAVA_CF))}, depositCoins: []sdk.Coin{sdk.NewCoin("ukava", sdkmath.NewInt(100*KAVA_CF))},
previousBorrowCoins: sdk.NewCoins(), initialBorrowCoins: sdk.NewCoins(),
borrowCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(20*KAVA_CF))), },
expected: []expected{
{
expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(20*KAVA_CF)), sdk.NewCoin("btcb", sdkmath.NewInt(100*BTCB_CF)), sdk.NewCoin("bnb", sdkmath.NewInt(100*BNB_CF)), sdk.NewCoin("xyz", sdkmath.NewInt(1))), expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(20*KAVA_CF)), sdk.NewCoin("btcb", sdkmath.NewInt(100*BTCB_CF)), sdk.NewCoin("bnb", sdkmath.NewInt(100*BNB_CF)), sdk.NewCoin("xyz", sdkmath.NewInt(1))),
expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(1080*KAVA_CF)), sdk.NewCoin("usdx", sdkmath.NewInt(200*USDX_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF))), expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(1080*KAVA_CF)), sdk.NewCoin("usdx", sdkmath.NewInt(200*USDX_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF))),
},
errArgs{
expectPass: true, expectPass: true,
contains: "", },
},
borrows: []borrowArgs{
{
borrowCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(20*KAVA_CF))),
wantErr: "",
},
}, },
}, },
{ {
"invalid: loan-to-value limited", name: "invalid: loan-to-value limited",
args{ setup: setupArgs{
usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"), usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"),
priceKAVA: sdk.MustNewDecFromStr("5.00"), priceKAVA: sdk.MustNewDecFromStr("5.00"),
loanToValueKAVA: sdk.MustNewDecFromStr("0.6"), loanToValueKAVA: sdk.MustNewDecFromStr("0.6"),
@ -84,18 +97,27 @@ func (suite *KeeperTestSuite) TestBorrow() {
loanToValueBNB: sdk.MustNewDecFromStr("0.01"), loanToValueBNB: sdk.MustNewDecFromStr("0.01"),
borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))), borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
depositCoins: []sdk.Coin{sdk.NewCoin("ukava", sdkmath.NewInt(20*KAVA_CF))}, // 20 KAVA x $5.00 price = $100 depositCoins: []sdk.Coin{sdk.NewCoin("ukava", sdkmath.NewInt(20*KAVA_CF))}, // 20 KAVA x $5.00 price = $100
borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(61*USDX_CF))), // 61 USDX x $1 price = $61 initialBorrowCoins: sdk.NewCoins(),
},
expected: []expected{
{
expectedAccountBalance: sdk.NewCoins(), expectedAccountBalance: sdk.NewCoins(),
expectedModAccountBalance: sdk.NewCoins(), expectedModAccountBalance: sdk.NewCoins(),
},
errArgs{
expectPass: false, expectPass: false,
contains: "exceeds the allowable amount as determined by the collateralization ratio", contains: "exceeds the allowable amount as determined by the collateralization ratio",
}, },
}, },
borrows: []borrowArgs{
{ {
"valid: multiple deposits", borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(61*USDX_CF))), // 61 USDX x $1 price = $61
args{ wantErr: "",
},
},
},
{
name: "valid: multiple deposits",
setup: setupArgs{
usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"), usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"),
priceKAVA: sdk.MustNewDecFromStr("2.00"), priceKAVA: sdk.MustNewDecFromStr("2.00"),
loanToValueKAVA: sdk.MustNewDecFromStr("0.80"), loanToValueKAVA: sdk.MustNewDecFromStr("0.80"),
@ -105,18 +127,28 @@ func (suite *KeeperTestSuite) TestBorrow() {
loanToValueBNB: sdk.MustNewDecFromStr("0.01"), loanToValueBNB: sdk.MustNewDecFromStr("0.01"),
borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))), borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF)), sdk.NewCoin("btcb", sdkmath.NewInt(0.1*BTCB_CF))), depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF)), sdk.NewCoin("btcb", sdkmath.NewInt(0.1*BTCB_CF))),
borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(180*USDX_CF))), initialBorrowCoins: sdk.NewCoins(),
},
expected: []expected{
{
expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF)), sdk.NewCoin("btcb", sdkmath.NewInt(99.9*BTCB_CF)), sdk.NewCoin("usdx", sdkmath.NewInt(180*USDX_CF)), sdk.NewCoin("bnb", sdkmath.NewInt(100*BNB_CF)), sdk.NewCoin("xyz", sdkmath.NewInt(1))), expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF)), sdk.NewCoin("btcb", sdkmath.NewInt(99.9*BTCB_CF)), sdk.NewCoin("usdx", sdkmath.NewInt(180*USDX_CF)), sdk.NewCoin("bnb", sdkmath.NewInt(100*BNB_CF)), sdk.NewCoin("xyz", sdkmath.NewInt(1))),
expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(1050*KAVA_CF)), sdk.NewCoin("usdx", sdkmath.NewInt(20*USDX_CF)), sdk.NewCoin("btcb", sdkmath.NewInt(0.1*BTCB_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF))), expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(1050*KAVA_CF)), sdk.NewCoin("usdx", sdkmath.NewInt(20*USDX_CF)), sdk.NewCoin("btcb", sdkmath.NewInt(0.1*BTCB_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF))),
},
errArgs{
expectPass: true, expectPass: true,
contains: "",
contains: "exceeds the allowable amount as determined by the collateralization ratio",
},
},
borrows: []borrowArgs{
{
borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(180*USDX_CF))),
wantErr: "",
},
}, },
}, },
{ {
"invalid: multiple deposits", name: "invalid: multiple deposits",
args{ setup: setupArgs{
usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"), usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"),
priceKAVA: sdk.MustNewDecFromStr("2.00"), priceKAVA: sdk.MustNewDecFromStr("2.00"),
loanToValueKAVA: sdk.MustNewDecFromStr("0.80"), loanToValueKAVA: sdk.MustNewDecFromStr("0.80"),
@ -126,18 +158,27 @@ func (suite *KeeperTestSuite) TestBorrow() {
loanToValueBNB: sdk.MustNewDecFromStr("0.01"), loanToValueBNB: sdk.MustNewDecFromStr("0.01"),
borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))), borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF)), sdk.NewCoin("btcb", sdkmath.NewInt(0.1*BTCB_CF))), depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF)), sdk.NewCoin("btcb", sdkmath.NewInt(0.1*BTCB_CF))),
borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(181*USDX_CF))), initialBorrowCoins: sdk.NewCoins(),
},
expected: []expected{
{
expectedAccountBalance: sdk.NewCoins(), expectedAccountBalance: sdk.NewCoins(),
expectedModAccountBalance: sdk.NewCoins(), expectedModAccountBalance: sdk.NewCoins(),
},
errArgs{
expectPass: false, expectPass: false,
contains: "exceeds the allowable amount as determined by the collateralization ratio", contains: "exceeds the allowable amount as determined by the collateralization ratio",
}, },
}, },
borrows: []borrowArgs{
{ {
"valid: multiple previous borrows", borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(181*USDX_CF))),
args{ wantErr: "",
},
},
},
{
name: "valid: multiple previous borrows",
setup: setupArgs{
usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"), usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"),
priceKAVA: sdk.MustNewDecFromStr("2.00"), priceKAVA: sdk.MustNewDecFromStr("2.00"),
loanToValueKAVA: sdk.MustNewDecFromStr("0.8"), loanToValueKAVA: sdk.MustNewDecFromStr("0.8"),
@ -147,19 +188,26 @@ func (suite *KeeperTestSuite) TestBorrow() {
loanToValueBNB: sdk.MustNewDecFromStr("0.8"), loanToValueBNB: sdk.MustNewDecFromStr("0.8"),
borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))), borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
depositCoins: sdk.NewCoins(sdk.NewCoin("bnb", sdkmath.NewInt(30*BNB_CF)), sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF))), // (50 KAVA x $2.00 price = $100) + (30 BNB x $5.00 price = $150) = $250 depositCoins: sdk.NewCoins(sdk.NewCoin("bnb", sdkmath.NewInt(30*BNB_CF)), sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF))), // (50 KAVA x $2.00 price = $100) + (30 BNB x $5.00 price = $150) = $250
previousBorrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(99*USDX_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF))), initialBorrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(99*USDX_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF))),
borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(1*USDX_CF))), },
expected: []expected{
{
expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF)), sdk.NewCoin("btcb", sdkmath.NewInt(100*BTCB_CF)), sdk.NewCoin("usdx", sdkmath.NewInt(100*USDX_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF)), sdk.NewCoin("bnb", sdkmath.NewInt(70*BNB_CF)), sdk.NewCoin("xyz", sdkmath.NewInt(1))), expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF)), sdk.NewCoin("btcb", sdkmath.NewInt(100*BTCB_CF)), sdk.NewCoin("usdx", sdkmath.NewInt(100*USDX_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF)), sdk.NewCoin("bnb", sdkmath.NewInt(70*BNB_CF)), sdk.NewCoin("xyz", sdkmath.NewInt(1))),
expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(1050*KAVA_CF)), sdk.NewCoin("bnb", sdkmath.NewInt(30*BUSD_CF)), sdk.NewCoin("usdx", sdkmath.NewInt(100*USDX_CF))), expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(1050*KAVA_CF)), sdk.NewCoin("bnb", sdkmath.NewInt(30*BUSD_CF)), sdk.NewCoin("usdx", sdkmath.NewInt(100*USDX_CF))),
},
errArgs{
expectPass: true, expectPass: true,
contains: "", },
},
borrows: []borrowArgs{
{
borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(1*USDX_CF))),
wantErr: "",
},
}, },
}, },
{ {
"invalid: over loan-to-value with multiple previous borrows", name: "invalid: over loan-to-value with multiple previous borrows",
args{ setup: setupArgs{
usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"), usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"),
priceKAVA: sdk.MustNewDecFromStr("2.00"), priceKAVA: sdk.MustNewDecFromStr("2.00"),
loanToValueKAVA: sdk.MustNewDecFromStr("0.8"), loanToValueKAVA: sdk.MustNewDecFromStr("0.8"),
@ -169,19 +217,26 @@ func (suite *KeeperTestSuite) TestBorrow() {
loanToValueBNB: sdk.MustNewDecFromStr("0.8"), loanToValueBNB: sdk.MustNewDecFromStr("0.8"),
borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))), borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
depositCoins: sdk.NewCoins(sdk.NewCoin("bnb", sdkmath.NewInt(30*BNB_CF)), sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF))), // (50 KAVA x $2.00 price = $100) + (30 BNB x $5.00 price = $150) = $250 depositCoins: sdk.NewCoins(sdk.NewCoin("bnb", sdkmath.NewInt(30*BNB_CF)), sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF))), // (50 KAVA x $2.00 price = $100) + (30 BNB x $5.00 price = $150) = $250
previousBorrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(100*USDX_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF))), initialBorrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(100*USDX_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF))),
borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(1*USDX_CF))), },
expected: []expected{
{
expectedAccountBalance: sdk.NewCoins(), expectedAccountBalance: sdk.NewCoins(),
expectedModAccountBalance: sdk.NewCoins(), expectedModAccountBalance: sdk.NewCoins(),
},
errArgs{
expectPass: false, expectPass: false,
contains: "exceeds the allowable amount as determined by the collateralization ratio", contains: "exceeds the allowable amount as determined by the collateralization ratio",
}, },
}, },
borrows: []borrowArgs{
{ {
"invalid: no price for asset", borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(1*USDX_CF))),
args{ wantErr: "",
},
},
},
{
name: "invalid: no price for asset",
setup: setupArgs{
usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"), usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"),
priceKAVA: sdk.MustNewDecFromStr("5.00"), priceKAVA: sdk.MustNewDecFromStr("5.00"),
loanToValueKAVA: sdk.MustNewDecFromStr("0.6"), loanToValueKAVA: sdk.MustNewDecFromStr("0.6"),
@ -191,19 +246,27 @@ func (suite *KeeperTestSuite) TestBorrow() {
loanToValueBNB: sdk.MustNewDecFromStr("0.01"), loanToValueBNB: sdk.MustNewDecFromStr("0.01"),
borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))), borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(100*KAVA_CF))), depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(100*KAVA_CF))),
previousBorrowCoins: sdk.NewCoins(), initialBorrowCoins: sdk.NewCoins(),
borrowCoins: sdk.NewCoins(sdk.NewCoin("xyz", sdkmath.NewInt(1))), },
expected: []expected{
{
expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(20*KAVA_CF)), sdk.NewCoin("btcb", sdkmath.NewInt(100*BTCB_CF)), sdk.NewCoin("bnb", sdkmath.NewInt(100*BNB_CF)), sdk.NewCoin("xyz", sdkmath.NewInt(1))), expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(20*KAVA_CF)), sdk.NewCoin("btcb", sdkmath.NewInt(100*BTCB_CF)), sdk.NewCoin("bnb", sdkmath.NewInt(100*BNB_CF)), sdk.NewCoin("xyz", sdkmath.NewInt(1))),
expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(1080*KAVA_CF)), sdk.NewCoin("usdx", sdkmath.NewInt(200*USDX_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF))), expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(1080*KAVA_CF)), sdk.NewCoin("usdx", sdkmath.NewInt(200*USDX_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF))),
},
errArgs{
expectPass: false, expectPass: false,
contains: "no price found for market", contains: "no price found for market",
}, },
}, },
borrows: []borrowArgs{
{ {
"invalid: borrow exceed module account balance", borrowCoins: sdk.NewCoins(sdk.NewCoin("xyz", sdkmath.NewInt(1))),
args{ wantErr: "",
},
},
},
{
name: "invalid: borrow exceed module account balance",
setup: setupArgs{
usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"), usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"),
priceKAVA: sdk.MustNewDecFromStr("2.00"), priceKAVA: sdk.MustNewDecFromStr("2.00"),
loanToValueKAVA: sdk.MustNewDecFromStr("0.8"), loanToValueKAVA: sdk.MustNewDecFromStr("0.8"),
@ -213,19 +276,26 @@ func (suite *KeeperTestSuite) TestBorrow() {
loanToValueBNB: sdk.MustNewDecFromStr("0.01"), loanToValueBNB: sdk.MustNewDecFromStr("0.01"),
borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))), borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(100*KAVA_CF))), depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(100*KAVA_CF))),
previousBorrowCoins: sdk.NewCoins(), initialBorrowCoins: sdk.NewCoins(),
borrowCoins: sdk.NewCoins(sdk.NewCoin("busd", sdkmath.NewInt(101*BUSD_CF))), },
expected: []expected{
{
expectedAccountBalance: sdk.NewCoins(), expectedAccountBalance: sdk.NewCoins(),
expectedModAccountBalance: sdk.NewCoins(), expectedModAccountBalance: sdk.NewCoins(),
},
errArgs{
expectPass: false, expectPass: false,
contains: "exceeds borrowable module account balance", contains: "exceeds borrowable module account balance",
}, },
}, },
borrows: []borrowArgs{
{ {
"invalid: over global asset borrow limit", borrowCoins: sdk.NewCoins(sdk.NewCoin("busd", sdkmath.NewInt(101*BUSD_CF))),
args{ wantErr: "",
},
},
},
{
name: "invalid: over global asset borrow limit",
setup: setupArgs{
usdxBorrowLimit: sdk.MustNewDecFromStr("20000000"), usdxBorrowLimit: sdk.MustNewDecFromStr("20000000"),
priceKAVA: sdk.MustNewDecFromStr("2.00"), priceKAVA: sdk.MustNewDecFromStr("2.00"),
loanToValueKAVA: sdk.MustNewDecFromStr("0.8"), loanToValueKAVA: sdk.MustNewDecFromStr("0.8"),
@ -235,19 +305,26 @@ func (suite *KeeperTestSuite) TestBorrow() {
loanToValueBNB: sdk.MustNewDecFromStr("0.01"), loanToValueBNB: sdk.MustNewDecFromStr("0.01"),
borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))), borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF))), depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF))),
previousBorrowCoins: sdk.NewCoins(), initialBorrowCoins: sdk.NewCoins(),
borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(25*USDX_CF))), },
expected: []expected{
{
expectedAccountBalance: sdk.NewCoins(), expectedAccountBalance: sdk.NewCoins(),
expectedModAccountBalance: sdk.NewCoins(), expectedModAccountBalance: sdk.NewCoins(),
},
errArgs{
expectPass: false, expectPass: false,
contains: "fails global asset borrow limit validation", contains: "fails global asset borrow limit validation",
}, },
}, },
borrows: []borrowArgs{
{ {
"invalid: borrowing an individual coin type results in a borrow that's under the minimum USD borrow limit", borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(25*USDX_CF))),
args{ wantErr: "",
},
},
},
{
name: "invalid: borrowing an individual coin type results in a borrow that's under the minimum USD borrow limit",
setup: setupArgs{
usdxBorrowLimit: sdk.MustNewDecFromStr("20000000"), usdxBorrowLimit: sdk.MustNewDecFromStr("20000000"),
priceKAVA: sdk.MustNewDecFromStr("2.00"), priceKAVA: sdk.MustNewDecFromStr("2.00"),
loanToValueKAVA: sdk.MustNewDecFromStr("0.8"), loanToValueKAVA: sdk.MustNewDecFromStr("0.8"),
@ -257,19 +334,26 @@ func (suite *KeeperTestSuite) TestBorrow() {
loanToValueBNB: sdk.MustNewDecFromStr("0.01"), loanToValueBNB: sdk.MustNewDecFromStr("0.01"),
borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))), borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF))), depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF))),
previousBorrowCoins: sdk.NewCoins(), initialBorrowCoins: sdk.NewCoins(),
},
expected: []expected{
{
expectedAccountBalance: sdk.NewCoins(),
expectedModAccountBalance: sdk.NewCoins(),
expectPass: false,
contains: "below the minimum borrow limit",
},
},
borrows: []borrowArgs{
{
borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(5*USDX_CF))), borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(5*USDX_CF))),
expectedAccountBalance: sdk.NewCoins(), wantErr: "",
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", name: "invalid: borrowing multiple coins results in a borrow that's under the minimum USD borrow limit",
args{ setup: setupArgs{
usdxBorrowLimit: sdk.MustNewDecFromStr("20000000"), usdxBorrowLimit: sdk.MustNewDecFromStr("20000000"),
priceKAVA: sdk.MustNewDecFromStr("2.00"), priceKAVA: sdk.MustNewDecFromStr("2.00"),
loanToValueKAVA: sdk.MustNewDecFromStr("0.8"), loanToValueKAVA: sdk.MustNewDecFromStr("0.8"),
@ -279,16 +363,139 @@ func (suite *KeeperTestSuite) TestBorrow() {
loanToValueBNB: sdk.MustNewDecFromStr("0.01"), loanToValueBNB: sdk.MustNewDecFromStr("0.01"),
borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))), borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF))), depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF))),
previousBorrowCoins: sdk.NewCoins(), initialBorrowCoins: sdk.NewCoins(),
borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(5*USDX_CF)), sdk.NewCoin("ukava", sdkmath.NewInt(2*USDX_CF))), },
expected: []expected{
{
expectedAccountBalance: sdk.NewCoins(), expectedAccountBalance: sdk.NewCoins(),
expectedModAccountBalance: sdk.NewCoins(), expectedModAccountBalance: sdk.NewCoins(),
},
errArgs{
expectPass: false, expectPass: false,
contains: "below the minimum borrow limit", contains: "below the minimum borrow limit",
}, },
}, },
borrows: []borrowArgs{
{
borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(5*USDX_CF)), sdk.NewCoin("ukava", sdkmath.NewInt(2*USDX_CF))),
wantErr: "",
},
},
},
{
name: "valid borrow multiple blocks",
setup: setupArgs{
usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"),
priceKAVA: sdk.MustNewDecFromStr("5.00"),
loanToValueKAVA: sdk.MustNewDecFromStr("0.6"),
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.Coin{sdk.NewCoin("ukava", sdkmath.NewInt(100*KAVA_CF))},
initialBorrowCoins: sdk.NewCoins(),
},
expected: []expected{
{
expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(20*KAVA_CF)), sdk.NewCoin("btcb", sdkmath.NewInt(100*BTCB_CF)), sdk.NewCoin("bnb", sdkmath.NewInt(100*BNB_CF)), sdk.NewCoin("xyz", sdkmath.NewInt(1))),
expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(1080*KAVA_CF)), sdk.NewCoin("usdx", sdkmath.NewInt(200*USDX_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF))),
expectPass: true,
},
{
expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(40*KAVA_CF)), sdk.NewCoin("btcb", sdkmath.NewInt(100*BTCB_CF)), sdk.NewCoin("bnb", sdkmath.NewInt(100*BNB_CF)), sdk.NewCoin("xyz", sdkmath.NewInt(1))),
expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(1060*KAVA_CF)), sdk.NewCoin("usdx", sdkmath.NewInt(200*USDX_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF))),
expectPass: true,
},
},
borrows: []borrowArgs{
{
borrowCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(20*KAVA_CF))),
wantErr: "",
},
{
borrowCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(20*KAVA_CF))),
wantErr: "",
},
},
},
{
name: "valid borrow followed by protocol reserves exceed available cash for busd when borrowing from ukava(incorrect)",
setup: setupArgs{
usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"),
priceKAVA: sdk.MustNewDecFromStr("5.00"),
loanToValueKAVA: sdk.MustNewDecFromStr("0.8"),
priceBTCB: sdk.MustNewDecFromStr("0.00"),
loanToValueBTCB: sdk.MustNewDecFromStr("0.01"),
priceBNB: sdk.MustNewDecFromStr("5.00"),
loanToValueBNB: sdk.MustNewDecFromStr("0.8"),
borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
depositCoins: sdk.NewCoins(sdk.NewCoin("bnb", sdkmath.NewInt(30*BNB_CF)), sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF))),
initialBorrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(99*USDX_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF))),
},
expected: []expected{
{
expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF)), sdk.NewCoin("btcb", sdkmath.NewInt(100*BTCB_CF)), sdk.NewCoin("usdx", sdkmath.NewInt(100*USDX_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF)), sdk.NewCoin("bnb", sdkmath.NewInt(70*BNB_CF)), sdk.NewCoin("xyz", sdkmath.NewInt(1))),
expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(1050*KAVA_CF)), sdk.NewCoin("bnb", sdkmath.NewInt(30*BUSD_CF)), sdk.NewCoin("usdx", sdkmath.NewInt(100*USDX_CF))),
expectPass: true,
},
{
expectedAccountBalance: sdk.NewCoins(),
expectedModAccountBalance: sdk.NewCoins(),
expectPass: false,
contains: "insolvency - protocol reserves exceed available cash",
},
},
borrows: []borrowArgs{
{
borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(1*USDX_CF))),
wantErr: "",
},
{
borrowCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(1*KAVA_CF))),
wantErr: "",
},
},
},
{
name: "valid borrow followed by protocol reserves exceed available cash for busd when borrowing from busd",
setup: setupArgs{
usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"),
priceKAVA: sdk.MustNewDecFromStr("2.00"),
loanToValueKAVA: sdk.MustNewDecFromStr("0.8"),
priceBTCB: sdk.MustNewDecFromStr("0.00"),
loanToValueBTCB: sdk.MustNewDecFromStr("0.01"),
priceBNB: sdk.MustNewDecFromStr("5.00"),
loanToValueBNB: sdk.MustNewDecFromStr("0.8"),
borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
depositCoins: sdk.NewCoins(sdk.NewCoin("bnb", sdkmath.NewInt(30*BNB_CF)), sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF))),
initialBorrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(99*USDX_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF))),
},
expected: []expected{
{
expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(50*KAVA_CF)), sdk.NewCoin("btcb", sdkmath.NewInt(100*BTCB_CF)), sdk.NewCoin("usdx", sdkmath.NewInt(100*USDX_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF)), sdk.NewCoin("bnb", sdkmath.NewInt(70*BNB_CF)), sdk.NewCoin("xyz", sdkmath.NewInt(1))),
expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(1050*KAVA_CF)), sdk.NewCoin("bnb", sdkmath.NewInt(30*BUSD_CF)), sdk.NewCoin("usdx", sdkmath.NewInt(100*USDX_CF))),
expectPass: true,
},
{
expectedAccountBalance: sdk.NewCoins(),
expectedModAccountBalance: sdk.NewCoins(),
expectPass: false,
contains: "insolvency - protocol reserves exceed available cash",
},
},
borrows: []borrowArgs{
{
borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(1*USDX_CF))),
wantErr: "",
},
{
borrowCoins: sdk.NewCoins(sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF))),
wantErr: "",
},
},
},
} }
for _, tc := range testCases { for _, tc := range testCases {
suite.Run(tc.name, func() { suite.Run(tc.name, func() {
@ -307,18 +514,18 @@ func (suite *KeeperTestSuite) TestBorrow() {
sdk.NewCoin("xyz", sdkmath.NewInt(1)), sdk.NewCoin("xyz", sdkmath.NewInt(1)),
), ),
}, },
[]sdk.AccAddress{tc.args.borrower}, []sdk.AccAddress{tc.setup.borrower},
) )
// hard module genesis state // hard module genesis state
hardGS := types.NewGenesisState(types.NewParams( hardGS := types.NewGenesisState(types.NewParams(
types.MoneyMarkets{ types.MoneyMarkets{
types.NewMoneyMarket("usdx", types.NewBorrowLimit(true, tc.args.usdxBorrowLimit, sdk.MustNewDecFromStr("1")), "usdx:usd", sdkmath.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, tc.setup.usdxBorrowLimit, sdk.MustNewDecFromStr("1")), "usdx:usd", sdkmath.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("busd", types.NewBorrowLimit(false, sdk.NewDec(100000000*BUSD_CF), sdk.MustNewDecFromStr("1")), "busd:usd", sdkmath.NewInt(BUSD_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("busd", types.NewBorrowLimit(false, sdk.NewDec(100000000*BUSD_CF), sdk.MustNewDecFromStr("1")), "busd:usd", sdkmath.NewInt(BUSD_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("ukava", types.NewBorrowLimit(false, sdk.NewDec(100000000*KAVA_CF), tc.args.loanToValueKAVA), "kava:usd", sdkmath.NewInt(KAVA_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("ukava", types.NewBorrowLimit(false, sdk.NewDec(100000000*KAVA_CF), tc.setup.loanToValueKAVA), "kava:usd", sdkmath.NewInt(KAVA_CF), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.99"), sdk.ZeroDec()),
types.NewMoneyMarket("btcb", types.NewBorrowLimit(false, sdk.NewDec(100000000*BTCB_CF), tc.args.loanToValueBTCB), "btcb:usd", sdkmath.NewInt(BTCB_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("btcb", types.NewBorrowLimit(false, sdk.NewDec(100000000*BTCB_CF), tc.setup.loanToValueBTCB), "btcb:usd", sdkmath.NewInt(BTCB_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", sdkmath.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.setup.loanToValueBNB), "bnb:usd", sdkmath.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", sdkmath.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.setup.loanToValueBNB), "xyz:usd", sdkmath.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), sdk.NewDec(10),
), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows, ), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows,
@ -353,19 +560,19 @@ func (suite *KeeperTestSuite) TestBorrow() {
{ {
MarketID: "kava:usd", MarketID: "kava:usd",
OracleAddress: sdk.AccAddress{}, OracleAddress: sdk.AccAddress{},
Price: tc.args.priceKAVA, Price: tc.setup.priceKAVA,
Expiry: time.Now().Add(1 * time.Hour), Expiry: time.Now().Add(1 * time.Hour),
}, },
{ {
MarketID: "btcb:usd", MarketID: "btcb:usd",
OracleAddress: sdk.AccAddress{}, OracleAddress: sdk.AccAddress{},
Price: tc.args.priceBTCB, Price: tc.setup.priceBTCB,
Expiry: time.Now().Add(1 * time.Hour), Expiry: time.Now().Add(1 * time.Hour),
}, },
{ {
MarketID: "bnb:usd", MarketID: "bnb:usd",
OracleAddress: sdk.AccAddress{}, OracleAddress: sdk.AccAddress{},
Price: tc.args.priceBNB, Price: tc.setup.priceBNB,
Expiry: time.Now().Add(1 * time.Hour), Expiry: time.Now().Add(1 * time.Hour),
}, },
}, },
@ -375,11 +582,13 @@ func (suite *KeeperTestSuite) TestBorrow() {
tApp.InitializeFromGenesisStates(authGS, tApp.InitializeFromGenesisStates(authGS,
app.GenesisState{pricefeedtypes.ModuleName: tApp.AppCodec().MustMarshalJSON(&pricefeedGS)}, app.GenesisState{pricefeedtypes.ModuleName: tApp.AppCodec().MustMarshalJSON(&pricefeedGS)},
app.GenesisState{types.ModuleName: tApp.AppCodec().MustMarshalJSON(&hardGS)}) app.GenesisState{types.ModuleName: tApp.AppCodec().MustMarshalJSON(&hardGS)})
// Mint coins to hard module account // Mint coins to hard module account
bankKeeper := tApp.GetBankKeeper() bankKeeper := tApp.GetBankKeeper()
hardMaccCoins := sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(1000*KAVA_CF)), hardMaccCoins := sdk.NewCoins(
sdk.NewCoin("usdx", sdkmath.NewInt(200*USDX_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF))) sdk.NewCoin("ukava", sdkmath.NewInt(1000*KAVA_CF)),
sdk.NewCoin("usdx", sdkmath.NewInt(200*USDX_CF)),
sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF)),
)
err := bankKeeper.MintCoins(ctx, types.ModuleAccountName, hardMaccCoins) err := bankKeeper.MintCoins(ctx, types.ModuleAccountName, hardMaccCoins)
suite.Require().NoError(err) suite.Require().NoError(err)
@ -387,41 +596,43 @@ func (suite *KeeperTestSuite) TestBorrow() {
suite.app = tApp suite.app = tApp
suite.ctx = ctx suite.ctx = ctx
suite.keeper = keeper suite.keeper = keeper
// Run BeginBlocker once to transition MoneyMarkets // Run BeginBlocker once to transition MoneyMarkets
hard.BeginBlocker(suite.ctx, suite.keeper) hard.BeginBlocker(suite.ctx, suite.keeper)
suite.Require().NoError(suite.keeper.Deposit(suite.ctx, tc.setup.borrower, tc.setup.depositCoins))
err = suite.keeper.Deposit(suite.ctx, tc.args.borrower, tc.args.depositCoins)
suite.Require().NoError(err)
// Execute user's previous borrows // Execute user's previous borrows
err = suite.keeper.Borrow(suite.ctx, tc.args.borrower, tc.args.previousBorrowCoins) if err = suite.keeper.Borrow(suite.ctx, tc.setup.borrower, tc.setup.initialBorrowCoins); tc.setup.initialBorrowCoins.IsZero() {
if tc.args.previousBorrowCoins.IsZero() { suite.Require().ErrorContains(err, "cannot borrow zero coins")
suite.Require().True(strings.Contains(err.Error(), "cannot borrow zero coins"))
} else { } else {
suite.Require().NoError(err) suite.Require().NoError(err)
} }
for i, borrow := range tc.borrows {
// Now that our state is properly set up, execute the last borrow // Now that our state is properly set up, execute the last borrow
err = suite.keeper.Borrow(suite.ctx, tc.args.borrower, tc.args.borrowCoins) err = suite.keeper.Borrow(suite.ctx, tc.setup.borrower, borrow.borrowCoins)
if tc.expected[i].expectPass {
if tc.errArgs.expectPass {
suite.Require().NoError(err) suite.Require().NoError(err)
// Check borrower balance // Check borrower balance
acc := suite.getAccount(tc.args.borrower) acc := suite.getAccount(tc.setup.borrower)
suite.Require().Equal(tc.args.expectedAccountBalance, suite.getAccountCoins(acc)) suite.Require().Equal(tc.expected[i].expectedAccountBalance, suite.getAccountCoins(acc))
// Check module account balance // Check module account balance
mAcc := suite.getModuleAccount(types.ModuleAccountName) mAcc := suite.getModuleAccount(types.ModuleAccountName)
suite.Require().Equal(tc.args.expectedModAccountBalance, suite.getAccountCoins(mAcc)) suite.Require().Equal(tc.expected[i].expectedModAccountBalance, suite.getAccountCoins(mAcc))
// Check that borrow struct is in store // Check that borrow struct is in store
_, f := suite.keeper.GetBorrow(suite.ctx, tc.args.borrower) _, f := suite.keeper.GetBorrow(suite.ctx, tc.setup.borrower)
suite.Require().True(f) suite.Require().True(f)
} else { } else {
suite.Require().Error(err) suite.Require().Error(err)
suite.Require().True(strings.Contains(err.Error(), tc.errArgs.contains)) suite.Require().ErrorContains(err, tc.expected[i].contains)
}
blockDuration := time.Second * 3600 * 30 // long blocks to accumulate larger interest
runAtTime := suite.ctx.BlockTime().Add(blockDuration)
suite.ctx = suite.ctx.WithBlockTime(runAtTime)
// Run BeginBlocker once to transition MoneyMarkets
hard.BeginBlocker(suite.ctx, suite.keeper)
} }
}) })
} }
@ -561,4 +772,37 @@ func (suite *KeeperTestSuite) TestValidateBorrow() {
sdk.NewCoins(sdk.NewCoin("ukava", availableToBorrow.AmountOf("ukava"))), sdk.NewCoins(sdk.NewCoin("ukava", availableToBorrow.AmountOf("ukava"))),
) )
suite.Require().NoError(err) suite.Require().NoError(err)
// now that it's all that you can borrow, we shouldn't be able to borrow anything
err = suite.keeper.Borrow(
suite.ctx,
borrower,
sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(2*USDX_CF))),
)
suite.Require().Error(err)
suite.Require().ErrorContains(err, "available to borrow: exceeds module account balance")
suite.ctx = suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(blockDuration))
hard.BeginBlocker(suite.ctx, suite.keeper)
// Should error since ukava has become insolvent at this point
err = suite.keeper.Borrow(
suite.ctx,
borrower,
sdk.NewCoins(sdk.NewCoin("ukava", availableToBorrow.AmountOf("ukava"))),
)
suite.Require().Error(err)
suite.Require().ErrorContains(err, "protocol reserves exceed available cash")
suite.ctx = suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(blockDuration))
hard.BeginBlocker(suite.ctx, suite.keeper)
// TODO: this is wrong, since usdk is not insolvent, ukava is.
err = suite.keeper.Borrow(
suite.ctx,
borrower,
sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(25*USDX_CF))),
)
suite.Require().Error(err)
suite.Require().ErrorContains(err, "protocol reserves exceed available cash")
} }