diff --git a/x/hard/keeper/borrow.go b/x/hard/keeper/borrow.go index 6c198d45..5f02361e 100644 --- a/x/hard/keeper/borrow.go +++ b/x/hard/keeper/borrow.go @@ -7,7 +7,6 @@ import ( sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/kava-labs/kava/x/hard/types" ) diff --git a/x/hard/keeper/borrow_test.go b/x/hard/keeper/borrow_test.go index 3d254cc2..348cdb47 100644 --- a/x/hard/keeper/borrow_test.go +++ b/x/hard/keeper/borrow_test.go @@ -1,7 +1,6 @@ package keeper_test import ( - "strings" "time" sdkmath "cosmossdk.io/math" @@ -9,7 +8,6 @@ import ( tmproto "github.com/cometbft/cometbft/proto/tendermint/types" tmtime "github.com/cometbft/cometbft/types/time" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/kava-labs/kava/app" "github.com/kava-labs/kava/x/hard" "github.com/kava-labs/kava/x/hard/types" @@ -25,268 +23,477 @@ const ( ) func (suite *KeeperTestSuite) TestBorrow() { - type args struct { - usdxBorrowLimit sdk.Dec - priceKAVA sdk.Dec - loanToValueKAVA sdk.Dec - priceBTCB sdk.Dec - loanToValueBTCB sdk.Dec - priceBNB sdk.Dec - loanToValueBNB sdk.Dec - borrower sdk.AccAddress - depositCoins []sdk.Coin - previousBorrowCoins sdk.Coins - borrowCoins sdk.Coins + type setupArgs struct { + usdxBorrowLimit sdk.Dec + priceKAVA sdk.Dec + loanToValueKAVA sdk.Dec + priceBTCB sdk.Dec + loanToValueBTCB sdk.Dec + priceBNB sdk.Dec + loanToValueBNB sdk.Dec + borrower sdk.AccAddress + depositCoins []sdk.Coin + initialBorrowCoins sdk.Coins + } + + type borrowArgs struct { + borrowCoins sdk.Coins + wantErr string + } + type expected struct { expectedAccountBalance sdk.Coins expectedModAccountBalance sdk.Coins - } - type errArgs struct { + expectPass bool contains string } + type borrowTest struct { - name string - args args - errArgs errArgs + name string + setup setupArgs + borrows []borrowArgs + expected []expected } + testCases := []borrowTest{ { - "valid", - args{ - 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))}, - previousBorrowCoins: sdk.NewCoins(), - borrowCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(20*KAVA_CF))), - 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))), + name: "valid", + 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(), }, - errArgs{ - expectPass: true, - contains: "", + 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, + }, + }, + borrows: []borrowArgs{ + { + borrowCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(20*KAVA_CF))), + wantErr: "", + }, }, }, { - "invalid: loan-to-value limited", - args{ - 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(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 - expectedAccountBalance: sdk.NewCoins(), - expectedModAccountBalance: sdk.NewCoins(), + name: "invalid: loan-to-value limited", + 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(20*KAVA_CF))}, // 20 KAVA x $5.00 price = $100 + initialBorrowCoins: sdk.NewCoins(), }, - errArgs{ - expectPass: false, - contains: "exceeds the allowable amount as determined by the collateralization ratio", + expected: []expected{ + { + expectedAccountBalance: sdk.NewCoins(), + expectedModAccountBalance: sdk.NewCoins(), + + expectPass: false, + contains: "exceeds the allowable amount as determined by the collateralization ratio", + }, + }, + borrows: []borrowArgs{ + { + borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(61*USDX_CF))), // 61 USDX x $1 price = $61 + wantErr: "", + }, }, }, { - "valid: multiple deposits", - args{ - usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"), - priceKAVA: sdk.MustNewDecFromStr("2.00"), - loanToValueKAVA: sdk.MustNewDecFromStr("0.80"), - priceBTCB: sdk.MustNewDecFromStr("10000.00"), - loanToValueBTCB: sdk.MustNewDecFromStr("0.10"), - priceBNB: sdk.MustNewDecFromStr("0.00"), - loanToValueBNB: sdk.MustNewDecFromStr("0.01"), - 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))), - borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(180*USDX_CF))), - 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))), + name: "valid: multiple deposits", + setup: setupArgs{ + usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"), + priceKAVA: sdk.MustNewDecFromStr("2.00"), + loanToValueKAVA: sdk.MustNewDecFromStr("0.80"), + priceBTCB: sdk.MustNewDecFromStr("10000.00"), + loanToValueBTCB: sdk.MustNewDecFromStr("0.10"), + priceBNB: sdk.MustNewDecFromStr("0.00"), + loanToValueBNB: sdk.MustNewDecFromStr("0.01"), + 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))), + initialBorrowCoins: sdk.NewCoins(), }, - errArgs{ - expectPass: true, - contains: "", + 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))), + 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))), + + expectPass: true, + + 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", - args{ - usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"), - priceKAVA: sdk.MustNewDecFromStr("2.00"), - loanToValueKAVA: sdk.MustNewDecFromStr("0.80"), - priceBTCB: sdk.MustNewDecFromStr("10000.00"), - loanToValueBTCB: sdk.MustNewDecFromStr("0.10"), - priceBNB: sdk.MustNewDecFromStr("0.00"), - loanToValueBNB: sdk.MustNewDecFromStr("0.01"), - 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))), - borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(181*USDX_CF))), - expectedAccountBalance: sdk.NewCoins(), - expectedModAccountBalance: sdk.NewCoins(), + name: "invalid: multiple deposits", + setup: setupArgs{ + usdxBorrowLimit: sdk.MustNewDecFromStr("100000000000"), + priceKAVA: sdk.MustNewDecFromStr("2.00"), + loanToValueKAVA: sdk.MustNewDecFromStr("0.80"), + priceBTCB: sdk.MustNewDecFromStr("10000.00"), + loanToValueBTCB: sdk.MustNewDecFromStr("0.10"), + priceBNB: sdk.MustNewDecFromStr("0.00"), + loanToValueBNB: sdk.MustNewDecFromStr("0.01"), + 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))), + initialBorrowCoins: sdk.NewCoins(), }, - errArgs{ - expectPass: false, - contains: "exceeds the allowable amount as determined by the collateralization ratio", + expected: []expected{ + { + expectedAccountBalance: sdk.NewCoins(), + expectedModAccountBalance: sdk.NewCoins(), + + expectPass: false, + contains: "exceeds the allowable amount as determined by the collateralization ratio", + }, + }, + borrows: []borrowArgs{ + { + borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(181*USDX_CF))), + wantErr: "", + }, }, }, { - "valid: multiple previous borrows", - args{ - 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))), // (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))), - borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(1*USDX_CF))), - 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))), + name: "valid: multiple previous borrows", + 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))), // (50 KAVA x $2.00 price = $100) + (30 BNB x $5.00 price = $150) = $250 + initialBorrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(99*USDX_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF))), }, - errArgs{ - expectPass: true, - contains: "", + 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, + }, + }, + borrows: []borrowArgs{ + { + borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(1*USDX_CF))), + wantErr: "", + }, }, }, { - "invalid: over loan-to-value with multiple previous borrows", - args{ - 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))), // (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))), - borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(1*USDX_CF))), - expectedAccountBalance: sdk.NewCoins(), - expectedModAccountBalance: sdk.NewCoins(), + name: "invalid: over loan-to-value with multiple previous borrows", + 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))), // (50 KAVA x $2.00 price = $100) + (30 BNB x $5.00 price = $150) = $250 + initialBorrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(100*USDX_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF))), }, - errArgs{ - expectPass: false, - contains: "exceeds the allowable amount as determined by the collateralization ratio", + expected: []expected{ + { + expectedAccountBalance: sdk.NewCoins(), + expectedModAccountBalance: sdk.NewCoins(), + expectPass: false, + contains: "exceeds the allowable amount as determined by the collateralization ratio", + }, + }, + borrows: []borrowArgs{ + { + borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(1*USDX_CF))), + wantErr: "", + }, }, }, { - "invalid: no price for asset", - args{ - 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.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(100*KAVA_CF))), - previousBorrowCoins: sdk.NewCoins(), - borrowCoins: sdk.NewCoins(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))), + name: "invalid: no price for asset", + 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.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(100*KAVA_CF))), + initialBorrowCoins: sdk.NewCoins(), }, - errArgs{ - expectPass: false, - contains: "no price found for market", + 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: false, + contains: "no price found for market", + }, + }, + borrows: []borrowArgs{ + { + borrowCoins: sdk.NewCoins(sdk.NewCoin("xyz", sdkmath.NewInt(1))), + wantErr: "", + }, }, }, { - "invalid: borrow exceed module account balance", - args{ - 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("0.00"), - loanToValueBNB: sdk.MustNewDecFromStr("0.01"), - borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))), - depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(100*KAVA_CF))), - previousBorrowCoins: sdk.NewCoins(), - borrowCoins: sdk.NewCoins(sdk.NewCoin("busd", sdkmath.NewInt(101*BUSD_CF))), - expectedAccountBalance: sdk.NewCoins(), - expectedModAccountBalance: sdk.NewCoins(), + name: "invalid: borrow exceed module account balance", + 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("0.00"), + loanToValueBNB: sdk.MustNewDecFromStr("0.01"), + borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))), + depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(100*KAVA_CF))), + initialBorrowCoins: sdk.NewCoins(), }, - errArgs{ - expectPass: false, - contains: "exceeds borrowable module account balance", + expected: []expected{ + { + expectedAccountBalance: sdk.NewCoins(), + expectedModAccountBalance: sdk.NewCoins(), + expectPass: false, + contains: "exceeds borrowable module account balance", + }, + }, + borrows: []borrowArgs{ + { + borrowCoins: sdk.NewCoins(sdk.NewCoin("busd", sdkmath.NewInt(101*BUSD_CF))), + wantErr: "", + }, }, }, { - "invalid: over global asset 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", sdkmath.NewInt(50*KAVA_CF))), - previousBorrowCoins: sdk.NewCoins(), - borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(25*USDX_CF))), - expectedAccountBalance: sdk.NewCoins(), - expectedModAccountBalance: sdk.NewCoins(), + name: "invalid: over global asset borrow limit", + setup: setupArgs{ + 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", sdkmath.NewInt(50*KAVA_CF))), + initialBorrowCoins: sdk.NewCoins(), }, - errArgs{ - expectPass: false, - contains: "fails global asset borrow limit validation", + expected: []expected{ + { + expectedAccountBalance: sdk.NewCoins(), + expectedModAccountBalance: sdk.NewCoins(), + expectPass: false, + contains: "fails global asset borrow limit validation", + }, + }, + borrows: []borrowArgs{ + { + borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(25*USDX_CF))), + wantErr: "", + }, }, }, { - "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", sdkmath.NewInt(50*KAVA_CF))), - previousBorrowCoins: sdk.NewCoins(), - borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(5*USDX_CF))), - expectedAccountBalance: sdk.NewCoins(), - expectedModAccountBalance: sdk.NewCoins(), + 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"), + 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", sdkmath.NewInt(50*KAVA_CF))), + initialBorrowCoins: sdk.NewCoins(), }, - errArgs{ - expectPass: false, - contains: "below the minimum borrow limit", + 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))), + wantErr: "", + }, }, }, { - "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", sdkmath.NewInt(50*KAVA_CF))), - previousBorrowCoins: sdk.NewCoins(), - borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(5*USDX_CF)), sdk.NewCoin("ukava", sdkmath.NewInt(2*USDX_CF))), - expectedAccountBalance: sdk.NewCoins(), - expectedModAccountBalance: sdk.NewCoins(), + name: "invalid: borrowing multiple coins results in a borrow that's under the minimum USD borrow limit", + setup: setupArgs{ + 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", sdkmath.NewInt(50*KAVA_CF))), + initialBorrowCoins: sdk.NewCoins(), }, - errArgs{ - expectPass: false, - contains: "below the minimum borrow limit", + 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)), 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: "", + }, }, }, } @@ -307,18 +514,18 @@ func (suite *KeeperTestSuite) TestBorrow() { sdk.NewCoin("xyz", sdkmath.NewInt(1)), ), }, - []sdk.AccAddress{tc.args.borrower}, + []sdk.AccAddress{tc.setup.borrower}, ) // hard module genesis state hardGS := types.NewGenesisState(types.NewParams( 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("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("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("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("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("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.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.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.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), ), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows, @@ -353,19 +560,19 @@ func (suite *KeeperTestSuite) TestBorrow() { { MarketID: "kava:usd", OracleAddress: sdk.AccAddress{}, - Price: tc.args.priceKAVA, + Price: tc.setup.priceKAVA, Expiry: time.Now().Add(1 * time.Hour), }, { MarketID: "btcb:usd", OracleAddress: sdk.AccAddress{}, - Price: tc.args.priceBTCB, + Price: tc.setup.priceBTCB, Expiry: time.Now().Add(1 * time.Hour), }, { MarketID: "bnb:usd", OracleAddress: sdk.AccAddress{}, - Price: tc.args.priceBNB, + Price: tc.setup.priceBNB, Expiry: time.Now().Add(1 * time.Hour), }, }, @@ -375,11 +582,13 @@ func (suite *KeeperTestSuite) TestBorrow() { tApp.InitializeFromGenesisStates(authGS, app.GenesisState{pricefeedtypes.ModuleName: tApp.AppCodec().MustMarshalJSON(&pricefeedGS)}, app.GenesisState{types.ModuleName: tApp.AppCodec().MustMarshalJSON(&hardGS)}) - // Mint coins to hard module account bankKeeper := tApp.GetBankKeeper() - hardMaccCoins := sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(1000*KAVA_CF)), - sdk.NewCoin("usdx", sdkmath.NewInt(200*USDX_CF)), sdk.NewCoin("busd", sdkmath.NewInt(100*BUSD_CF))) + hardMaccCoins := sdk.NewCoins( + 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) suite.Require().NoError(err) @@ -387,41 +596,43 @@ func (suite *KeeperTestSuite) TestBorrow() { suite.app = tApp suite.ctx = ctx suite.keeper = keeper - // Run BeginBlocker once to transition MoneyMarkets hard.BeginBlocker(suite.ctx, suite.keeper) - - err = suite.keeper.Deposit(suite.ctx, tc.args.borrower, tc.args.depositCoins) - suite.Require().NoError(err) - + suite.Require().NoError(suite.keeper.Deposit(suite.ctx, tc.setup.borrower, tc.setup.depositCoins)) // Execute user's previous borrows - err = suite.keeper.Borrow(suite.ctx, tc.args.borrower, tc.args.previousBorrowCoins) - if tc.args.previousBorrowCoins.IsZero() { - suite.Require().True(strings.Contains(err.Error(), "cannot borrow zero coins")) + if err = suite.keeper.Borrow(suite.ctx, tc.setup.borrower, tc.setup.initialBorrowCoins); tc.setup.initialBorrowCoins.IsZero() { + suite.Require().ErrorContains(err, "cannot borrow zero coins") } else { suite.Require().NoError(err) } - // Now that our state is properly set up, execute the last borrow - err = suite.keeper.Borrow(suite.ctx, tc.args.borrower, tc.args.borrowCoins) + for i, borrow := range tc.borrows { + // Now that our state is properly set up, execute the last borrow + err = suite.keeper.Borrow(suite.ctx, tc.setup.borrower, borrow.borrowCoins) + if tc.expected[i].expectPass { + suite.Require().NoError(err) - if tc.errArgs.expectPass { - suite.Require().NoError(err) + // Check borrower balance + acc := suite.getAccount(tc.setup.borrower) + suite.Require().Equal(tc.expected[i].expectedAccountBalance, suite.getAccountCoins(acc)) - // Check borrower balance - acc := suite.getAccount(tc.args.borrower) - suite.Require().Equal(tc.args.expectedAccountBalance, suite.getAccountCoins(acc)) + // Check module account balance + mAcc := suite.getModuleAccount(types.ModuleAccountName) + suite.Require().Equal(tc.expected[i].expectedModAccountBalance, suite.getAccountCoins(mAcc)) - // Check module account balance - mAcc := suite.getModuleAccount(types.ModuleAccountName) - suite.Require().Equal(tc.args.expectedModAccountBalance, suite.getAccountCoins(mAcc)) + // Check that borrow struct is in store + _, f := suite.keeper.GetBorrow(suite.ctx, tc.setup.borrower) + suite.Require().True(f) + } else { + suite.Require().Error(err) + 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) - // Check that borrow struct is in store - _, f := suite.keeper.GetBorrow(suite.ctx, tc.args.borrower) - suite.Require().True(f) - } else { - suite.Require().Error(err) - suite.Require().True(strings.Contains(err.Error(), tc.errArgs.contains)) } }) } @@ -561,4 +772,37 @@ func (suite *KeeperTestSuite) TestValidateBorrow() { sdk.NewCoins(sdk.NewCoin("ukava", availableToBorrow.AmountOf("ukava"))), ) 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") }