mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-24 15:25:18 +00:00
Add collateral type to cdp (#629)
* add collateral type field to cdp and collateral param * fix upstream tests * fix simulations * fix validation logic * update incentive to use collateral type instead of denom * use collateral type instead of denom in cdp * remove unused code * address review comments
This commit is contained in:
parent
60d7f522e2
commit
daa1b2bb83
10
CHANGELOG.md
10
CHANGELOG.md
@ -46,6 +46,16 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
|
||||
[\#578](https://github.com/Kava-Labs/kava/pulls/578) Add v0.3 compatible REST client that supports
|
||||
|
||||
[\#629](https://github.com/Kava-Labs/kava/pulls/629) Add CDP collateral type as a field for CDPs and collateral parameters.
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* CDPs have an additional field, Type, which is a string that represents the unique collateral type that this CDP holds. This enables, for example, a single denom such as 'bnb' to have two CDP types, 'bnb-a' and 'bnb-b'.
|
||||
* CollateralParam has an additional field, Type, which is a string that represents the collateral type of CDPs that this collateral parameter governs. It must be non-empty at genesis or when altering CDP fields. It is UNSAFE to alter the type of an existing collateral param using unchain governance.
|
||||
* CDP messages must specify the collateral type 'bnb-a', rather than the denom of the cdp.
|
||||
* In the incentive module, fields previously named `Denom` have been changed to `CollateralType`. Previously, 'Denom' was validated to check that it satisfied `sdk.ValidateDenom`, now, the validation checks that the `CollateralType` is not blank.
|
||||
* Incentive module messages now require the user to specify the collateral type ('bnb-a'), rather than the denom of the cdp ('bnb')
|
||||
|
||||
```plaintext
|
||||
/v0_3/node_info
|
||||
/v0_3/auth/accounts/<address>
|
||||
|
@ -121,6 +121,7 @@ func sendBtcCdp() {
|
||||
addr,
|
||||
sdk.NewInt64Coin("btc", 200000000),
|
||||
sdk.NewInt64Coin("usdx", 10000000),
|
||||
"btc-a",
|
||||
)
|
||||
|
||||
// helper methods for transactions
|
||||
@ -154,6 +155,7 @@ func sendXrpCdp() {
|
||||
addr,
|
||||
sdk.NewInt64Coin("xrp", 200000000),
|
||||
sdk.NewInt64Coin("usdx", 10000000),
|
||||
"xrp-a",
|
||||
)
|
||||
|
||||
// helper methods for transactions
|
||||
|
@ -31,12 +31,12 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k Keeper) {
|
||||
continue
|
||||
}
|
||||
|
||||
err := k.UpdateFeesForAllCdps(ctx, cp.Denom)
|
||||
err := k.UpdateFeesForAllCdps(ctx, cp.Type)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = k.LiquidateCdps(ctx, cp.LiquidationMarketID, cp.Denom, cp.LiquidationRatio)
|
||||
err = k.LiquidateCdps(ctx, cp.LiquidationMarketID, cp.Type, cp.LiquidationRatio)
|
||||
if err != nil && !errors.Is(err, pricefeedtypes.ErrNoValidPrice) {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -103,8 +103,8 @@ func (suite *ModuleTestSuite) createCdps() {
|
||||
tracker.debt += int64(debt)
|
||||
}
|
||||
}
|
||||
suite.Nil(suite.keeper.AddCdp(suite.ctx, addrs[j], c(collateral, int64(amount)), c("usdx", int64(debt))))
|
||||
c, f := suite.keeper.GetCDP(suite.ctx, collateral, uint64(j+1))
|
||||
suite.Nil(suite.keeper.AddCdp(suite.ctx, addrs[j], c(collateral, int64(amount)), c("usdx", int64(debt)), collateral+"-a"))
|
||||
c, f := suite.keeper.GetCDP(suite.ctx, collateral+"-a", uint64(j+1))
|
||||
suite.True(f)
|
||||
cdps[j] = c
|
||||
}
|
||||
@ -153,9 +153,9 @@ func (suite *ModuleTestSuite) TestBeginBlock() {
|
||||
}
|
||||
|
||||
func (suite *ModuleTestSuite) TestSeizeSingleCdpWithFees() {
|
||||
err := suite.keeper.AddCdp(suite.ctx, suite.addrs[0], c("xrp", 10000000000), c("usdx", 1000000000))
|
||||
err := suite.keeper.AddCdp(suite.ctx, suite.addrs[0], c("xrp", 10000000000), c("usdx", 1000000000), "xrp-a")
|
||||
suite.NoError(err)
|
||||
suite.Equal(i(1000000000), suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx"))
|
||||
suite.Equal(i(1000000000), suite.keeper.GetTotalPrincipal(suite.ctx, "xrp-a", "usdx"))
|
||||
sk := suite.app.GetSupplyKeeper()
|
||||
cdpMacc := sk.GetModuleAccount(suite.ctx, cdp.ModuleName)
|
||||
suite.Equal(i(1000000000), cdpMacc.GetCoins().AmountOf("debt"))
|
||||
@ -166,11 +166,11 @@ func (suite *ModuleTestSuite) TestSeizeSingleCdpWithFees() {
|
||||
|
||||
cdpMacc = sk.GetModuleAccount(suite.ctx, cdp.ModuleName)
|
||||
suite.Equal(i(1000000900), (cdpMacc.GetCoins().AmountOf("debt")))
|
||||
cdp, _ := suite.keeper.GetCDP(suite.ctx, "xrp", 1)
|
||||
cdp, _ := suite.keeper.GetCDP(suite.ctx, "xrp-a", 1)
|
||||
|
||||
err = suite.keeper.SeizeCollateral(suite.ctx, cdp)
|
||||
suite.NoError(err)
|
||||
_, found := suite.keeper.GetCDP(suite.ctx, "xrp", 1)
|
||||
_, found := suite.keeper.GetCDP(suite.ctx, "xrp-a", 1)
|
||||
suite.False(found)
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ const (
|
||||
QueryGetCdpsByCollateralization = types.QueryGetCdpsByCollateralization
|
||||
QueryGetParams = types.QueryGetParams
|
||||
RestOwner = types.RestOwner
|
||||
RestCollateralDenom = types.RestCollateralDenom
|
||||
RestCollateralType = types.RestCollateralType
|
||||
RestRatio = types.RestRatio
|
||||
)
|
||||
|
||||
|
@ -26,8 +26,8 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
|
||||
cdpQueryCmd.AddCommand(flags.GetCommands(
|
||||
QueryCdpCmd(queryRoute, cdc),
|
||||
QueryCdpsByDenomCmd(queryRoute, cdc),
|
||||
QueryCdpsByDenomAndRatioCmd(queryRoute, cdc),
|
||||
QueryCdpsByCollateralTypeCmd(queryRoute, cdc),
|
||||
QueryCdpsByCollateralTypeAndRatioCmd(queryRoute, cdc),
|
||||
QueryCdpDepositsCmd(queryRoute, cdc),
|
||||
QueryParamsCmd(queryRoute, cdc),
|
||||
QueryGetAccounts(queryRoute, cdc),
|
||||
@ -39,13 +39,13 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
// QueryCdpCmd returns the command handler for querying a particular cdp
|
||||
func QueryCdpCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "cdp [owner-addr] [collateral-name]",
|
||||
Use: "cdp [owner-addr] [collateral-type]",
|
||||
Short: "get info about a cdp",
|
||||
Long: strings.TrimSpace(
|
||||
fmt.Sprintf(`Get a CDP by the owner address and the collateral name.
|
||||
|
||||
Example:
|
||||
$ %s query %s cdp kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw uatom
|
||||
$ %s query %s cdp kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw atom-a
|
||||
`, version.ClientName, types.ModuleName)),
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
@ -57,8 +57,8 @@ $ %s query %s cdp kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw uatom
|
||||
return err
|
||||
}
|
||||
bz, err := cdc.MarshalJSON(types.QueryCdpParams{
|
||||
CollateralDenom: args[1],
|
||||
Owner: ownerAddress,
|
||||
CollateralType: args[1],
|
||||
Owner: ownerAddress,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@ -79,23 +79,23 @@ $ %s query %s cdp kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw uatom
|
||||
}
|
||||
}
|
||||
|
||||
// QueryCdpsByDenomCmd returns the command handler for querying cdps for a collateral type
|
||||
func QueryCdpsByDenomCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
// QueryCdpsByCollateralTypeCmd returns the command handler for querying cdps for a collateral type
|
||||
func QueryCdpsByCollateralTypeCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "cdps [collateral-name]",
|
||||
Use: "cdps [collateral-type]",
|
||||
Short: "query CDPs by collateral",
|
||||
Long: strings.TrimSpace(
|
||||
fmt.Sprintf(`List all CDPs collateralized with the specified asset.
|
||||
|
||||
Example:
|
||||
$ %s query %s cdps uatom
|
||||
$ %s query %s cdps atom-a
|
||||
`, version.ClientName, types.ModuleName)),
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
|
||||
// Prepare params for querier
|
||||
bz, err := cdc.MarshalJSON(types.QueryCdpsParams{CollateralDenom: args[0]})
|
||||
bz, err := cdc.MarshalJSON(types.QueryCdpsParams{CollateralType: args[0]})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -115,18 +115,18 @@ $ %s query %s cdps uatom
|
||||
}
|
||||
}
|
||||
|
||||
// QueryCdpsByDenomAndRatioCmd returns the command handler for querying cdps
|
||||
// QueryCdpsByCollateralTypeAndRatioCmd returns the command handler for querying cdps
|
||||
// that are under the specified collateral ratio
|
||||
func QueryCdpsByDenomAndRatioCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
func QueryCdpsByCollateralTypeAndRatioCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "cdps-by-ratio [collateral-name] [collateralization-ratio]",
|
||||
Use: "cdps-by-ratio [collateral-type] [collateralization-ratio]",
|
||||
Short: "get cdps under a collateralization ratio",
|
||||
Long: strings.TrimSpace(
|
||||
fmt.Sprintf(`List all CDPs under a specified collateralization ratio.
|
||||
Collateralization ratio is: collateral * price / debt.
|
||||
|
||||
Example:
|
||||
$ %s query %s cdps-by-ratio uatom 1.5
|
||||
$ %s query %s cdps-by-ratio atom-a 1.6
|
||||
`, version.ClientName, types.ModuleName)),
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
@ -138,8 +138,8 @@ $ %s query %s cdps-by-ratio uatom 1.5
|
||||
return err
|
||||
}
|
||||
bz, err := cdc.MarshalJSON(types.QueryCdpsByRatioParams{
|
||||
CollateralDenom: args[0],
|
||||
Ratio: ratio,
|
||||
CollateralType: args[0],
|
||||
Ratio: ratio,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@ -163,13 +163,13 @@ $ %s query %s cdps-by-ratio uatom 1.5
|
||||
// QueryCdpDepositsCmd returns the command handler for querying the deposits of a particular cdp
|
||||
func QueryCdpDepositsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "deposits [owner-addr] [collateral-name]",
|
||||
Use: "deposits [owner-addr] [collateral-type]",
|
||||
Short: "get deposits for a cdp",
|
||||
Long: strings.TrimSpace(
|
||||
fmt.Sprintf(`Get the deposits of a CDP.
|
||||
|
||||
Example:
|
||||
$ %s query %s deposits kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw uatom
|
||||
$ %s query %s deposits kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw atom-a
|
||||
`, version.ClientName, types.ModuleName)),
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
@ -181,8 +181,8 @@ $ %s query %s deposits kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw uatom
|
||||
return err
|
||||
}
|
||||
bz, err := cdc.MarshalJSON(types.QueryCdpParams{
|
||||
CollateralDenom: args[1],
|
||||
Owner: ownerAddress,
|
||||
CollateralType: args[1],
|
||||
Owner: ownerAddress,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -39,15 +39,15 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command {
|
||||
// GetCmdCreateCdp returns the command handler for creating a cdp
|
||||
func GetCmdCreateCdp(cdc *codec.Codec) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "create [collateral] [debt]",
|
||||
Use: "create [collateral] [debt] [collateral-type]",
|
||||
Short: "create a new cdp",
|
||||
Long: strings.TrimSpace(
|
||||
fmt.Sprintf(`Create a new cdp, depositing some collateral and drawing some debt.
|
||||
|
||||
Example:
|
||||
$ %s tx %s create 10000000uatom 1000usdx --from myKeyName
|
||||
$ %s tx %s create 10000000uatom 1000usdx atom-a --from myKeyName
|
||||
`, version.ClientName, types.ModuleName)),
|
||||
Args: cobra.ExactArgs(2),
|
||||
Args: cobra.ExactArgs(3),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
@ -61,7 +61,7 @@ $ %s tx %s create 10000000uatom 1000usdx --from myKeyName
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg := types.NewMsgCreateCDP(cliCtx.GetFromAddress(), collateral, debt)
|
||||
msg := types.NewMsgCreateCDP(cliCtx.GetFromAddress(), collateral, debt, args[2])
|
||||
err = msg.ValidateBasic()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -74,15 +74,15 @@ $ %s tx %s create 10000000uatom 1000usdx --from myKeyName
|
||||
// GetCmdDeposit cli command for depositing to a cdp.
|
||||
func GetCmdDeposit(cdc *codec.Codec) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "deposit [owner-addr] [collateral]",
|
||||
Use: "deposit [owner-addr] [collateral] [collateral-type]",
|
||||
Short: "deposit collateral to an existing cdp",
|
||||
Long: strings.TrimSpace(
|
||||
fmt.Sprintf(`Add collateral to an existing cdp.
|
||||
|
||||
Example:
|
||||
$ %s tx %s deposit kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw 10000000uatom --from myKeyName
|
||||
$ %s tx %s deposit kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw 10000000uatom atom-a --from myKeyName
|
||||
`, version.ClientName, types.ModuleName)),
|
||||
Args: cobra.ExactArgs(2),
|
||||
Args: cobra.ExactArgs(3),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
@ -96,7 +96,7 @@ $ %s tx %s deposit kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw 10000000uatom --f
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg := types.NewMsgDeposit(owner, cliCtx.GetFromAddress(), collateral)
|
||||
msg := types.NewMsgDeposit(owner, cliCtx.GetFromAddress(), collateral, args[2])
|
||||
err = msg.ValidateBasic()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -109,13 +109,13 @@ $ %s tx %s deposit kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw 10000000uatom --f
|
||||
// GetCmdWithdraw cli command for withdrawing from a cdp.
|
||||
func GetCmdWithdraw(cdc *codec.Codec) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "withdraw [owner-addr] [collateral]",
|
||||
Use: "withdraw [owner-addr] [collateral] [collateral-type]",
|
||||
Short: "withdraw collateral from an existing cdp",
|
||||
Long: strings.TrimSpace(
|
||||
fmt.Sprintf(`Remove collateral from an existing cdp.
|
||||
|
||||
Example:
|
||||
$ %s tx %s withdraw kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw 10000000uatom --from myKeyName
|
||||
$ %s tx %s withdraw kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw 10000000uatom atom-a --from myKeyName
|
||||
`, version.ClientName, types.ModuleName)),
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
@ -131,7 +131,7 @@ $ %s tx %s withdraw kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw 10000000uatom --
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg := types.NewMsgWithdraw(owner, cliCtx.GetFromAddress(), collateral)
|
||||
msg := types.NewMsgWithdraw(owner, cliCtx.GetFromAddress(), collateral, args[2])
|
||||
err = msg.ValidateBasic()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -144,13 +144,13 @@ $ %s tx %s withdraw kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw 10000000uatom --
|
||||
// GetCmdDraw cli command for depositing to a cdp.
|
||||
func GetCmdDraw(cdc *codec.Codec) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "draw [collateral-name] [debt]",
|
||||
Use: "draw [collateral-type] [debt]",
|
||||
Short: "draw debt off an existing cdp",
|
||||
Long: strings.TrimSpace(
|
||||
fmt.Sprintf(`Create debt in an existing cdp and send the newly minted asset to your account.
|
||||
|
||||
Example:
|
||||
$ %s tx %s draw uatom 1000usdx --from myKeyName
|
||||
$ %s tx %s draw atom-a 1000usdx --from myKeyName
|
||||
`, version.ClientName, types.ModuleName)),
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
@ -181,7 +181,7 @@ func GetCmdRepay(cdc *codec.Codec) *cobra.Command {
|
||||
fmt.Sprintf(`Cancel out debt in an existing cdp.
|
||||
|
||||
Example:
|
||||
$ %s tx %s repay uatom 1000usdx --from myKeyName
|
||||
$ %s tx %s repay atom-a 1000usdx --from myKeyName
|
||||
`, version.ClientName, types.ModuleName)),
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
@ -16,10 +16,10 @@ import (
|
||||
func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) {
|
||||
r.HandleFunc("/cdp/accounts", getAccountsHandlerFn(cliCtx)).Methods("GET")
|
||||
r.HandleFunc("/cdp/parameters", getParamsHandlerFn(cliCtx)).Methods("GET")
|
||||
r.HandleFunc(fmt.Sprintf("/cdp/cdps/cdp/{%s}/{%s}", types.RestOwner, types.RestCollateralDenom), queryCdpHandlerFn(cliCtx)).Methods("GET")
|
||||
r.HandleFunc(fmt.Sprintf("/cdp/cdps/denom/{%s}", types.RestCollateralDenom), queryCdpsHandlerFn(cliCtx)).Methods("GET")
|
||||
r.HandleFunc(fmt.Sprintf("/cdp/cdps/ratio/{%s}/{%s}", types.RestCollateralDenom, types.RestRatio), queryCdpsByRatioHandlerFn(cliCtx)).Methods("GET")
|
||||
r.HandleFunc(fmt.Sprintf("/cdp/cdps/cdp/deposits/{%s}/{%s}", types.RestOwner, types.RestCollateralDenom), queryCdpDepositsHandlerFn(cliCtx)).Methods("GET")
|
||||
r.HandleFunc(fmt.Sprintf("/cdp/cdps/cdp/{%s}/{%s}", types.RestOwner, types.RestCollateralType), queryCdpHandlerFn(cliCtx)).Methods("GET")
|
||||
r.HandleFunc(fmt.Sprintf("/cdp/cdps/collateralType/{%s}", types.RestCollateralType), queryCdpsHandlerFn(cliCtx)).Methods("GET")
|
||||
r.HandleFunc(fmt.Sprintf("/cdp/cdps/ratio/{%s}/{%s}", types.RestCollateralType, types.RestRatio), queryCdpsByRatioHandlerFn(cliCtx)).Methods("GET")
|
||||
r.HandleFunc(fmt.Sprintf("/cdp/cdps/cdp/deposits/{%s}/{%s}", types.RestOwner, types.RestCollateralType), queryCdpDepositsHandlerFn(cliCtx)).Methods("GET")
|
||||
}
|
||||
|
||||
func queryCdpHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
@ -31,7 +31,7 @@ func queryCdpHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
|
||||
vars := mux.Vars(r)
|
||||
ownerBech32 := vars[types.RestOwner]
|
||||
collateralDenom := vars[types.RestCollateralDenom]
|
||||
collateralType := vars[types.RestCollateralType]
|
||||
|
||||
owner, err := sdk.AccAddressFromBech32(ownerBech32)
|
||||
if err != nil {
|
||||
@ -39,7 +39,7 @@ func queryCdpHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
params := types.NewQueryCdpParams(owner, collateralDenom)
|
||||
params := types.NewQueryCdpParams(owner, collateralType)
|
||||
|
||||
bz, err := cliCtx.Codec.MarshalJSON(params)
|
||||
if err != nil {
|
||||
@ -66,9 +66,9 @@ func queryCdpsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
collateralDenom := vars[types.RestCollateralDenom]
|
||||
collateralType := vars[types.RestCollateralType]
|
||||
|
||||
params := types.NewQueryCdpsParams(collateralDenom)
|
||||
params := types.NewQueryCdpsParams(collateralType)
|
||||
|
||||
bz, err := cliCtx.Codec.MarshalJSON(params)
|
||||
if err != nil {
|
||||
@ -95,7 +95,7 @@ func queryCdpsByRatioHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
collateralDenom := vars[types.RestCollateralDenom]
|
||||
collateralType := vars[types.RestCollateralType]
|
||||
ratioStr := vars[types.RestRatio]
|
||||
|
||||
ratioDec, sdkError := sdk.NewDecFromStr(ratioStr)
|
||||
@ -104,7 +104,7 @@ func queryCdpsByRatioHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
params := types.NewQueryCdpsByRatioParams(collateralDenom, ratioDec)
|
||||
params := types.NewQueryCdpsByRatioParams(collateralType, ratioDec)
|
||||
bz, err := cliCtx.Codec.MarshalJSON(params)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err))
|
||||
@ -131,7 +131,7 @@ func queryCdpDepositsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
|
||||
vars := mux.Vars(r)
|
||||
ownerBech32 := vars[types.RestOwner]
|
||||
collateralDenom := vars[types.RestCollateralDenom]
|
||||
collateralType := vars[types.RestCollateralType]
|
||||
|
||||
owner, err := sdk.AccAddressFromBech32(ownerBech32)
|
||||
if err != nil {
|
||||
@ -139,7 +139,7 @@ func queryCdpDepositsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
params := types.NewQueryCdpDeposits(owner, collateralDenom)
|
||||
params := types.NewQueryCdpDeposits(owner, collateralType)
|
||||
|
||||
bz, err := cliCtx.Codec.MarshalJSON(params)
|
||||
if err != nil {
|
||||
|
@ -16,40 +16,43 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) {
|
||||
|
||||
// PostCdpReq defines the properties of cdp request's body.
|
||||
type PostCdpReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||
Collateral sdk.Coin `json:"collateral" yaml:"collateral"`
|
||||
Principal sdk.Coin `json:"principal" yaml:"principal"`
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||
Collateral sdk.Coin `json:"collateral" yaml:"collateral"`
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
Principal sdk.Coin `json:"principal" yaml:"principal"`
|
||||
}
|
||||
|
||||
// PostDepositReq defines the properties of cdp request's body.
|
||||
type PostDepositReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
Owner sdk.AccAddress `json:"owner" yaml:"owner"`
|
||||
Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"`
|
||||
Collateral sdk.Coin `json:"collateral" yaml:"collateral"`
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
Owner sdk.AccAddress `json:"owner" yaml:"owner"`
|
||||
Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"`
|
||||
Collateral sdk.Coin `json:"collateral" yaml:"collateral"`
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
}
|
||||
|
||||
// PostWithdrawalReq defines the properties of cdp request's body.
|
||||
type PostWithdrawalReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
Owner sdk.AccAddress `json:"owner" yaml:"owner"`
|
||||
Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"`
|
||||
Collateral sdk.Coin `json:"collateral" yaml:"collateral"`
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
Owner sdk.AccAddress `json:"owner" yaml:"owner"`
|
||||
Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"`
|
||||
Collateral sdk.Coin `json:"collateral" yaml:"collateral"`
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
}
|
||||
|
||||
// PostDrawReq defines the properties of cdp request's body.
|
||||
type PostDrawReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
Owner sdk.AccAddress `json:"owner" yaml:"owner"`
|
||||
Denom string `json:"denom" yaml:"denom"`
|
||||
Principal sdk.Coin `json:"principal" yaml:"principal"`
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
Owner sdk.AccAddress `json:"owner" yaml:"owner"`
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
Principal sdk.Coin `json:"principal" yaml:"principal"`
|
||||
}
|
||||
|
||||
// PostRepayReq defines the properties of cdp request's body.
|
||||
type PostRepayReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
Owner sdk.AccAddress `json:"owner" yaml:"owner"`
|
||||
Denom string `json:"denom" yaml:"denom"`
|
||||
Payment sdk.Coin `json:"payment" yaml:"payment"`
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
Owner sdk.AccAddress `json:"owner" yaml:"owner"`
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
Payment sdk.Coin `json:"payment" yaml:"payment"`
|
||||
}
|
||||
|
@ -16,10 +16,10 @@ import (
|
||||
|
||||
func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) {
|
||||
r.HandleFunc("/cdp", postCdpHandlerFn(cliCtx)).Methods("POST")
|
||||
r.HandleFunc("/cdp/{owner}/{denom}/deposits", postDepositHandlerFn(cliCtx)).Methods("POST")
|
||||
r.HandleFunc("/cdp/{owner}/{denom}/withdraw", postWithdrawHandlerFn(cliCtx)).Methods("POST")
|
||||
r.HandleFunc("/cdp/{owner}/{denom}/draw", postDrawHandlerFn(cliCtx)).Methods("POST")
|
||||
r.HandleFunc("/cdp/{owner}/{denom}/repay", postRepayHandlerFn(cliCtx)).Methods("POST")
|
||||
r.HandleFunc("/cdp/{owner}/{collateralType}/deposits", postDepositHandlerFn(cliCtx)).Methods("POST")
|
||||
r.HandleFunc("/cdp/{owner}/{collateralType}/withdraw", postWithdrawHandlerFn(cliCtx)).Methods("POST")
|
||||
r.HandleFunc("/cdp/{owner}/{collateralType}/draw", postDrawHandlerFn(cliCtx)).Methods("POST")
|
||||
r.HandleFunc("/cdp/{owner}/{collateralType}/repay", postRepayHandlerFn(cliCtx)).Methods("POST")
|
||||
|
||||
}
|
||||
|
||||
@ -50,6 +50,7 @@ func postCdpHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
requestBody.Sender,
|
||||
requestBody.Collateral,
|
||||
requestBody.Principal,
|
||||
requestBody.CollateralType,
|
||||
)
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
@ -76,6 +77,7 @@ func postDepositHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
requestBody.Owner,
|
||||
requestBody.Depositor,
|
||||
requestBody.Collateral,
|
||||
requestBody.CollateralType,
|
||||
)
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
@ -102,6 +104,7 @@ func postWithdrawHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
requestBody.Owner,
|
||||
requestBody.Depositor,
|
||||
requestBody.Collateral,
|
||||
requestBody.CollateralType,
|
||||
)
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
@ -137,7 +140,7 @@ func postDrawHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
|
||||
msg := types.NewMsgDrawDebt(
|
||||
requestBody.Owner,
|
||||
requestBody.Denom,
|
||||
requestBody.CollateralType,
|
||||
requestBody.Principal,
|
||||
)
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
@ -174,7 +177,7 @@ func postRepayHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
|
||||
msg := types.NewMsgRepayDebt(
|
||||
requestBody.Owner,
|
||||
requestBody.Denom,
|
||||
requestBody.CollateralType,
|
||||
requestBody.Payment,
|
||||
)
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
|
@ -59,7 +59,7 @@ func InitGenesis(ctx sdk.Context, k Keeper, pk types.PricefeedKeeper, sk types.S
|
||||
|
||||
// set the per second fee rate for each collateral type
|
||||
for _, cp := range gs.Params.CollateralParams {
|
||||
k.SetTotalPrincipal(ctx, cp.Denom, gs.Params.DebtParam.Denom, sdk.ZeroInt())
|
||||
k.SetTotalPrincipal(ctx, cp.Type, gs.Params.DebtParam.Denom, sdk.ZeroInt())
|
||||
}
|
||||
|
||||
// add cdps
|
||||
@ -72,9 +72,9 @@ func InitGenesis(ctx sdk.Context, k Keeper, pk types.PricefeedKeeper, sk types.S
|
||||
panic(fmt.Sprintf("error setting cdp: %v", err))
|
||||
}
|
||||
k.IndexCdpByOwner(ctx, cdp)
|
||||
ratio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.GetTotalPrincipal())
|
||||
k.IndexCdpByCollateralRatio(ctx, cdp.Collateral.Denom, cdp.ID, ratio)
|
||||
k.IncrementTotalPrincipal(ctx, cdp.Collateral.Denom, cdp.GetTotalPrincipal())
|
||||
ratio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal())
|
||||
k.IndexCdpByCollateralRatio(ctx, cdp.Type, cdp.ID, ratio)
|
||||
k.IncrementTotalPrincipal(ctx, cdp.Type, cdp.GetTotalPrincipal())
|
||||
}
|
||||
|
||||
k.SetNextCdpID(ctx, gs.StartingCdpID)
|
||||
|
@ -27,7 +27,7 @@ func NewHandler(k Keeper) sdk.Handler {
|
||||
}
|
||||
|
||||
func handleMsgCreateCDP(ctx sdk.Context, k Keeper, msg MsgCreateCDP) (*sdk.Result, error) {
|
||||
err := k.AddCdp(ctx, msg.Sender, msg.Collateral, msg.Principal)
|
||||
err := k.AddCdp(ctx, msg.Sender, msg.Collateral, msg.Principal, msg.CollateralType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -39,7 +39,7 @@ func handleMsgCreateCDP(ctx sdk.Context, k Keeper, msg MsgCreateCDP) (*sdk.Resul
|
||||
sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender.String()),
|
||||
),
|
||||
)
|
||||
id, _ := k.GetCdpID(ctx, msg.Sender, msg.Collateral.Denom)
|
||||
id, _ := k.GetCdpID(ctx, msg.Sender, msg.CollateralType)
|
||||
|
||||
return &sdk.Result{
|
||||
Data: GetCdpIDBytes(id),
|
||||
@ -48,7 +48,7 @@ func handleMsgCreateCDP(ctx sdk.Context, k Keeper, msg MsgCreateCDP) (*sdk.Resul
|
||||
}
|
||||
|
||||
func handleMsgDeposit(ctx sdk.Context, k Keeper, msg MsgDeposit) (*sdk.Result, error) {
|
||||
err := k.DepositCollateral(ctx, msg.Owner, msg.Depositor, msg.Collateral)
|
||||
err := k.DepositCollateral(ctx, msg.Owner, msg.Depositor, msg.Collateral, msg.CollateralType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -64,7 +64,7 @@ func handleMsgDeposit(ctx sdk.Context, k Keeper, msg MsgDeposit) (*sdk.Result, e
|
||||
}
|
||||
|
||||
func handleMsgWithdraw(ctx sdk.Context, k Keeper, msg MsgWithdraw) (*sdk.Result, error) {
|
||||
err := k.WithdrawCollateral(ctx, msg.Owner, msg.Depositor, msg.Collateral)
|
||||
err := k.WithdrawCollateral(ctx, msg.Owner, msg.Depositor, msg.Collateral, msg.CollateralType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -80,7 +80,7 @@ func handleMsgWithdraw(ctx sdk.Context, k Keeper, msg MsgWithdraw) (*sdk.Result,
|
||||
}
|
||||
|
||||
func handleMsgDrawDebt(ctx sdk.Context, k Keeper, msg MsgDrawDebt) (*sdk.Result, error) {
|
||||
err := k.AddPrincipal(ctx, msg.Sender, msg.CdpDenom, msg.Principal)
|
||||
err := k.AddPrincipal(ctx, msg.Sender, msg.CollateralType, msg.Principal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -96,7 +96,7 @@ func handleMsgDrawDebt(ctx sdk.Context, k Keeper, msg MsgDrawDebt) (*sdk.Result,
|
||||
}
|
||||
|
||||
func handleMsgRepayDebt(ctx sdk.Context, k Keeper, msg MsgRepayDebt) (*sdk.Result, error) {
|
||||
err := k.RepayPrincipal(ctx, msg.Sender, msg.CdpDenom, msg.Payment)
|
||||
err := k.RepayPrincipal(ctx, msg.Sender, msg.CollateralType, msg.Payment)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ func (suite *HandlerTestSuite) TestMsgCreateCdp() {
|
||||
addrs[0],
|
||||
c("xrp", 200000000),
|
||||
c("usdx", 10000000),
|
||||
"xrp-a",
|
||||
)
|
||||
res, err := suite.handler(suite.ctx, msg)
|
||||
suite.Require().NoError(err)
|
||||
|
@ -49,6 +49,7 @@ func NewCDPGenState(asset string, liquidationRatio sdk.Dec) app.GenesisState {
|
||||
CollateralParams: cdp.CollateralParams{
|
||||
{
|
||||
Denom: asset,
|
||||
Type: asset + "-a",
|
||||
LiquidationRatio: liquidationRatio,
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr
|
||||
@ -114,6 +115,7 @@ func NewCDPGenStateMulti() app.GenesisState {
|
||||
CollateralParams: cdp.CollateralParams{
|
||||
{
|
||||
Denom: "xrp",
|
||||
Type: "xrp-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("2.0"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 500000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr
|
||||
@ -126,6 +128,7 @@ func NewCDPGenStateMulti() app.GenesisState {
|
||||
},
|
||||
{
|
||||
Denom: "btc",
|
||||
Type: "btc-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 500000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000000782997609"), // %2.5 apr
|
||||
@ -156,10 +159,10 @@ func NewCDPGenStateMulti() app.GenesisState {
|
||||
|
||||
func cdps() (cdps cdp.CDPs) {
|
||||
_, addrs := app.GeneratePrivKeyAddressPairs(3)
|
||||
c1 := cdp.NewCDP(uint64(1), addrs[0], sdk.NewCoin("xrp", sdk.NewInt(100000000)), sdk.NewCoin("usdx", sdk.NewInt(8000000)), tmtime.Canonical(time.Now()))
|
||||
c2 := cdp.NewCDP(uint64(2), addrs[1], sdk.NewCoin("xrp", sdk.NewInt(100000000)), sdk.NewCoin("usdx", sdk.NewInt(10000000)), tmtime.Canonical(time.Now()))
|
||||
c3 := cdp.NewCDP(uint64(3), addrs[1], sdk.NewCoin("btc", sdk.NewInt(1000000000)), sdk.NewCoin("usdx", sdk.NewInt(10000000)), tmtime.Canonical(time.Now()))
|
||||
c4 := cdp.NewCDP(uint64(4), addrs[2], sdk.NewCoin("xrp", sdk.NewInt(1000000000)), sdk.NewCoin("usdx", sdk.NewInt(50000000)), tmtime.Canonical(time.Now()))
|
||||
c1 := cdp.NewCDP(uint64(1), addrs[0], sdk.NewCoin("xrp", sdk.NewInt(100000000)), "xrp-a", sdk.NewCoin("usdx", sdk.NewInt(8000000)), tmtime.Canonical(time.Now()))
|
||||
c2 := cdp.NewCDP(uint64(2), addrs[1], sdk.NewCoin("xrp", sdk.NewInt(100000000)), "xrp-a", sdk.NewCoin("usdx", sdk.NewInt(10000000)), tmtime.Canonical(time.Now()))
|
||||
c3 := cdp.NewCDP(uint64(3), addrs[1], sdk.NewCoin("btc", sdk.NewInt(1000000000)), "btc-a", sdk.NewCoin("usdx", sdk.NewInt(10000000)), tmtime.Canonical(time.Now()))
|
||||
c4 := cdp.NewCDP(uint64(4), addrs[2], sdk.NewCoin("xrp", sdk.NewInt(1000000000)), "xrp-a", sdk.NewCoin("usdx", sdk.NewInt(50000000)), tmtime.Canonical(time.Now()))
|
||||
cdps = append(cdps, c1, c2, c3, c4)
|
||||
return
|
||||
}
|
||||
|
@ -12,14 +12,14 @@ const (
|
||||
)
|
||||
|
||||
// AuctionCollateral creates auctions from the input deposits which attempt to raise the corresponding amount of debt
|
||||
func (k Keeper) AuctionCollateral(ctx sdk.Context, deposits types.Deposits, debt sdk.Int, bidDenom string) error {
|
||||
func (k Keeper) AuctionCollateral(ctx sdk.Context, deposits types.Deposits, collateralType string, debt sdk.Int, bidDenom string) error {
|
||||
|
||||
auctionSize := k.getAuctionSize(ctx, deposits[0].Amount.Denom)
|
||||
auctionSize := k.getAuctionSize(ctx, collateralType)
|
||||
totalCollateral := deposits.SumCollateral()
|
||||
for _, deposit := range deposits {
|
||||
|
||||
debtCoveredByDeposit := (sdk.NewDecFromInt(deposit.Amount.Amount).Quo(sdk.NewDecFromInt(totalCollateral))).Mul(sdk.NewDecFromInt(debt)).RoundInt()
|
||||
err := k.CreateAuctionsFromDeposit(ctx, deposit.Amount, deposit.Depositor, debtCoveredByDeposit, auctionSize, bidDenom)
|
||||
err := k.CreateAuctionsFromDeposit(ctx, deposit.Amount, collateralType, deposit.Depositor, debtCoveredByDeposit, auctionSize, bidDenom)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -29,7 +29,7 @@ func (k Keeper) AuctionCollateral(ctx sdk.Context, deposits types.Deposits, debt
|
||||
|
||||
// CreateAuctionsFromDeposit creates auctions from the input deposit
|
||||
func (k Keeper) CreateAuctionsFromDeposit(
|
||||
ctx sdk.Context, collateral sdk.Coin, returnAddr sdk.AccAddress, debt, auctionSize sdk.Int,
|
||||
ctx sdk.Context, collateral sdk.Coin, collateralType string, returnAddr sdk.AccAddress, debt, auctionSize sdk.Int,
|
||||
principalDenom string) error {
|
||||
|
||||
// number of auctions of auctionSize
|
||||
@ -69,7 +69,7 @@ func (k Keeper) CreateAuctionsFromDeposit(
|
||||
unallocatedDebt = unallocatedDebt.Sub(sdk.OneInt())
|
||||
}
|
||||
|
||||
penalty := k.ApplyLiquidationPenalty(ctx, collateral.Denom, debtAmount)
|
||||
penalty := k.ApplyLiquidationPenalty(ctx, collateralType, debtAmount)
|
||||
|
||||
_, err := k.auctionKeeper.StartCollateralAuction(
|
||||
ctx, types.LiquidatorMacc, sdk.NewCoin(collateral.Denom, auctionSize),
|
||||
@ -95,7 +95,7 @@ func (k Keeper) CreateAuctionsFromDeposit(
|
||||
unallocatedDebt = unallocatedDebt.Sub(sdk.OneInt())
|
||||
}
|
||||
|
||||
penalty := k.ApplyLiquidationPenalty(ctx, collateral.Denom, lastAuctionDebt)
|
||||
penalty := k.ApplyLiquidationPenalty(ctx, collateralType, lastAuctionDebt)
|
||||
|
||||
_, err := k.auctionKeeper.StartCollateralAuction(
|
||||
ctx, types.LiquidatorMacc, sdk.NewCoin(collateral.Denom, lastAuctionCollateral),
|
||||
|
@ -62,7 +62,7 @@ func (suite *AuctionTestSuite) TestCollateralAuction() {
|
||||
err := sk.MintCoins(suite.ctx, types.LiquidatorMacc, cs(c("debt", 21000000000), c("bnb", 190000000000)))
|
||||
suite.Require().NoError(err)
|
||||
testDeposit := types.NewDeposit(1, suite.addrs[0], c("bnb", 190000000000))
|
||||
err = suite.keeper.AuctionCollateral(suite.ctx, types.Deposits{testDeposit}, i(21000000000), "usdx")
|
||||
err = suite.keeper.AuctionCollateral(suite.ctx, types.Deposits{testDeposit}, "bnb-a", i(21000000000), "usdx")
|
||||
suite.Require().NoError(err)
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
@ -16,13 +15,13 @@ import (
|
||||
const BaseDigitFactor = 1000000000000000000
|
||||
|
||||
// AddCdp adds a cdp for a specific owner and collateral type
|
||||
func (k Keeper) AddCdp(ctx sdk.Context, owner sdk.AccAddress, collateral sdk.Coin, principal sdk.Coin) error {
|
||||
func (k Keeper) AddCdp(ctx sdk.Context, owner sdk.AccAddress, collateral sdk.Coin, principal sdk.Coin, collateralType string) error {
|
||||
// validation
|
||||
err := k.ValidateCollateral(ctx, collateral)
|
||||
err := k.ValidateCollateral(ctx, collateral, collateralType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, found := k.GetCdpByOwnerAndDenom(ctx, owner, collateral.Denom)
|
||||
_, found := k.GetCdpByOwnerAndCollateralType(ctx, owner, collateralType)
|
||||
if found {
|
||||
return sdkerrors.Wrapf(types.ErrCdpAlreadyExists, "owner %s, denom %s", owner, collateral.Denom)
|
||||
}
|
||||
@ -31,18 +30,18 @@ func (k Keeper) AddCdp(ctx sdk.Context, owner sdk.AccAddress, collateral sdk.Coi
|
||||
return err
|
||||
}
|
||||
|
||||
err = k.ValidateDebtLimit(ctx, collateral.Denom, principal)
|
||||
err = k.ValidateDebtLimit(ctx, collateralType, principal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = k.ValidateCollateralizationRatio(ctx, collateral, principal, sdk.NewCoin(principal.Denom, sdk.ZeroInt()))
|
||||
err = k.ValidateCollateralizationRatio(ctx, collateral, collateralType, principal, sdk.NewCoin(principal.Denom, sdk.ZeroInt()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// send coins from the owners account to the cdp module
|
||||
id := k.GetNextCdpID(ctx)
|
||||
cdp := types.NewCDP(id, owner, collateral, principal, ctx.BlockHeader().Time)
|
||||
cdp := types.NewCDP(id, owner, collateral, collateralType, principal, ctx.BlockHeader().Time)
|
||||
deposit := types.NewDeposit(cdp.ID, owner, collateral)
|
||||
err = k.supplyKeeper.SendCoinsFromAccountToModule(ctx, owner, types.ModuleName, sdk.NewCoins(collateral))
|
||||
if err != nil {
|
||||
@ -66,10 +65,10 @@ func (k Keeper) AddCdp(ctx sdk.Context, owner sdk.AccAddress, collateral sdk.Coi
|
||||
}
|
||||
|
||||
// update total principal for input collateral type
|
||||
k.IncrementTotalPrincipal(ctx, collateral.Denom, principal)
|
||||
k.IncrementTotalPrincipal(ctx, collateralType, principal)
|
||||
|
||||
// set the cdp, deposit, and indexes in the store
|
||||
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, collateral, principal)
|
||||
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, collateral, cdp.Type, principal)
|
||||
err = k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -109,7 +108,7 @@ func (k Keeper) SetCdpAndCollateralRatioIndex(ctx sdk.Context, cdp types.CDP, ra
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
k.IndexCdpByCollateralRatio(ctx, cdp.Collateral.Denom, cdp.ID, ratio)
|
||||
k.IndexCdpByCollateralRatio(ctx, cdp.Type, cdp.ID, ratio)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -126,14 +125,14 @@ func (k Keeper) BurnDebtCoins(ctx sdk.Context, moduleAccount string, denom strin
|
||||
}
|
||||
|
||||
// GetCdpID returns the id of the cdp corresponding to a specific owner and collateral denom
|
||||
func (k Keeper) GetCdpID(ctx sdk.Context, owner sdk.AccAddress, denom string) (uint64, bool) {
|
||||
func (k Keeper) GetCdpID(ctx sdk.Context, owner sdk.AccAddress, collateralType string) (uint64, bool) {
|
||||
|
||||
cdpIDs, found := k.GetCdpIdsByOwner(ctx, owner)
|
||||
if !found {
|
||||
return 0, false
|
||||
}
|
||||
for _, id := range cdpIDs {
|
||||
_, found = k.GetCDP(ctx, denom, id)
|
||||
_, found = k.GetCDP(ctx, collateralType, id)
|
||||
if found {
|
||||
return id, true
|
||||
}
|
||||
@ -154,14 +153,14 @@ func (k Keeper) GetCdpIdsByOwner(ctx sdk.Context, owner sdk.AccAddress) ([]uint6
|
||||
return cdpIDs, true
|
||||
}
|
||||
|
||||
// GetCdpByOwnerAndDenom queries cdps owned by owner and returns the cdp with matching denom
|
||||
func (k Keeper) GetCdpByOwnerAndDenom(ctx sdk.Context, owner sdk.AccAddress, denom string) (types.CDP, bool) {
|
||||
// GetCdpByOwnerAndCollateralType queries cdps owned by owner and returns the cdp with matching denom
|
||||
func (k Keeper) GetCdpByOwnerAndCollateralType(ctx sdk.Context, owner sdk.AccAddress, collateralType string) (types.CDP, bool) {
|
||||
cdpIDs, found := k.GetCdpIdsByOwner(ctx, owner)
|
||||
if !found {
|
||||
return types.CDP{}, false
|
||||
}
|
||||
for _, id := range cdpIDs {
|
||||
cdp, found := k.GetCDP(ctx, denom, id)
|
||||
cdp, found := k.GetCDP(ctx, collateralType, id)
|
||||
if found {
|
||||
return cdp, true
|
||||
}
|
||||
@ -170,10 +169,10 @@ func (k Keeper) GetCdpByOwnerAndDenom(ctx sdk.Context, owner sdk.AccAddress, den
|
||||
}
|
||||
|
||||
// GetCDP returns the cdp associated with a particular collateral denom and id
|
||||
func (k Keeper) GetCDP(ctx sdk.Context, collateralDenom string, cdpID uint64) (types.CDP, bool) {
|
||||
func (k Keeper) GetCDP(ctx sdk.Context, collateralType string, cdpID uint64) (types.CDP, bool) {
|
||||
// get store
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.CdpKeyPrefix)
|
||||
db, found := k.GetDenomPrefix(ctx, collateralDenom)
|
||||
db, found := k.GetCollateralTypePrefix(ctx, collateralType)
|
||||
if !found {
|
||||
return types.CDP{}, false
|
||||
}
|
||||
@ -191,7 +190,7 @@ func (k Keeper) GetCDP(ctx sdk.Context, collateralDenom string, cdpID uint64) (t
|
||||
// SetCDP sets a cdp in the store
|
||||
func (k Keeper) SetCDP(ctx sdk.Context, cdp types.CDP) error {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.CdpKeyPrefix)
|
||||
db, found := k.GetDenomPrefix(ctx, cdp.Collateral.Denom)
|
||||
db, found := k.GetCollateralTypePrefix(ctx, cdp.Type)
|
||||
if !found {
|
||||
return sdkerrors.Wrapf(types.ErrDenomPrefixNotFound, "%s", cdp.Collateral.Denom)
|
||||
}
|
||||
@ -203,7 +202,7 @@ func (k Keeper) SetCDP(ctx sdk.Context, cdp types.CDP) error {
|
||||
// DeleteCDP deletes a cdp from the store
|
||||
func (k Keeper) DeleteCDP(ctx sdk.Context, cdp types.CDP) error {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.CdpKeyPrefix)
|
||||
db, found := k.GetDenomPrefix(ctx, cdp.Collateral.Denom)
|
||||
db, found := k.GetCollateralTypePrefix(ctx, cdp.Type)
|
||||
if !found {
|
||||
return sdkerrors.Wrapf(types.ErrDenomPrefixNotFound, "%s", cdp.Collateral.Denom)
|
||||
}
|
||||
@ -221,18 +220,18 @@ func (k Keeper) GetAllCdps(ctx sdk.Context) (cdps types.CDPs) {
|
||||
return
|
||||
}
|
||||
|
||||
// GetAllCdpsByDenom returns all cdps of a particular collateral type from the store
|
||||
func (k Keeper) GetAllCdpsByDenom(ctx sdk.Context, denom string) (cdps types.CDPs) {
|
||||
k.IterateCdpsByDenom(ctx, denom, func(cdp types.CDP) bool {
|
||||
// GetAllCdpsByCollateralType returns all cdps of a particular collateral type from the store
|
||||
func (k Keeper) GetAllCdpsByCollateralType(ctx sdk.Context, collateralType string) (cdps types.CDPs) {
|
||||
k.IterateCdpsByCollateralType(ctx, collateralType, func(cdp types.CDP) bool {
|
||||
cdps = append(cdps, cdp)
|
||||
return false
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// GetAllCdpsByDenomAndRatio returns all cdps of a particular collateral type and below a certain collateralization ratio
|
||||
func (k Keeper) GetAllCdpsByDenomAndRatio(ctx sdk.Context, denom string, targetRatio sdk.Dec) (cdps types.CDPs) {
|
||||
k.IterateCdpsByCollateralRatio(ctx, denom, targetRatio, func(cdp types.CDP) bool {
|
||||
// GetAllCdpsByCollateralTypeAndRatio returns all cdps of a particular collateral type and below a certain collateralization ratio
|
||||
func (k Keeper) GetAllCdpsByCollateralTypeAndRatio(ctx sdk.Context, collateralType string, targetRatio sdk.Dec) (cdps types.CDPs) {
|
||||
k.IterateCdpsByCollateralRatio(ctx, collateralType, targetRatio, func(cdp types.CDP) bool {
|
||||
cdps = append(cdps, cdp)
|
||||
return false
|
||||
})
|
||||
@ -292,21 +291,21 @@ func (k Keeper) RemoveCdpOwnerIndex(ctx sdk.Context, cdp types.CDP) {
|
||||
}
|
||||
|
||||
// IndexCdpByCollateralRatio sets the cdp id in the store, indexed by the collateral type and collateral to debt ratio
|
||||
func (k Keeper) IndexCdpByCollateralRatio(ctx sdk.Context, denom string, id uint64, collateralRatio sdk.Dec) {
|
||||
func (k Keeper) IndexCdpByCollateralRatio(ctx sdk.Context, collateralType string, id uint64, collateralRatio sdk.Dec) {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.CollateralRatioIndexPrefix)
|
||||
db, found := k.GetDenomPrefix(ctx, denom)
|
||||
db, found := k.GetCollateralTypePrefix(ctx, collateralType)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("denom %s prefix not found", denom))
|
||||
panic(fmt.Sprintf("denom %s prefix not found", collateralType))
|
||||
}
|
||||
store.Set(types.CollateralRatioKey(db, id, collateralRatio), types.GetCdpIDBytes(id))
|
||||
}
|
||||
|
||||
// RemoveCdpCollateralRatioIndex deletes the cdp id from the store's index of cdps by collateral type and collateral to debt ratio
|
||||
func (k Keeper) RemoveCdpCollateralRatioIndex(ctx sdk.Context, denom string, id uint64, collateralRatio sdk.Dec) {
|
||||
func (k Keeper) RemoveCdpCollateralRatioIndex(ctx sdk.Context, collateralType string, id uint64, collateralRatio sdk.Dec) {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.CollateralRatioIndexPrefix)
|
||||
db, found := k.GetDenomPrefix(ctx, denom)
|
||||
db, found := k.GetCollateralTypePrefix(ctx, collateralType)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("denom %s prefix not found", denom))
|
||||
panic(fmt.Sprintf("denom %s prefix not found", collateralType))
|
||||
}
|
||||
store.Delete(types.CollateralRatioKey(db, id, collateralRatio))
|
||||
}
|
||||
@ -346,8 +345,8 @@ func (k Keeper) SetGovDenom(ctx sdk.Context, denom string) {
|
||||
}
|
||||
|
||||
// ValidateCollateral validates that a collateral is valid for use in cdps
|
||||
func (k Keeper) ValidateCollateral(ctx sdk.Context, collateral sdk.Coin) error {
|
||||
cp, found := k.GetCollateral(ctx, collateral.Denom)
|
||||
func (k Keeper) ValidateCollateral(ctx sdk.Context, collateral sdk.Coin, collateralType string) error {
|
||||
cp, found := k.GetCollateral(ctx, collateralType)
|
||||
if !found {
|
||||
return sdkerrors.Wrap(types.ErrCollateralNotSupported, collateral.Denom)
|
||||
}
|
||||
@ -387,12 +386,12 @@ func (k Keeper) ValidatePrincipalDraw(ctx sdk.Context, principal sdk.Coin, expec
|
||||
}
|
||||
|
||||
// ValidateDebtLimit validates that the input debt amount does not exceed the global debt limit or the debt limit for that collateral
|
||||
func (k Keeper) ValidateDebtLimit(ctx sdk.Context, collateralDenom string, principal sdk.Coin) error {
|
||||
cp, found := k.GetCollateral(ctx, collateralDenom)
|
||||
func (k Keeper) ValidateDebtLimit(ctx sdk.Context, collateralType string, principal sdk.Coin) error {
|
||||
cp, found := k.GetCollateral(ctx, collateralType)
|
||||
if !found {
|
||||
return sdkerrors.Wrap(types.ErrCollateralNotSupported, collateralDenom)
|
||||
return sdkerrors.Wrap(types.ErrCollateralNotSupported, collateralType)
|
||||
}
|
||||
totalPrincipal := k.GetTotalPrincipal(ctx, collateralDenom, principal.Denom).Add(principal.Amount)
|
||||
totalPrincipal := k.GetTotalPrincipal(ctx, collateralType, principal.Denom).Add(principal.Amount)
|
||||
collateralLimit := cp.DebtLimit.Amount
|
||||
if totalPrincipal.GT(collateralLimit) {
|
||||
return sdkerrors.Wrapf(types.ErrExceedsDebtLimit, "debt increase %s > collateral debt limit %s", sdk.NewCoins(sdk.NewCoin(principal.Denom, totalPrincipal)), sdk.NewCoins(sdk.NewCoin(principal.Denom, collateralLimit)))
|
||||
@ -405,12 +404,12 @@ func (k Keeper) ValidateDebtLimit(ctx sdk.Context, collateralDenom string, princ
|
||||
}
|
||||
|
||||
// ValidateCollateralizationRatio validate that adding the input principal doesn't put the cdp below the liquidation ratio
|
||||
func (k Keeper) ValidateCollateralizationRatio(ctx sdk.Context, collateral sdk.Coin, principal sdk.Coin, fees sdk.Coin) error {
|
||||
collateralizationRatio, err := k.CalculateCollateralizationRatio(ctx, collateral, principal, fees, spot)
|
||||
func (k Keeper) ValidateCollateralizationRatio(ctx sdk.Context, collateral sdk.Coin, collateralType string, principal sdk.Coin, fees sdk.Coin) error {
|
||||
collateralizationRatio, err := k.CalculateCollateralizationRatio(ctx, collateral, collateralType, principal, fees, spot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
liquidationRatio := k.getLiquidationRatio(ctx, collateral.Denom)
|
||||
liquidationRatio := k.getLiquidationRatio(ctx, collateralType)
|
||||
if collateralizationRatio.LT(liquidationRatio) {
|
||||
return sdkerrors.Wrapf(types.ErrInvalidCollateralRatio, "collateral %s, collateral ratio %s, liquidation ratio %s", collateral.Denom, collateralizationRatio, liquidationRatio)
|
||||
}
|
||||
@ -418,21 +417,21 @@ func (k Keeper) ValidateCollateralizationRatio(ctx sdk.Context, collateral sdk.C
|
||||
}
|
||||
|
||||
// CalculateCollateralToDebtRatio returns the collateral to debt ratio of the input collateral and debt amounts
|
||||
func (k Keeper) CalculateCollateralToDebtRatio(ctx sdk.Context, collateral sdk.Coin, debt sdk.Coin) sdk.Dec {
|
||||
func (k Keeper) CalculateCollateralToDebtRatio(ctx sdk.Context, collateral sdk.Coin, collateralType string, debt sdk.Coin) sdk.Dec {
|
||||
debtTotal := k.convertDebtToBaseUnits(ctx, debt)
|
||||
|
||||
if debtTotal.IsZero() || debtTotal.GTE(types.MaxSortableDec) {
|
||||
return types.MaxSortableDec.Sub(sdk.SmallestDec())
|
||||
}
|
||||
|
||||
collateralBaseUnits := k.convertCollateralToBaseUnits(ctx, collateral)
|
||||
collateralBaseUnits := k.convertCollateralToBaseUnits(ctx, collateral, collateralType)
|
||||
return collateralBaseUnits.Quo(debtTotal)
|
||||
}
|
||||
|
||||
// LoadAugmentedCDP creates a new augmented CDP from an existing CDP
|
||||
func (k Keeper) LoadAugmentedCDP(ctx sdk.Context, cdp types.CDP) types.AugmentedCDP {
|
||||
// calculate collateralization ratio
|
||||
collateralizationRatio, err := k.CalculateCollateralizationRatio(ctx, cdp.Collateral, cdp.Principal, cdp.AccumulatedFees, liquidation)
|
||||
collateralizationRatio, err := k.CalculateCollateralizationRatio(ctx, cdp.Collateral, cdp.Type, cdp.Principal, cdp.AccumulatedFees, liquidation)
|
||||
if err != nil {
|
||||
return types.AugmentedCDP{CDP: cdp}
|
||||
}
|
||||
@ -446,16 +445,16 @@ func (k Keeper) LoadAugmentedCDP(ctx sdk.Context, cdp types.CDP) types.Augmented
|
||||
}
|
||||
|
||||
// CalculateCollateralizationRatio returns the collateralization ratio of the input collateral to the input debt plus fees
|
||||
func (k Keeper) CalculateCollateralizationRatio(ctx sdk.Context, collateral sdk.Coin, principal sdk.Coin, fees sdk.Coin, pfType pricefeedType) (sdk.Dec, error) {
|
||||
func (k Keeper) CalculateCollateralizationRatio(ctx sdk.Context, collateral sdk.Coin, collateralType string, principal sdk.Coin, fees sdk.Coin, pfType pricefeedType) (sdk.Dec, error) {
|
||||
if collateral.IsZero() {
|
||||
return sdk.ZeroDec(), nil
|
||||
}
|
||||
var marketID string
|
||||
switch pfType {
|
||||
case spot:
|
||||
marketID = k.getSpotMarketID(ctx, collateral.Denom)
|
||||
marketID = k.getSpotMarketID(ctx, collateralType)
|
||||
case liquidation:
|
||||
marketID = k.getliquidationMarketID(ctx, collateral.Denom)
|
||||
marketID = k.getliquidationMarketID(ctx, collateralType)
|
||||
default:
|
||||
return sdk.Dec{}, pfType.IsValid()
|
||||
}
|
||||
@ -464,7 +463,7 @@ func (k Keeper) CalculateCollateralizationRatio(ctx sdk.Context, collateral sdk.
|
||||
if err != nil {
|
||||
return sdk.Dec{}, err
|
||||
}
|
||||
collateralBaseUnits := k.convertCollateralToBaseUnits(ctx, collateral)
|
||||
collateralBaseUnits := k.convertCollateralToBaseUnits(ctx, collateral, collateralType)
|
||||
collateralValue := collateralBaseUnits.Mul(price.Price)
|
||||
|
||||
prinicpalBaseUnits := k.convertDebtToBaseUnits(ctx, principal)
|
||||
@ -477,14 +476,14 @@ func (k Keeper) CalculateCollateralizationRatio(ctx sdk.Context, collateral sdk.
|
||||
}
|
||||
|
||||
// CalculateCollateralizationRatioFromAbsoluteRatio takes a coin's denom and an absolute ratio and returns the respective collateralization ratio
|
||||
func (k Keeper) CalculateCollateralizationRatioFromAbsoluteRatio(ctx sdk.Context, collateralDenom string, absoluteRatio sdk.Dec, pfType pricefeedType) (sdk.Dec, error) {
|
||||
func (k Keeper) CalculateCollateralizationRatioFromAbsoluteRatio(ctx sdk.Context, collateralType string, absoluteRatio sdk.Dec, pfType pricefeedType) (sdk.Dec, error) {
|
||||
// get price of collateral
|
||||
var marketID string
|
||||
switch pfType {
|
||||
case spot:
|
||||
marketID = k.getSpotMarketID(ctx, collateralDenom)
|
||||
marketID = k.getSpotMarketID(ctx, collateralType)
|
||||
case liquidation:
|
||||
marketID = k.getliquidationMarketID(ctx, collateralDenom)
|
||||
marketID = k.getliquidationMarketID(ctx, collateralType)
|
||||
default:
|
||||
return sdk.Dec{}, pfType.IsValid()
|
||||
}
|
||||
@ -525,8 +524,8 @@ func (k Keeper) UpdatePricefeedStatus(ctx sdk.Context, marketID string) (ok bool
|
||||
}
|
||||
|
||||
// converts the input collateral to base units (ie multiplies the input by 10^(-ConversionFactor))
|
||||
func (k Keeper) convertCollateralToBaseUnits(ctx sdk.Context, collateral sdk.Coin) (baseUnits sdk.Dec) {
|
||||
cp, _ := k.GetCollateral(ctx, collateral.Denom)
|
||||
func (k Keeper) convertCollateralToBaseUnits(ctx sdk.Context, collateral sdk.Coin, collateralType string) (baseUnits sdk.Dec) {
|
||||
cp, _ := k.GetCollateral(ctx, collateralType)
|
||||
return sdk.NewDecFromInt(collateral.Amount).Mul(sdk.NewDecFromIntWithPrec(sdk.OneInt(), cp.ConversionFactor.Int64()))
|
||||
}
|
||||
|
||||
@ -548,5 +547,5 @@ func (pft pricefeedType) IsValid() error {
|
||||
case spot, liquidation:
|
||||
return nil
|
||||
}
|
||||
return errors.New(fmt.Sprintf("invalid pricefeed type: %s", pft))
|
||||
return fmt.Errorf("invalid pricefeed type: %s", pft)
|
||||
}
|
||||
|
@ -47,17 +47,17 @@ func (suite *CdpTestSuite) TestAddCdp() {
|
||||
acc := ak.NewAccountWithAddress(suite.ctx, addrs[0])
|
||||
acc.SetCoins(cs(c("xrp", 200000000), c("btc", 500000000)))
|
||||
ak.SetAccount(suite.ctx, acc)
|
||||
err := suite.keeper.AddCdp(suite.ctx, addrs[0], c("xrp", 200000000), c("usdx", 26000000))
|
||||
err := suite.keeper.AddCdp(suite.ctx, addrs[0], c("xrp", 200000000), c("usdx", 26000000), "xrp-a")
|
||||
suite.Require().True(errors.Is(err, types.ErrInvalidCollateralRatio))
|
||||
err = suite.keeper.AddCdp(suite.ctx, addrs[0], c("xrp", 500000000), c("usdx", 26000000))
|
||||
err = suite.keeper.AddCdp(suite.ctx, addrs[0], c("xrp", 500000000), c("usdx", 26000000), "xrp-a")
|
||||
suite.Error(err) // insufficient balance
|
||||
err = suite.keeper.AddCdp(suite.ctx, addrs[0], c("xrp", 200000000), c("xusd", 10000000))
|
||||
err = suite.keeper.AddCdp(suite.ctx, addrs[0], c("xrp", 200000000), c("xusd", 10000000), "xrp-a")
|
||||
suite.Require().True(errors.Is(err, types.ErrDebtNotSupported))
|
||||
|
||||
acc2 := ak.NewAccountWithAddress(suite.ctx, addrs[1])
|
||||
acc2.SetCoins(cs(c("btc", 500000000000)))
|
||||
ak.SetAccount(suite.ctx, acc2)
|
||||
err = suite.keeper.AddCdp(suite.ctx, addrs[1], c("btc", 500000000000), c("usdx", 500000000001))
|
||||
err = suite.keeper.AddCdp(suite.ctx, addrs[1], c("btc", 500000000000), c("usdx", 500000000001), "btc-a")
|
||||
suite.Require().True(errors.Is(err, types.ErrExceedsDebtLimit))
|
||||
|
||||
ctx := suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(time.Hour * 2))
|
||||
@ -66,18 +66,18 @@ func (suite *CdpTestSuite) TestAddCdp() {
|
||||
suite.Error(err)
|
||||
ok := suite.keeper.UpdatePricefeedStatus(ctx, "xrp:usd")
|
||||
suite.False(ok)
|
||||
err = suite.keeper.AddCdp(ctx, addrs[0], c("xrp", 100000000), c("usdx", 10000000))
|
||||
err = suite.keeper.AddCdp(ctx, addrs[0], c("xrp", 100000000), c("usdx", 10000000), "xrp-a")
|
||||
suite.Require().True(errors.Is(err, types.ErrPricefeedDown))
|
||||
|
||||
err = pk.SetCurrentPrices(suite.ctx, "xrp:usd")
|
||||
ok = suite.keeper.UpdatePricefeedStatus(suite.ctx, "xrp:usd")
|
||||
suite.True(ok)
|
||||
suite.NoError(err)
|
||||
err = suite.keeper.AddCdp(suite.ctx, addrs[0], c("xrp", 100000000), c("usdx", 10000000))
|
||||
err = suite.keeper.AddCdp(suite.ctx, addrs[0], c("xrp", 100000000), c("usdx", 10000000), "xrp-a")
|
||||
suite.NoError(err)
|
||||
id := suite.keeper.GetNextCdpID(suite.ctx)
|
||||
suite.Equal(uint64(2), id)
|
||||
tp := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx")
|
||||
tp := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp-a", "usdx")
|
||||
suite.Equal(i(10000000), tp)
|
||||
sk := suite.app.GetSupplyKeeper()
|
||||
macc := sk.GetModuleAccount(suite.ctx, types.ModuleName)
|
||||
@ -85,30 +85,30 @@ func (suite *CdpTestSuite) TestAddCdp() {
|
||||
acc = ak.GetAccount(suite.ctx, addrs[0])
|
||||
suite.Equal(cs(c("usdx", 10000000), c("xrp", 100000000), c("btc", 500000000)), acc.GetCoins())
|
||||
|
||||
err = suite.keeper.AddCdp(suite.ctx, addrs[0], c("btc", 500000000), c("usdx", 26667000000))
|
||||
err = suite.keeper.AddCdp(suite.ctx, addrs[0], c("btc", 500000000), c("usdx", 26667000000), "btc-a")
|
||||
suite.Require().True(errors.Is(err, types.ErrInvalidCollateralRatio))
|
||||
|
||||
err = suite.keeper.AddCdp(suite.ctx, addrs[0], c("btc", 500000000), c("usdx", 100000000))
|
||||
err = suite.keeper.AddCdp(suite.ctx, addrs[0], c("btc", 500000000), c("usdx", 100000000), "btc-a")
|
||||
suite.NoError(err)
|
||||
id = suite.keeper.GetNextCdpID(suite.ctx)
|
||||
suite.Equal(uint64(3), id)
|
||||
tp = suite.keeper.GetTotalPrincipal(suite.ctx, "btc", "usdx")
|
||||
tp = suite.keeper.GetTotalPrincipal(suite.ctx, "btc-a", "usdx")
|
||||
suite.Equal(i(100000000), tp)
|
||||
macc = sk.GetModuleAccount(suite.ctx, types.ModuleName)
|
||||
suite.Equal(cs(c("debt", 110000000), c("xrp", 100000000), c("btc", 500000000)), macc.GetCoins())
|
||||
acc = ak.GetAccount(suite.ctx, addrs[0])
|
||||
suite.Equal(cs(c("usdx", 110000000), c("xrp", 100000000)), acc.GetCoins())
|
||||
|
||||
err = suite.keeper.AddCdp(suite.ctx, addrs[0], c("lol", 100), c("usdx", 10))
|
||||
err = suite.keeper.AddCdp(suite.ctx, addrs[0], c("lol", 100), c("usdx", 10), "lol-a")
|
||||
suite.Require().True(errors.Is(err, types.ErrCollateralNotSupported))
|
||||
err = suite.keeper.AddCdp(suite.ctx, addrs[0], c("xrp", 100), c("usdx", 10))
|
||||
err = suite.keeper.AddCdp(suite.ctx, addrs[0], c("xrp", 100), c("usdx", 10), "xrp-a")
|
||||
suite.Require().True(errors.Is(err, types.ErrCdpAlreadyExists))
|
||||
}
|
||||
|
||||
func (suite *CdpTestSuite) TestGetSetDenomByte() {
|
||||
_, found := suite.keeper.GetDenomPrefix(suite.ctx, "lol")
|
||||
func (suite *CdpTestSuite) TestGetSetCollateralTypeByte() {
|
||||
_, found := suite.keeper.GetCollateralTypePrefix(suite.ctx, "lol-a")
|
||||
suite.False(found)
|
||||
db, found := suite.keeper.GetDenomPrefix(suite.ctx, "xrp")
|
||||
db, found := suite.keeper.GetCollateralTypePrefix(suite.ctx, "xrp-a")
|
||||
suite.True(found)
|
||||
suite.Equal(byte(0x20), db)
|
||||
}
|
||||
@ -129,66 +129,66 @@ func (suite *CdpTestSuite) TestGetNextCdpID() {
|
||||
|
||||
func (suite *CdpTestSuite) TestGetSetCdp() {
|
||||
_, addrs := app.GeneratePrivKeyAddressPairs(1)
|
||||
cdp := types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 1), c("usdx", 1), tmtime.Canonical(time.Now()))
|
||||
cdp := types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 1), "xrp-a", c("usdx", 1), tmtime.Canonical(time.Now()))
|
||||
err := suite.keeper.SetCDP(suite.ctx, cdp)
|
||||
suite.NoError(err)
|
||||
|
||||
t, found := suite.keeper.GetCDP(suite.ctx, "xrp", types.DefaultCdpStartingID)
|
||||
t, found := suite.keeper.GetCDP(suite.ctx, "xrp-a", types.DefaultCdpStartingID)
|
||||
suite.True(found)
|
||||
suite.Equal(cdp, t)
|
||||
_, found = suite.keeper.GetCDP(suite.ctx, "xrp", uint64(2))
|
||||
_, found = suite.keeper.GetCDP(suite.ctx, "xrp-a", uint64(2))
|
||||
suite.False(found)
|
||||
suite.keeper.DeleteCDP(suite.ctx, cdp)
|
||||
_, found = suite.keeper.GetCDP(suite.ctx, "btc", types.DefaultCdpStartingID)
|
||||
_, found = suite.keeper.GetCDP(suite.ctx, "btc-a", types.DefaultCdpStartingID)
|
||||
suite.False(found)
|
||||
}
|
||||
|
||||
func (suite *CdpTestSuite) TestGetSetCdpId() {
|
||||
_, addrs := app.GeneratePrivKeyAddressPairs(2)
|
||||
cdp := types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 1), c("usdx", 1), tmtime.Canonical(time.Now()))
|
||||
cdp := types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 1), "xrp-a", c("usdx", 1), tmtime.Canonical(time.Now()))
|
||||
err := suite.keeper.SetCDP(suite.ctx, cdp)
|
||||
suite.NoError(err)
|
||||
suite.keeper.IndexCdpByOwner(suite.ctx, cdp)
|
||||
id, found := suite.keeper.GetCdpID(suite.ctx, addrs[0], "xrp")
|
||||
id, found := suite.keeper.GetCdpID(suite.ctx, addrs[0], "xrp-a")
|
||||
suite.True(found)
|
||||
suite.Equal(types.DefaultCdpStartingID, id)
|
||||
_, found = suite.keeper.GetCdpID(suite.ctx, addrs[0], "lol")
|
||||
_, found = suite.keeper.GetCdpID(suite.ctx, addrs[0], "lol-a")
|
||||
suite.False(found)
|
||||
_, found = suite.keeper.GetCdpID(suite.ctx, addrs[1], "xrp")
|
||||
_, found = suite.keeper.GetCdpID(suite.ctx, addrs[1], "xrp-a")
|
||||
suite.False(found)
|
||||
}
|
||||
|
||||
func (suite *CdpTestSuite) TestGetSetCdpByOwnerAndDenom() {
|
||||
func (suite *CdpTestSuite) TestGetSetCdpByOwnerAndCollateralType() {
|
||||
_, addrs := app.GeneratePrivKeyAddressPairs(2)
|
||||
cdp := types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 1), c("usdx", 1), tmtime.Canonical(time.Now()))
|
||||
cdp := types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 1), "xrp-a", c("usdx", 1), tmtime.Canonical(time.Now()))
|
||||
err := suite.keeper.SetCDP(suite.ctx, cdp)
|
||||
suite.NoError(err)
|
||||
suite.keeper.IndexCdpByOwner(suite.ctx, cdp)
|
||||
t, found := suite.keeper.GetCdpByOwnerAndDenom(suite.ctx, addrs[0], "xrp")
|
||||
t, found := suite.keeper.GetCdpByOwnerAndCollateralType(suite.ctx, addrs[0], "xrp-a")
|
||||
suite.True(found)
|
||||
suite.Equal(cdp, t)
|
||||
_, found = suite.keeper.GetCdpByOwnerAndDenom(suite.ctx, addrs[0], "lol")
|
||||
_, found = suite.keeper.GetCdpByOwnerAndCollateralType(suite.ctx, addrs[0], "lol-a")
|
||||
suite.False(found)
|
||||
_, found = suite.keeper.GetCdpByOwnerAndDenom(suite.ctx, addrs[1], "xrp")
|
||||
_, found = suite.keeper.GetCdpByOwnerAndCollateralType(suite.ctx, addrs[1], "xrp-a")
|
||||
suite.False(found)
|
||||
suite.NotPanics(func() { suite.keeper.IndexCdpByOwner(suite.ctx, cdp) })
|
||||
}
|
||||
|
||||
func (suite *CdpTestSuite) TestCalculateCollateralToDebtRatio() {
|
||||
_, addrs := app.GeneratePrivKeyAddressPairs(1)
|
||||
cdp := types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 3), c("usdx", 1), tmtime.Canonical(time.Now()))
|
||||
cr := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, cdp.Collateral, cdp.Principal)
|
||||
cdp := types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 3), "xrp-a", c("usdx", 1), tmtime.Canonical(time.Now()))
|
||||
cr := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, cdp.Collateral, cdp.Type, cdp.Principal)
|
||||
suite.Equal(sdk.MustNewDecFromStr("3.0"), cr)
|
||||
cdp = types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 1), c("usdx", 2), tmtime.Canonical(time.Now()))
|
||||
cr = suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, cdp.Collateral, cdp.Principal)
|
||||
cdp = types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 1), "xrp-a", c("usdx", 2), tmtime.Canonical(time.Now()))
|
||||
cr = suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, cdp.Collateral, cdp.Type, cdp.Principal)
|
||||
suite.Equal(sdk.MustNewDecFromStr("0.5"), cr)
|
||||
}
|
||||
|
||||
func (suite *CdpTestSuite) TestSetCdpByCollateralRatio() {
|
||||
_, addrs := app.GeneratePrivKeyAddressPairs(1)
|
||||
cdp := types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 3), c("usdx", 1), tmtime.Canonical(time.Now()))
|
||||
cr := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, cdp.Collateral, cdp.Principal)
|
||||
suite.NotPanics(func() { suite.keeper.IndexCdpByCollateralRatio(suite.ctx, cdp.Collateral.Denom, cdp.ID, cr) })
|
||||
cdp := types.NewCDP(types.DefaultCdpStartingID, addrs[0], c("xrp", 3), "xrp-a", c("usdx", 1), tmtime.Canonical(time.Now()))
|
||||
cr := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, cdp.Collateral, cdp.Type, cdp.Principal)
|
||||
suite.NotPanics(func() { suite.keeper.IndexCdpByCollateralRatio(suite.ctx, cdp.Type, cdp.ID, cr) })
|
||||
}
|
||||
|
||||
func (suite *CdpTestSuite) TestIterateCdps() {
|
||||
@ -197,29 +197,29 @@ func (suite *CdpTestSuite) TestIterateCdps() {
|
||||
err := suite.keeper.SetCDP(suite.ctx, c)
|
||||
suite.NoError(err)
|
||||
suite.keeper.IndexCdpByOwner(suite.ctx, c)
|
||||
cr := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, c.Collateral, c.Principal)
|
||||
suite.keeper.IndexCdpByCollateralRatio(suite.ctx, c.Collateral.Denom, c.ID, cr)
|
||||
cr := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, c.Collateral, c.Type, c.Principal)
|
||||
suite.keeper.IndexCdpByCollateralRatio(suite.ctx, c.Type, c.ID, cr)
|
||||
}
|
||||
t := suite.keeper.GetAllCdps(suite.ctx)
|
||||
suite.Equal(4, len(t))
|
||||
}
|
||||
|
||||
func (suite *CdpTestSuite) TestIterateCdpsByDenom() {
|
||||
func (suite *CdpTestSuite) TestIterateCdpsByCollateralType() {
|
||||
cdps := cdps()
|
||||
for _, c := range cdps {
|
||||
err := suite.keeper.SetCDP(suite.ctx, c)
|
||||
suite.NoError(err)
|
||||
suite.keeper.IndexCdpByOwner(suite.ctx, c)
|
||||
cr := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, c.Collateral, c.Principal)
|
||||
suite.keeper.IndexCdpByCollateralRatio(suite.ctx, c.Collateral.Denom, c.ID, cr)
|
||||
cr := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, c.Collateral, c.Type, c.Principal)
|
||||
suite.keeper.IndexCdpByCollateralRatio(suite.ctx, c.Type, c.ID, cr)
|
||||
}
|
||||
xrpCdps := suite.keeper.GetAllCdpsByDenom(suite.ctx, "xrp")
|
||||
xrpCdps := suite.keeper.GetAllCdpsByCollateralType(suite.ctx, "xrp-a")
|
||||
suite.Equal(3, len(xrpCdps))
|
||||
btcCdps := suite.keeper.GetAllCdpsByDenom(suite.ctx, "btc")
|
||||
btcCdps := suite.keeper.GetAllCdpsByCollateralType(suite.ctx, "btc-a")
|
||||
suite.Equal(1, len(btcCdps))
|
||||
suite.keeper.DeleteCDP(suite.ctx, cdps[0])
|
||||
suite.keeper.RemoveCdpOwnerIndex(suite.ctx, cdps[0])
|
||||
xrpCdps = suite.keeper.GetAllCdpsByDenom(suite.ctx, "xrp")
|
||||
xrpCdps = suite.keeper.GetAllCdpsByCollateralType(suite.ctx, "xrp-a")
|
||||
suite.Equal(2, len(xrpCdps))
|
||||
suite.keeper.DeleteCDP(suite.ctx, cdps[1])
|
||||
suite.keeper.RemoveCdpOwnerIndex(suite.ctx, cdps[1])
|
||||
@ -235,31 +235,31 @@ func (suite *CdpTestSuite) TestIterateCdpsByCollateralRatio() {
|
||||
err := suite.keeper.SetCDP(suite.ctx, c)
|
||||
suite.NoError(err)
|
||||
suite.keeper.IndexCdpByOwner(suite.ctx, c)
|
||||
cr := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, c.Collateral, c.Principal)
|
||||
suite.keeper.IndexCdpByCollateralRatio(suite.ctx, c.Collateral.Denom, c.ID, cr)
|
||||
cr := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, c.Collateral, c.Type, c.Principal)
|
||||
suite.keeper.IndexCdpByCollateralRatio(suite.ctx, c.Type, c.ID, cr)
|
||||
}
|
||||
xrpCdps := suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("1.25"))
|
||||
xrpCdps := suite.keeper.GetAllCdpsByCollateralTypeAndRatio(suite.ctx, "xrp-a", d("1.25"))
|
||||
suite.Equal(0, len(xrpCdps))
|
||||
xrpCdps = suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("1.25").Add(sdk.SmallestDec()))
|
||||
xrpCdps = suite.keeper.GetAllCdpsByCollateralTypeAndRatio(suite.ctx, "xrp-a", d("1.25").Add(sdk.SmallestDec()))
|
||||
suite.Equal(1, len(xrpCdps))
|
||||
xrpCdps = suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("2.0").Add(sdk.SmallestDec()))
|
||||
xrpCdps = suite.keeper.GetAllCdpsByCollateralTypeAndRatio(suite.ctx, "xrp-a", d("2.0").Add(sdk.SmallestDec()))
|
||||
suite.Equal(2, len(xrpCdps))
|
||||
xrpCdps = suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("100.0").Add(sdk.SmallestDec()))
|
||||
xrpCdps = suite.keeper.GetAllCdpsByCollateralTypeAndRatio(suite.ctx, "xrp-a", d("100.0").Add(sdk.SmallestDec()))
|
||||
suite.Equal(3, len(xrpCdps))
|
||||
suite.keeper.DeleteCDP(suite.ctx, cdps[0])
|
||||
suite.keeper.RemoveCdpOwnerIndex(suite.ctx, cdps[0])
|
||||
cr := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, cdps[0].Collateral, cdps[0].Principal)
|
||||
suite.keeper.RemoveCdpCollateralRatioIndex(suite.ctx, cdps[0].Collateral.Denom, cdps[0].ID, cr)
|
||||
xrpCdps = suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("2.0").Add(sdk.SmallestDec()))
|
||||
cr := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, cdps[0].Collateral, cdps[0].Type, cdps[0].Principal)
|
||||
suite.keeper.RemoveCdpCollateralRatioIndex(suite.ctx, cdps[0].Type, cdps[0].ID, cr)
|
||||
xrpCdps = suite.keeper.GetAllCdpsByCollateralTypeAndRatio(suite.ctx, "xrp-a", d("2.0").Add(sdk.SmallestDec()))
|
||||
suite.Equal(1, len(xrpCdps))
|
||||
}
|
||||
|
||||
func (suite *CdpTestSuite) TestValidateCollateral() {
|
||||
c := sdk.NewCoin("xrp", sdk.NewInt(1))
|
||||
err := suite.keeper.ValidateCollateral(suite.ctx, c)
|
||||
err := suite.keeper.ValidateCollateral(suite.ctx, c, "xrp-a")
|
||||
suite.NoError(err)
|
||||
c = sdk.NewCoin("lol", sdk.NewInt(1))
|
||||
err = suite.keeper.ValidateCollateral(suite.ctx, c)
|
||||
err = suite.keeper.ValidateCollateral(suite.ctx, c, "lol-a")
|
||||
suite.Require().True(errors.Is(err, types.ErrCollateralNotSupported))
|
||||
}
|
||||
|
||||
@ -271,10 +271,10 @@ func (suite *CdpTestSuite) TestValidatePrincipal() {
|
||||
err = suite.keeper.ValidatePrincipalAdd(suite.ctx, d)
|
||||
suite.Require().True(errors.Is(err, types.ErrDebtNotSupported))
|
||||
d = sdk.NewCoin("usdx", sdk.NewInt(1000000000001))
|
||||
err = suite.keeper.ValidateDebtLimit(suite.ctx, "xrp", d)
|
||||
err = suite.keeper.ValidateDebtLimit(suite.ctx, "xrp-a", d)
|
||||
suite.Require().True(errors.Is(err, types.ErrExceedsDebtLimit))
|
||||
d = sdk.NewCoin("usdx", sdk.NewInt(100000000))
|
||||
err = suite.keeper.ValidateDebtLimit(suite.ctx, "xrp", d)
|
||||
err = suite.keeper.ValidateDebtLimit(suite.ctx, "xrp-a", d)
|
||||
suite.NoError(err)
|
||||
}
|
||||
|
||||
@ -283,13 +283,13 @@ func (suite *CdpTestSuite) TestCalculateCollateralizationRatio() {
|
||||
err := suite.keeper.SetCDP(suite.ctx, c)
|
||||
suite.NoError(err)
|
||||
suite.keeper.IndexCdpByOwner(suite.ctx, c)
|
||||
cr := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, c.Collateral, c.Principal)
|
||||
suite.keeper.IndexCdpByCollateralRatio(suite.ctx, c.Collateral.Denom, c.ID, cr)
|
||||
cr, err = suite.keeper.CalculateCollateralizationRatio(suite.ctx, c.Collateral, c.Principal, c.AccumulatedFees, "spot")
|
||||
cr := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, c.Collateral, c.Type, c.Principal)
|
||||
suite.keeper.IndexCdpByCollateralRatio(suite.ctx, c.Type, c.ID, cr)
|
||||
cr, err = suite.keeper.CalculateCollateralizationRatio(suite.ctx, c.Collateral, c.Type, c.Principal, c.AccumulatedFees, "spot")
|
||||
suite.NoError(err)
|
||||
suite.Equal(d("2.5"), cr)
|
||||
c.AccumulatedFees = sdk.NewCoin("usdx", i(10000000))
|
||||
cr, err = suite.keeper.CalculateCollateralizationRatio(suite.ctx, c.Collateral, c.Principal, c.AccumulatedFees, "spot")
|
||||
cr, err = suite.keeper.CalculateCollateralizationRatio(suite.ctx, c.Collateral, c.Type, c.Principal, c.AccumulatedFees, "spot")
|
||||
suite.NoError(err)
|
||||
suite.Equal(d("1.25"), cr)
|
||||
}
|
||||
|
@ -11,15 +11,15 @@ import (
|
||||
)
|
||||
|
||||
// DepositCollateral adds collateral to a cdp
|
||||
func (k Keeper) DepositCollateral(ctx sdk.Context, owner, depositor sdk.AccAddress, collateral sdk.Coin) error {
|
||||
func (k Keeper) DepositCollateral(ctx sdk.Context, owner, depositor sdk.AccAddress, collateral sdk.Coin, collateralType string) error {
|
||||
// check that collateral exists and has a functioning pricefeed
|
||||
err := k.ValidateCollateral(ctx, collateral)
|
||||
err := k.ValidateCollateral(ctx, collateral, collateralType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cdp, found := k.GetCdpByOwnerAndDenom(ctx, owner, collateral.Denom)
|
||||
cdp, found := k.GetCdpByOwnerAndCollateralType(ctx, owner, collateralType)
|
||||
if !found {
|
||||
return sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, collateral %s", owner, collateral.Denom)
|
||||
return sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, collateral %s", owner, collateralType)
|
||||
}
|
||||
|
||||
deposit, found := k.GetDeposit(ctx, cdp.ID, depositor)
|
||||
@ -42,37 +42,37 @@ func (k Keeper) DepositCollateral(ctx sdk.Context, owner, depositor sdk.AccAddre
|
||||
|
||||
k.SetDeposit(ctx, deposit)
|
||||
|
||||
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.GetTotalPrincipal())
|
||||
k.RemoveCdpCollateralRatioIndex(ctx, cdp.Collateral.Denom, cdp.ID, oldCollateralToDebtRatio)
|
||||
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal())
|
||||
k.RemoveCdpCollateralRatioIndex(ctx, cdp.Type, cdp.ID, oldCollateralToDebtRatio)
|
||||
|
||||
cdp.Collateral = cdp.Collateral.Add(collateral)
|
||||
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.GetTotalPrincipal())
|
||||
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal())
|
||||
return k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio)
|
||||
}
|
||||
|
||||
// WithdrawCollateral removes collateral from a cdp if it does not put the cdp below the liquidation ratio
|
||||
func (k Keeper) WithdrawCollateral(ctx sdk.Context, owner, depositor sdk.AccAddress, collateral sdk.Coin) error {
|
||||
err := k.ValidateCollateral(ctx, collateral)
|
||||
func (k Keeper) WithdrawCollateral(ctx sdk.Context, owner, depositor sdk.AccAddress, collateral sdk.Coin, collateralType string) error {
|
||||
err := k.ValidateCollateral(ctx, collateral, collateralType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cdp, found := k.GetCdpByOwnerAndDenom(ctx, owner, collateral.Denom)
|
||||
cdp, found := k.GetCdpByOwnerAndCollateralType(ctx, owner, collateralType)
|
||||
if !found {
|
||||
return sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, collateral %s", owner, collateral.Denom)
|
||||
}
|
||||
deposit, found := k.GetDeposit(ctx, cdp.ID, depositor)
|
||||
if !found {
|
||||
return sdkerrors.Wrapf(types.ErrDepositNotFound, "depositor %s, collateral %s", depositor, collateral.Denom)
|
||||
return sdkerrors.Wrapf(types.ErrDepositNotFound, "depositor %s, collateral %s %s", depositor, collateral.Denom, collateralType)
|
||||
}
|
||||
if collateral.Amount.GT(deposit.Amount.Amount) {
|
||||
return sdkerrors.Wrapf(types.ErrInvalidWithdrawAmount, "collateral %s, deposit %s", collateral, deposit.Amount)
|
||||
}
|
||||
|
||||
collateralizationRatio, err := k.CalculateCollateralizationRatio(ctx, cdp.Collateral.Sub(collateral), cdp.Principal, cdp.AccumulatedFees, spot)
|
||||
collateralizationRatio, err := k.CalculateCollateralizationRatio(ctx, cdp.Collateral.Sub(collateral), cdp.Type, cdp.Principal, cdp.AccumulatedFees, spot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
liquidationRatio := k.getLiquidationRatio(ctx, collateral.Denom)
|
||||
liquidationRatio := k.getLiquidationRatio(ctx, cdp.Type)
|
||||
if collateralizationRatio.LT(liquidationRatio) {
|
||||
return sdkerrors.Wrapf(types.ErrInvalidCollateralRatio, "collateral %s, collateral ratio %s, liquidation ration %s", collateral.Denom, collateralizationRatio, liquidationRatio)
|
||||
}
|
||||
@ -88,11 +88,11 @@ func (k Keeper) WithdrawCollateral(ctx sdk.Context, owner, depositor sdk.AccAddr
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.GetTotalPrincipal())
|
||||
k.RemoveCdpCollateralRatioIndex(ctx, cdp.Collateral.Denom, cdp.ID, oldCollateralToDebtRatio)
|
||||
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal())
|
||||
k.RemoveCdpCollateralRatioIndex(ctx, cdp.Type, cdp.ID, oldCollateralToDebtRatio)
|
||||
|
||||
cdp.Collateral = cdp.Collateral.Sub(collateral)
|
||||
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.GetTotalPrincipal())
|
||||
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal())
|
||||
err = k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -44,7 +44,7 @@ func (suite *DepositTestSuite) SetupTest() {
|
||||
suite.keeper = keeper
|
||||
suite.ctx = ctx
|
||||
suite.addrs = addrs
|
||||
err := suite.keeper.AddCdp(suite.ctx, addrs[0], c("xrp", 400000000), c("usdx", 10000000))
|
||||
err := suite.keeper.AddCdp(suite.ctx, addrs[0], c("xrp", 400000000), c("usdx", 10000000), "xrp-a")
|
||||
suite.NoError(err)
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ func (suite *DepositTestSuite) TestGetSetDeposit() {
|
||||
}
|
||||
|
||||
func (suite *DepositTestSuite) TestDepositCollateral() {
|
||||
err := suite.keeper.DepositCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], c("xrp", 10000000))
|
||||
err := suite.keeper.DepositCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], c("xrp", 10000000), "xrp-a")
|
||||
suite.NoError(err)
|
||||
d, found := suite.keeper.GetDeposit(suite.ctx, uint64(1), suite.addrs[0])
|
||||
suite.True(found)
|
||||
@ -73,19 +73,19 @@ func (suite *DepositTestSuite) TestDepositCollateral() {
|
||||
ds := suite.keeper.GetDeposits(suite.ctx, uint64(1))
|
||||
suite.Equal(1, len(ds))
|
||||
suite.True(ds[0].Equals(td))
|
||||
cd, _ := suite.keeper.GetCDP(suite.ctx, "xrp", uint64(1))
|
||||
cd, _ := suite.keeper.GetCDP(suite.ctx, "xrp-a", uint64(1))
|
||||
suite.Equal(c("xrp", 410000000), cd.Collateral)
|
||||
ak := suite.app.GetAccountKeeper()
|
||||
acc := ak.GetAccount(suite.ctx, suite.addrs[0])
|
||||
suite.Equal(i(90000000), acc.GetCoins().AmountOf("xrp"))
|
||||
|
||||
err = suite.keeper.DepositCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], c("btc", 1))
|
||||
err = suite.keeper.DepositCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], c("btc", 1), "btc-a")
|
||||
suite.Require().True(errors.Is(err, types.ErrCdpNotFound))
|
||||
|
||||
err = suite.keeper.DepositCollateral(suite.ctx, suite.addrs[1], suite.addrs[0], c("xrp", 1))
|
||||
err = suite.keeper.DepositCollateral(suite.ctx, suite.addrs[1], suite.addrs[0], c("xrp", 1), "xrp-a")
|
||||
suite.Require().True(errors.Is(err, types.ErrCdpNotFound))
|
||||
|
||||
err = suite.keeper.DepositCollateral(suite.ctx, suite.addrs[0], suite.addrs[1], c("xrp", 10000000))
|
||||
err = suite.keeper.DepositCollateral(suite.ctx, suite.addrs[0], suite.addrs[1], c("xrp", 10000000), "xrp-a")
|
||||
suite.NoError(err)
|
||||
d, found = suite.keeper.GetDeposit(suite.ctx, uint64(1), suite.addrs[1])
|
||||
suite.True(found)
|
||||
@ -97,21 +97,21 @@ func (suite *DepositTestSuite) TestDepositCollateral() {
|
||||
}
|
||||
|
||||
func (suite *DepositTestSuite) TestWithdrawCollateral() {
|
||||
err := suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], c("xrp", 400000000))
|
||||
err := suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], c("xrp", 400000000), "xrp-a")
|
||||
suite.Require().True(errors.Is(err, types.ErrInvalidCollateralRatio))
|
||||
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], c("xrp", 321000000))
|
||||
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], c("xrp", 321000000), "xrp-a")
|
||||
suite.Require().True(errors.Is(err, types.ErrInvalidCollateralRatio))
|
||||
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[1], suite.addrs[0], c("xrp", 10000000))
|
||||
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[1], suite.addrs[0], c("xrp", 10000000), "xrp-a")
|
||||
suite.Require().True(errors.Is(err, types.ErrCdpNotFound))
|
||||
|
||||
cd, _ := suite.keeper.GetCDP(suite.ctx, "xrp", uint64(1))
|
||||
cd, _ := suite.keeper.GetCDP(suite.ctx, "xrp-a", uint64(1))
|
||||
cd.AccumulatedFees = c("usdx", 1)
|
||||
err = suite.keeper.SetCDP(suite.ctx, cd)
|
||||
suite.NoError(err)
|
||||
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], c("xrp", 320000000))
|
||||
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], c("xrp", 320000000), "xrp-a")
|
||||
suite.Require().True(errors.Is(err, types.ErrInvalidCollateralRatio))
|
||||
|
||||
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], c("xrp", 10000000))
|
||||
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], c("xrp", 10000000), "xrp-a")
|
||||
suite.NoError(err)
|
||||
dep, _ := suite.keeper.GetDeposit(suite.ctx, uint64(1), suite.addrs[0])
|
||||
td := types.NewDeposit(uint64(1), suite.addrs[0], c("xrp", 390000000))
|
||||
@ -120,7 +120,7 @@ func (suite *DepositTestSuite) TestWithdrawCollateral() {
|
||||
acc := ak.GetAccount(suite.ctx, suite.addrs[0])
|
||||
suite.Equal(i(110000000), acc.GetCoins().AmountOf("xrp"))
|
||||
|
||||
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[0], suite.addrs[1], c("xrp", 10000000))
|
||||
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[0], suite.addrs[1], c("xrp", 10000000), "xrp-a")
|
||||
suite.Require().True(errors.Is(err, types.ErrDepositNotFound))
|
||||
}
|
||||
|
||||
|
@ -10,23 +10,23 @@ import (
|
||||
)
|
||||
|
||||
// AddPrincipal adds debt to a cdp if the additional debt does not put the cdp below the liquidation ratio
|
||||
func (k Keeper) AddPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom string, principal sdk.Coin) error {
|
||||
func (k Keeper) AddPrincipal(ctx sdk.Context, owner sdk.AccAddress, collateralType string, principal sdk.Coin) error {
|
||||
// validation
|
||||
cdp, found := k.GetCdpByOwnerAndDenom(ctx, owner, denom)
|
||||
cdp, found := k.GetCdpByOwnerAndCollateralType(ctx, owner, collateralType)
|
||||
if !found {
|
||||
return sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, denom %s", owner, denom)
|
||||
return sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, denom %s", owner, collateralType)
|
||||
}
|
||||
err := k.ValidatePrincipalDraw(ctx, principal, cdp.Principal.Denom)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = k.ValidateDebtLimit(ctx, cdp.Collateral.Denom, principal)
|
||||
err = k.ValidateDebtLimit(ctx, cdp.Type, principal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = k.ValidateCollateralizationRatio(ctx, cdp.Collateral, cdp.Principal.Add(principal), cdp.AccumulatedFees)
|
||||
err = k.ValidateCollateralizationRatio(ctx, cdp.Collateral, cdp.Type, cdp.Principal.Add(principal), cdp.AccumulatedFees)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -57,27 +57,27 @@ func (k Keeper) AddPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom string
|
||||
)
|
||||
|
||||
// remove old collateral:debt index
|
||||
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.GetTotalPrincipal())
|
||||
k.RemoveCdpCollateralRatioIndex(ctx, denom, cdp.ID, oldCollateralToDebtRatio)
|
||||
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal())
|
||||
k.RemoveCdpCollateralRatioIndex(ctx, cdp.Type, cdp.ID, oldCollateralToDebtRatio)
|
||||
|
||||
// update cdp state
|
||||
cdp.Principal = cdp.Principal.Add(principal)
|
||||
|
||||
// increment total principal for the input collateral type
|
||||
k.IncrementTotalPrincipal(ctx, cdp.Collateral.Denom, principal)
|
||||
k.IncrementTotalPrincipal(ctx, cdp.Type, principal)
|
||||
|
||||
// set cdp state and indexes in the store
|
||||
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.GetTotalPrincipal())
|
||||
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal())
|
||||
return k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio)
|
||||
}
|
||||
|
||||
// RepayPrincipal removes debt from the cdp
|
||||
// If all debt is repaid, the collateral is returned to depositors and the cdp is removed from the store
|
||||
func (k Keeper) RepayPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom string, payment sdk.Coin) error {
|
||||
func (k Keeper) RepayPrincipal(ctx sdk.Context, owner sdk.AccAddress, collateralType string, payment sdk.Coin) error {
|
||||
// validation
|
||||
cdp, found := k.GetCdpByOwnerAndDenom(ctx, owner, denom)
|
||||
cdp, found := k.GetCdpByOwnerAndCollateralType(ctx, owner, collateralType)
|
||||
if !found {
|
||||
return sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, denom %s", owner, denom)
|
||||
return sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, denom %s", owner, collateralType)
|
||||
}
|
||||
|
||||
err := k.ValidatePaymentCoins(ctx, cdp, payment)
|
||||
@ -134,8 +134,8 @@ func (k Keeper) RepayPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom stri
|
||||
)
|
||||
|
||||
// remove the old collateral:debt ratio index
|
||||
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, totalPrincipal)
|
||||
k.RemoveCdpCollateralRatioIndex(ctx, denom, cdp.ID, oldCollateralToDebtRatio)
|
||||
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, totalPrincipal)
|
||||
k.RemoveCdpCollateralRatioIndex(ctx, cdp.Type, cdp.ID, oldCollateralToDebtRatio)
|
||||
|
||||
// update cdp state
|
||||
if !principalPayment.IsZero() {
|
||||
@ -144,7 +144,7 @@ func (k Keeper) RepayPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom stri
|
||||
cdp.AccumulatedFees = cdp.AccumulatedFees.Sub(feePayment)
|
||||
|
||||
// decrement the total principal for the input collateral type
|
||||
k.DecrementTotalPrincipal(ctx, denom, feePayment.Add(principalPayment))
|
||||
k.DecrementTotalPrincipal(ctx, cdp.Type, feePayment.Add(principalPayment))
|
||||
|
||||
// if the debt is fully paid, return collateral to depositors,
|
||||
// and remove the cdp and indexes from the store
|
||||
@ -167,7 +167,7 @@ func (k Keeper) RepayPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom stri
|
||||
}
|
||||
|
||||
// set cdp state and update indexes
|
||||
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.GetTotalPrincipal())
|
||||
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal())
|
||||
return k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio)
|
||||
}
|
||||
|
||||
|
@ -46,72 +46,72 @@ func (suite *DrawTestSuite) SetupTest() {
|
||||
suite.keeper = keeper
|
||||
suite.ctx = ctx
|
||||
suite.addrs = addrs
|
||||
err := suite.keeper.AddCdp(suite.ctx, addrs[0], c("xrp", 400000000), c("usdx", 10000000))
|
||||
err := suite.keeper.AddCdp(suite.ctx, addrs[0], c("xrp", 400000000), c("usdx", 10000000), "xrp-a")
|
||||
suite.NoError(err)
|
||||
}
|
||||
|
||||
func (suite *DrawTestSuite) TestAddRepayPrincipal() {
|
||||
|
||||
err := suite.keeper.AddPrincipal(suite.ctx, suite.addrs[0], "xrp", c("usdx", 10000000))
|
||||
err := suite.keeper.AddPrincipal(suite.ctx, suite.addrs[0], "xrp-a", c("usdx", 10000000))
|
||||
suite.NoError(err)
|
||||
|
||||
t, found := suite.keeper.GetCDP(suite.ctx, "xrp", uint64(1))
|
||||
t, found := suite.keeper.GetCDP(suite.ctx, "xrp-a", uint64(1))
|
||||
suite.True(found)
|
||||
suite.Equal(c("usdx", 20000000), t.Principal)
|
||||
ctd := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, t.Collateral, t.Principal.Add(t.AccumulatedFees))
|
||||
ctd := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, t.Collateral, "xrp-a", t.Principal.Add(t.AccumulatedFees))
|
||||
suite.Equal(d("20.0"), ctd)
|
||||
ts := suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("20.0"))
|
||||
ts := suite.keeper.GetAllCdpsByCollateralTypeAndRatio(suite.ctx, "xrp-a", d("20.0"))
|
||||
suite.Equal(0, len(ts))
|
||||
ts = suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("20.0").Add(sdk.SmallestDec()))
|
||||
ts = suite.keeper.GetAllCdpsByCollateralTypeAndRatio(suite.ctx, "xrp-a", d("20.0").Add(sdk.SmallestDec()))
|
||||
suite.Equal(ts[0], t)
|
||||
tp := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx")
|
||||
tp := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp-a", "usdx")
|
||||
suite.Equal(i(20000000), tp)
|
||||
sk := suite.app.GetSupplyKeeper()
|
||||
acc := sk.GetModuleAccount(suite.ctx, types.ModuleName)
|
||||
suite.Equal(cs(c("xrp", 400000000), c("debt", 20000000)), acc.GetCoins())
|
||||
|
||||
err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[0], "xrp", c("susd", 10000000))
|
||||
err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[0], "xrp-a", c("susd", 10000000))
|
||||
suite.Require().True(errors.Is(err, types.ErrInvalidDebtRequest))
|
||||
|
||||
err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[1], "xrp", c("usdx", 10000000))
|
||||
err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[1], "xrp-a", c("usdx", 10000000))
|
||||
suite.Require().True(errors.Is(err, types.ErrCdpNotFound))
|
||||
err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[0], "xrp", c("xusd", 10000000))
|
||||
err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[0], "xrp-a", c("xusd", 10000000))
|
||||
suite.Require().True(errors.Is(err, types.ErrInvalidDebtRequest))
|
||||
err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[0], "xrp", c("usdx", 311000000))
|
||||
err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[0], "xrp-a", c("usdx", 311000000))
|
||||
suite.Require().True(errors.Is(err, types.ErrInvalidCollateralRatio))
|
||||
|
||||
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[0], "xrp", c("usdx", 10000000))
|
||||
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[0], "xrp-a", c("usdx", 10000000))
|
||||
suite.NoError(err)
|
||||
|
||||
t, found = suite.keeper.GetCDP(suite.ctx, "xrp", uint64(1))
|
||||
t, found = suite.keeper.GetCDP(suite.ctx, "xrp-a", uint64(1))
|
||||
suite.True(found)
|
||||
suite.Equal(c("usdx", 10000000), t.Principal)
|
||||
|
||||
ctd = suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, t.Collateral, t.Principal.Add(t.AccumulatedFees))
|
||||
ctd = suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, t.Collateral, "xrp-a", t.Principal.Add(t.AccumulatedFees))
|
||||
suite.Equal(d("40.0"), ctd)
|
||||
ts = suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("40.0"))
|
||||
ts = suite.keeper.GetAllCdpsByCollateralTypeAndRatio(suite.ctx, "xrp-a", d("40.0"))
|
||||
suite.Equal(0, len(ts))
|
||||
ts = suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("40.0").Add(sdk.SmallestDec()))
|
||||
ts = suite.keeper.GetAllCdpsByCollateralTypeAndRatio(suite.ctx, "xrp-a", d("40.0").Add(sdk.SmallestDec()))
|
||||
suite.Equal(ts[0], t)
|
||||
sk = suite.app.GetSupplyKeeper()
|
||||
acc = sk.GetModuleAccount(suite.ctx, types.ModuleName)
|
||||
suite.Equal(cs(c("xrp", 400000000), c("debt", 10000000)), acc.GetCoins())
|
||||
|
||||
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[0], "xrp", c("xusd", 10000000))
|
||||
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[0], "xrp-a", c("xusd", 10000000))
|
||||
suite.Require().True(errors.Is(err, types.ErrInvalidPayment))
|
||||
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[1], "xrp", c("xusd", 10000000))
|
||||
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[1], "xrp-a", c("xusd", 10000000))
|
||||
suite.Require().True(errors.Is(err, types.ErrCdpNotFound))
|
||||
|
||||
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[0], "xrp", c("usdx", 9000000))
|
||||
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[0], "xrp-a", c("usdx", 9000000))
|
||||
suite.Require().True(errors.Is(err, types.ErrBelowDebtFloor))
|
||||
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[0], "xrp", c("usdx", 10000000))
|
||||
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[0], "xrp-a", c("usdx", 10000000))
|
||||
suite.NoError(err)
|
||||
|
||||
_, found = suite.keeper.GetCDP(suite.ctx, "xrp", uint64(1))
|
||||
_, found = suite.keeper.GetCDP(suite.ctx, "xrp-a", uint64(1))
|
||||
suite.False(found)
|
||||
ts = suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", types.MaxSortableDec)
|
||||
ts = suite.keeper.GetAllCdpsByCollateralTypeAndRatio(suite.ctx, "xrp-a", types.MaxSortableDec)
|
||||
suite.Equal(0, len(ts))
|
||||
ts = suite.keeper.GetAllCdpsByDenom(suite.ctx, "xrp")
|
||||
ts = suite.keeper.GetAllCdpsByCollateralType(suite.ctx, "xrp-a")
|
||||
suite.Equal(0, len(ts))
|
||||
sk = suite.app.GetSupplyKeeper()
|
||||
acc = sk.GetModuleAccount(suite.ctx, types.ModuleName)
|
||||
@ -120,43 +120,43 @@ func (suite *DrawTestSuite) TestAddRepayPrincipal() {
|
||||
}
|
||||
|
||||
func (suite *DrawTestSuite) TestRepayPrincipalOverpay() {
|
||||
err := suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[0], "xrp", c("usdx", 20000000))
|
||||
err := suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[0], "xrp-a", c("usdx", 20000000))
|
||||
suite.NoError(err)
|
||||
ak := suite.app.GetAccountKeeper()
|
||||
acc := ak.GetAccount(suite.ctx, suite.addrs[0])
|
||||
suite.Equal(i(10000000000), (acc.GetCoins().AmountOf("usdx")))
|
||||
_, found := suite.keeper.GetCDP(suite.ctx, "xrp", 1)
|
||||
_, found := suite.keeper.GetCDP(suite.ctx, "xrp-a", 1)
|
||||
suite.False(found)
|
||||
}
|
||||
|
||||
func (suite *DrawTestSuite) TestAddRepayPrincipalFees() {
|
||||
err := suite.keeper.AddCdp(suite.ctx, suite.addrs[2], c("xrp", 1000000000000), c("usdx", 100000000000))
|
||||
err := suite.keeper.AddCdp(suite.ctx, suite.addrs[2], c("xrp", 1000000000000), c("usdx", 100000000000), "xrp-a")
|
||||
suite.NoError(err)
|
||||
suite.ctx = suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(time.Minute * 10))
|
||||
err = suite.keeper.UpdateFeesForAllCdps(suite.ctx, "xrp")
|
||||
err = suite.keeper.UpdateFeesForAllCdps(suite.ctx, "xrp-a")
|
||||
suite.NoError(err)
|
||||
err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[2], "xrp", c("usdx", 10000000))
|
||||
err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[2], "xrp-a", c("usdx", 10000000))
|
||||
suite.NoError(err)
|
||||
t, _ := suite.keeper.GetCDP(suite.ctx, "xrp", uint64(2))
|
||||
t, _ := suite.keeper.GetCDP(suite.ctx, "xrp-a", uint64(2))
|
||||
suite.Equal(c("usdx", 92827), t.AccumulatedFees)
|
||||
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[2], "xrp", c("usdx", 100))
|
||||
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[2], "xrp-a", c("usdx", 100))
|
||||
suite.NoError(err)
|
||||
t, _ = suite.keeper.GetCDP(suite.ctx, "xrp", uint64(2))
|
||||
t, _ = suite.keeper.GetCDP(suite.ctx, "xrp-a", uint64(2))
|
||||
suite.Equal(c("usdx", 92727), t.AccumulatedFees)
|
||||
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[2], "xrp", c("usdx", 100010092727))
|
||||
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[2], "xrp-a", c("usdx", 100010092727))
|
||||
suite.NoError(err)
|
||||
_, f := suite.keeper.GetCDP(suite.ctx, "xrp", uint64(2))
|
||||
_, f := suite.keeper.GetCDP(suite.ctx, "xrp-a", uint64(2))
|
||||
suite.False(f)
|
||||
|
||||
err = suite.keeper.AddCdp(suite.ctx, suite.addrs[2], c("xrp", 1000000000000), c("usdx", 100000000))
|
||||
err = suite.keeper.AddCdp(suite.ctx, suite.addrs[2], c("xrp", 1000000000000), c("usdx", 100000000), "xrp-a")
|
||||
suite.NoError(err)
|
||||
|
||||
suite.ctx = suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(time.Second * 31536000)) // move forward one year in time
|
||||
err = suite.keeper.UpdateFeesForAllCdps(suite.ctx, "xrp")
|
||||
err = suite.keeper.UpdateFeesForAllCdps(suite.ctx, "xrp-a")
|
||||
suite.NoError(err)
|
||||
err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[2], "xrp", c("usdx", 100000000))
|
||||
err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[2], "xrp-a", c("usdx", 100000000))
|
||||
suite.NoError(err)
|
||||
t, _ = suite.keeper.GetCDP(suite.ctx, "xrp", uint64(3))
|
||||
t, _ = suite.keeper.GetCDP(suite.ctx, "xrp-a", uint64(3))
|
||||
suite.Equal(c("usdx", 5000000), t.AccumulatedFees)
|
||||
}
|
||||
|
||||
@ -164,9 +164,9 @@ func (suite *DrawTestSuite) TestPricefeedFailure() {
|
||||
ctx := suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(time.Hour * 2))
|
||||
pfk := suite.app.GetPriceFeedKeeper()
|
||||
pfk.SetCurrentPrices(ctx, "xrp:usd")
|
||||
err := suite.keeper.AddPrincipal(ctx, suite.addrs[0], "xrp", c("usdx", 10000000))
|
||||
err := suite.keeper.AddPrincipal(ctx, suite.addrs[0], "xrp-a", c("usdx", 10000000))
|
||||
suite.Error(err)
|
||||
err = suite.keeper.RepayPrincipal(ctx, suite.addrs[0], "xrp", c("usdx", 10000000))
|
||||
err = suite.keeper.RepayPrincipal(ctx, suite.addrs[0], "xrp-a", c("usdx", 10000000))
|
||||
suite.NoError(err)
|
||||
}
|
||||
|
||||
@ -177,7 +177,7 @@ func (suite *DrawTestSuite) TestModuleAccountFailure() {
|
||||
acc := sk.GetModuleAccount(ctx, types.ModuleName)
|
||||
ak := suite.app.GetAccountKeeper()
|
||||
ak.RemoveAccount(ctx, acc)
|
||||
suite.keeper.RepayPrincipal(ctx, suite.addrs[0], "xrp", c("usdx", 10000000))
|
||||
suite.keeper.RepayPrincipal(ctx, suite.addrs[0], "xrp-a", c("usdx", 10000000))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/store/prefix"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
@ -9,11 +11,11 @@ import (
|
||||
|
||||
// CalculateFees returns the fees accumulated since fees were last calculated based on
|
||||
// the input amount of outstanding debt (principal) and the number of periods (seconds) that have passed
|
||||
func (k Keeper) CalculateFees(ctx sdk.Context, principal sdk.Coin, periods sdk.Int, denom string) sdk.Coin {
|
||||
func (k Keeper) CalculateFees(ctx sdk.Context, principal sdk.Coin, periods sdk.Int, collateralType string) sdk.Coin {
|
||||
// how fees are calculated:
|
||||
// feesAccumulated = (outstandingDebt * (feeRate^periods)) - outstandingDebt
|
||||
// Note that since we can't do x^y using sdk.Decimal, we are converting to int and using RelativePow
|
||||
feePerSecond := k.getFeeRate(ctx, denom)
|
||||
feePerSecond := k.getFeeRate(ctx, collateralType)
|
||||
scalar := sdk.NewInt(1000000000000000000)
|
||||
feeRateInt := feePerSecond.Mul(sdk.NewDecFromInt(scalar)).TruncateInt()
|
||||
accumulator := sdk.NewDecFromInt(types.RelativePow(feeRateInt, periods, scalar)).Mul(sdk.SmallestDec())
|
||||
@ -23,14 +25,14 @@ func (k Keeper) CalculateFees(ctx sdk.Context, principal sdk.Coin, periods sdk.I
|
||||
}
|
||||
|
||||
// UpdateFeesForAllCdps updates the fees for each of the CDPs
|
||||
func (k Keeper) UpdateFeesForAllCdps(ctx sdk.Context, collateralDenom string) error {
|
||||
func (k Keeper) UpdateFeesForAllCdps(ctx sdk.Context, collateralType string) error {
|
||||
var iterationErr error
|
||||
k.IterateCdpsByDenom(ctx, collateralDenom, func(cdp types.CDP) bool {
|
||||
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.GetTotalPrincipal())
|
||||
k.IterateCdpsByCollateralType(ctx, collateralType, func(cdp types.CDP) bool {
|
||||
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal())
|
||||
// periods = bblock timestamp - fees updated
|
||||
periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix()))
|
||||
|
||||
newFees := k.CalculateFees(ctx, cdp.Principal, periods, collateralDenom)
|
||||
newFees := k.CalculateFees(ctx, cdp.Principal, periods, collateralType)
|
||||
|
||||
// exit without updating fees if amount has rounded down to zero
|
||||
// cdp will get updated next block when newFees, newFeesSavings, newFeesSurplus >0
|
||||
@ -62,9 +64,9 @@ func (k Keeper) UpdateFeesForAllCdps(ctx sdk.Context, collateralDenom string) er
|
||||
return true
|
||||
}
|
||||
|
||||
previousDebt := k.GetTotalPrincipal(ctx, collateralDenom, dp.Denom)
|
||||
previousDebt := k.GetTotalPrincipal(ctx, cdp.Type, dp.Denom)
|
||||
newDebt := previousDebt.Add(newFees.Amount)
|
||||
k.SetTotalPrincipal(ctx, collateralDenom, dp.Denom, newDebt)
|
||||
k.SetTotalPrincipal(ctx, cdp.Type, dp.Denom, newDebt)
|
||||
|
||||
// mint surplus coins divided between the liquidator and savings module accounts.
|
||||
err = k.supplyKeeper.MintCoins(ctx, types.LiquidatorMacc, sdk.NewCoins(sdk.NewCoin(dp.Denom, newFeesSurplus)))
|
||||
@ -84,8 +86,8 @@ func (k Keeper) UpdateFeesForAllCdps(ctx sdk.Context, collateralDenom string) er
|
||||
|
||||
// and set the fees updated time to the current block time since we just updated it
|
||||
cdp.FeesUpdated = ctx.BlockTime()
|
||||
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.GetTotalPrincipal())
|
||||
k.RemoveCdpCollateralRatioIndex(ctx, cdp.Collateral.Denom, cdp.ID, oldCollateralToDebtRatio)
|
||||
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal())
|
||||
k.RemoveCdpCollateralRatioIndex(ctx, cdp.Type, cdp.ID, oldCollateralToDebtRatio)
|
||||
err = k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio)
|
||||
if err != nil {
|
||||
iterationErr = err
|
||||
@ -97,27 +99,27 @@ func (k Keeper) UpdateFeesForAllCdps(ctx sdk.Context, collateralDenom string) er
|
||||
}
|
||||
|
||||
// IncrementTotalPrincipal increments the total amount of debt that has been drawn with that collateral type
|
||||
func (k Keeper) IncrementTotalPrincipal(ctx sdk.Context, collateralDenom string, principal sdk.Coin) {
|
||||
total := k.GetTotalPrincipal(ctx, collateralDenom, principal.Denom)
|
||||
func (k Keeper) IncrementTotalPrincipal(ctx sdk.Context, collateralType string, principal sdk.Coin) {
|
||||
total := k.GetTotalPrincipal(ctx, collateralType, principal.Denom)
|
||||
total = total.Add(principal.Amount)
|
||||
k.SetTotalPrincipal(ctx, collateralDenom, principal.Denom, total)
|
||||
k.SetTotalPrincipal(ctx, collateralType, principal.Denom, total)
|
||||
}
|
||||
|
||||
// DecrementTotalPrincipal decrements the total amount of debt that has been drawn for a particular collateral type
|
||||
func (k Keeper) DecrementTotalPrincipal(ctx sdk.Context, collateralDenom string, principal sdk.Coin) {
|
||||
total := k.GetTotalPrincipal(ctx, collateralDenom, principal.Denom)
|
||||
func (k Keeper) DecrementTotalPrincipal(ctx sdk.Context, collateralType string, principal sdk.Coin) {
|
||||
total := k.GetTotalPrincipal(ctx, collateralType, principal.Denom)
|
||||
// NOTE: negative total principal can happen in tests due to rounding errors
|
||||
// in fee calculation
|
||||
total = sdk.MaxInt(total.Sub(principal.Amount), sdk.ZeroInt())
|
||||
k.SetTotalPrincipal(ctx, collateralDenom, principal.Denom, total)
|
||||
k.SetTotalPrincipal(ctx, collateralType, principal.Denom, total)
|
||||
}
|
||||
|
||||
// GetTotalPrincipal returns the total amount of principal that has been drawn for a particular collateral
|
||||
func (k Keeper) GetTotalPrincipal(ctx sdk.Context, collateralDenom string, principalDenom string) (total sdk.Int) {
|
||||
func (k Keeper) GetTotalPrincipal(ctx sdk.Context, collateralType, principalDenom string) (total sdk.Int) {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.PrincipalKeyPrefix)
|
||||
bz := store.Get([]byte(collateralDenom + principalDenom))
|
||||
bz := store.Get([]byte(collateralType + principalDenom))
|
||||
if bz == nil {
|
||||
k.SetTotalPrincipal(ctx, collateralDenom, principalDenom, sdk.ZeroInt())
|
||||
k.SetTotalPrincipal(ctx, collateralType, principalDenom, sdk.ZeroInt())
|
||||
return sdk.ZeroInt()
|
||||
}
|
||||
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &total)
|
||||
@ -125,7 +127,11 @@ func (k Keeper) GetTotalPrincipal(ctx sdk.Context, collateralDenom string, princ
|
||||
}
|
||||
|
||||
// SetTotalPrincipal sets the total amount of principal that has been drawn for the input collateral
|
||||
func (k Keeper) SetTotalPrincipal(ctx sdk.Context, collateralDenom string, principalDenom string, total sdk.Int) {
|
||||
func (k Keeper) SetTotalPrincipal(ctx sdk.Context, collateralType, principalDenom string, total sdk.Int) {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.PrincipalKeyPrefix)
|
||||
store.Set([]byte(collateralDenom+principalDenom), k.cdc.MustMarshalBinaryLengthPrefixed(total))
|
||||
_, found := k.GetCollateralTypePrefix(ctx, collateralType)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("collateral not found: %s", collateralType))
|
||||
}
|
||||
store.Set([]byte(collateralType+principalDenom), k.cdc.MustMarshalBinaryLengthPrefixed(total))
|
||||
}
|
||||
|
@ -56,12 +56,12 @@ func (suite *FeeTestSuite) createCdps() {
|
||||
// use the created account to create a cdp that SHOULD have fees updated
|
||||
// to get a ratio between 100 - 110% of liquidation ratio we can use 200xrp ($50) and 24 usdx (208% collateralization with liquidation ratio of 200%)
|
||||
// create CDP for the first address
|
||||
err := suite.keeper.AddCdp(suite.ctx, addrs[0], c("xrp", 200000000), c("usdx", 24000000))
|
||||
err := suite.keeper.AddCdp(suite.ctx, addrs[0], c("xrp", 200000000), c("usdx", 24000000), "xrp-a")
|
||||
suite.NoError(err) // check that no error was thrown
|
||||
|
||||
// use the other account to create a cdp that SHOULD NOT have fees updated - 500% collateralization
|
||||
// create CDP for the second address
|
||||
err = suite.keeper.AddCdp(suite.ctx, addrs[1], c("xrp", 200000000), c("usdx", 10000000))
|
||||
err = suite.keeper.AddCdp(suite.ctx, addrs[1], c("xrp", 200000000), c("usdx", 10000000), "xrp-a")
|
||||
suite.NoError(err) // check that no error was thrown
|
||||
|
||||
}
|
||||
@ -76,11 +76,11 @@ func (suite *FeeTestSuite) TestUpdateFees() {
|
||||
// fees to accumulate, in this example 600 seconds
|
||||
oldtime := suite.ctx.BlockTime()
|
||||
suite.ctx = suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(time.Second * 600))
|
||||
err := suite.keeper.UpdateFeesForAllCdps(suite.ctx, "xrp")
|
||||
err := suite.keeper.UpdateFeesForAllCdps(suite.ctx, "xrp-a")
|
||||
suite.NoError(err) // check that we don't have any error
|
||||
|
||||
// cdp we expect fees to accumulate for
|
||||
cdp1, found := suite.keeper.GetCDP(suite.ctx, "xrp", 1)
|
||||
cdp1, found := suite.keeper.GetCDP(suite.ctx, "xrp-a", 1)
|
||||
suite.True(found)
|
||||
// check fees are not zero
|
||||
// check that the fees have been updated
|
||||
@ -89,7 +89,7 @@ func (suite *FeeTestSuite) TestUpdateFees() {
|
||||
suite.Equal(sdk.NewInt(22), cdp1.AccumulatedFees.Amount)
|
||||
suite.Equal(suite.ctx.BlockTime(), cdp1.FeesUpdated)
|
||||
// cdp we expect fees to not accumulate for because of rounding to zero
|
||||
cdp2, found := suite.keeper.GetCDP(suite.ctx, "xrp", 2)
|
||||
cdp2, found := suite.keeper.GetCDP(suite.ctx, "xrp-a", 2)
|
||||
suite.True(found)
|
||||
// check fees are zero
|
||||
suite.True(cdp2.AccumulatedFees.IsZero())
|
||||
|
@ -49,6 +49,7 @@ func NewCDPGenState(asset string, liquidationRatio sdk.Dec) app.GenesisState {
|
||||
CollateralParams: cdp.CollateralParams{
|
||||
{
|
||||
Denom: asset,
|
||||
Type: asset + "-a",
|
||||
LiquidationRatio: liquidationRatio,
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr
|
||||
@ -121,6 +122,7 @@ func NewCDPGenStateMulti() app.GenesisState {
|
||||
CollateralParams: cdp.CollateralParams{
|
||||
{
|
||||
Denom: "xrp",
|
||||
Type: "xrp-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("2.0"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 500000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr
|
||||
@ -133,6 +135,7 @@ func NewCDPGenStateMulti() app.GenesisState {
|
||||
},
|
||||
{
|
||||
Denom: "btc",
|
||||
Type: "btc-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 500000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000000782997609"), // %2.5 apr
|
||||
@ -145,6 +148,7 @@ func NewCDPGenStateMulti() app.GenesisState {
|
||||
},
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 500000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr
|
||||
@ -185,6 +189,7 @@ func NewCDPGenStateHighDebtLimit() app.GenesisState {
|
||||
CollateralParams: cdp.CollateralParams{
|
||||
{
|
||||
Denom: "xrp",
|
||||
Type: "xrp-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("2.0"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 50000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr
|
||||
@ -197,6 +202,7 @@ func NewCDPGenStateHighDebtLimit() app.GenesisState {
|
||||
},
|
||||
{
|
||||
Denom: "btc",
|
||||
Type: "btc-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 50000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000000782997609"), // %2.5 apr
|
||||
@ -227,10 +233,10 @@ func NewCDPGenStateHighDebtLimit() app.GenesisState {
|
||||
|
||||
func cdps() (cdps cdp.CDPs) {
|
||||
_, addrs := app.GeneratePrivKeyAddressPairs(3)
|
||||
c1 := cdp.NewCDP(uint64(1), addrs[0], sdk.NewCoin("xrp", sdk.NewInt(10000000)), sdk.NewCoin("usdx", sdk.NewInt(8000000)), tmtime.Canonical(time.Now()))
|
||||
c2 := cdp.NewCDP(uint64(2), addrs[1], sdk.NewCoin("xrp", sdk.NewInt(100000000)), sdk.NewCoin("usdx", sdk.NewInt(10000000)), tmtime.Canonical(time.Now()))
|
||||
c3 := cdp.NewCDP(uint64(3), addrs[1], sdk.NewCoin("btc", sdk.NewInt(1000000000)), sdk.NewCoin("usdx", sdk.NewInt(10000000)), tmtime.Canonical(time.Now()))
|
||||
c4 := cdp.NewCDP(uint64(4), addrs[2], sdk.NewCoin("xrp", sdk.NewInt(1000000000)), sdk.NewCoin("usdx", sdk.NewInt(500000000)), tmtime.Canonical(time.Now()))
|
||||
c1 := cdp.NewCDP(uint64(1), addrs[0], sdk.NewCoin("xrp", sdk.NewInt(10000000)), "xrp-a", sdk.NewCoin("usdx", sdk.NewInt(8000000)), tmtime.Canonical(time.Now()))
|
||||
c2 := cdp.NewCDP(uint64(2), addrs[1], sdk.NewCoin("xrp", sdk.NewInt(100000000)), "xrp-a", sdk.NewCoin("usdx", sdk.NewInt(10000000)), tmtime.Canonical(time.Now()))
|
||||
c3 := cdp.NewCDP(uint64(3), addrs[1], sdk.NewCoin("btc", sdk.NewInt(1000000000)), "btc-a", sdk.NewCoin("usdx", sdk.NewInt(10000000)), tmtime.Canonical(time.Now()))
|
||||
c4 := cdp.NewCDP(uint64(4), addrs[2], sdk.NewCoin("xrp", sdk.NewInt(1000000000)), "xrp-a", sdk.NewCoin("usdx", sdk.NewInt(500000000)), tmtime.Canonical(time.Now()))
|
||||
cdps = append(cdps, c1, c2, c3, c4)
|
||||
return
|
||||
}
|
||||
|
@ -43,22 +43,22 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramstore subspace.Subspace,
|
||||
}
|
||||
|
||||
// CdpDenomIndexIterator returns an sdk.Iterator for all cdps with matching collateral denom
|
||||
func (k Keeper) CdpDenomIndexIterator(ctx sdk.Context, denom string) sdk.Iterator {
|
||||
func (k Keeper) CdpDenomIndexIterator(ctx sdk.Context, collateralType string) sdk.Iterator {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.CdpKeyPrefix)
|
||||
db, found := k.GetDenomPrefix(ctx, denom)
|
||||
db, found := k.GetCollateralTypePrefix(ctx, collateralType)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("denom %s prefix not found", denom))
|
||||
panic(fmt.Sprintf("denom %s prefix not found", collateralType))
|
||||
}
|
||||
return sdk.KVStorePrefixIterator(store, types.DenomIterKey(db))
|
||||
}
|
||||
|
||||
// CdpCollateralRatioIndexIterator returns an sdk.Iterator for all cdps that have collateral denom
|
||||
// matching denom and collateral:debt ratio LESS THAN targetRatio
|
||||
func (k Keeper) CdpCollateralRatioIndexIterator(ctx sdk.Context, denom string, targetRatio sdk.Dec) sdk.Iterator {
|
||||
func (k Keeper) CdpCollateralRatioIndexIterator(ctx sdk.Context, collateralType string, targetRatio sdk.Dec) sdk.Iterator {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.CollateralRatioIndexPrefix)
|
||||
db, found := k.GetDenomPrefix(ctx, denom)
|
||||
db, found := k.GetCollateralTypePrefix(ctx, collateralType)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("denom %s prefix not found", denom))
|
||||
panic(fmt.Sprintf("denom %s prefix not found", collateralType))
|
||||
}
|
||||
return store.Iterator(types.CollateralRatioIterKey(db, sdk.ZeroDec()), types.CollateralRatioIterKey(db, targetRatio))
|
||||
}
|
||||
@ -78,9 +78,9 @@ func (k Keeper) IterateAllCdps(ctx sdk.Context, cb func(cdp types.CDP) (stop boo
|
||||
}
|
||||
}
|
||||
|
||||
// IterateCdpsByDenom iterates over cdps with matching denom and performs a callback function
|
||||
func (k Keeper) IterateCdpsByDenom(ctx sdk.Context, denom string, cb func(cdp types.CDP) (stop bool)) {
|
||||
iterator := k.CdpDenomIndexIterator(ctx, denom)
|
||||
// IterateCdpsByCollateralType iterates over cdps with matching denom and performs a callback function
|
||||
func (k Keeper) IterateCdpsByCollateralType(ctx sdk.Context, collateralType string, cb func(cdp types.CDP) (stop bool)) {
|
||||
iterator := k.CdpDenomIndexIterator(ctx, collateralType)
|
||||
|
||||
defer iterator.Close()
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
@ -94,14 +94,13 @@ func (k Keeper) IterateCdpsByDenom(ctx sdk.Context, denom string, cb func(cdp ty
|
||||
|
||||
// IterateCdpsByCollateralRatio iterate over cdps with collateral denom equal to denom and
|
||||
// collateral:debt ratio LESS THAN targetRatio and performs a callback function.
|
||||
func (k Keeper) IterateCdpsByCollateralRatio(ctx sdk.Context, denom string, targetRatio sdk.Dec, cb func(cdp types.CDP) (stop bool)) {
|
||||
iterator := k.CdpCollateralRatioIndexIterator(ctx, denom, targetRatio)
|
||||
func (k Keeper) IterateCdpsByCollateralRatio(ctx sdk.Context, collateralType string, targetRatio sdk.Dec, cb func(cdp types.CDP) (stop bool)) {
|
||||
iterator := k.CdpCollateralRatioIndexIterator(ctx, collateralType, targetRatio)
|
||||
|
||||
defer iterator.Close()
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
db, id, _ := types.SplitCollateralRatioKey(iterator.Key())
|
||||
d := k.getDenomFromByte(ctx, db)
|
||||
cdp, found := k.GetCDP(ctx, d, id)
|
||||
_, id, _ := types.SplitCollateralRatioKey(iterator.Key())
|
||||
cdp, found := k.GetCDP(ctx, collateralType, id)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("cdp %d does not exist", id))
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ func createCdps(n int) (app.TestApp, sdk.Context, keeper.Keeper) {
|
||||
)
|
||||
cdpKeeper := tApp.GetCDPKeeper()
|
||||
for i := 0; i < n; i++ {
|
||||
err := cdpKeeper.AddCdp(ctx, addrs[i], coins[i][0], c("usdx", 100000000))
|
||||
err := cdpKeeper.AddCdp(ctx, addrs[i], coins[i][0], c("usdx", 100000000), "btc-a")
|
||||
if err != nil {
|
||||
panic("failed to create cdp")
|
||||
}
|
||||
@ -138,7 +138,7 @@ func BenchmarkCdpCreation(b *testing.B) {
|
||||
cdpKeeper := tApp.GetCDPKeeper()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
err := cdpKeeper.AddCdp(ctx, addrs[i], coins[i][0], c("usdx", 100000000))
|
||||
err := cdpKeeper.AddCdp(ctx, addrs[i], coins[i][0], c("usdx", 100000000), "btc-a")
|
||||
if err != nil {
|
||||
b.Error("unexpected error")
|
||||
}
|
||||
|
@ -21,10 +21,10 @@ func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
|
||||
}
|
||||
|
||||
// GetCollateral returns the collateral param with corresponding denom
|
||||
func (k Keeper) GetCollateral(ctx sdk.Context, denom string) (types.CollateralParam, bool) {
|
||||
func (k Keeper) GetCollateral(ctx sdk.Context, collateralType string) (types.CollateralParam, bool) {
|
||||
params := k.GetParams(ctx)
|
||||
for _, cp := range params.CollateralParams {
|
||||
if cp.Denom == denom {
|
||||
if cp.Type == collateralType {
|
||||
return cp, true
|
||||
}
|
||||
}
|
||||
@ -40,11 +40,11 @@ func (k Keeper) GetDebtParam(ctx sdk.Context, denom string) (types.DebtParam, bo
|
||||
return types.DebtParam{}, false
|
||||
}
|
||||
|
||||
// GetDenomPrefix returns the prefix of the matching denom
|
||||
func (k Keeper) GetDenomPrefix(ctx sdk.Context, denom string) (byte, bool) {
|
||||
// GetCollateralTypePrefix returns the prefix of the matching denom
|
||||
func (k Keeper) GetCollateralTypePrefix(ctx sdk.Context, collateralType string) (byte, bool) {
|
||||
params := k.GetParams(ctx)
|
||||
for _, cp := range params.CollateralParams {
|
||||
if cp.Denom == denom {
|
||||
if cp.Type == collateralType {
|
||||
return cp.Prefix, true
|
||||
}
|
||||
}
|
||||
@ -62,51 +62,51 @@ func (k Keeper) getDenomFromByte(ctx sdk.Context, db byte) string {
|
||||
panic(fmt.Sprintf("no collateral denom with prefix %b", db))
|
||||
}
|
||||
|
||||
func (k Keeper) getSpotMarketID(ctx sdk.Context, denom string) string {
|
||||
cp, found := k.GetCollateral(ctx, denom)
|
||||
func (k Keeper) getSpotMarketID(ctx sdk.Context, collateralType string) string {
|
||||
cp, found := k.GetCollateral(ctx, collateralType)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("collateral not found: %s", denom))
|
||||
panic(fmt.Sprintf("collateral not found: %s", collateralType))
|
||||
}
|
||||
return cp.SpotMarketID
|
||||
}
|
||||
|
||||
func (k Keeper) getliquidationMarketID(ctx sdk.Context, denom string) string {
|
||||
cp, found := k.GetCollateral(ctx, denom)
|
||||
func (k Keeper) getliquidationMarketID(ctx sdk.Context, collateralType string) string {
|
||||
cp, found := k.GetCollateral(ctx, collateralType)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("collateral not found: %s", denom))
|
||||
panic(fmt.Sprintf("collateral not found: %s", collateralType))
|
||||
}
|
||||
return cp.LiquidationMarketID
|
||||
}
|
||||
|
||||
func (k Keeper) getLiquidationRatio(ctx sdk.Context, denom string) sdk.Dec {
|
||||
cp, found := k.GetCollateral(ctx, denom)
|
||||
func (k Keeper) getLiquidationRatio(ctx sdk.Context, collateralType string) sdk.Dec {
|
||||
cp, found := k.GetCollateral(ctx, collateralType)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("collateral not found: %s", denom))
|
||||
panic(fmt.Sprintf("collateral not found: %s", collateralType))
|
||||
}
|
||||
return cp.LiquidationRatio
|
||||
}
|
||||
|
||||
func (k Keeper) getLiquidationPenalty(ctx sdk.Context, denom string) sdk.Dec {
|
||||
cp, found := k.GetCollateral(ctx, denom)
|
||||
func (k Keeper) getLiquidationPenalty(ctx sdk.Context, collateralType string) sdk.Dec {
|
||||
cp, found := k.GetCollateral(ctx, collateralType)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("collateral not found: %s", denom))
|
||||
panic(fmt.Sprintf("collateral not found: %s", collateralType))
|
||||
}
|
||||
return cp.LiquidationPenalty
|
||||
}
|
||||
|
||||
func (k Keeper) getAuctionSize(ctx sdk.Context, denom string) sdk.Int {
|
||||
cp, found := k.GetCollateral(ctx, denom)
|
||||
func (k Keeper) getAuctionSize(ctx sdk.Context, collateralType string) sdk.Int {
|
||||
cp, found := k.GetCollateral(ctx, collateralType)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("collateral not found: %s", denom))
|
||||
panic(fmt.Sprintf("collateral not found: %s", collateralType))
|
||||
}
|
||||
return cp.AuctionSize
|
||||
}
|
||||
|
||||
// GetFeeRate returns the per second fee rate for the input denom
|
||||
func (k Keeper) getFeeRate(ctx sdk.Context, denom string) (fee sdk.Dec) {
|
||||
collalateralParam, found := k.GetCollateral(ctx, denom)
|
||||
func (k Keeper) getFeeRate(ctx sdk.Context, collateralType string) (fee sdk.Dec) {
|
||||
collalateralParam, found := k.GetCollateral(ctx, collateralType)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("could not get fee rate for %s, collateral not found", denom))
|
||||
panic(fmt.Sprintf("could not get fee rate for %s, collateral not found", collateralType))
|
||||
}
|
||||
return collalateralParam.StabilityFee
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ func NewQuerier(keeper Keeper) sdk.Querier {
|
||||
case types.QueryGetCdp:
|
||||
return queryGetCdp(ctx, req, keeper)
|
||||
case types.QueryGetCdps:
|
||||
return queryGetCdpsByDenom(ctx, req, keeper)
|
||||
return queryGetCdpsByCollateralType(ctx, req, keeper)
|
||||
case types.QueryGetCdpsByCollateralization:
|
||||
return queryGetCdpsByRatio(ctx, req, keeper)
|
||||
case types.QueryGetParams:
|
||||
@ -41,14 +41,14 @@ func queryGetCdp(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte,
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
|
||||
}
|
||||
|
||||
_, valid := keeper.GetDenomPrefix(ctx, requestParams.CollateralDenom)
|
||||
_, valid := keeper.GetCollateralTypePrefix(ctx, requestParams.CollateralType)
|
||||
if !valid {
|
||||
return nil, sdkerrors.Wrap(types.ErrCollateralNotSupported, requestParams.CollateralDenom)
|
||||
return nil, sdkerrors.Wrap(types.ErrCollateralNotSupported, requestParams.CollateralType)
|
||||
}
|
||||
|
||||
cdp, found := keeper.GetCdpByOwnerAndDenom(ctx, requestParams.Owner, requestParams.CollateralDenom)
|
||||
cdp, found := keeper.GetCdpByOwnerAndCollateralType(ctx, requestParams.Owner, requestParams.CollateralType)
|
||||
if !found {
|
||||
return nil, sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, denom %s", requestParams.Owner, requestParams.CollateralDenom)
|
||||
return nil, sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, denom %s", requestParams.Owner, requestParams.CollateralType)
|
||||
}
|
||||
|
||||
augmentedCDP := keeper.LoadAugmentedCDP(ctx, cdp)
|
||||
@ -69,14 +69,14 @@ func queryGetDeposits(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
|
||||
}
|
||||
|
||||
_, valid := keeper.GetDenomPrefix(ctx, requestParams.CollateralDenom)
|
||||
_, valid := keeper.GetCollateralTypePrefix(ctx, requestParams.CollateralType)
|
||||
if !valid {
|
||||
return nil, sdkerrors.Wrap(types.ErrCollateralNotSupported, requestParams.CollateralDenom)
|
||||
return nil, sdkerrors.Wrap(types.ErrCollateralNotSupported, requestParams.CollateralType)
|
||||
}
|
||||
|
||||
cdp, found := keeper.GetCdpByOwnerAndDenom(ctx, requestParams.Owner, requestParams.CollateralDenom)
|
||||
cdp, found := keeper.GetCdpByOwnerAndCollateralType(ctx, requestParams.Owner, requestParams.CollateralType)
|
||||
if !found {
|
||||
return nil, sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, denom %s", requestParams.Owner, requestParams.CollateralDenom)
|
||||
return nil, sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, denom %s", requestParams.Owner, requestParams.CollateralType)
|
||||
}
|
||||
|
||||
deposits := keeper.GetDeposits(ctx, cdp.ID)
|
||||
@ -96,17 +96,17 @@ func queryGetCdpsByRatio(ctx sdk.Context, req abci.RequestQuery, keeper Keeper)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
|
||||
}
|
||||
_, valid := keeper.GetDenomPrefix(ctx, requestParams.CollateralDenom)
|
||||
_, valid := keeper.GetCollateralTypePrefix(ctx, requestParams.CollateralType)
|
||||
if !valid {
|
||||
return nil, sdkerrors.Wrap(types.ErrCollateralNotSupported, requestParams.CollateralDenom)
|
||||
return nil, sdkerrors.Wrap(types.ErrCollateralNotSupported, requestParams.CollateralType)
|
||||
}
|
||||
|
||||
ratio, err := keeper.CalculateCollateralizationRatioFromAbsoluteRatio(ctx, requestParams.CollateralDenom, requestParams.Ratio, "liquidation")
|
||||
ratio, err := keeper.CalculateCollateralizationRatioFromAbsoluteRatio(ctx, requestParams.CollateralType, requestParams.Ratio, "liquidation")
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrap(err, "couldn't get collateralization ratio from absolute ratio")
|
||||
}
|
||||
|
||||
cdps := keeper.GetAllCdpsByDenomAndRatio(ctx, requestParams.CollateralDenom, ratio)
|
||||
cdps := keeper.GetAllCdpsByCollateralTypeAndRatio(ctx, requestParams.CollateralType, ratio)
|
||||
// augment CDPs by adding collateral value and collateralization ratio
|
||||
var augmentedCDPs types.AugmentedCDPs
|
||||
for _, cdp := range cdps {
|
||||
@ -121,18 +121,18 @@ func queryGetCdpsByRatio(ctx sdk.Context, req abci.RequestQuery, keeper Keeper)
|
||||
}
|
||||
|
||||
// query all cdps with matching collateral denom
|
||||
func queryGetCdpsByDenom(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
|
||||
func queryGetCdpsByCollateralType(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
|
||||
var requestParams types.QueryCdpsParams
|
||||
err := types.ModuleCdc.UnmarshalJSON(req.Data, &requestParams)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
|
||||
}
|
||||
_, valid := keeper.GetDenomPrefix(ctx, requestParams.CollateralDenom)
|
||||
_, valid := keeper.GetCollateralTypePrefix(ctx, requestParams.CollateralType)
|
||||
if !valid {
|
||||
return nil, sdkerrors.Wrap(types.ErrCollateralNotSupported, requestParams.CollateralDenom)
|
||||
return nil, sdkerrors.Wrap(types.ErrCollateralNotSupported, requestParams.CollateralType)
|
||||
}
|
||||
|
||||
cdps := keeper.GetAllCdpsByDenom(ctx, requestParams.CollateralDenom)
|
||||
cdps := keeper.GetAllCdpsByCollateralType(ctx, requestParams.CollateralType)
|
||||
// augment CDPs by adding collateral value and collateralization ratio
|
||||
var augmentedCDPs types.AugmentedCDPs
|
||||
for _, cdp := range cdps {
|
||||
|
@ -97,9 +97,9 @@ func (suite *QuerierTestSuite) SetupTest() {
|
||||
amount = simulation.RandIntBetween(rand.New(rand.NewSource(int64(j))), 500000000, 5000000000)
|
||||
debt = simulation.RandIntBetween(rand.New(rand.NewSource(int64(j))), 1000000000, 25000000000)
|
||||
}
|
||||
err = suite.keeper.AddCdp(suite.ctx, addrs[j], c(collateral, int64(amount)), c("usdx", int64(debt)))
|
||||
err = suite.keeper.AddCdp(suite.ctx, addrs[j], c(collateral, int64(amount)), c("usdx", int64(debt)), collateral+"-a")
|
||||
suite.NoError(err)
|
||||
c, f := suite.keeper.GetCDP(suite.ctx, collateral, uint64(j+1))
|
||||
c, f := suite.keeper.GetCDP(suite.ctx, collateral+"-a", uint64(j+1))
|
||||
suite.True(f)
|
||||
cdps[j] = c
|
||||
aCDP := suite.keeper.LoadAugmentedCDP(suite.ctx, c)
|
||||
@ -116,7 +116,7 @@ func (suite *QuerierTestSuite) TestQueryCdp() {
|
||||
ctx := suite.ctx.WithIsCheckTx(false)
|
||||
query := abci.RequestQuery{
|
||||
Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryGetCdp}, "/"),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryCdpParams(suite.cdps[0].Owner, suite.cdps[0].Collateral.Denom)),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryCdpParams(suite.cdps[0].Owner, suite.cdps[0].Collateral.Denom+"-a")),
|
||||
}
|
||||
bz, err := suite.querier(ctx, []string{types.QueryGetCdp}, query)
|
||||
suite.Nil(err)
|
||||
@ -128,7 +128,7 @@ func (suite *QuerierTestSuite) TestQueryCdp() {
|
||||
|
||||
query = abci.RequestQuery{
|
||||
Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryGetCdp}, "/"),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryCdpParams(suite.cdps[0].Owner, "lol")),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryCdpParams(suite.cdps[0].Owner, "lol-a")),
|
||||
}
|
||||
_, err = suite.querier(ctx, []string{types.QueryGetCdp}, query)
|
||||
suite.Error(err)
|
||||
@ -146,18 +146,18 @@ func (suite *QuerierTestSuite) TestQueryCdp() {
|
||||
|
||||
query = abci.RequestQuery{
|
||||
Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryGetCdp}, "/"),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryCdpParams(suite.cdps[0].Owner, "xrp")),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryCdpParams(suite.cdps[0].Owner, "xrp-a")),
|
||||
}
|
||||
_, err = suite.querier(ctx, []string{types.QueryGetCdp}, query)
|
||||
suite.Error(err)
|
||||
|
||||
}
|
||||
|
||||
func (suite *QuerierTestSuite) TestQueryCdpsByDenom() {
|
||||
func (suite *QuerierTestSuite) TestQueryCdpsByCollateralType() {
|
||||
ctx := suite.ctx.WithIsCheckTx(false)
|
||||
query := abci.RequestQuery{
|
||||
Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryGetCdps}, "/"),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryCdpsParams(suite.cdps[0].Collateral.Denom)),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryCdpsParams(suite.cdps[0].Collateral.Denom + "-a")),
|
||||
}
|
||||
bz, err := suite.querier(ctx, []string{types.QueryGetCdps}, query)
|
||||
suite.Nil(err)
|
||||
@ -169,7 +169,7 @@ func (suite *QuerierTestSuite) TestQueryCdpsByDenom() {
|
||||
|
||||
query = abci.RequestQuery{
|
||||
Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryGetCdps}, "/"),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryCdpsParams("lol")),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryCdpsParams("lol-a")),
|
||||
}
|
||||
_, err = suite.querier(ctx, []string{types.QueryGetCdps}, query)
|
||||
suite.Error(err)
|
||||
@ -183,8 +183,8 @@ func (suite *QuerierTestSuite) TestQueryCdpsByRatio() {
|
||||
expectedXrpIds := []int{}
|
||||
expectedBtcIds := []int{}
|
||||
for _, cdp := range suite.cdps {
|
||||
absoluteRatio := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, cdp.Collateral, cdp.Principal)
|
||||
collateralizationRatio, err := suite.keeper.CalculateCollateralizationRatioFromAbsoluteRatio(suite.ctx, cdp.Collateral.Denom, absoluteRatio, "liquidation")
|
||||
absoluteRatio := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, cdp.Collateral, cdp.Type, cdp.Principal)
|
||||
collateralizationRatio, err := suite.keeper.CalculateCollateralizationRatioFromAbsoluteRatio(suite.ctx, cdp.Type, absoluteRatio, "liquidation")
|
||||
suite.Nil(err)
|
||||
if cdp.Collateral.Denom == "xrp" {
|
||||
if collateralizationRatio.LT(xrpRatio) {
|
||||
@ -202,7 +202,7 @@ func (suite *QuerierTestSuite) TestQueryCdpsByRatio() {
|
||||
ctx := suite.ctx.WithIsCheckTx(false)
|
||||
query := abci.RequestQuery{
|
||||
Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryGetCdpsByCollateralization}, "/"),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryCdpsByRatioParams("xrp", xrpRatio)),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryCdpsByRatioParams("xrp-a", xrpRatio)),
|
||||
}
|
||||
bz, err := suite.querier(ctx, []string{types.QueryGetCdpsByCollateralization}, query)
|
||||
suite.Nil(err)
|
||||
@ -219,7 +219,7 @@ func (suite *QuerierTestSuite) TestQueryCdpsByRatio() {
|
||||
|
||||
query = abci.RequestQuery{
|
||||
Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryGetCdpsByCollateralization}, "/"),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryCdpsByRatioParams("btc", btcRatio)),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryCdpsByRatioParams("btc-a", btcRatio)),
|
||||
}
|
||||
bz, err = suite.querier(ctx, []string{types.QueryGetCdpsByCollateralization}, query)
|
||||
suite.Nil(err)
|
||||
@ -236,7 +236,7 @@ func (suite *QuerierTestSuite) TestQueryCdpsByRatio() {
|
||||
|
||||
query = abci.RequestQuery{
|
||||
Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryGetCdpsByCollateralization}, "/"),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryCdpsByRatioParams("xrp", d("0.003"))),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryCdpsByRatioParams("xrp-a", d("0.003"))),
|
||||
}
|
||||
bz, err = suite.querier(ctx, []string{types.QueryGetCdpsByCollateralization}, query)
|
||||
suite.Nil(err)
|
||||
@ -265,7 +265,7 @@ func (suite *QuerierTestSuite) TestQueryDeposits() {
|
||||
ctx := suite.ctx.WithIsCheckTx(false)
|
||||
query := abci.RequestQuery{
|
||||
Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryGetCdpDeposits}, "/"),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryCdpDeposits(suite.cdps[0].Owner, suite.cdps[0].Collateral.Denom)),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryCdpDeposits(suite.cdps[0].Owner, suite.cdps[0].Collateral.Denom+"-a")),
|
||||
}
|
||||
|
||||
bz, err := suite.querier(ctx, []string{types.QueryGetCdpDeposits}, query)
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
// (this is the equivalent of saying that fees are no longer accumulated by a cdp once it gets liquidated)
|
||||
func (k Keeper) SeizeCollateral(ctx sdk.Context, cdp types.CDP) error {
|
||||
// Calculate the previous collateral ratio
|
||||
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.GetTotalPrincipal())
|
||||
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Type, cdp.GetTotalPrincipal())
|
||||
|
||||
// Move debt coins from cdp to liquidator account
|
||||
deposits := k.GetDeposits(ctx, cdp.ID)
|
||||
@ -48,23 +48,23 @@ func (k Keeper) SeizeCollateral(ctx sdk.Context, cdp types.CDP) error {
|
||||
)
|
||||
}
|
||||
|
||||
err = k.AuctionCollateral(ctx, deposits, debt, cdp.Principal.Denom)
|
||||
err = k.AuctionCollateral(ctx, deposits, cdp.Type, debt, cdp.Principal.Denom)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Decrement total principal for this collateral type
|
||||
coinsToDecrement := cdp.GetTotalPrincipal()
|
||||
k.DecrementTotalPrincipal(ctx, cdp.Collateral.Denom, coinsToDecrement)
|
||||
k.DecrementTotalPrincipal(ctx, cdp.Type, coinsToDecrement)
|
||||
|
||||
// Delete CDP from state
|
||||
k.RemoveCdpOwnerIndex(ctx, cdp)
|
||||
k.RemoveCdpCollateralRatioIndex(ctx, cdp.Collateral.Denom, cdp.ID, oldCollateralToDebtRatio)
|
||||
k.RemoveCdpCollateralRatioIndex(ctx, cdp.Type, cdp.ID, oldCollateralToDebtRatio)
|
||||
return k.DeleteCDP(ctx, cdp)
|
||||
}
|
||||
|
||||
// LiquidateCdps seizes collateral from all CDPs below the input liquidation ratio
|
||||
func (k Keeper) LiquidateCdps(ctx sdk.Context, marketID string, denom string, liquidationRatio sdk.Dec) error {
|
||||
func (k Keeper) LiquidateCdps(ctx sdk.Context, marketID string, collateralType string, liquidationRatio sdk.Dec) error {
|
||||
price, err := k.pricefeedKeeper.GetCurrentPrice(ctx, marketID)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -77,7 +77,7 @@ func (k Keeper) LiquidateCdps(ctx sdk.Context, marketID string, denom string, li
|
||||
// liquidation ratio = 1.5
|
||||
// normalizedRatio = (1/(0.5/1.5)) = 3
|
||||
normalizedRatio := sdk.OneDec().Quo(priceDivLiqRatio)
|
||||
cdpsToLiquidate := k.GetAllCdpsByDenomAndRatio(ctx, denom, normalizedRatio)
|
||||
cdpsToLiquidate := k.GetAllCdpsByCollateralTypeAndRatio(ctx, collateralType, normalizedRatio)
|
||||
for _, c := range cdpsToLiquidate {
|
||||
err := k.SeizeCollateral(ctx, c)
|
||||
if err != nil {
|
||||
@ -88,8 +88,8 @@ func (k Keeper) LiquidateCdps(ctx sdk.Context, marketID string, denom string, li
|
||||
}
|
||||
|
||||
// ApplyLiquidationPenalty multiplies the input debt amount by the liquidation penalty
|
||||
func (k Keeper) ApplyLiquidationPenalty(ctx sdk.Context, denom string, debt sdk.Int) sdk.Int {
|
||||
penalty := k.getLiquidationPenalty(ctx, denom)
|
||||
func (k Keeper) ApplyLiquidationPenalty(ctx sdk.Context, collateralType string, debt sdk.Int) sdk.Int {
|
||||
penalty := k.getLiquidationPenalty(ctx, collateralType)
|
||||
return sdk.NewDecFromInt(debt).Mul(penalty).RoundInt()
|
||||
}
|
||||
|
||||
|
@ -105,9 +105,9 @@ func (suite *SeizeTestSuite) createCdps() {
|
||||
tracker.debt += int64(debt)
|
||||
}
|
||||
}
|
||||
err := suite.keeper.AddCdp(suite.ctx, addrs[j], c(collateral, int64(amount)), c("usdx", int64(debt)))
|
||||
err := suite.keeper.AddCdp(suite.ctx, addrs[j], c(collateral, int64(amount)), c("usdx", int64(debt)), collateral+"-a")
|
||||
suite.NoError(err)
|
||||
c, f := suite.keeper.GetCDP(suite.ctx, collateral, uint64(j+1))
|
||||
c, f := suite.keeper.GetCDP(suite.ctx, collateral+"-a", uint64(j+1))
|
||||
suite.True(f)
|
||||
cdps[j] = c
|
||||
}
|
||||
@ -131,14 +131,14 @@ func (suite *SeizeTestSuite) setPrice(price sdk.Dec, market string) {
|
||||
func (suite *SeizeTestSuite) TestSeizeCollateral() {
|
||||
suite.createCdps()
|
||||
sk := suite.app.GetSupplyKeeper()
|
||||
cdp, found := suite.keeper.GetCDP(suite.ctx, "xrp", uint64(2))
|
||||
cdp, found := suite.keeper.GetCDP(suite.ctx, "xrp-a", uint64(2))
|
||||
suite.True(found)
|
||||
p := cdp.Principal.Amount
|
||||
cl := cdp.Collateral.Amount
|
||||
tpb := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx")
|
||||
tpb := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp-a", "usdx")
|
||||
err := suite.keeper.SeizeCollateral(suite.ctx, cdp)
|
||||
suite.NoError(err)
|
||||
tpa := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx")
|
||||
tpa := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp-a", "usdx")
|
||||
suite.Equal(tpb.Sub(tpa), p)
|
||||
auctionKeeper := suite.app.GetAuctionKeeper()
|
||||
_, found = auctionKeeper.GetAuction(suite.ctx, auction.DefaultNextAuctionID)
|
||||
@ -148,34 +148,34 @@ func (suite *SeizeTestSuite) TestSeizeCollateral() {
|
||||
ak := suite.app.GetAccountKeeper()
|
||||
acc := ak.GetAccount(suite.ctx, suite.addrs[1])
|
||||
suite.Equal(p.Int64(), acc.GetCoins().AmountOf("usdx").Int64())
|
||||
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[1], suite.addrs[1], c("xrp", 10))
|
||||
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[1], suite.addrs[1], c("xrp", 10), "xrp-a")
|
||||
suite.Require().True(errors.Is(err, types.ErrCdpNotFound))
|
||||
}
|
||||
|
||||
func (suite *SeizeTestSuite) TestSeizeCollateralMultiDeposit() {
|
||||
suite.createCdps()
|
||||
sk := suite.app.GetSupplyKeeper()
|
||||
cdp, found := suite.keeper.GetCDP(suite.ctx, "xrp", uint64(2))
|
||||
cdp, found := suite.keeper.GetCDP(suite.ctx, "xrp-a", uint64(2))
|
||||
suite.True(found)
|
||||
err := suite.keeper.DepositCollateral(suite.ctx, suite.addrs[1], suite.addrs[0], c("xrp", 6999000000))
|
||||
err := suite.keeper.DepositCollateral(suite.ctx, suite.addrs[1], suite.addrs[0], c("xrp", 6999000000), "xrp-a")
|
||||
suite.NoError(err)
|
||||
cdp, found = suite.keeper.GetCDP(suite.ctx, "xrp", uint64(2))
|
||||
cdp, found = suite.keeper.GetCDP(suite.ctx, "xrp-a", uint64(2))
|
||||
suite.True(found)
|
||||
deposits := suite.keeper.GetDeposits(suite.ctx, cdp.ID)
|
||||
suite.Equal(2, len(deposits))
|
||||
p := cdp.Principal.Amount
|
||||
cl := cdp.Collateral.Amount
|
||||
tpb := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx")
|
||||
tpb := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp-a", "usdx")
|
||||
err = suite.keeper.SeizeCollateral(suite.ctx, cdp)
|
||||
suite.NoError(err)
|
||||
tpa := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx")
|
||||
tpa := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp-a", "usdx")
|
||||
suite.Equal(tpb.Sub(tpa), p)
|
||||
auctionMacc := sk.GetModuleAccount(suite.ctx, auction.ModuleName)
|
||||
suite.Equal(cs(c("debt", p.Int64()), c("xrp", cl.Int64())), auctionMacc.GetCoins())
|
||||
ak := suite.app.GetAccountKeeper()
|
||||
acc := ak.GetAccount(suite.ctx, suite.addrs[1])
|
||||
suite.Equal(p.Int64(), acc.GetCoins().AmountOf("usdx").Int64())
|
||||
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[1], suite.addrs[1], c("xrp", 10))
|
||||
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[1], suite.addrs[1], c("xrp", 10), "xrp-a")
|
||||
suite.Require().True(errors.Is(err, types.ErrCdpNotFound))
|
||||
}
|
||||
|
||||
@ -185,9 +185,9 @@ func (suite *SeizeTestSuite) TestLiquidateCdps() {
|
||||
acc := sk.GetModuleAccount(suite.ctx, types.ModuleName)
|
||||
originalXrpCollateral := acc.GetCoins().AmountOf("xrp")
|
||||
suite.setPrice(d("0.2"), "xrp:usd")
|
||||
p, found := suite.keeper.GetCollateral(suite.ctx, "xrp")
|
||||
p, found := suite.keeper.GetCollateral(suite.ctx, "xrp-a")
|
||||
suite.True(found)
|
||||
suite.keeper.LiquidateCdps(suite.ctx, "xrp:usd", "xrp", p.LiquidationRatio)
|
||||
suite.keeper.LiquidateCdps(suite.ctx, "xrp:usd", "xrp-a", p.LiquidationRatio)
|
||||
acc = sk.GetModuleAccount(suite.ctx, types.ModuleName)
|
||||
finalXrpCollateral := acc.GetCoins().AmountOf("xrp")
|
||||
seizedXrpCollateral := originalXrpCollateral.Sub(finalXrpCollateral)
|
||||
@ -196,13 +196,13 @@ func (suite *SeizeTestSuite) TestLiquidateCdps() {
|
||||
}
|
||||
|
||||
func (suite *SeizeTestSuite) TestApplyLiquidationPenalty() {
|
||||
penalty := suite.keeper.ApplyLiquidationPenalty(suite.ctx, "xrp", i(1000))
|
||||
penalty := suite.keeper.ApplyLiquidationPenalty(suite.ctx, "xrp-a", i(1000))
|
||||
suite.Equal(i(50), penalty)
|
||||
penalty = suite.keeper.ApplyLiquidationPenalty(suite.ctx, "btc", i(1000))
|
||||
penalty = suite.keeper.ApplyLiquidationPenalty(suite.ctx, "btc-a", i(1000))
|
||||
suite.Equal(i(25), penalty)
|
||||
penalty = suite.keeper.ApplyLiquidationPenalty(suite.ctx, "xrp", i(675760172))
|
||||
penalty = suite.keeper.ApplyLiquidationPenalty(suite.ctx, "xrp-a", i(675760172))
|
||||
suite.Equal(i(33788009), penalty)
|
||||
suite.Panics(func() { suite.keeper.ApplyLiquidationPenalty(suite.ctx, "lol", i(1000)) })
|
||||
suite.Panics(func() { suite.keeper.ApplyLiquidationPenalty(suite.ctx, "lol-a", i(1000)) })
|
||||
}
|
||||
|
||||
func TestSeizeTestSuite(t *testing.T) {
|
||||
|
116
x/cdp/legacy/v0_9/types.go
Normal file
116
x/cdp/legacy/v0_9/types.go
Normal file
@ -0,0 +1,116 @@
|
||||
package v0_9
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// CDP is the state of a single collateralized debt position.
|
||||
type CDP struct {
|
||||
ID uint64 `json:"id" yaml:"id"` // unique id for cdp
|
||||
Owner sdk.AccAddress `json:"owner" yaml:"owner"` // Account that authorizes changes to the CDP
|
||||
Collateral sdk.Coin `json:"collateral" yaml:"collateral"` // Amount of collateral stored in this CDP
|
||||
Principal sdk.Coin `json:"principal" yaml:"principal"`
|
||||
AccumulatedFees sdk.Coin `json:"accumulated_fees" yaml:"accumulated_fees"`
|
||||
FeesUpdated time.Time `json:"fees_updated" yaml:"fees_updated"` // Amount of stable coin drawn from this CDP
|
||||
}
|
||||
|
||||
// NewCDP creates a new CDP object
|
||||
func NewCDP(id uint64, owner sdk.AccAddress, collateral sdk.Coin, principal sdk.Coin, time time.Time) CDP {
|
||||
fees := sdk.NewCoin(principal.Denom, sdk.ZeroInt())
|
||||
return CDP{
|
||||
ID: id,
|
||||
Owner: owner,
|
||||
Collateral: collateral,
|
||||
Principal: principal,
|
||||
AccumulatedFees: fees,
|
||||
FeesUpdated: time,
|
||||
}
|
||||
}
|
||||
|
||||
// CDPs a collection of CDP objects
|
||||
type CDPs []CDP
|
||||
|
||||
// Deposit defines an amount of coins deposited by an account to a cdp
|
||||
type Deposit struct {
|
||||
CdpID uint64 `json:"cdp_id" yaml:"cdp_id"` // cdpID of the cdp
|
||||
Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"` // Address of the depositor
|
||||
Amount sdk.Coin `json:"amount" yaml:"amount"` // Deposit amount
|
||||
}
|
||||
|
||||
// NewDeposit creates a new Deposit object
|
||||
func NewDeposit(cdpID uint64, depositor sdk.AccAddress, amount sdk.Coin) Deposit {
|
||||
return Deposit{cdpID, depositor, amount}
|
||||
}
|
||||
|
||||
// Deposits a collection of Deposit objects
|
||||
type Deposits []Deposit
|
||||
|
||||
// GenesisState is the state that must be provided at genesis.
|
||||
type GenesisState struct {
|
||||
Params Params `json:"params" yaml:"params"`
|
||||
CDPs CDPs `json:"cdps" yaml:"cdps"`
|
||||
Deposits Deposits `json:"deposits" yaml:"deposits"`
|
||||
StartingCdpID uint64 `json:"starting_cdp_id" yaml:"starting_cdp_id"`
|
||||
DebtDenom string `json:"debt_denom" yaml:"debt_denom"`
|
||||
GovDenom string `json:"gov_denom" yaml:"gov_denom"`
|
||||
PreviousDistributionTime time.Time `json:"previous_distribution_time" yaml:"previous_distribution_time"`
|
||||
}
|
||||
|
||||
// Params governance parameters for cdp module
|
||||
type Params struct {
|
||||
CollateralParams CollateralParams `json:"collateral_params" yaml:"collateral_params"`
|
||||
DebtParam DebtParam `json:"debt_param" yaml:"debt_param"`
|
||||
GlobalDebtLimit sdk.Coin `json:"global_debt_limit" yaml:"global_debt_limit"`
|
||||
SurplusAuctionThreshold sdk.Int `json:"surplus_auction_threshold" yaml:"surplus_auction_threshold"`
|
||||
SurplusAuctionLot sdk.Int `json:"surplus_auction_lot" yaml:"surplus_auction_lot"`
|
||||
DebtAuctionThreshold sdk.Int `json:"debt_auction_threshold" yaml:"debt_auction_threshold"`
|
||||
DebtAuctionLot sdk.Int `json:"debt_auction_lot" yaml:"debt_auction_lot"`
|
||||
SavingsDistributionFrequency time.Duration `json:"savings_distribution_frequency" yaml:"savings_distribution_frequency"`
|
||||
CircuitBreaker bool `json:"circuit_breaker" yaml:"circuit_breaker"`
|
||||
}
|
||||
|
||||
// NewParams returns a new params object
|
||||
func NewParams(
|
||||
debtLimit sdk.Coin, collateralParams CollateralParams, debtParam DebtParam, surplusThreshold,
|
||||
surplusLot, debtThreshold, debtLot sdk.Int, distributionFreq time.Duration, breaker bool,
|
||||
) Params {
|
||||
return Params{
|
||||
GlobalDebtLimit: debtLimit,
|
||||
CollateralParams: collateralParams,
|
||||
DebtParam: debtParam,
|
||||
SurplusAuctionThreshold: surplusThreshold,
|
||||
SurplusAuctionLot: surplusLot,
|
||||
DebtAuctionThreshold: debtThreshold,
|
||||
DebtAuctionLot: debtLot,
|
||||
SavingsDistributionFrequency: distributionFreq,
|
||||
CircuitBreaker: breaker,
|
||||
}
|
||||
}
|
||||
|
||||
// CollateralParam governance parameters for each collateral type within the cdp module
|
||||
type CollateralParam struct {
|
||||
Denom string `json:"denom" yaml:"denom"` // Coin name of collateral type
|
||||
LiquidationRatio sdk.Dec `json:"liquidation_ratio" yaml:"liquidation_ratio"` // The ratio (Collateral (priced in stable coin) / Debt) under which a CDP will be liquidated
|
||||
DebtLimit sdk.Coin `json:"debt_limit" yaml:"debt_limit"` // Maximum amount of debt allowed to be drawn from this collateral type
|
||||
StabilityFee sdk.Dec `json:"stability_fee" yaml:"stability_fee"` // per second stability fee for loans opened using this collateral
|
||||
AuctionSize sdk.Int `json:"auction_size" yaml:"auction_size"` // Max amount of collateral to sell off in any one auction.
|
||||
LiquidationPenalty sdk.Dec `json:"liquidation_penalty" yaml:"liquidation_penalty"` // percentage penalty (between [0, 1]) applied to a cdp if it is liquidated
|
||||
Prefix byte `json:"prefix" yaml:"prefix"`
|
||||
SpotMarketID string `json:"spot_market_id" yaml:"spot_market_id"` // marketID of the spot price of the asset from the pricefeed - used for opening CDPs, depositing, withdrawing
|
||||
LiquidationMarketID string `json:"liquidation_market_id" yaml:"liquidation_market_id"` // marketID of the pricefeed used for liquidation
|
||||
ConversionFactor sdk.Int `json:"conversion_factor" yaml:"conversion_factor"` // factor for converting internal units to one base unit of collateral
|
||||
}
|
||||
|
||||
// CollateralParams array of CollateralParam
|
||||
type CollateralParams []CollateralParam
|
||||
|
||||
// DebtParam governance params for debt assets
|
||||
type DebtParam struct {
|
||||
Denom string `json:"denom" yaml:"denom"`
|
||||
ReferenceAsset string `json:"reference_asset" yaml:"reference_asset"`
|
||||
ConversionFactor sdk.Int `json:"conversion_factor" yaml:"conversion_factor"`
|
||||
DebtFloor sdk.Int `json:"debt_floor" yaml:"debt_floor"` // minimum active loan size, used to prevent dust
|
||||
SavingsRate sdk.Dec `json:"savings_rate" yaml:"savings_rate"` // the percentage of stability fees that are redirected to savings rate
|
||||
}
|
@ -79,6 +79,7 @@ func randomCdpGenState(selection int) types.GenesisState {
|
||||
CollateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "xrp",
|
||||
Type: "xrp-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("2.0"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 20000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000004431822130"),
|
||||
@ -91,6 +92,7 @@ func randomCdpGenState(selection int) types.GenesisState {
|
||||
},
|
||||
{
|
||||
Denom: "btc",
|
||||
Type: "btc-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.25"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 50000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000000782997609"),
|
||||
@ -103,6 +105,7 @@ func randomCdpGenState(selection int) types.GenesisState {
|
||||
},
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 30000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000002293273137"),
|
||||
@ -140,6 +143,7 @@ func randomCdpGenState(selection int) types.GenesisState {
|
||||
CollateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 100000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000002293273137"),
|
||||
|
@ -78,7 +78,7 @@ func SimulateMsgCdp(ak types.AccountKeeper, k keeper.Keeper, pfk types.Pricefeed
|
||||
}
|
||||
spendableCoins = spendableCoins.Sub(fees)
|
||||
|
||||
existingCDP, found := k.GetCdpByOwnerAndDenom(ctx, acc.GetAddress(), randCollateralParam.Denom)
|
||||
existingCDP, found := k.GetCdpByOwnerAndCollateralType(ctx, acc.GetAddress(), randCollateralParam.Denom)
|
||||
if !found {
|
||||
// calculate the minimum amount of collateral that is needed to create a cdp with the debt floor amount of debt and the minimum liquidation ratio
|
||||
// (debtFloor * liquidationRatio)/priceShifted
|
||||
@ -101,7 +101,7 @@ func SimulateMsgCdp(ak types.AccountKeeper, k keeper.Keeper, pfk types.Pricefeed
|
||||
// calculate the max amount of debt that could be drawn for the chosen deposit
|
||||
maxDebtDraw := collateralDepositValue.Quo(randCollateralParam.LiquidationRatio).TruncateInt()
|
||||
// check that the debt limit hasn't been reached
|
||||
availableAssetDebt := randCollateralParam.DebtLimit.Amount.Sub(k.GetTotalPrincipal(ctx, randCollateralParam.Denom, debtParam.Denom))
|
||||
availableAssetDebt := randCollateralParam.DebtLimit.Amount.Sub(k.GetTotalPrincipal(ctx, randCollateralParam.Type, debtParam.Denom))
|
||||
if availableAssetDebt.LTE(debtParam.DebtFloor) {
|
||||
// debt limit has been reached
|
||||
return simulation.NewOperationMsgBasic(types.ModuleName, "no-operation", "debt limit reached, cannot open cdp", false, nil), nil, nil
|
||||
@ -111,7 +111,7 @@ func SimulateMsgCdp(ak types.AccountKeeper, k keeper.Keeper, pfk types.Pricefeed
|
||||
// randomly select a debt draw amount
|
||||
debtDraw := sdk.NewInt(int64(simulation.RandIntBetween(r, int(debtParam.DebtFloor.Int64()), int(maxDebtDraw.Int64()))))
|
||||
|
||||
msg := types.NewMsgCreateCDP(acc.GetAddress(), sdk.NewCoin(randCollateralParam.Denom, collateralDeposit), sdk.NewCoin(debtParam.Denom, debtDraw))
|
||||
msg := types.NewMsgCreateCDP(acc.GetAddress(), sdk.NewCoin(randCollateralParam.Denom, collateralDeposit), sdk.NewCoin(debtParam.Denom, debtDraw), randCollateralParam.Type)
|
||||
|
||||
tx := helpers.GenTx(
|
||||
[]sdk.Msg{msg},
|
||||
@ -158,7 +158,7 @@ func SimulateMsgCdp(ak types.AccountKeeper, k keeper.Keeper, pfk types.Pricefeed
|
||||
// deposit 25% of the time
|
||||
if hasCoins(spendableCoins, randCollateralParam.Denom) && shouldDeposit(r) {
|
||||
randDepositAmount := sdk.NewInt(int64(simulation.RandIntBetween(r, 1, int(spendableCoins.AmountOf(randCollateralParam.Denom).Int64()))))
|
||||
msg := types.NewMsgDeposit(acc.GetAddress(), acc.GetAddress(), sdk.NewCoin(randCollateralParam.Denom, randDepositAmount))
|
||||
msg := types.NewMsgDeposit(acc.GetAddress(), acc.GetAddress(), sdk.NewCoin(randCollateralParam.Denom, randDepositAmount), randCollateralParam.Type)
|
||||
|
||||
tx := helpers.GenTx(
|
||||
[]sdk.Msg{msg},
|
||||
|
@ -12,20 +12,22 @@ import (
|
||||
|
||||
// CDP is the state of a single collateralized debt position.
|
||||
type CDP struct {
|
||||
ID uint64 `json:"id" yaml:"id"` // unique id for cdp
|
||||
Owner sdk.AccAddress `json:"owner" yaml:"owner"` // Account that authorizes changes to the CDP
|
||||
Collateral sdk.Coin `json:"collateral" yaml:"collateral"` // Amount of collateral stored in this CDP
|
||||
Principal sdk.Coin `json:"principal" yaml:"principal"`
|
||||
AccumulatedFees sdk.Coin `json:"accumulated_fees" yaml:"accumulated_fees"`
|
||||
FeesUpdated time.Time `json:"fees_updated" yaml:"fees_updated"` // Amount of stable coin drawn from this CDP
|
||||
ID uint64 `json:"id" yaml:"id"` // unique id for cdp
|
||||
Owner sdk.AccAddress `json:"owner" yaml:"owner"` // Account that authorizes changes to the CDP
|
||||
Type string `json:"type" yaml:"type"` // string representing the unique collateral type of the CDP
|
||||
Collateral sdk.Coin `json:"collateral" yaml:"collateral"` // Amount of collateral stored in this CDP
|
||||
Principal sdk.Coin `json:"principal" yaml:"principal"` // Amount of debt drawn using the CDP
|
||||
AccumulatedFees sdk.Coin `json:"accumulated_fees" yaml:"accumulated_fees"` // Fees accumulated since the CDP was opened or debt was last repayed
|
||||
FeesUpdated time.Time `json:"fees_updated" yaml:"fees_updated"` // Amount of stable coin drawn from this CDP
|
||||
}
|
||||
|
||||
// NewCDP creates a new CDP object
|
||||
func NewCDP(id uint64, owner sdk.AccAddress, collateral sdk.Coin, principal sdk.Coin, time time.Time) CDP {
|
||||
func NewCDP(id uint64, owner sdk.AccAddress, collateral sdk.Coin, collateralType string, principal sdk.Coin, time time.Time) CDP {
|
||||
fees := sdk.NewCoin(principal.Denom, sdk.ZeroInt())
|
||||
return CDP{
|
||||
ID: id,
|
||||
Owner: owner,
|
||||
Type: collateralType,
|
||||
Collateral: collateral,
|
||||
Principal: principal,
|
||||
AccumulatedFees: fees,
|
||||
@ -45,7 +47,7 @@ func (cdp CDP) String() string {
|
||||
Fees Last Updated: %s`,
|
||||
cdp.Owner,
|
||||
cdp.ID,
|
||||
cdp.Collateral.Denom,
|
||||
cdp.Type,
|
||||
cdp.Collateral,
|
||||
cdp.Principal,
|
||||
cdp.AccumulatedFees,
|
||||
@ -73,10 +75,13 @@ func (cdp CDP) Validate() error {
|
||||
if cdp.FeesUpdated.IsZero() {
|
||||
return errors.New("cdp updated fee time cannot be zero")
|
||||
}
|
||||
if strings.TrimSpace(cdp.Type) == "" {
|
||||
return fmt.Errorf("cdp type cannot be empty")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTotalPrinciple returns the total principle for the cdp
|
||||
// GetTotalPrincipal returns the total principle for the cdp
|
||||
func (cdp CDP) GetTotalPrincipal() sdk.Coin {
|
||||
return cdp.Principal.Add(cdp.AccumulatedFees)
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ func (suite *CdpValidationSuite) TestCdpValidation() {
|
||||
}{
|
||||
{
|
||||
name: "valid cdp",
|
||||
cdp: types.NewCDP(1, suite.addrs[0], sdk.NewInt64Coin("bnb", 100000), sdk.NewInt64Coin("usdx", 100000), tmtime.Now()),
|
||||
cdp: types.NewCDP(1, suite.addrs[0], sdk.NewInt64Coin("bnb", 100000), "bnb-a", sdk.NewInt64Coin("usdx", 100000), tmtime.Now()),
|
||||
errArgs: errArgs{
|
||||
expectPass: true,
|
||||
contains: "",
|
||||
@ -50,7 +50,7 @@ func (suite *CdpValidationSuite) TestCdpValidation() {
|
||||
},
|
||||
{
|
||||
name: "invalid cdp id",
|
||||
cdp: types.NewCDP(0, suite.addrs[0], sdk.NewInt64Coin("bnb", 100000), sdk.NewInt64Coin("usdx", 100000), tmtime.Now()),
|
||||
cdp: types.NewCDP(0, suite.addrs[0], sdk.NewInt64Coin("bnb", 100000), "bnb-a", sdk.NewInt64Coin("usdx", 100000), tmtime.Now()),
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
contains: "cdp id cannot be 0",
|
||||
@ -58,7 +58,7 @@ func (suite *CdpValidationSuite) TestCdpValidation() {
|
||||
},
|
||||
{
|
||||
name: "invalid collateral",
|
||||
cdp: types.CDP{1, suite.addrs[0], sdk.Coin{"", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(0)}, tmtime.Now()},
|
||||
cdp: types.CDP{1, suite.addrs[0], "bnb-a", sdk.Coin{"", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(0)}, tmtime.Now()},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
contains: "invalid coins: collateral",
|
||||
@ -66,7 +66,7 @@ func (suite *CdpValidationSuite) TestCdpValidation() {
|
||||
},
|
||||
{
|
||||
name: "invalid prinicpal",
|
||||
cdp: types.CDP{1, suite.addrs[0], sdk.Coin{"xrp", sdk.NewInt(100)}, sdk.Coin{"", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(0)}, tmtime.Now()},
|
||||
cdp: types.CDP{1, suite.addrs[0], "xrp-a", sdk.Coin{"xrp", sdk.NewInt(100)}, sdk.Coin{"", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(0)}, tmtime.Now()},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
contains: "invalid coins: principal",
|
||||
@ -74,7 +74,7 @@ func (suite *CdpValidationSuite) TestCdpValidation() {
|
||||
},
|
||||
{
|
||||
name: "invalid fees",
|
||||
cdp: types.CDP{1, suite.addrs[0], sdk.Coin{"xrp", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(100)}, sdk.Coin{"", sdk.NewInt(0)}, tmtime.Now()},
|
||||
cdp: types.CDP{1, suite.addrs[0], "xrp-a", sdk.Coin{"xrp", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(100)}, sdk.Coin{"", sdk.NewInt(0)}, tmtime.Now()},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
contains: "invalid coins: accumulated fees",
|
||||
@ -82,12 +82,20 @@ func (suite *CdpValidationSuite) TestCdpValidation() {
|
||||
},
|
||||
{
|
||||
name: "invalid fees updated",
|
||||
cdp: types.CDP{1, suite.addrs[0], sdk.Coin{"xrp", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(0)}, time.Time{}},
|
||||
cdp: types.CDP{1, suite.addrs[0], "xrp-a", sdk.Coin{"xrp", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(0)}, time.Time{}},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
contains: "cdp updated fee time cannot be zero",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid type",
|
||||
cdp: types.CDP{1, suite.addrs[0], "", sdk.Coin{"xrp", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(100)}, sdk.Coin{"usdx", sdk.NewInt(0)}, tmtime.Now()},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
contains: "cdp type cannot be empty",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@ -161,11 +169,11 @@ func (suite *CdpValidationSuite) TestDepositValidation() {
|
||||
|
||||
func (suite *CdpValidationSuite) TestCdpGetTotalPrinciple() {
|
||||
principal := sdk.Coin{"usdx", sdk.NewInt(100500)}
|
||||
acummulatedFees := sdk.Coin{"usdx", sdk.NewInt(25000)}
|
||||
accumulatedFees := sdk.Coin{"usdx", sdk.NewInt(25000)}
|
||||
|
||||
cdp := types.CDP{Principal: principal, AccumulatedFees: acummulatedFees}
|
||||
cdp := types.CDP{Principal: principal, AccumulatedFees: accumulatedFees}
|
||||
|
||||
suite.Require().Equal(cdp.GetTotalPrincipal(), principal.Add(acummulatedFees))
|
||||
suite.Require().Equal(cdp.GetTotalPrincipal(), principal.Add(accumulatedFees))
|
||||
}
|
||||
|
||||
func TestCdpValidationSuite(t *testing.T) {
|
||||
|
@ -20,17 +20,19 @@ var (
|
||||
|
||||
// MsgCreateCDP creates a cdp
|
||||
type MsgCreateCDP struct {
|
||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||
Collateral sdk.Coin `json:"collateral" yaml:"collateral"`
|
||||
Principal sdk.Coin `json:"principal" yaml:"principal"`
|
||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||
Collateral sdk.Coin `json:"collateral" yaml:"collateral"`
|
||||
Principal sdk.Coin `json:"principal" yaml:"principal"`
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
}
|
||||
|
||||
// NewMsgCreateCDP returns a new MsgPlaceBid.
|
||||
func NewMsgCreateCDP(sender sdk.AccAddress, collateral sdk.Coin, principal sdk.Coin) MsgCreateCDP {
|
||||
func NewMsgCreateCDP(sender sdk.AccAddress, collateral sdk.Coin, principal sdk.Coin, collateralType string) MsgCreateCDP {
|
||||
return MsgCreateCDP{
|
||||
Sender: sender,
|
||||
Collateral: collateral,
|
||||
Principal: principal,
|
||||
Sender: sender,
|
||||
Collateral: collateral,
|
||||
Principal: principal,
|
||||
CollateralType: collateralType,
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,6 +53,9 @@ func (msg MsgCreateCDP) ValidateBasic() error {
|
||||
if msg.Principal.IsZero() || !msg.Principal.IsValid() {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "principal amount %s", msg.Principal)
|
||||
}
|
||||
if strings.TrimSpace(msg.CollateralType) == "" {
|
||||
return fmt.Errorf("collateral type cannot be empty")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -76,17 +81,19 @@ func (msg MsgCreateCDP) String() string {
|
||||
|
||||
// MsgDeposit deposit collateral to an existing cdp.
|
||||
type MsgDeposit struct {
|
||||
Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"`
|
||||
Owner sdk.AccAddress `json:"owner" yaml:"owner"`
|
||||
Collateral sdk.Coin `json:"collateral" yaml:"collateral"`
|
||||
Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"`
|
||||
Owner sdk.AccAddress `json:"owner" yaml:"owner"`
|
||||
Collateral sdk.Coin `json:"collateral" yaml:"collateral"`
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
}
|
||||
|
||||
// NewMsgDeposit returns a new MsgDeposit
|
||||
func NewMsgDeposit(owner sdk.AccAddress, depositor sdk.AccAddress, collateral sdk.Coin) MsgDeposit {
|
||||
func NewMsgDeposit(owner sdk.AccAddress, depositor sdk.AccAddress, collateral sdk.Coin, collateralType string) MsgDeposit {
|
||||
return MsgDeposit{
|
||||
Owner: owner,
|
||||
Depositor: depositor,
|
||||
Collateral: collateral,
|
||||
Owner: owner,
|
||||
Depositor: depositor,
|
||||
Collateral: collateral,
|
||||
CollateralType: collateralType,
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,6 +114,9 @@ func (msg MsgDeposit) ValidateBasic() error {
|
||||
if !msg.Collateral.IsValid() || msg.Collateral.IsZero() {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "collateral amount %s", msg.Collateral)
|
||||
}
|
||||
if strings.TrimSpace(msg.CollateralType) == "" {
|
||||
return fmt.Errorf("collateral type cannot be empty")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -127,22 +137,25 @@ func (msg MsgDeposit) String() string {
|
||||
Sender: %s
|
||||
Owner: %s
|
||||
Collateral: %s
|
||||
`, msg.Owner, msg.Owner, msg.Collateral)
|
||||
CollateralType: %s
|
||||
`, msg.Owner, msg.Owner, msg.Collateral, msg.CollateralType)
|
||||
}
|
||||
|
||||
// MsgWithdraw withdraw collateral from an existing cdp.
|
||||
type MsgWithdraw struct {
|
||||
Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"`
|
||||
Owner sdk.AccAddress `json:"owner" yaml:"owner"`
|
||||
Collateral sdk.Coin `json:"collateral" yaml:"collateral"`
|
||||
Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"`
|
||||
Owner sdk.AccAddress `json:"owner" yaml:"owner"`
|
||||
Collateral sdk.Coin `json:"collateral" yaml:"collateral"`
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
}
|
||||
|
||||
// NewMsgWithdraw returns a new MsgDeposit
|
||||
func NewMsgWithdraw(owner sdk.AccAddress, depositor sdk.AccAddress, collateral sdk.Coin) MsgWithdraw {
|
||||
func NewMsgWithdraw(owner sdk.AccAddress, depositor sdk.AccAddress, collateral sdk.Coin, collateralType string) MsgWithdraw {
|
||||
return MsgWithdraw{
|
||||
Owner: owner,
|
||||
Depositor: depositor,
|
||||
Collateral: collateral,
|
||||
Owner: owner,
|
||||
Depositor: depositor,
|
||||
Collateral: collateral,
|
||||
CollateralType: collateralType,
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,6 +176,9 @@ func (msg MsgWithdraw) ValidateBasic() error {
|
||||
if !msg.Collateral.IsValid() || msg.Collateral.IsZero() {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "collateral amount %s", msg.Collateral)
|
||||
}
|
||||
if strings.TrimSpace(msg.CollateralType) == "" {
|
||||
return fmt.Errorf("collateral type cannot be empty")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -188,17 +204,17 @@ func (msg MsgWithdraw) String() string {
|
||||
|
||||
// MsgDrawDebt draw debt off of collateral in cdp
|
||||
type MsgDrawDebt struct {
|
||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||
CdpDenom string `json:"cdp_denom" yaml:"cdp_denom"`
|
||||
Principal sdk.Coin `json:"principal" yaml:"principal"`
|
||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
Principal sdk.Coin `json:"principal" yaml:"principal"`
|
||||
}
|
||||
|
||||
// NewMsgDrawDebt returns a new MsgDrawDebt
|
||||
func NewMsgDrawDebt(sender sdk.AccAddress, denom string, principal sdk.Coin) MsgDrawDebt {
|
||||
func NewMsgDrawDebt(sender sdk.AccAddress, collateralType string, principal sdk.Coin) MsgDrawDebt {
|
||||
return MsgDrawDebt{
|
||||
Sender: sender,
|
||||
CdpDenom: denom,
|
||||
Principal: principal,
|
||||
Sender: sender,
|
||||
CollateralType: collateralType,
|
||||
Principal: principal,
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,8 +229,8 @@ func (msg MsgDrawDebt) ValidateBasic() error {
|
||||
if msg.Sender.Empty() {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be empty")
|
||||
}
|
||||
if strings.TrimSpace(msg.CdpDenom) == "" {
|
||||
return errors.New("cdp denom cannot be blank")
|
||||
if strings.TrimSpace(msg.CollateralType) == "" {
|
||||
return errors.New("cdp collateral type cannot be blank")
|
||||
}
|
||||
if msg.Principal.IsZero() || !msg.Principal.IsValid() {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "principal amount %s", msg.Principal)
|
||||
@ -237,24 +253,24 @@ func (msg MsgDrawDebt) GetSigners() []sdk.AccAddress {
|
||||
func (msg MsgDrawDebt) String() string {
|
||||
return fmt.Sprintf(`Draw debt from CDP Message:
|
||||
Sender: %s
|
||||
CDP Denom: %s
|
||||
Collateral Type: %s
|
||||
Principal: %s
|
||||
`, msg.Sender, msg.CdpDenom, msg.Principal)
|
||||
`, msg.Sender, msg.CollateralType, msg.Principal)
|
||||
}
|
||||
|
||||
// MsgRepayDebt repay debt drawn off the collateral in a CDP
|
||||
type MsgRepayDebt struct {
|
||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||
CdpDenom string `json:"cdp_denom" yaml:"cdp_denom"`
|
||||
Payment sdk.Coin `json:"payment" yaml:"payment"`
|
||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
Payment sdk.Coin `json:"payment" yaml:"payment"`
|
||||
}
|
||||
|
||||
// NewMsgRepayDebt returns a new MsgRepayDebt
|
||||
func NewMsgRepayDebt(sender sdk.AccAddress, denom string, payment sdk.Coin) MsgRepayDebt {
|
||||
func NewMsgRepayDebt(sender sdk.AccAddress, collateralType string, payment sdk.Coin) MsgRepayDebt {
|
||||
return MsgRepayDebt{
|
||||
Sender: sender,
|
||||
CdpDenom: denom,
|
||||
Payment: payment,
|
||||
Sender: sender,
|
||||
CollateralType: collateralType,
|
||||
Payment: payment,
|
||||
}
|
||||
}
|
||||
|
||||
@ -269,8 +285,8 @@ func (msg MsgRepayDebt) ValidateBasic() error {
|
||||
if msg.Sender.Empty() {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be empty")
|
||||
}
|
||||
if strings.TrimSpace(msg.CdpDenom) == "" {
|
||||
return errors.New("cdp denom cannot be blank")
|
||||
if strings.TrimSpace(msg.CollateralType) == "" {
|
||||
return errors.New("cdp collateral type cannot be blank")
|
||||
}
|
||||
if msg.Payment.IsZero() || !msg.Payment.IsValid() {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "payment amount %s", msg.Payment)
|
||||
@ -293,7 +309,7 @@ func (msg MsgRepayDebt) GetSigners() []sdk.AccAddress {
|
||||
func (msg MsgRepayDebt) String() string {
|
||||
return fmt.Sprintf(`Draw debt from CDP Message:
|
||||
Sender: %s
|
||||
CDP Denom: %s
|
||||
Collateral Type: %s
|
||||
Payment: %s
|
||||
`, msg.Sender, msg.CdpDenom, msg.Payment)
|
||||
`, msg.Sender, msg.CollateralType, msg.Payment)
|
||||
}
|
||||
|
@ -19,16 +19,18 @@ var (
|
||||
|
||||
func TestMsgCreateCDP(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
sender sdk.AccAddress
|
||||
collateral sdk.Coin
|
||||
principal sdk.Coin
|
||||
expectPass bool
|
||||
description string
|
||||
sender sdk.AccAddress
|
||||
collateral sdk.Coin
|
||||
principal sdk.Coin
|
||||
collateralType string
|
||||
expectPass bool
|
||||
}{
|
||||
{"create cdp", addrs[0], coinsSingle, coinsSingle, true},
|
||||
{"create cdp no collateral", addrs[0], coinsZero, coinsSingle, false},
|
||||
{"create cdp no debt", addrs[0], coinsSingle, coinsZero, false},
|
||||
{"create cdp empty owner", sdk.AccAddress{}, coinsSingle, coinsSingle, false},
|
||||
{"create cdp", addrs[0], coinsSingle, coinsSingle, "type-a", true},
|
||||
{"create cdp no collateral", addrs[0], coinsZero, coinsSingle, "type-a", false},
|
||||
{"create cdp no debt", addrs[0], coinsSingle, coinsZero, "type-a", false},
|
||||
{"create cdp empty owner", sdk.AccAddress{}, coinsSingle, coinsSingle, "type-a", false},
|
||||
{"create cdp empty type", addrs[0], coinsSingle, coinsSingle, "", false},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
@ -36,6 +38,7 @@ func TestMsgCreateCDP(t *testing.T) {
|
||||
tc.sender,
|
||||
tc.collateral,
|
||||
tc.principal,
|
||||
tc.collateralType,
|
||||
)
|
||||
if tc.expectPass {
|
||||
require.NoError(t, msg.ValidateBasic(), "test: %v", tc.description)
|
||||
@ -47,17 +50,19 @@ func TestMsgCreateCDP(t *testing.T) {
|
||||
|
||||
func TestMsgDeposit(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
sender sdk.AccAddress
|
||||
depositor sdk.AccAddress
|
||||
collateral sdk.Coin
|
||||
expectPass bool
|
||||
description string
|
||||
sender sdk.AccAddress
|
||||
depositor sdk.AccAddress
|
||||
collateral sdk.Coin
|
||||
collateralType string
|
||||
expectPass bool
|
||||
}{
|
||||
{"deposit", addrs[0], addrs[1], coinsSingle, true},
|
||||
{"deposit", addrs[0], addrs[0], coinsSingle, true},
|
||||
{"deposit no collateral", addrs[0], addrs[1], coinsZero, false},
|
||||
{"deposit empty owner", sdk.AccAddress{}, addrs[1], coinsSingle, false},
|
||||
{"deposit empty depositor", addrs[0], sdk.AccAddress{}, coinsSingle, false},
|
||||
{"deposit", addrs[0], addrs[1], coinsSingle, "type-a", true},
|
||||
{"deposit same owner", addrs[0], addrs[0], coinsSingle, "type-a", true},
|
||||
{"deposit no collateral", addrs[0], addrs[1], coinsZero, "type-a", false},
|
||||
{"deposit empty owner", sdk.AccAddress{}, addrs[1], coinsSingle, "type-a", false},
|
||||
{"deposit empty depositor", addrs[0], sdk.AccAddress{}, coinsSingle, "type-a", false},
|
||||
{"deposit empty type", addrs[0], addrs[0], coinsSingle, "", false},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
@ -65,6 +70,7 @@ func TestMsgDeposit(t *testing.T) {
|
||||
tc.sender,
|
||||
tc.depositor,
|
||||
tc.collateral,
|
||||
tc.collateralType,
|
||||
)
|
||||
if tc.expectPass {
|
||||
require.NoError(t, msg.ValidateBasic(), "test: %v", tc.description)
|
||||
@ -76,17 +82,19 @@ func TestMsgDeposit(t *testing.T) {
|
||||
|
||||
func TestMsgWithdraw(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
sender sdk.AccAddress
|
||||
depositor sdk.AccAddress
|
||||
collateral sdk.Coin
|
||||
expectPass bool
|
||||
description string
|
||||
sender sdk.AccAddress
|
||||
depositor sdk.AccAddress
|
||||
collateral sdk.Coin
|
||||
collateralType string
|
||||
expectPass bool
|
||||
}{
|
||||
{"withdraw", addrs[0], addrs[1], coinsSingle, true},
|
||||
{"withdraw", addrs[0], addrs[0], coinsSingle, true},
|
||||
{"withdraw no collateral", addrs[0], addrs[1], coinsZero, false},
|
||||
{"withdraw empty owner", sdk.AccAddress{}, addrs[1], coinsSingle, false},
|
||||
{"withdraw empty depositor", addrs[0], sdk.AccAddress{}, coinsSingle, false},
|
||||
{"withdraw", addrs[0], addrs[1], coinsSingle, "type-a", true},
|
||||
{"withdraw", addrs[0], addrs[0], coinsSingle, "type-a", true},
|
||||
{"withdraw no collateral", addrs[0], addrs[1], coinsZero, "type-a", false},
|
||||
{"withdraw empty owner", sdk.AccAddress{}, addrs[1], coinsSingle, "type-a", false},
|
||||
{"withdraw empty depositor", addrs[0], sdk.AccAddress{}, coinsSingle, "type-a", false},
|
||||
{"withdraw empty type", addrs[0], addrs[0], coinsSingle, "", false},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
@ -94,6 +102,7 @@ func TestMsgWithdraw(t *testing.T) {
|
||||
tc.sender,
|
||||
tc.depositor,
|
||||
tc.collateral,
|
||||
tc.collateralType,
|
||||
)
|
||||
if tc.expectPass {
|
||||
require.NoError(t, msg.ValidateBasic(), "test: %v", tc.description)
|
||||
@ -105,11 +114,11 @@ func TestMsgWithdraw(t *testing.T) {
|
||||
|
||||
func TestMsgDrawDebt(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
sender sdk.AccAddress
|
||||
denom string
|
||||
principal sdk.Coin
|
||||
expectPass bool
|
||||
description string
|
||||
sender sdk.AccAddress
|
||||
collateralType string
|
||||
principal sdk.Coin
|
||||
expectPass bool
|
||||
}{
|
||||
{"draw debt", addrs[0], sdk.DefaultBondDenom, coinsSingle, true},
|
||||
{"draw debt no debt", addrs[0], sdk.DefaultBondDenom, coinsZero, false},
|
||||
@ -120,7 +129,7 @@ func TestMsgDrawDebt(t *testing.T) {
|
||||
for _, tc := range tests {
|
||||
msg := NewMsgDrawDebt(
|
||||
tc.sender,
|
||||
tc.denom,
|
||||
tc.collateralType,
|
||||
tc.principal,
|
||||
)
|
||||
if tc.expectPass {
|
||||
|
@ -107,7 +107,8 @@ func DefaultParams() Params {
|
||||
|
||||
// CollateralParam governance parameters for each collateral type within the cdp module
|
||||
type CollateralParam struct {
|
||||
Denom string `json:"denom" yaml:"denom"` // Coin name of collateral type
|
||||
Denom string `json:"denom" yaml:"denom"` // Coin name of collateral type
|
||||
Type string `json:"type" yaml:"type"`
|
||||
LiquidationRatio sdk.Dec `json:"liquidation_ratio" yaml:"liquidation_ratio"` // The ratio (Collateral (priced in stable coin) / Debt) under which a CDP will be liquidated
|
||||
DebtLimit sdk.Coin `json:"debt_limit" yaml:"debt_limit"` // Maximum amount of debt allowed to be drawn from this collateral type
|
||||
StabilityFee sdk.Dec `json:"stability_fee" yaml:"stability_fee"` // per second stability fee for loans opened using this collateral
|
||||
@ -123,6 +124,7 @@ type CollateralParam struct {
|
||||
func (cp CollateralParam) String() string {
|
||||
return fmt.Sprintf(`Collateral:
|
||||
Denom: %s
|
||||
Type: %s
|
||||
Liquidation Ratio: %s
|
||||
Stability Fee: %s
|
||||
Liquidation Penalty: %s
|
||||
@ -132,7 +134,7 @@ func (cp CollateralParam) String() string {
|
||||
Spot Market ID: %s
|
||||
Liquidation Market ID: %s
|
||||
Conversion Factor: %s`,
|
||||
cp.Denom, cp.LiquidationRatio, cp.StabilityFee, cp.LiquidationPenalty, cp.DebtLimit, cp.AuctionSize, cp.Prefix, cp.SpotMarketID, cp.LiquidationMarketID, cp.ConversionFactor)
|
||||
cp.Denom, cp.Type, cp.LiquidationRatio, cp.StabilityFee, cp.LiquidationPenalty, cp.DebtLimit, cp.AuctionSize, cp.Prefix, cp.SpotMarketID, cp.LiquidationMarketID, cp.ConversionFactor)
|
||||
}
|
||||
|
||||
// CollateralParams array of CollateralParam
|
||||
@ -299,8 +301,8 @@ func validateCollateralParams(i interface{}) error {
|
||||
return fmt.Errorf("invalid parameter type: %T", i)
|
||||
}
|
||||
|
||||
collateralDupMap := make(map[string]bool)
|
||||
prefixDupMap := make(map[int]bool)
|
||||
typeDupMap := make(map[string]bool)
|
||||
for _, cp := range collateralParams {
|
||||
if err := sdk.ValidateDenom(cp.Denom); err != nil {
|
||||
return fmt.Errorf("collateral denom invalid %s", cp.Denom)
|
||||
@ -310,6 +312,10 @@ func validateCollateralParams(i interface{}) error {
|
||||
return fmt.Errorf("spot market id cannot be blank %s", cp)
|
||||
}
|
||||
|
||||
if strings.TrimSpace(cp.Type) == "" {
|
||||
return fmt.Errorf("collateral type cannot be blank %s", cp)
|
||||
}
|
||||
|
||||
if strings.TrimSpace(cp.LiquidationMarketID) == "" {
|
||||
return fmt.Errorf("liquidation market id cannot be blank %s", cp)
|
||||
}
|
||||
@ -326,12 +332,11 @@ func validateCollateralParams(i interface{}) error {
|
||||
|
||||
prefixDupMap[prefix] = true
|
||||
|
||||
_, found = collateralDupMap[cp.Denom]
|
||||
_, found = typeDupMap[cp.Type]
|
||||
if found {
|
||||
return fmt.Errorf("duplicate collateral denom: %s", cp.Denom)
|
||||
return fmt.Errorf("duplicate cdp collateral type: %s", cp.Type)
|
||||
}
|
||||
|
||||
collateralDupMap[cp.Denom] = true
|
||||
typeDupMap[cp.Type] = true
|
||||
|
||||
if !cp.DebtLimit.IsValid() {
|
||||
return fmt.Errorf("debt limit for all collaterals should be positive, is %s for %s", cp.DebtLimit, cp.Denom)
|
||||
|
@ -66,6 +66,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
collateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
@ -103,6 +104,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
collateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
@ -140,6 +142,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
collateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
@ -177,6 +180,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
collateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
@ -189,6 +193,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
},
|
||||
{
|
||||
Denom: "xrp",
|
||||
Type: "xrp-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
@ -226,6 +231,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
collateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
@ -238,6 +244,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
},
|
||||
{
|
||||
Denom: "xrp",
|
||||
Type: "xrp-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
@ -275,6 +282,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
collateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
@ -287,6 +295,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
},
|
||||
{
|
||||
Denom: "xrp",
|
||||
Type: "xrp-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("susd", 2000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
@ -361,6 +370,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
collateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
@ -392,12 +402,13 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid collateral params duplicate denom",
|
||||
name: "invalid collateral params duplicate denom + type",
|
||||
args: args{
|
||||
globalDebtLimit: sdk.NewInt64Coin("usdx", 2000000000000),
|
||||
collateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
@ -410,6 +421,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
},
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
@ -437,7 +449,58 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
contains: "duplicate collateral denom",
|
||||
contains: "duplicate cdp collateral type",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid collateral params duplicate denom + different type",
|
||||
args: args{
|
||||
globalDebtLimit: sdk.NewInt64Coin("usdx", 2000000000000),
|
||||
collateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
LiquidationPenalty: sdk.MustNewDecFromStr("0.05"),
|
||||
AuctionSize: sdk.NewInt(50000000000),
|
||||
Prefix: 0x20,
|
||||
SpotMarketID: "bnb:usd",
|
||||
LiquidationMarketID: "bnb:usd",
|
||||
ConversionFactor: sdk.NewInt(8),
|
||||
},
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-b",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
LiquidationPenalty: sdk.MustNewDecFromStr("0.05"),
|
||||
AuctionSize: sdk.NewInt(50000000000),
|
||||
Prefix: 0x21,
|
||||
SpotMarketID: "bnb:usd",
|
||||
LiquidationMarketID: "bnb:usd",
|
||||
ConversionFactor: sdk.NewInt(8),
|
||||
},
|
||||
},
|
||||
debtParam: types.DebtParam{
|
||||
Denom: "usdx",
|
||||
ReferenceAsset: "usd",
|
||||
ConversionFactor: sdk.NewInt(6),
|
||||
DebtFloor: sdk.NewInt(10000000),
|
||||
SavingsRate: sdk.MustNewDecFromStr("0.95"),
|
||||
},
|
||||
surplusThreshold: types.DefaultSurplusThreshold,
|
||||
surplusLot: types.DefaultSurplusLot,
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
distributionFreq: types.DefaultSavingsDistributionFrequency,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: true,
|
||||
contains: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -447,6 +510,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
collateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
@ -459,6 +523,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
},
|
||||
{
|
||||
Denom: "xrp",
|
||||
Type: "xrp-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
@ -496,6 +561,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
collateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.Coin{},
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
@ -533,6 +599,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
collateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
@ -570,6 +637,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
collateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
@ -607,6 +675,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
collateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.1"),
|
||||
@ -644,6 +713,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
collateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
@ -681,6 +751,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
collateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 2000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"),
|
||||
|
@ -13,60 +13,60 @@ const (
|
||||
QueryGetParams = "params"
|
||||
QueryGetAccounts = "accounts"
|
||||
RestOwner = "owner"
|
||||
RestCollateralDenom = "collateral-denom"
|
||||
RestCollateralType = "collateral-type"
|
||||
RestRatio = "ratio"
|
||||
)
|
||||
|
||||
// QueryCdpsParams params for query /cdp/cdps
|
||||
type QueryCdpsParams struct {
|
||||
CollateralDenom string // get CDPs with this collateral denom
|
||||
CollateralType string // get CDPs with this collateral type
|
||||
}
|
||||
|
||||
// NewQueryCdpsParams returns QueryCdpsParams
|
||||
func NewQueryCdpsParams(denom string) QueryCdpsParams {
|
||||
func NewQueryCdpsParams(collateralType string) QueryCdpsParams {
|
||||
return QueryCdpsParams{
|
||||
CollateralDenom: denom,
|
||||
CollateralType: collateralType,
|
||||
}
|
||||
}
|
||||
|
||||
// QueryCdpParams params for query /cdp/cdp
|
||||
type QueryCdpParams struct {
|
||||
CollateralDenom string // get CDPs with this collateral denom
|
||||
Owner sdk.AccAddress // get CDPs belonging to this owner
|
||||
CollateralType string // get CDPs with this collateral type
|
||||
Owner sdk.AccAddress // get CDPs belonging to this owner
|
||||
}
|
||||
|
||||
// NewQueryCdpParams returns QueryCdpParams
|
||||
func NewQueryCdpParams(owner sdk.AccAddress, denom string) QueryCdpParams {
|
||||
func NewQueryCdpParams(owner sdk.AccAddress, collateralType string) QueryCdpParams {
|
||||
return QueryCdpParams{
|
||||
Owner: owner,
|
||||
CollateralDenom: denom,
|
||||
Owner: owner,
|
||||
CollateralType: collateralType,
|
||||
}
|
||||
}
|
||||
|
||||
// QueryCdpDeposits params for query /cdp/deposits
|
||||
type QueryCdpDeposits struct {
|
||||
CollateralDenom string // get CDPs with this collateral denom
|
||||
Owner sdk.AccAddress // get CDPs belonging to this owner
|
||||
CollateralType string // get CDPs with this collateral type
|
||||
Owner sdk.AccAddress // get CDPs belonging to this owner
|
||||
}
|
||||
|
||||
// NewQueryCdpDeposits returns QueryCdpDeposits
|
||||
func NewQueryCdpDeposits(owner sdk.AccAddress, denom string) QueryCdpDeposits {
|
||||
func NewQueryCdpDeposits(owner sdk.AccAddress, collateralType string) QueryCdpDeposits {
|
||||
return QueryCdpDeposits{
|
||||
Owner: owner,
|
||||
CollateralDenom: denom,
|
||||
Owner: owner,
|
||||
CollateralType: collateralType,
|
||||
}
|
||||
}
|
||||
|
||||
// QueryCdpsByRatioParams params for query /cdp/cdps/ratio
|
||||
type QueryCdpsByRatioParams struct {
|
||||
CollateralDenom string // get CDPs with this collateral denom
|
||||
Ratio sdk.Dec // get CDPs below this collateral:debt ratio
|
||||
CollateralType string
|
||||
Ratio sdk.Dec // get CDPs below this collateral:debt ratio
|
||||
}
|
||||
|
||||
// NewQueryCdpsByRatioParams returns QueryCdpsByRatioParams
|
||||
func NewQueryCdpsByRatioParams(denom string, ratio sdk.Dec) QueryCdpsByRatioParams {
|
||||
func NewQueryCdpsByRatioParams(collateralType string, ratio sdk.Dec) QueryCdpsByRatioParams {
|
||||
return QueryCdpsByRatioParams{
|
||||
CollateralDenom: denom,
|
||||
Ratio: ratio,
|
||||
CollateralType: collateralType,
|
||||
Ratio: ratio,
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ func (suite *PermissionTestSuite) TestSubParamChangePermission_Allows() {
|
||||
testCPs := cdptypes.CollateralParams{
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: d("2.0"),
|
||||
DebtLimit: c("usdx", 1000000000000),
|
||||
StabilityFee: d("1.000000001547125958"),
|
||||
@ -44,6 +45,7 @@ func (suite *PermissionTestSuite) TestSubParamChangePermission_Allows() {
|
||||
},
|
||||
{
|
||||
Denom: "btc",
|
||||
Type: "btc-a",
|
||||
LiquidationRatio: d("1.5"),
|
||||
DebtLimit: c("usdx", 1000000000),
|
||||
StabilityFee: d("1.000000001547125958"),
|
||||
|
@ -87,6 +87,7 @@ func (suite *KeeperTestSuite) TestSubmitProposal() {
|
||||
|
||||
testCP := cdptypes.CollateralParams{{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: d("1.5"),
|
||||
DebtLimit: c("usdx", 1000000000000),
|
||||
StabilityFee: d("1.000000001547125958"), // %5 apr
|
||||
|
@ -28,7 +28,7 @@ const (
|
||||
QuerierRoute = types.QuerierRoute
|
||||
QueryGetClaims = types.QueryGetClaims
|
||||
RestClaimOwner = types.RestClaimOwner
|
||||
RestClaimDenom = types.RestClaimDenom
|
||||
RestClaimCollateralType = types.RestClaimCollateralType
|
||||
QueryGetParams = types.QueryGetParams
|
||||
)
|
||||
|
||||
|
@ -51,8 +51,8 @@ func queryClaimsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
return err
|
||||
}
|
||||
bz, err := cdc.MarshalJSON(types.QueryClaimsParams{
|
||||
Owner: ownerAddress,
|
||||
Denom: args[1],
|
||||
Owner: ownerAddress,
|
||||
CollateralType: args[1],
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -34,7 +34,7 @@ func queryClaimsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
|
||||
vars := mux.Vars(r)
|
||||
ownerBech32 := vars[types.RestClaimOwner]
|
||||
denom := vars[types.RestClaimDenom]
|
||||
denom := vars[types.RestClaimCollateralType]
|
||||
|
||||
owner, err := sdk.AccAddressFromBech32(ownerBech32)
|
||||
if err != nil {
|
||||
|
@ -42,7 +42,7 @@ func postClaimHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
msg := types.NewMsgClaimReward(requestBody.Sender, requestBody.Denom)
|
||||
msg := types.NewMsgClaimReward(requestBody.Sender, requestBody.CollateralType)
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
|
@ -25,7 +25,7 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, supplyKeeper types.SupplyKeep
|
||||
k.SetParams(ctx, gs.Params)
|
||||
|
||||
for _, r := range gs.Params.Rewards {
|
||||
k.SetNextClaimPeriodID(ctx, r.Denom, 1)
|
||||
k.SetNextClaimPeriodID(ctx, r.CollateralType, 1)
|
||||
}
|
||||
|
||||
// only set the previous block time if it's different than default
|
||||
@ -47,7 +47,7 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, supplyKeeper types.SupplyKeep
|
||||
}
|
||||
|
||||
for _, id := range gs.NextClaimPeriodIDs {
|
||||
k.SetNextClaimPeriodID(ctx, id.Denom, id.ID)
|
||||
k.SetNextClaimPeriodID(ctx, id.CollateralType, id.ID)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,13 +24,13 @@ func NewHandler(k keeper.Keeper) sdk.Handler {
|
||||
|
||||
func handleMsgClaimReward(ctx sdk.Context, k keeper.Keeper, msg types.MsgClaimReward) (*sdk.Result, error) {
|
||||
|
||||
claims, found := k.GetClaimsByAddressAndDenom(ctx, msg.Sender, msg.Denom)
|
||||
claims, found := k.GetClaimsByAddressAndCollateralType(ctx, msg.Sender, msg.CollateralType)
|
||||
if !found {
|
||||
return nil, sdkerrors.Wrapf(types.ErrNoClaimsFound, "address: %s, denom: %s", msg.Sender, msg.Denom)
|
||||
return nil, sdkerrors.Wrapf(types.ErrNoClaimsFound, "address: %s, collateral type: %s", msg.Sender, msg.CollateralType)
|
||||
}
|
||||
|
||||
for _, claim := range claims {
|
||||
err := k.PayoutClaim(ctx, claim.Owner, claim.Denom, claim.ClaimPeriodID)
|
||||
err := k.PayoutClaim(ctx, claim.Owner, claim.CollateralType, claim.ClaimPeriodID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -37,10 +37,10 @@ func NewKeeper(
|
||||
}
|
||||
}
|
||||
|
||||
// GetRewardPeriod returns the reward period from the store for the input denom and a boolean for if it was found
|
||||
func (k Keeper) GetRewardPeriod(ctx sdk.Context, denom string) (types.RewardPeriod, bool) {
|
||||
// GetRewardPeriod returns the reward period from the store for the input collateral type and a boolean for if it was found
|
||||
func (k Keeper) GetRewardPeriod(ctx sdk.Context, collateralType string) (types.RewardPeriod, bool) {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.RewardPeriodKeyPrefix)
|
||||
bz := store.Get([]byte(denom))
|
||||
bz := store.Get([]byte(collateralType))
|
||||
if bz == nil {
|
||||
return types.RewardPeriod{}, false
|
||||
}
|
||||
@ -53,13 +53,13 @@ func (k Keeper) GetRewardPeriod(ctx sdk.Context, denom string) (types.RewardPeri
|
||||
func (k Keeper) SetRewardPeriod(ctx sdk.Context, rp types.RewardPeriod) {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.RewardPeriodKeyPrefix)
|
||||
bz := k.cdc.MustMarshalBinaryBare(rp)
|
||||
store.Set([]byte(rp.Denom), bz)
|
||||
store.Set([]byte(rp.CollateralType), bz)
|
||||
}
|
||||
|
||||
// DeleteRewardPeriod deletes the reward period in the store for the input denom,
|
||||
func (k Keeper) DeleteRewardPeriod(ctx sdk.Context, denom string) {
|
||||
// DeleteRewardPeriod deletes the reward period in the store for the input collateral type,
|
||||
func (k Keeper) DeleteRewardPeriod(ctx sdk.Context, collateralType string) {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.RewardPeriodKeyPrefix)
|
||||
store.Delete([]byte(denom))
|
||||
store.Delete([]byte(collateralType))
|
||||
}
|
||||
|
||||
// IterateRewardPeriods iterates over all reward period objects in the store and preforms a callback function
|
||||
@ -86,44 +86,44 @@ func (k Keeper) GetAllRewardPeriods(ctx sdk.Context) types.RewardPeriods {
|
||||
return rps
|
||||
}
|
||||
|
||||
// GetNextClaimPeriodID returns the highest claim period id in the store for the input denom
|
||||
func (k Keeper) GetNextClaimPeriodID(ctx sdk.Context, denom string) uint64 {
|
||||
// GetNextClaimPeriodID returns the highest claim period id in the store for the input collateral type
|
||||
func (k Keeper) GetNextClaimPeriodID(ctx sdk.Context, collateralType string) uint64 {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.NextClaimPeriodIDPrefix)
|
||||
bz := store.Get([]byte(denom))
|
||||
bz := store.Get([]byte(collateralType))
|
||||
if bz == nil {
|
||||
k.SetNextClaimPeriodID(ctx, denom, 1)
|
||||
k.SetNextClaimPeriodID(ctx, collateralType, 1)
|
||||
return uint64(1)
|
||||
}
|
||||
return types.BytesToUint64(bz)
|
||||
}
|
||||
|
||||
// SetNextClaimPeriodID sets the highest claim period id in the store for the input denom
|
||||
func (k Keeper) SetNextClaimPeriodID(ctx sdk.Context, denom string, id uint64) {
|
||||
// SetNextClaimPeriodID sets the highest claim period id in the store for the input collateral type
|
||||
func (k Keeper) SetNextClaimPeriodID(ctx sdk.Context, collateralType string, id uint64) {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.NextClaimPeriodIDPrefix)
|
||||
store.Set([]byte(denom), sdk.Uint64ToBigEndian(id))
|
||||
store.Set([]byte(collateralType), sdk.Uint64ToBigEndian(id))
|
||||
}
|
||||
|
||||
// IterateClaimPeriodIDKeysAndValues iterates over the claim period id (value) and denom (key) of each claim period id in the store and performs a callback function
|
||||
func (k Keeper) IterateClaimPeriodIDKeysAndValues(ctx sdk.Context, cb func(denom string, id uint64) (stop bool)) {
|
||||
// IterateClaimPeriodIDKeysAndValues iterates over the claim period id (value) and collateral type (key) of each claim period id in the store and performs a callback function
|
||||
func (k Keeper) IterateClaimPeriodIDKeysAndValues(ctx sdk.Context, cb func(collateralType string, id uint64) (stop bool)) {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.NextClaimPeriodIDPrefix)
|
||||
iterator := sdk.KVStorePrefixIterator(store, []byte{})
|
||||
defer iterator.Close()
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
id := types.BytesToUint64(iterator.Value())
|
||||
denom := string(iterator.Key())
|
||||
if cb(denom, id) {
|
||||
collateralType := string(iterator.Key())
|
||||
if cb(collateralType, id) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetAllClaimPeriodIDPairs returns all denom:nextClaimPeriodID pairs in the store
|
||||
// GetAllClaimPeriodIDPairs returns all collateralType:nextClaimPeriodID pairs in the store
|
||||
func (k Keeper) GetAllClaimPeriodIDPairs(ctx sdk.Context) types.GenesisClaimPeriodIDs {
|
||||
ids := types.GenesisClaimPeriodIDs{}
|
||||
k.IterateClaimPeriodIDKeysAndValues(ctx, func(denom string, id uint64) (stop bool) {
|
||||
k.IterateClaimPeriodIDKeysAndValues(ctx, func(collateralType string, id uint64) (stop bool) {
|
||||
genID := types.GenesisClaimPeriodID{
|
||||
Denom: denom,
|
||||
ID: id,
|
||||
CollateralType: collateralType,
|
||||
ID: id,
|
||||
}
|
||||
ids = append(ids, genID)
|
||||
return false
|
||||
@ -131,11 +131,11 @@ func (k Keeper) GetAllClaimPeriodIDPairs(ctx sdk.Context) types.GenesisClaimPeri
|
||||
return ids
|
||||
}
|
||||
|
||||
// GetClaimPeriod returns claim period in the store for the input ID and denom and a boolean for if it was found
|
||||
func (k Keeper) GetClaimPeriod(ctx sdk.Context, id uint64, denom string) (types.ClaimPeriod, bool) {
|
||||
// GetClaimPeriod returns claim period in the store for the input ID and collateral type and a boolean for if it was found
|
||||
func (k Keeper) GetClaimPeriod(ctx sdk.Context, id uint64, collateralType string) (types.ClaimPeriod, bool) {
|
||||
var cp types.ClaimPeriod
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimPeriodKeyPrefix)
|
||||
bz := store.Get(types.GetClaimPeriodPrefix(denom, id))
|
||||
bz := store.Get(types.GetClaimPeriodPrefix(collateralType, id))
|
||||
if bz == nil {
|
||||
return types.ClaimPeriod{}, false
|
||||
}
|
||||
@ -143,17 +143,17 @@ func (k Keeper) GetClaimPeriod(ctx sdk.Context, id uint64, denom string) (types.
|
||||
return cp, true
|
||||
}
|
||||
|
||||
// SetClaimPeriod sets the claim period in the store for the input ID and denom
|
||||
// SetClaimPeriod sets the claim period in the store for the input ID and collateral type
|
||||
func (k Keeper) SetClaimPeriod(ctx sdk.Context, cp types.ClaimPeriod) {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimPeriodKeyPrefix)
|
||||
bz := k.cdc.MustMarshalBinaryBare(cp)
|
||||
store.Set(types.GetClaimPeriodPrefix(cp.Denom, cp.ID), bz)
|
||||
store.Set(types.GetClaimPeriodPrefix(cp.CollateralType, cp.ID), bz)
|
||||
}
|
||||
|
||||
// DeleteClaimPeriod deletes the claim period in the store for the input ID and denom
|
||||
func (k Keeper) DeleteClaimPeriod(ctx sdk.Context, id uint64, denom string) {
|
||||
// DeleteClaimPeriod deletes the claim period in the store for the input ID and collateral type
|
||||
func (k Keeper) DeleteClaimPeriod(ctx sdk.Context, id uint64, collateralType string) {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimPeriodKeyPrefix)
|
||||
store.Delete(types.GetClaimPeriodPrefix(denom, id))
|
||||
store.Delete(types.GetClaimPeriodPrefix(collateralType, id))
|
||||
}
|
||||
|
||||
// IterateClaimPeriods iterates over all claim period objects in the store and preforms a callback function
|
||||
@ -180,10 +180,10 @@ func (k Keeper) GetAllClaimPeriods(ctx sdk.Context) types.ClaimPeriods {
|
||||
return cps
|
||||
}
|
||||
|
||||
// GetClaim returns the claim in the store corresponding the the input address denom and id and a boolean for if the claim was found
|
||||
func (k Keeper) GetClaim(ctx sdk.Context, addr sdk.AccAddress, denom string, id uint64) (types.Claim, bool) {
|
||||
// GetClaim returns the claim in the store corresponding the the input address collateral type and id and a boolean for if the claim was found
|
||||
func (k Keeper) GetClaim(ctx sdk.Context, addr sdk.AccAddress, collateralType string, id uint64) (types.Claim, bool) {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimKeyPrefix)
|
||||
bz := store.Get(types.GetClaimPrefix(addr, denom, id))
|
||||
bz := store.Get(types.GetClaimPrefix(addr, collateralType, id))
|
||||
if bz == nil {
|
||||
return types.Claim{}, false
|
||||
}
|
||||
@ -192,18 +192,18 @@ func (k Keeper) GetClaim(ctx sdk.Context, addr sdk.AccAddress, denom string, id
|
||||
return c, true
|
||||
}
|
||||
|
||||
// SetClaim sets the claim in the store corresponding to the input address, denom, and id
|
||||
// SetClaim sets the claim in the store corresponding to the input address, collateral type, and id
|
||||
func (k Keeper) SetClaim(ctx sdk.Context, c types.Claim) {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimKeyPrefix)
|
||||
bz := k.cdc.MustMarshalBinaryBare(c)
|
||||
store.Set(types.GetClaimPrefix(c.Owner, c.Denom, c.ClaimPeriodID), bz)
|
||||
store.Set(types.GetClaimPrefix(c.Owner, c.CollateralType, c.ClaimPeriodID), bz)
|
||||
|
||||
}
|
||||
|
||||
// DeleteClaim deletes the claim in the store corresponding to the input address, denom, and id
|
||||
func (k Keeper) DeleteClaim(ctx sdk.Context, owner sdk.AccAddress, denom string, id uint64) {
|
||||
// DeleteClaim deletes the claim in the store corresponding to the input address, collateral type, and id
|
||||
func (k Keeper) DeleteClaim(ctx sdk.Context, owner sdk.AccAddress, collateralType string, id uint64) {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimKeyPrefix)
|
||||
store.Delete(types.GetClaimPrefix(owner, denom, id))
|
||||
store.Delete(types.GetClaimPrefix(owner, collateralType, id))
|
||||
}
|
||||
|
||||
// IterateClaims iterates over all claim objects in the store and preforms a callback function
|
||||
|
@ -140,8 +140,8 @@ func (suite *KeeperTestSuite) TestIterateMethods() {
|
||||
suite.Equal(2, len(claims))
|
||||
|
||||
var genIDs types.GenesisClaimPeriodIDs
|
||||
suite.keeper.IterateClaimPeriodIDKeysAndValues(suite.ctx, func(denom string, id uint64) (stop bool) {
|
||||
genID := types.GenesisClaimPeriodID{Denom: denom, ID: id}
|
||||
suite.keeper.IterateClaimPeriodIDKeysAndValues(suite.ctx, func(collateralType string, id uint64) (stop bool) {
|
||||
genID := types.GenesisClaimPeriodID{CollateralType: collateralType, ID: id}
|
||||
genIDs = append(genIDs, genID)
|
||||
return false
|
||||
})
|
||||
|
@ -13,21 +13,21 @@ import (
|
||||
)
|
||||
|
||||
// PayoutClaim sends the timelocked claim coins to the input address
|
||||
func (k Keeper) PayoutClaim(ctx sdk.Context, addr sdk.AccAddress, denom string, id uint64) error {
|
||||
claim, found := k.GetClaim(ctx, addr, denom, id)
|
||||
func (k Keeper) PayoutClaim(ctx sdk.Context, addr sdk.AccAddress, collateralType string, id uint64) error {
|
||||
claim, found := k.GetClaim(ctx, addr, collateralType, id)
|
||||
if !found {
|
||||
return sdkerrors.Wrapf(types.ErrClaimNotFound, "id: %d, denom %s, address: %s", id, denom, addr)
|
||||
return sdkerrors.Wrapf(types.ErrClaimNotFound, "id: %d, collateral type %s, address: %s", id, collateralType, addr)
|
||||
}
|
||||
claimPeriod, found := k.GetClaimPeriod(ctx, id, denom)
|
||||
claimPeriod, found := k.GetClaimPeriod(ctx, id, collateralType)
|
||||
if !found {
|
||||
return sdkerrors.Wrapf(types.ErrClaimPeriodNotFound, "id: %d, denom: %s", id, denom)
|
||||
return sdkerrors.Wrapf(types.ErrClaimPeriodNotFound, "id: %d, collateral type: %s", id, collateralType)
|
||||
}
|
||||
err := k.SendTimeLockedCoinsToAccount(ctx, types.IncentiveMacc, addr, sdk.NewCoins(claim.Reward), int64(claimPeriod.TimeLock.Seconds()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
k.DeleteClaim(ctx, addr, denom, id)
|
||||
k.DeleteClaim(ctx, addr, collateralType, id)
|
||||
|
||||
ctx.EventManager().EmitEvent(
|
||||
sdk.NewEvent(
|
||||
@ -97,13 +97,13 @@ func (k Keeper) DeleteExpiredClaimsAndClaimPeriods(ctx sdk.Context) {
|
||||
return false
|
||||
}
|
||||
k.IterateClaims(ctx, func(c types.Claim) (stop bool) {
|
||||
if !(c.Denom == cp.Denom && c.ClaimPeriodID == cp.ID) {
|
||||
if !(c.CollateralType == cp.CollateralType && c.ClaimPeriodID == cp.ID) {
|
||||
return false
|
||||
}
|
||||
k.DeleteClaim(ctx, c.Owner, c.Denom, c.ClaimPeriodID)
|
||||
k.DeleteClaim(ctx, c.Owner, c.CollateralType, c.ClaimPeriodID)
|
||||
return false
|
||||
})
|
||||
k.DeleteClaimPeriod(ctx, cp.ID, cp.Denom)
|
||||
k.DeleteClaimPeriod(ctx, cp.ID, cp.CollateralType)
|
||||
ctx.EventManager().EmitEvent(
|
||||
sdk.NewEvent(
|
||||
types.EventTypeClaimPeriodExpiry,
|
||||
@ -115,14 +115,14 @@ func (k Keeper) DeleteExpiredClaimsAndClaimPeriods(ctx sdk.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// GetClaimsByAddressAndDenom returns all claims for a specific user and address and a bool for if any were found
|
||||
func (k Keeper) GetClaimsByAddressAndDenom(ctx sdk.Context, addr sdk.AccAddress, denom string) (claims types.Claims, found bool) {
|
||||
// GetClaimsByAddressAndCollateralType returns all claims for a specific user and address and a bool for if any were found
|
||||
func (k Keeper) GetClaimsByAddressAndCollateralType(ctx sdk.Context, addr sdk.AccAddress, collateralType string) (claims types.Claims, found bool) {
|
||||
found = false
|
||||
k.IterateClaimPeriods(ctx, func(cp types.ClaimPeriod) (stop bool) {
|
||||
if cp.Denom != denom {
|
||||
if cp.CollateralType != collateralType {
|
||||
return false
|
||||
}
|
||||
c, hasClaim := k.GetClaim(ctx, addr, cp.Denom, cp.ID)
|
||||
c, hasClaim := k.GetClaim(ctx, addr, cp.CollateralType, cp.ID)
|
||||
if !hasClaim {
|
||||
return false
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ func queryGetClaims(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, e
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
|
||||
}
|
||||
claims, _ := k.GetClaimsByAddressAndDenom(ctx, requestParams.Owner, requestParams.Denom)
|
||||
claims, _ := k.GetClaimsByAddressAndCollateralType(ctx, requestParams.Owner, requestParams.CollateralType)
|
||||
|
||||
bz, err := codec.MarshalJSONIndent(k.cdc, claims)
|
||||
if err != nil {
|
||||
|
@ -12,9 +12,9 @@ import (
|
||||
|
||||
// HandleRewardPeriodExpiry deletes expired RewardPeriods from the store and creates a ClaimPeriod in the store for each expired RewardPeriod
|
||||
func (k Keeper) HandleRewardPeriodExpiry(ctx sdk.Context, rp types.RewardPeriod) {
|
||||
k.CreateUniqueClaimPeriod(ctx, rp.Denom, rp.ClaimEnd, rp.ClaimTimeLock)
|
||||
k.CreateUniqueClaimPeriod(ctx, rp.CollateralType, rp.ClaimEnd, rp.ClaimTimeLock)
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.RewardPeriodKeyPrefix)
|
||||
store.Delete([]byte(rp.Denom))
|
||||
store.Delete([]byte(rp.CollateralType))
|
||||
return
|
||||
}
|
||||
|
||||
@ -36,10 +36,10 @@ func (k Keeper) CreateAndDeleteRewardPeriods(ctx sdk.Context) {
|
||||
params := k.GetParams(ctx)
|
||||
|
||||
for _, r := range params.Rewards {
|
||||
_, found := k.GetRewardPeriod(ctx, r.Denom)
|
||||
_, found := k.GetRewardPeriod(ctx, r.CollateralType)
|
||||
// if governance has made a reward inactive, delete the current period
|
||||
if found && !r.Active {
|
||||
k.DeleteRewardPeriod(ctx, r.Denom)
|
||||
k.DeleteRewardPeriod(ctx, r.CollateralType)
|
||||
}
|
||||
// if a reward period for an active reward is not found, create one
|
||||
if !found && r.Active {
|
||||
@ -61,7 +61,7 @@ func (k Keeper) ApplyRewardsToCdps(ctx sdk.Context) {
|
||||
k.IterateRewardPeriods(ctx, func(rp types.RewardPeriod) bool {
|
||||
expired := false
|
||||
// the total amount of usdx created with the collateral type being incentivized
|
||||
totalPrincipal := k.cdpKeeper.GetTotalPrincipal(ctx, rp.Denom, types.PrincipalDenom)
|
||||
totalPrincipal := k.cdpKeeper.GetTotalPrincipal(ctx, rp.CollateralType, types.PrincipalDenom)
|
||||
// the number of seconds since last payout
|
||||
timeElapsed := sdk.NewInt(ctx.BlockTime().Unix() - previousBlockTime.Unix())
|
||||
if rp.End.Before(ctx.BlockTime()) {
|
||||
@ -71,15 +71,15 @@ func (k Keeper) ApplyRewardsToCdps(ctx sdk.Context) {
|
||||
|
||||
// the amount of rewards to pay (rewardAmount * timeElapsed)
|
||||
rewardsThisPeriod := rp.Reward.Amount.Mul(timeElapsed)
|
||||
id := k.GetNextClaimPeriodID(ctx, rp.Denom)
|
||||
k.cdpKeeper.IterateCdpsByDenom(ctx, rp.Denom, func(cdp cdptypes.CDP) bool {
|
||||
id := k.GetNextClaimPeriodID(ctx, rp.CollateralType)
|
||||
k.cdpKeeper.IterateCdpsByCollateralType(ctx, rp.CollateralType, func(cdp cdptypes.CDP) bool {
|
||||
rewardsShare := sdk.NewDecFromInt(cdp.GetTotalPrincipal().Amount).Quo(sdk.NewDecFromInt(totalPrincipal))
|
||||
// sanity check - don't create zero claims
|
||||
if rewardsShare.IsZero() {
|
||||
return false
|
||||
}
|
||||
rewardsEarned := rewardsShare.Mul(sdk.NewDecFromInt(rewardsThisPeriod)).RoundInt()
|
||||
k.AddToClaim(ctx, cdp.Owner, rp.Denom, id, sdk.NewCoin(types.GovDenom, rewardsEarned))
|
||||
k.AddToClaim(ctx, cdp.Owner, rp.CollateralType, id, sdk.NewCoin(types.GovDenom, rewardsEarned))
|
||||
return false
|
||||
})
|
||||
if !expired {
|
||||
@ -93,9 +93,9 @@ func (k Keeper) ApplyRewardsToCdps(ctx sdk.Context) {
|
||||
}
|
||||
|
||||
// CreateUniqueClaimPeriod creates a new claim period in the store and updates the highest claim period id
|
||||
func (k Keeper) CreateUniqueClaimPeriod(ctx sdk.Context, denom string, end time.Time, timeLock time.Duration) {
|
||||
id := k.GetNextClaimPeriodID(ctx, denom)
|
||||
claimPeriod := types.NewClaimPeriod(denom, id, end, timeLock)
|
||||
func (k Keeper) CreateUniqueClaimPeriod(ctx sdk.Context, collateralType string, end time.Time, timeLock time.Duration) {
|
||||
id := k.GetNextClaimPeriodID(ctx, collateralType)
|
||||
claimPeriod := types.NewClaimPeriod(collateralType, id, end, timeLock)
|
||||
ctx.EventManager().EmitEvent(
|
||||
sdk.NewEvent(
|
||||
types.EventTypeClaimPeriod,
|
||||
@ -103,16 +103,16 @@ func (k Keeper) CreateUniqueClaimPeriod(ctx sdk.Context, denom string, end time.
|
||||
),
|
||||
)
|
||||
k.SetClaimPeriod(ctx, claimPeriod)
|
||||
k.SetNextClaimPeriodID(ctx, denom, id+1)
|
||||
k.SetNextClaimPeriodID(ctx, collateralType, id+1)
|
||||
}
|
||||
|
||||
// AddToClaim adds the amount to an existing claim or creates a new one for that amount
|
||||
func (k Keeper) AddToClaim(ctx sdk.Context, addr sdk.AccAddress, denom string, id uint64, amount sdk.Coin) {
|
||||
claim, found := k.GetClaim(ctx, addr, denom, id)
|
||||
func (k Keeper) AddToClaim(ctx sdk.Context, addr sdk.AccAddress, collateralType string, id uint64, amount sdk.Coin) {
|
||||
claim, found := k.GetClaim(ctx, addr, collateralType, id)
|
||||
if found {
|
||||
claim.Reward = claim.Reward.Add(amount)
|
||||
} else {
|
||||
claim = types.NewClaim(addr, amount, denom, id)
|
||||
claim = types.NewClaim(addr, amount, collateralType, id)
|
||||
}
|
||||
k.SetClaim(ctx, claim)
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ func (suite *KeeperTestSuite) TestApplyRewardsToCdps() {
|
||||
})
|
||||
suite.Equal(3, len(claims))
|
||||
// there should be no associated claim period, because the reward period has not ended yet
|
||||
_, found := suite.keeper.GetClaimPeriod(suite.ctx, 1, "bnb")
|
||||
_, found := suite.keeper.GetClaimPeriod(suite.ctx, 1, "bnb-a")
|
||||
suite.False(found)
|
||||
|
||||
// move ctx to the reward period expiry and check that the claim period has been created and the next claim period id has increased
|
||||
@ -128,9 +128,9 @@ func (suite *KeeperTestSuite) TestApplyRewardsToCdps() {
|
||||
// delete the old reward period amd create a new one
|
||||
suite.keeper.CreateAndDeleteRewardPeriods(suite.ctx)
|
||||
})
|
||||
_, found = suite.keeper.GetClaimPeriod(suite.ctx, 1, "bnb")
|
||||
_, found = suite.keeper.GetClaimPeriod(suite.ctx, 1, "bnb-a")
|
||||
suite.True(found)
|
||||
testID := suite.keeper.GetNextClaimPeriodID(suite.ctx, "bnb")
|
||||
testID := suite.keeper.GetNextClaimPeriodID(suite.ctx, "bnb-a")
|
||||
suite.Equal(uint64(2), testID)
|
||||
|
||||
// move the context forward by 100 periods
|
||||
@ -186,6 +186,7 @@ func (suite *KeeperTestSuite) setupCdpChain() {
|
||||
CollateralParams: cdp.CollateralParams{
|
||||
{
|
||||
Denom: "bnb",
|
||||
Type: "bnb-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("2.0"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 1000000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.000000001547125958"), // %5 apr
|
||||
@ -213,10 +214,10 @@ func (suite *KeeperTestSuite) setupCdpChain() {
|
||||
}
|
||||
incentiveGS := types.NewGenesisState(
|
||||
types.NewParams(
|
||||
true, types.Rewards{types.NewReward(true, "bnb", c("ukava", 1000000000), time.Hour*7*24, time.Hour*24*365, time.Hour*7*24)},
|
||||
true, types.Rewards{types.NewReward(true, "bnb-a", c("ukava", 1000000000), time.Hour*7*24, time.Hour*24*365, time.Hour*7*24)},
|
||||
),
|
||||
types.DefaultPreviousBlockTime,
|
||||
types.RewardPeriods{types.NewRewardPeriod("bnb", ctx.BlockTime(), ctx.BlockTime().Add(time.Hour*7*24), c("ukava", 1000), ctx.BlockTime().Add(time.Hour*7*24*2), time.Hour*365*24)},
|
||||
types.RewardPeriods{types.NewRewardPeriod("bnb-a", ctx.BlockTime(), ctx.BlockTime().Add(time.Hour*7*24), c("ukava", 1000), ctx.BlockTime().Add(time.Hour*7*24*2), time.Hour*365*24)},
|
||||
types.ClaimPeriods{},
|
||||
types.Claims{},
|
||||
types.GenesisClaimPeriodIDs{})
|
||||
@ -242,11 +243,11 @@ func (suite *KeeperTestSuite) setupCdpChain() {
|
||||
suite.ctx = ctx
|
||||
// create 3 cdps
|
||||
cdpKeeper := tApp.GetCDPKeeper()
|
||||
err := cdpKeeper.AddCdp(suite.ctx, addrs[0], c("bnb", 10000000000), c("usdx", 10000000))
|
||||
err := cdpKeeper.AddCdp(suite.ctx, addrs[0], c("bnb", 10000000000), c("usdx", 10000000), "bnb-a")
|
||||
suite.Require().NoError(err)
|
||||
err = cdpKeeper.AddCdp(suite.ctx, addrs[1], c("bnb", 100000000000), c("usdx", 100000000))
|
||||
err = cdpKeeper.AddCdp(suite.ctx, addrs[1], c("bnb", 100000000000), c("usdx", 100000000), "bnb-a")
|
||||
suite.Require().NoError(err)
|
||||
err = cdpKeeper.AddCdp(suite.ctx, addrs[2], c("bnb", 1000000000000), c("usdx", 1000000000))
|
||||
err = cdpKeeper.AddCdp(suite.ctx, addrs[2], c("bnb", 1000000000000), c("usdx", 1000000000), "bnb-a")
|
||||
suite.Require().NoError(err)
|
||||
// total usd is 1110
|
||||
|
||||
|
@ -28,7 +28,7 @@ func RandomizedGenState(simState *module.SimulationState) {
|
||||
simState.Cdc.MustUnmarshalJSON(simState.GenState[cdp.ModuleName], &cdpGenesis)
|
||||
if len(CollateralDenoms) == 0 {
|
||||
for _, collateral := range cdpGenesis.Params.CollateralParams {
|
||||
CollateralDenoms = append(CollateralDenoms, collateral.Denom)
|
||||
CollateralDenoms = append(CollateralDenoms, collateral.Type)
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,11 +88,11 @@ func genRewardPeriods(r *rand.Rand, timestamp time.Time, rewards types.Rewards)
|
||||
end := start.Add(reward.Duration).UTC()
|
||||
baseRewardAmount := reward.AvailableRewards.Amount.Quo(sdk.NewInt(100)) // base period reward is 1/100 total reward
|
||||
// Earlier periods have larger rewards
|
||||
amount := sdk.NewCoin(reward.Denom, baseRewardAmount.Mul(sdk.NewInt(int64(i))))
|
||||
amount := sdk.NewCoin("ukava", baseRewardAmount.Mul(sdk.NewInt(int64(i))))
|
||||
claimEnd := end.Add(reward.ClaimDuration)
|
||||
claimTimeLock := reward.TimeLock
|
||||
// Create reward period and append to array
|
||||
rewardPeriods[i] = types.NewRewardPeriod(reward.Denom, start, end, amount, claimEnd, claimTimeLock)
|
||||
rewardPeriods[i] = types.NewRewardPeriod(reward.CollateralType, start, end, amount, claimEnd, claimTimeLock)
|
||||
// Update start time of next reward period
|
||||
rewardPeriodStart = end
|
||||
}
|
||||
@ -105,7 +105,7 @@ func genClaimPeriods(rewardPeriods types.RewardPeriods) types.ClaimPeriods {
|
||||
claimPeriods := make(types.ClaimPeriods, len(rewardPeriods))
|
||||
for i, rewardPeriod := range rewardPeriods {
|
||||
// Increment reward period count for this denom (this is our claim period's ID)
|
||||
denom := rewardPeriod.Denom
|
||||
denom := rewardPeriod.CollateralType
|
||||
numbRewardPeriods := denomRewardPeriodsCount[denom] + 1
|
||||
denomRewardPeriodsCount[denom] = numbRewardPeriods
|
||||
// Set end and timelock from the associated reward period
|
||||
@ -123,11 +123,11 @@ func genNextClaimPeriodIds(cps types.ClaimPeriods) types.GenesisClaimPeriodIDs {
|
||||
mostRecentClaimPeriodByDenom := make(map[string]uint64)
|
||||
var claimPeriodIDs types.GenesisClaimPeriodIDs
|
||||
for _, cp := range cps {
|
||||
if cp.ID <= mostRecentClaimPeriodByDenom[cp.Denom] {
|
||||
if cp.ID <= mostRecentClaimPeriodByDenom[cp.CollateralType] {
|
||||
continue
|
||||
}
|
||||
claimPeriodIDs = append(claimPeriodIDs, types.GenesisClaimPeriodID{Denom: cp.Denom, ID: cp.ID})
|
||||
mostRecentClaimPeriodByDenom[cp.Denom] = cp.ID
|
||||
claimPeriodIDs = append(claimPeriodIDs, types.GenesisClaimPeriodID{CollateralType: cp.CollateralType, ID: cp.ID})
|
||||
mostRecentClaimPeriodByDenom[cp.CollateralType] = cp.ID
|
||||
|
||||
}
|
||||
return claimPeriodIDs
|
||||
|
@ -78,7 +78,7 @@ func SimulateMsgClaimReward(ak auth.AccountKeeper, sk types.SupplyKeeper, k keep
|
||||
claimer, claim, found := findValidAccountClaimPair(accs, openClaims, func(acc simulation.Account, claim types.Claim) bool {
|
||||
if validAccounts[acc.Address.String()] { // Address must be valid type
|
||||
if claim.Owner.Equals(acc.Address) { // Account must be claim owner
|
||||
allClaims, found := k.GetClaimsByAddressAndDenom(ctx, claim.Owner, claim.Denom)
|
||||
allClaims, found := k.GetClaimsByAddressAndCollateralType(ctx, claim.Owner, claim.CollateralType)
|
||||
if found { // found should always be true
|
||||
var rewards sdk.Coins
|
||||
for _, individualClaim := range allClaims {
|
||||
@ -105,7 +105,7 @@ func SimulateMsgClaimReward(ak auth.AccountKeeper, sk types.SupplyKeeper, k keep
|
||||
return simulation.NoOpMsg(types.ModuleName), nil, fmt.Errorf("couldn't find account %s", claimer.Address)
|
||||
}
|
||||
|
||||
msg := types.NewMsgClaimReward(claimer.Address, claim.Denom)
|
||||
msg := types.NewMsgClaimReward(claimer.Address, claim.CollateralType)
|
||||
|
||||
tx := helpers.GenTx(
|
||||
[]sdk.Msg{msg},
|
||||
|
@ -7,9 +7,9 @@ import (
|
||||
// DONTCOVER
|
||||
|
||||
var (
|
||||
ErrClaimNotFound = sdkerrors.Register(ModuleName, 1, "no claim with input id found for owner and denom")
|
||||
ErrClaimPeriodNotFound = sdkerrors.Register(ModuleName, 2, "no claim period found for id and denom")
|
||||
ErrClaimNotFound = sdkerrors.Register(ModuleName, 1, "no claim with input id found for owner and collateral type")
|
||||
ErrClaimPeriodNotFound = sdkerrors.Register(ModuleName, 2, "no claim period found for id and collateral type")
|
||||
ErrInvalidAccountType = sdkerrors.Register(ModuleName, 3, "account type not supported")
|
||||
ErrNoClaimsFound = sdkerrors.Register(ModuleName, 4, "no claims with denom found for address")
|
||||
ErrNoClaimsFound = sdkerrors.Register(ModuleName, 4, "no claims with collateral type found for address")
|
||||
ErrInsufficientModAccountBalance = sdkerrors.Register(ModuleName, 5, "module account has insufficient balance to pay claim")
|
||||
)
|
||||
|
@ -17,8 +17,8 @@ type SupplyKeeper interface {
|
||||
|
||||
// CdpKeeper defines the expected cdp keeper for interacting with cdps
|
||||
type CdpKeeper interface {
|
||||
IterateCdpsByDenom(ctx sdk.Context, denom string, cb func(cdp cdptypes.CDP) (stop bool))
|
||||
GetTotalPrincipal(ctx sdk.Context, collateralDenom string, principalDenom string) (total sdk.Int)
|
||||
IterateCdpsByCollateralType(ctx sdk.Context, collateralType string, cb func(cdp cdptypes.CDP) (stop bool))
|
||||
GetTotalPrincipal(ctx sdk.Context, collateralType string, principalDenom string) (total sdk.Int)
|
||||
}
|
||||
|
||||
// AccountKeeper defines the expected keeper interface for interacting with account
|
||||
|
@ -4,15 +4,14 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// GenesisClaimPeriodID stores the next claim id and its corresponding denom
|
||||
// GenesisClaimPeriodID stores the next claim id and its corresponding collateral type
|
||||
type GenesisClaimPeriodID struct {
|
||||
Denom string `json:"denom" yaml:"denom"`
|
||||
ID uint64 `json:"id" yaml:"id"`
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
ID uint64 `json:"id" yaml:"id"`
|
||||
}
|
||||
|
||||
// Validate performs a basic check of a GenesisClaimPeriodID fields.
|
||||
@ -20,7 +19,10 @@ func (gcp GenesisClaimPeriodID) Validate() error {
|
||||
if gcp.ID == 0 {
|
||||
return errors.New("genesis claim period id cannot be 0")
|
||||
}
|
||||
return sdk.ValidateDenom(gcp.Denom)
|
||||
if strings.TrimSpace(gcp.CollateralType) == "" {
|
||||
return fmt.Errorf("collateral type cannot be blank: %v", gcp)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenesisClaimPeriodIDs array of GenesisClaimPeriodID
|
||||
@ -32,9 +34,9 @@ func (gcps GenesisClaimPeriodIDs) Validate() error {
|
||||
seenIDS := make(map[string]bool)
|
||||
var key string
|
||||
for _, gcp := range gcps {
|
||||
key = gcp.Denom + string(gcp.ID)
|
||||
key = gcp.CollateralType + string(gcp.ID)
|
||||
if seenIDS[key] {
|
||||
return fmt.Errorf("duplicated genesis claim period with id %d and denom %s", gcp.ID, gcp.Denom)
|
||||
return fmt.Errorf("duplicated genesis claim period with id %d and collateral type %s", gcp.ID, gcp.CollateralType)
|
||||
}
|
||||
|
||||
if err := gcp.Validate(); err != nil {
|
||||
|
@ -20,29 +20,29 @@ func TestGenesisClaimPeriodIDsValidate(t *testing.T) {
|
||||
{
|
||||
"valid",
|
||||
GenesisClaimPeriodIDs{
|
||||
{Denom: "bnb", ID: 1},
|
||||
{CollateralType: "bnb", ID: 1},
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"invalid denom",
|
||||
"invalid collateral type",
|
||||
GenesisClaimPeriodIDs{
|
||||
{Denom: "", ID: 1},
|
||||
{CollateralType: "", ID: 1},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid ID",
|
||||
GenesisClaimPeriodIDs{
|
||||
{Denom: "bnb", ID: 0},
|
||||
{CollateralType: "bnb", ID: 0},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"duplicate",
|
||||
GenesisClaimPeriodIDs{
|
||||
{Denom: "bnb", ID: 1},
|
||||
{Denom: "bnb", ID: 1},
|
||||
{CollateralType: "bnb", ID: 1},
|
||||
{CollateralType: "bnb", ID: 1},
|
||||
},
|
||||
false,
|
||||
},
|
||||
@ -74,7 +74,7 @@ func TestGenesisStateValidate(t *testing.T) {
|
||||
rewardPeriods := RewardPeriods{NewRewardPeriod("bnb", now, now.Add(time.Hour), sdk.NewCoin("bnb", sdk.OneInt()), now, 10)}
|
||||
claimPeriods := ClaimPeriods{NewClaimPeriod("bnb", 10, now, 100)}
|
||||
claims := Claims{NewClaim(owner, sdk.NewCoin("bnb", sdk.OneInt()), "bnb", 10)}
|
||||
gcps := GenesisClaimPeriodIDs{{Denom: "bnb", ID: 1}}
|
||||
gcps := GenesisClaimPeriodIDs{{CollateralType: "bnb", ID: 1}}
|
||||
|
||||
testCases := []struct {
|
||||
msg string
|
||||
|
@ -33,24 +33,24 @@ var (
|
||||
)
|
||||
|
||||
// Keys
|
||||
// 0x00:Denom <> RewardPeriod the current active reward period (max 1 reward period per denom)
|
||||
// 0x01:Denom:ID <> ClaimPeriod object for that ID, indexed by denom and ID
|
||||
// 0x02:Denom:ID:Owner <> Claim object, indexed by Denom, ID and owner
|
||||
// 0x03:Denom <> NextClaimPeriodIDPrefix the ID of the next claim period, indexed by denom
|
||||
// 0x00:CollateralType <> RewardPeriod the current active reward period (max 1 reward period per collateral type)
|
||||
// 0x01:CollateralType:ID <> ClaimPeriod object for that ID, indexed by collateral type and ID
|
||||
// 0x02:CollateralType:ID:Owner <> Claim object, indexed by collateral type, ID and owner
|
||||
// 0x03:CollateralType <> NextClaimPeriodIDPrefix the ID of the next claim period, indexed by collateral type
|
||||
|
||||
// BytesToUint64 returns uint64 format from a byte array
|
||||
func BytesToUint64(bz []byte) uint64 {
|
||||
return binary.BigEndian.Uint64(bz)
|
||||
}
|
||||
|
||||
// GetClaimPeriodPrefix returns the key (denom + id) for a claim prefix
|
||||
func GetClaimPeriodPrefix(denom string, id uint64) []byte {
|
||||
return createKey([]byte(denom), sdk.Uint64ToBigEndian(id))
|
||||
// GetClaimPeriodPrefix returns the key (collateral type + id) for a claim prefix
|
||||
func GetClaimPeriodPrefix(collateralType string, id uint64) []byte {
|
||||
return createKey([]byte(collateralType), sdk.Uint64ToBigEndian(id))
|
||||
}
|
||||
|
||||
// GetClaimPrefix returns the key (denom + id + address) for a claim
|
||||
func GetClaimPrefix(addr sdk.AccAddress, denom string, id uint64) []byte {
|
||||
return createKey([]byte(denom), sdk.Uint64ToBigEndian(id), addr)
|
||||
// GetClaimPrefix returns the key (collateral type + id + address) for a claim
|
||||
func GetClaimPrefix(addr sdk.AccAddress, collateralType string, id uint64) []byte {
|
||||
return createKey([]byte(collateralType), sdk.Uint64ToBigEndian(id), addr)
|
||||
}
|
||||
|
||||
func createKey(bytes ...[]byte) (r []byte) {
|
||||
|
@ -1,6 +1,9 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
@ -10,15 +13,15 @@ var _ sdk.Msg = &MsgClaimReward{}
|
||||
|
||||
// MsgClaimReward message type used to claim rewards
|
||||
type MsgClaimReward struct {
|
||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||
Denom string `json:"denom" yaml:"denom"`
|
||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
}
|
||||
|
||||
// NewMsgClaimReward returns a new MsgClaimReward.
|
||||
func NewMsgClaimReward(sender sdk.AccAddress, denom string) MsgClaimReward {
|
||||
func NewMsgClaimReward(sender sdk.AccAddress, collateralType string) MsgClaimReward {
|
||||
return MsgClaimReward{
|
||||
Sender: sender,
|
||||
Denom: denom,
|
||||
Sender: sender,
|
||||
CollateralType: collateralType,
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,7 +36,10 @@ func (msg MsgClaimReward) ValidateBasic() error {
|
||||
if msg.Sender.Empty() {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be empty")
|
||||
}
|
||||
return sdk.ValidateDenom(msg.Denom)
|
||||
if strings.TrimSpace(msg.CollateralType) == "" {
|
||||
return fmt.Errorf("collateral type cannot be blank")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSignBytes gets the canonical byte representation of the Msg.
|
||||
|
@ -13,9 +13,9 @@ import (
|
||||
)
|
||||
|
||||
type msgTest struct {
|
||||
from sdk.AccAddress
|
||||
denom string
|
||||
expectPass bool
|
||||
from sdk.AccAddress
|
||||
collateralType string
|
||||
expectPass bool
|
||||
}
|
||||
|
||||
type MsgTestSuite struct {
|
||||
@ -27,19 +27,19 @@ type MsgTestSuite struct {
|
||||
func (suite *MsgTestSuite) SetupTest() {
|
||||
tests := []msgTest{
|
||||
{
|
||||
from: sdk.AccAddress(crypto.AddressHash([]byte("KavaTest1"))),
|
||||
denom: "bnb",
|
||||
expectPass: true,
|
||||
from: sdk.AccAddress(crypto.AddressHash([]byte("KavaTest1"))),
|
||||
collateralType: "bnb",
|
||||
expectPass: true,
|
||||
},
|
||||
{
|
||||
from: sdk.AccAddress(crypto.AddressHash([]byte("KavaTest1"))),
|
||||
denom: "",
|
||||
expectPass: false,
|
||||
from: sdk.AccAddress(crypto.AddressHash([]byte("KavaTest1"))),
|
||||
collateralType: "",
|
||||
expectPass: false,
|
||||
},
|
||||
{
|
||||
from: sdk.AccAddress{},
|
||||
denom: "bnb",
|
||||
expectPass: false,
|
||||
from: sdk.AccAddress{},
|
||||
collateralType: "bnb",
|
||||
expectPass: false,
|
||||
},
|
||||
}
|
||||
suite.tests = tests
|
||||
@ -47,7 +47,7 @@ func (suite *MsgTestSuite) SetupTest() {
|
||||
|
||||
func (suite *MsgTestSuite) TestMsgValidation() {
|
||||
for _, t := range suite.tests {
|
||||
msg := types.NewMsgClaimReward(t.from, t.denom)
|
||||
msg := types.NewMsgClaimReward(t.from, t.collateralType)
|
||||
err := msg.ValidateBasic()
|
||||
if t.expectPass {
|
||||
suite.Require().NoError(err)
|
||||
|
@ -2,6 +2,7 @@ package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@ -93,7 +94,7 @@ func validateRewardsParam(i interface{}) error {
|
||||
// Reward stores the specified state for a single reward period.
|
||||
type Reward struct {
|
||||
Active bool `json:"active" yaml:"active"` // governance switch to disable a period
|
||||
Denom string `json:"denom" yaml:"denom"` // the collateral denom rewards apply to, must be found in the cdp collaterals
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"` // the collateral type rewards apply to, must be found in the cdp collaterals
|
||||
AvailableRewards sdk.Coin `json:"available_rewards" yaml:"available_rewards"` // the total amount of coins distributed per period
|
||||
Duration time.Duration `json:"duration" yaml:"duration"` // the duration of the period
|
||||
TimeLock time.Duration `json:"time_lock" yaml:"time_lock"` // how long rewards for this period are timelocked
|
||||
@ -101,10 +102,10 @@ type Reward struct {
|
||||
}
|
||||
|
||||
// NewReward returns a new Reward
|
||||
func NewReward(active bool, denom string, reward sdk.Coin, duration time.Duration, timelock time.Duration, claimDuration time.Duration) Reward {
|
||||
func NewReward(active bool, collateralType string, reward sdk.Coin, duration time.Duration, timelock time.Duration, claimDuration time.Duration) Reward {
|
||||
return Reward{
|
||||
Active: active,
|
||||
Denom: denom,
|
||||
CollateralType: collateralType,
|
||||
AvailableRewards: reward,
|
||||
Duration: duration,
|
||||
TimeLock: timelock,
|
||||
@ -116,32 +117,35 @@ func NewReward(active bool, denom string, reward sdk.Coin, duration time.Duratio
|
||||
func (r Reward) String() string {
|
||||
return fmt.Sprintf(`Reward:
|
||||
Active: %t,
|
||||
Denom: %s,
|
||||
CollateralType: %s,
|
||||
Available Rewards: %s,
|
||||
Duration: %s,
|
||||
Time Lock: %s,
|
||||
Claim Duration: %s`,
|
||||
r.Active, r.Denom, r.AvailableRewards, r.Duration, r.TimeLock, r.ClaimDuration)
|
||||
r.Active, r.CollateralType, r.AvailableRewards, r.Duration, r.TimeLock, r.ClaimDuration)
|
||||
}
|
||||
|
||||
// Validate performs a basic check of a reward fields.
|
||||
func (r Reward) Validate() error {
|
||||
if !r.AvailableRewards.IsValid() {
|
||||
return fmt.Errorf("invalid reward coins %s for %s", r.AvailableRewards, r.Denom)
|
||||
return fmt.Errorf("invalid reward coins %s for %s", r.AvailableRewards, r.CollateralType)
|
||||
}
|
||||
if !r.AvailableRewards.IsPositive() {
|
||||
return fmt.Errorf("reward amount must be positive, is %s for %s", r.AvailableRewards, r.Denom)
|
||||
return fmt.Errorf("reward amount must be positive, is %s for %s", r.AvailableRewards, r.CollateralType)
|
||||
}
|
||||
if r.Duration <= 0 {
|
||||
return fmt.Errorf("reward duration must be positive, is %s for %s", r.Duration, r.Denom)
|
||||
return fmt.Errorf("reward duration must be positive, is %s for %s", r.Duration, r.CollateralType)
|
||||
}
|
||||
if r.TimeLock < 0 {
|
||||
return fmt.Errorf("reward timelock must be non-negative, is %s for %s", r.TimeLock, r.Denom)
|
||||
return fmt.Errorf("reward timelock must be non-negative, is %s for %s", r.TimeLock, r.CollateralType)
|
||||
}
|
||||
if r.ClaimDuration <= 0 {
|
||||
return fmt.Errorf("claim duration must be positive, is %s for %s", r.ClaimDuration, r.Denom)
|
||||
return fmt.Errorf("claim duration must be positive, is %s for %s", r.ClaimDuration, r.CollateralType)
|
||||
}
|
||||
return sdk.ValidateDenom(r.Denom)
|
||||
if strings.TrimSpace(r.CollateralType) == "" {
|
||||
return fmt.Errorf("collateral type cannot be blank: %s", r)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Rewards array of Reward
|
||||
@ -150,17 +154,17 @@ type Rewards []Reward
|
||||
// Validate checks if all the rewards are valid and there are no duplicated
|
||||
// entries.
|
||||
func (rs Rewards) Validate() error {
|
||||
rewardDenoms := make(map[string]bool)
|
||||
rewardCollateralTypes := make(map[string]bool)
|
||||
for _, r := range rs {
|
||||
if rewardDenoms[r.Denom] {
|
||||
return fmt.Errorf("cannot have duplicate reward denoms: %s", r.Denom)
|
||||
if rewardCollateralTypes[r.CollateralType] {
|
||||
return fmt.Errorf("cannot have duplicate reward collateral types: %s", r.CollateralType)
|
||||
}
|
||||
|
||||
if err := r.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rewardDenoms[r.Denom] = true
|
||||
rewardCollateralTypes[r.CollateralType] = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ func (suite *ParamTestSuite) SetupTest() {
|
||||
Rewards: types.Rewards{
|
||||
types.Reward{
|
||||
Active: true,
|
||||
Denom: "bnb",
|
||||
CollateralType: "bnb-a",
|
||||
AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)),
|
||||
Duration: time.Hour * 24 * 7,
|
||||
TimeLock: time.Hour * 8766,
|
||||
@ -58,7 +58,7 @@ func (suite *ParamTestSuite) SetupTest() {
|
||||
Rewards: types.Rewards{
|
||||
types.Reward{
|
||||
Active: true,
|
||||
Denom: "bnb",
|
||||
CollateralType: "bnb-a",
|
||||
AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)),
|
||||
Duration: time.Hour * 24 * 7,
|
||||
TimeLock: time.Hour * 8766,
|
||||
@ -78,7 +78,7 @@ func (suite *ParamTestSuite) SetupTest() {
|
||||
Rewards: types.Rewards{
|
||||
types.Reward{
|
||||
Active: true,
|
||||
Denom: "bnb",
|
||||
CollateralType: "bnb-a",
|
||||
AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)),
|
||||
Duration: time.Hour * 24 * 7,
|
||||
TimeLock: time.Hour * 8766,
|
||||
@ -86,7 +86,7 @@ func (suite *ParamTestSuite) SetupTest() {
|
||||
},
|
||||
types.Reward{
|
||||
Active: true,
|
||||
Denom: "bnb",
|
||||
CollateralType: "bnb-a",
|
||||
AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)),
|
||||
Duration: time.Hour * 24 * 7,
|
||||
TimeLock: time.Hour * 8766,
|
||||
@ -96,7 +96,7 @@ func (suite *ParamTestSuite) SetupTest() {
|
||||
},
|
||||
errResult: errResult{
|
||||
expectPass: false,
|
||||
contains: "cannot have duplicate reward denoms",
|
||||
contains: "cannot have duplicate reward collateral type",
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -106,7 +106,7 @@ func (suite *ParamTestSuite) SetupTest() {
|
||||
Rewards: types.Rewards{
|
||||
types.Reward{
|
||||
Active: true,
|
||||
Denom: "bnb",
|
||||
CollateralType: "bnb-a",
|
||||
AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)),
|
||||
Duration: time.Hour * -24 * 7,
|
||||
TimeLock: time.Hour * 8766,
|
||||
@ -126,7 +126,7 @@ func (suite *ParamTestSuite) SetupTest() {
|
||||
Rewards: types.Rewards{
|
||||
types.Reward{
|
||||
Active: true,
|
||||
Denom: "bnb",
|
||||
CollateralType: "bnb-a",
|
||||
AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)),
|
||||
Duration: time.Hour * 24 * 7,
|
||||
TimeLock: time.Hour * -8766,
|
||||
@ -146,7 +146,7 @@ func (suite *ParamTestSuite) SetupTest() {
|
||||
Rewards: types.Rewards{
|
||||
types.Reward{
|
||||
Active: true,
|
||||
Denom: "bnb",
|
||||
CollateralType: "bnb-a",
|
||||
AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)),
|
||||
Duration: time.Hour * 24 * 7,
|
||||
TimeLock: time.Hour * 8766,
|
||||
@ -166,7 +166,7 @@ func (suite *ParamTestSuite) SetupTest() {
|
||||
Rewards: types.Rewards{
|
||||
types.Reward{
|
||||
Active: true,
|
||||
Denom: "bnb",
|
||||
CollateralType: "bnb-a",
|
||||
AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(0)),
|
||||
Duration: time.Hour * 24 * 7,
|
||||
TimeLock: time.Hour * 8766,
|
||||
@ -180,13 +180,13 @@ func (suite *ParamTestSuite) SetupTest() {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty reward denom",
|
||||
name: "empty reward collateral type",
|
||||
params: types.Params{
|
||||
Active: true,
|
||||
Rewards: types.Rewards{
|
||||
types.Reward{
|
||||
Active: true,
|
||||
Denom: "",
|
||||
CollateralType: "",
|
||||
AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(1)),
|
||||
Duration: time.Hour * 24 * 7,
|
||||
TimeLock: time.Hour * 8766,
|
||||
@ -196,7 +196,7 @@ func (suite *ParamTestSuite) SetupTest() {
|
||||
},
|
||||
errResult: errResult{
|
||||
expectPass: false,
|
||||
contains: "invalid denom",
|
||||
contains: "collateral type cannot be blank",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -7,31 +7,31 @@ import (
|
||||
|
||||
// Querier routes for the incentive module
|
||||
const (
|
||||
QueryGetClaims = "claims"
|
||||
RestClaimOwner = "owner"
|
||||
RestClaimDenom = "denom"
|
||||
QueryGetParams = "parameters"
|
||||
QueryGetRewardPeriods = "reward-periods"
|
||||
QueryGetClaimPeriods = "claim-periods"
|
||||
QueryGetClaims = "claims"
|
||||
RestClaimOwner = "owner"
|
||||
RestClaimCollateralType = "collateral_type"
|
||||
QueryGetParams = "parameters"
|
||||
QueryGetRewardPeriods = "reward-periods"
|
||||
QueryGetClaimPeriods = "claim-periods"
|
||||
)
|
||||
|
||||
// QueryClaimsParams params for query /incentive/claims
|
||||
type QueryClaimsParams struct {
|
||||
Owner sdk.AccAddress
|
||||
Denom string
|
||||
Owner sdk.AccAddress
|
||||
CollateralType string
|
||||
}
|
||||
|
||||
// NewQueryClaimsParams returns QueryClaimsParams
|
||||
func NewQueryClaimsParams(owner sdk.AccAddress, denom string) QueryClaimsParams {
|
||||
func NewQueryClaimsParams(owner sdk.AccAddress, collateralType string) QueryClaimsParams {
|
||||
return QueryClaimsParams{
|
||||
Owner: owner,
|
||||
Denom: denom,
|
||||
Owner: owner,
|
||||
CollateralType: collateralType,
|
||||
}
|
||||
}
|
||||
|
||||
// PostClaimReq defines the properties of claim transaction's request body.
|
||||
type PostClaimReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||
Denom string `json:"denom" yaml:"denom"`
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package types
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@ -10,35 +11,35 @@ import (
|
||||
|
||||
// RewardPeriod stores the state of an ongoing reward
|
||||
type RewardPeriod struct {
|
||||
Denom string `json:"denom" yaml:"denom"`
|
||||
Start time.Time `json:"start" yaml:"start"`
|
||||
End time.Time `json:"end" yaml:"end"`
|
||||
Reward sdk.Coin `json:"reward" yaml:"reward"` // per second reward payouts
|
||||
ClaimEnd time.Time `json:"claim_end" yaml:"claim_end"`
|
||||
ClaimTimeLock time.Duration `json:"claim_time_lock" yaml:"claim_time_lock"` // the amount of time rewards are timelocked once they are sent to users
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
Start time.Time `json:"start" yaml:"start"`
|
||||
End time.Time `json:"end" yaml:"end"`
|
||||
Reward sdk.Coin `json:"reward" yaml:"reward"` // per second reward payouts
|
||||
ClaimEnd time.Time `json:"claim_end" yaml:"claim_end"`
|
||||
ClaimTimeLock time.Duration `json:"claim_time_lock" yaml:"claim_time_lock"` // the amount of time rewards are timelocked once they are sent to users
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer
|
||||
func (rp RewardPeriod) String() string {
|
||||
return fmt.Sprintf(`Reward Period:
|
||||
Denom: %s,
|
||||
Collateral Type: %s,
|
||||
Start: %s,
|
||||
End: %s,
|
||||
Reward: %s,
|
||||
Claim End: %s,
|
||||
Claim Time Lock: %s
|
||||
`, rp.Denom, rp.Start, rp.End, rp.Reward, rp.ClaimEnd, rp.ClaimTimeLock)
|
||||
`, rp.CollateralType, rp.Start, rp.End, rp.Reward, rp.ClaimEnd, rp.ClaimTimeLock)
|
||||
}
|
||||
|
||||
// NewRewardPeriod returns a new RewardPeriod
|
||||
func NewRewardPeriod(denom string, start time.Time, end time.Time, reward sdk.Coin, claimEnd time.Time, claimTimeLock time.Duration) RewardPeriod {
|
||||
func NewRewardPeriod(collateralType string, start time.Time, end time.Time, reward sdk.Coin, claimEnd time.Time, claimTimeLock time.Duration) RewardPeriod {
|
||||
return RewardPeriod{
|
||||
Denom: denom,
|
||||
Start: start,
|
||||
End: end,
|
||||
Reward: reward,
|
||||
ClaimEnd: claimEnd,
|
||||
ClaimTimeLock: claimTimeLock,
|
||||
CollateralType: collateralType,
|
||||
Start: start,
|
||||
End: end,
|
||||
Reward: reward,
|
||||
ClaimEnd: claimEnd,
|
||||
ClaimTimeLock: claimTimeLock,
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,7 +63,10 @@ func (rp RewardPeriod) Validate() error {
|
||||
if rp.ClaimTimeLock == 0 {
|
||||
return errors.New("reward claim time lock cannot be 0")
|
||||
}
|
||||
return sdk.ValidateDenom(rp.Denom)
|
||||
if strings.TrimSpace(rp.CollateralType) == "" {
|
||||
return fmt.Errorf("reward period collateral type cannot be blank: %s", rp)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RewardPeriods array of RewardPeriod
|
||||
@ -73,14 +77,14 @@ type RewardPeriods []RewardPeriod
|
||||
func (rps RewardPeriods) Validate() error {
|
||||
seenPeriods := make(map[string]bool)
|
||||
for _, rp := range rps {
|
||||
if seenPeriods[rp.Denom] {
|
||||
return fmt.Errorf("duplicated reward period with denom %s", rp.Denom)
|
||||
if seenPeriods[rp.CollateralType] {
|
||||
return fmt.Errorf("duplicated reward period with collateral type %s", rp.CollateralType)
|
||||
}
|
||||
|
||||
if err := rp.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
seenPeriods[rp.Denom] = true
|
||||
seenPeriods[rp.CollateralType] = true
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -88,19 +92,19 @@ func (rps RewardPeriods) Validate() error {
|
||||
|
||||
// ClaimPeriod stores the state of an ongoing claim period
|
||||
type ClaimPeriod struct {
|
||||
Denom string `json:"denom" yaml:"denom"`
|
||||
ID uint64 `json:"id" yaml:"id"`
|
||||
End time.Time `json:"end" yaml:"end"`
|
||||
TimeLock time.Duration `json:"time_lock" yaml:"time_lock"`
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
ID uint64 `json:"id" yaml:"id"`
|
||||
End time.Time `json:"end" yaml:"end"`
|
||||
TimeLock time.Duration `json:"time_lock" yaml:"time_lock"`
|
||||
}
|
||||
|
||||
// NewClaimPeriod returns a new ClaimPeriod
|
||||
func NewClaimPeriod(denom string, id uint64, end time.Time, timeLock time.Duration) ClaimPeriod {
|
||||
func NewClaimPeriod(collateralType string, id uint64, end time.Time, timeLock time.Duration) ClaimPeriod {
|
||||
return ClaimPeriod{
|
||||
Denom: denom,
|
||||
ID: id,
|
||||
End: end,
|
||||
TimeLock: timeLock,
|
||||
CollateralType: collateralType,
|
||||
ID: id,
|
||||
End: end,
|
||||
TimeLock: timeLock,
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,17 +119,20 @@ func (cp ClaimPeriod) Validate() error {
|
||||
if cp.TimeLock == 0 {
|
||||
return errors.New("claim period time lock cannot be 0")
|
||||
}
|
||||
return sdk.ValidateDenom(cp.Denom)
|
||||
if strings.TrimSpace(cp.CollateralType) == "" {
|
||||
return fmt.Errorf("claim period collateral type cannot be blank: %s", cp)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer
|
||||
func (cp ClaimPeriod) String() string {
|
||||
return fmt.Sprintf(`Claim Period:
|
||||
Denom: %s,
|
||||
Collateral Type: %s,
|
||||
ID: %d,
|
||||
End: %s,
|
||||
Claim Time Lock: %s
|
||||
`, cp.Denom, cp.ID, cp.End, cp.TimeLock)
|
||||
`, cp.CollateralType, cp.ID, cp.End, cp.TimeLock)
|
||||
}
|
||||
|
||||
// ClaimPeriods array of ClaimPeriod
|
||||
@ -137,9 +144,9 @@ func (cps ClaimPeriods) Validate() error {
|
||||
seenPeriods := make(map[string]bool)
|
||||
var key string
|
||||
for _, cp := range cps {
|
||||
key = cp.Denom + string(cp.ID)
|
||||
key = cp.CollateralType + string(cp.ID)
|
||||
if seenPeriods[key] {
|
||||
return fmt.Errorf("duplicated claim period with id %d and denom %s", cp.ID, cp.Denom)
|
||||
return fmt.Errorf("duplicated claim period with id %d and collateral type %s", cp.ID, cp.CollateralType)
|
||||
}
|
||||
|
||||
if err := cp.Validate(); err != nil {
|
||||
@ -153,19 +160,19 @@ func (cps ClaimPeriods) Validate() error {
|
||||
|
||||
// Claim stores the rewards that can be claimed by owner
|
||||
type Claim struct {
|
||||
Owner sdk.AccAddress `json:"owner" yaml:"owner"`
|
||||
Reward sdk.Coin `json:"reward" yaml:"reward"`
|
||||
Denom string `json:"denom" yaml:"denom"`
|
||||
ClaimPeriodID uint64 `json:"claim_period_id" yaml:"claim_period_id"`
|
||||
Owner sdk.AccAddress `json:"owner" yaml:"owner"`
|
||||
Reward sdk.Coin `json:"reward" yaml:"reward"`
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
ClaimPeriodID uint64 `json:"claim_period_id" yaml:"claim_period_id"`
|
||||
}
|
||||
|
||||
// NewClaim returns a new Claim
|
||||
func NewClaim(owner sdk.AccAddress, reward sdk.Coin, denom string, claimPeriodID uint64) Claim {
|
||||
func NewClaim(owner sdk.AccAddress, reward sdk.Coin, collateralType string, claimPeriodID uint64) Claim {
|
||||
return Claim{
|
||||
Owner: owner,
|
||||
Reward: reward,
|
||||
Denom: denom,
|
||||
ClaimPeriodID: claimPeriodID,
|
||||
Owner: owner,
|
||||
Reward: reward,
|
||||
CollateralType: collateralType,
|
||||
ClaimPeriodID: claimPeriodID,
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,17 +187,20 @@ func (c Claim) Validate() error {
|
||||
if c.ClaimPeriodID == 0 {
|
||||
return errors.New("claim period id cannot be 0")
|
||||
}
|
||||
return sdk.ValidateDenom(c.Denom)
|
||||
if strings.TrimSpace(c.CollateralType) == "" {
|
||||
return fmt.Errorf("claim collateral type cannot be blank: %s", c)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer
|
||||
func (c Claim) String() string {
|
||||
return fmt.Sprintf(`Claim:
|
||||
Owner: %s,
|
||||
Denom: %s,
|
||||
Collateral Type: %s,
|
||||
Reward: %s,
|
||||
Claim Period ID: %d,
|
||||
`, c.Owner, c.Denom, c.Reward, c.ClaimPeriodID)
|
||||
`, c.Owner, c.CollateralType, c.Reward, c.ClaimPeriodID)
|
||||
}
|
||||
|
||||
// Claims array of Claim
|
||||
@ -202,9 +212,9 @@ func (cs Claims) Validate() error {
|
||||
seemClaims := make(map[string]bool)
|
||||
var key string
|
||||
for _, c := range cs {
|
||||
key = c.Denom + string(c.ClaimPeriodID) + c.Owner.String()
|
||||
key = c.CollateralType + string(c.ClaimPeriodID) + c.Owner.String()
|
||||
if c.Owner != nil && seemClaims[key] {
|
||||
return fmt.Errorf("duplicated claim from owner %s and denom %s", c.Owner, c.Denom)
|
||||
return fmt.Errorf("duplicated claim from owner %s and collateral type %s", c.Owner, c.CollateralType)
|
||||
}
|
||||
|
||||
if err := c.Validate(); err != nil {
|
||||
@ -222,11 +232,11 @@ func NewRewardPeriodFromReward(reward Reward, blockTime time.Time) RewardPeriod
|
||||
rewardsPerSecond := sdk.NewDecFromInt(reward.AvailableRewards.Amount).Quo(sdk.NewDecFromInt(sdk.NewInt(int64(reward.Duration.Seconds())))).TruncateInt()
|
||||
rewardCoinPerSecond := sdk.NewCoin(reward.AvailableRewards.Denom, rewardsPerSecond)
|
||||
return RewardPeriod{
|
||||
Denom: reward.Denom,
|
||||
Start: blockTime,
|
||||
End: blockTime.Add(reward.Duration),
|
||||
Reward: rewardCoinPerSecond,
|
||||
ClaimEnd: blockTime.Add(reward.Duration).Add(reward.ClaimDuration),
|
||||
ClaimTimeLock: reward.TimeLock,
|
||||
CollateralType: reward.CollateralType,
|
||||
Start: blockTime,
|
||||
End: blockTime.Add(reward.Duration),
|
||||
Reward: rewardCoinPerSecond,
|
||||
ClaimEnd: blockTime.Add(reward.Duration).Add(reward.ClaimDuration),
|
||||
ClaimTimeLock: reward.TimeLock,
|
||||
}
|
||||
}
|
||||
|
@ -93,15 +93,15 @@ func TestRewardPeriodsValidate(t *testing.T) {
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid denom",
|
||||
"invalid collateral type",
|
||||
RewardPeriods{
|
||||
{
|
||||
Start: now,
|
||||
End: now.Add(time.Hour),
|
||||
Reward: sdk.NewCoin("bnb", sdk.OneInt()),
|
||||
ClaimEnd: now,
|
||||
ClaimTimeLock: 10,
|
||||
Denom: "",
|
||||
Start: now,
|
||||
End: now.Add(time.Hour),
|
||||
Reward: sdk.NewCoin("bnb", sdk.OneInt()),
|
||||
ClaimEnd: now,
|
||||
ClaimTimeLock: 10,
|
||||
CollateralType: "",
|
||||
},
|
||||
},
|
||||
false,
|
||||
@ -170,9 +170,9 @@ func TestClaimPeriodsValidate(t *testing.T) {
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid denom",
|
||||
"invalid collateral type",
|
||||
ClaimPeriods{
|
||||
{ID: 10, End: now, TimeLock: 100, Denom: ""},
|
||||
{ID: 10, End: now, TimeLock: 100, CollateralType: ""},
|
||||
},
|
||||
false,
|
||||
},
|
||||
@ -243,13 +243,13 @@ func TestClaimsValidate(t *testing.T) {
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid denom",
|
||||
"invalid collateral type",
|
||||
Claims{
|
||||
{
|
||||
Owner: owner,
|
||||
Reward: sdk.NewCoin("bnb", sdk.OneInt()),
|
||||
ClaimPeriodID: 10,
|
||||
Denom: "",
|
||||
Owner: owner,
|
||||
Reward: sdk.NewCoin("bnb", sdk.OneInt()),
|
||||
ClaimPeriodID: 10,
|
||||
CollateralType: "",
|
||||
},
|
||||
},
|
||||
false,
|
||||
|
Loading…
Reference in New Issue
Block a user