mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-26 00:05:18 +00:00
Incentive PR 4: claim Hard rewards via the Incentive module (#780)
* claim hard reward keeper methods * test hard claim payout * claim hard rewards via cli * query hard claims via cli * rest txs and queries * add handler test * add claim type event field
This commit is contained in:
parent
72a6df17fd
commit
3a08fc582b
@ -23,7 +23,8 @@ const (
|
|||||||
ModuleName = types.ModuleName
|
ModuleName = types.ModuleName
|
||||||
QuerierRoute = types.QuerierRoute
|
QuerierRoute = types.QuerierRoute
|
||||||
QueryGetClaimPeriods = types.QueryGetClaimPeriods
|
QueryGetClaimPeriods = types.QueryGetClaimPeriods
|
||||||
QueryGetClaims = types.QueryGetClaims
|
QueryGetCdpClaims = types.QueryGetCdpClaims
|
||||||
|
QueryGetHardClaims = types.QueryGetHardClaims
|
||||||
QueryGetParams = types.QueryGetParams
|
QueryGetParams = types.QueryGetParams
|
||||||
QueryGetRewardPeriods = types.QueryGetRewardPeriods
|
QueryGetRewardPeriods = types.QueryGetRewardPeriods
|
||||||
RestClaimCollateralType = types.RestClaimCollateralType
|
RestClaimCollateralType = types.RestClaimCollateralType
|
||||||
@ -35,24 +36,27 @@ const (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// function aliases
|
// function aliases
|
||||||
CalculateTimeElapsed = keeper.CalculateTimeElapsed
|
CalculateTimeElapsed = keeper.CalculateTimeElapsed
|
||||||
NewKeeper = keeper.NewKeeper
|
NewKeeper = keeper.NewKeeper
|
||||||
NewQuerier = keeper.NewQuerier
|
NewQuerier = keeper.NewQuerier
|
||||||
DefaultGenesisState = types.DefaultGenesisState
|
DefaultGenesisState = types.DefaultGenesisState
|
||||||
DefaultParams = types.DefaultParams
|
DefaultParams = types.DefaultParams
|
||||||
GetTotalVestingPeriodLength = types.GetTotalVestingPeriodLength
|
GetTotalVestingPeriodLength = types.GetTotalVestingPeriodLength
|
||||||
NewGenesisAccumulationTime = types.NewGenesisAccumulationTime
|
NewGenesisAccumulationTime = types.NewGenesisAccumulationTime
|
||||||
NewGenesisState = types.NewGenesisState
|
NewGenesisState = types.NewGenesisState
|
||||||
NewMsgClaimUSDXMintingReward = types.NewMsgClaimUSDXMintingReward
|
NewMsgClaimUSDXMintingReward = types.NewMsgClaimUSDXMintingReward
|
||||||
NewMultiplier = types.NewMultiplier
|
NewMsgClaimHardLiquidityProviderReward = types.NewMsgClaimHardLiquidityProviderReward
|
||||||
NewParams = types.NewParams
|
NewMultiplier = types.NewMultiplier
|
||||||
NewPeriod = types.NewPeriod
|
NewParams = types.NewParams
|
||||||
NewQueryClaimsParams = types.NewQueryClaimsParams
|
NewPeriod = types.NewPeriod
|
||||||
NewRewardIndex = types.NewRewardIndex
|
NewQueryCdpClaimsParams = types.NewQueryCdpClaimsParams
|
||||||
NewRewardPeriod = types.NewRewardPeriod
|
NewQueryHardClaimsParams = types.NewQueryHardClaimsParams
|
||||||
NewUSDXMintingClaim = types.NewUSDXMintingClaim
|
NewRewardIndex = types.NewRewardIndex
|
||||||
ParamKeyTable = types.ParamKeyTable
|
NewRewardPeriod = types.NewRewardPeriod
|
||||||
RegisterCodec = types.RegisterCodec
|
NewUSDXMintingClaim = types.NewUSDXMintingClaim
|
||||||
|
NewHardLiquidityProviderClaim = types.NewHardLiquidityProviderClaim
|
||||||
|
ParamKeyTable = types.ParamKeyTable
|
||||||
|
RegisterCodec = types.RegisterCodec
|
||||||
|
|
||||||
// variable aliases
|
// variable aliases
|
||||||
PreviousUSDXMintingRewardAccrualTimeKeyPrefix = types.PreviousUSDXMintingRewardAccrualTimeKeyPrefix
|
PreviousUSDXMintingRewardAccrualTimeKeyPrefix = types.PreviousUSDXMintingRewardAccrualTimeKeyPrefix
|
||||||
@ -99,7 +103,8 @@ type (
|
|||||||
Multipliers = types.Multipliers
|
Multipliers = types.Multipliers
|
||||||
Params = types.Params
|
Params = types.Params
|
||||||
PostClaimReq = types.PostClaimReq
|
PostClaimReq = types.PostClaimReq
|
||||||
QueryClaimsParams = types.QueryClaimsParams
|
QueryCdpClaimsParams = types.QueryCdpClaimsParams
|
||||||
|
QueryHardClaimsParams = types.QueryHardClaimsParams
|
||||||
RewardIndex = types.RewardIndex
|
RewardIndex = types.RewardIndex
|
||||||
RewardIndexes = types.RewardIndexes
|
RewardIndexes = types.RewardIndexes
|
||||||
RewardPeriod = types.RewardPeriod
|
RewardPeriod = types.RewardPeriod
|
||||||
|
@ -25,7 +25,8 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
|||||||
|
|
||||||
incentiveQueryCmd.AddCommand(flags.GetCommands(
|
incentiveQueryCmd.AddCommand(flags.GetCommands(
|
||||||
queryParamsCmd(queryRoute, cdc),
|
queryParamsCmd(queryRoute, cdc),
|
||||||
queryClaimsCmd(queryRoute, cdc),
|
queryCdpClaimsCmd(queryRoute, cdc),
|
||||||
|
queryHardClaimsCmd(queryRoute, cdc),
|
||||||
)...)
|
)...)
|
||||||
|
|
||||||
return incentiveQueryCmd
|
return incentiveQueryCmd
|
||||||
@ -35,16 +36,16 @@ const (
|
|||||||
flagOwner = "owner"
|
flagOwner = "owner"
|
||||||
)
|
)
|
||||||
|
|
||||||
func queryClaimsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
func queryCdpClaimsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "claims ",
|
Use: "cdp-claims",
|
||||||
Short: "query USDX minting claims",
|
Short: "query USDX minting claims",
|
||||||
Long: strings.TrimSpace(
|
Long: strings.TrimSpace(
|
||||||
fmt.Sprintf(`Query USDX minting claims with optional flag for finding claims for a specifc owner
|
fmt.Sprintf(`Query USDX minting claims with optional flag for finding claims for a specifc owner
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
$ %s query %s claims
|
$ %s query %s cdp-claims
|
||||||
$ %s query %s claims --owner kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw
|
$ %s query %s cdp-claims --owner kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw
|
||||||
`,
|
`,
|
||||||
version.ClientName, types.ModuleName, version.ClientName, types.ModuleName)),
|
version.ClientName, types.ModuleName, version.ClientName, types.ModuleName)),
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
@ -60,14 +61,67 @@ func queryClaimsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
params := types.NewQueryClaimsParams(page, limit, owner)
|
params := types.NewQueryCdpClaimsParams(page, limit, owner)
|
||||||
bz, err := cdc.MarshalJSON(params)
|
bz, err := cdc.MarshalJSON(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query
|
// Query
|
||||||
route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetClaims)
|
route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetCdpClaims)
|
||||||
|
res, height, err := cliCtx.QueryWithData(route, bz)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cliCtx = cliCtx.WithHeight(height)
|
||||||
|
|
||||||
|
var claims types.USDXMintingClaims
|
||||||
|
if err := cdc.UnmarshalJSON(res, &claims); err != nil {
|
||||||
|
return fmt.Errorf("failed to unmarshal claims: %w", err)
|
||||||
|
}
|
||||||
|
return cliCtx.PrintOutput(claims)
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cmd.Flags().String(flagOwner, "", "(optional) filter by claim owner address")
|
||||||
|
cmd.Flags().Int(flags.FlagPage, 1, "pagination page of CDPs to to query for")
|
||||||
|
cmd.Flags().Int(flags.FlagLimit, 100, "pagination limit of CDPs to query for")
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func queryHardClaimsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "hard-claims",
|
||||||
|
Short: "query Hard liquidity provider claims",
|
||||||
|
Long: strings.TrimSpace(
|
||||||
|
fmt.Sprintf(`Query Hard liquidity provider claims with optional flag for finding claims for a specifc owner
|
||||||
|
|
||||||
|
Example:
|
||||||
|
$ %s query %s hard-claims
|
||||||
|
$ %s query %s hard-claims --owner kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw
|
||||||
|
`,
|
||||||
|
version.ClientName, types.ModuleName, version.ClientName, types.ModuleName)),
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||||
|
|
||||||
|
strOwner := viper.GetString(flagOwner)
|
||||||
|
page := viper.GetInt(flags.FlagPage)
|
||||||
|
limit := viper.GetInt(flags.FlagLimit)
|
||||||
|
|
||||||
|
// Prepare params for querier
|
||||||
|
owner, err := sdk.AccAddressFromBech32(strOwner)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
params := types.NewQueryHardClaimsParams(page, limit, owner)
|
||||||
|
bz, err := cdc.MarshalJSON(params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query
|
||||||
|
route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetHardClaims)
|
||||||
res, height, err := cliCtx.QueryWithData(route, bz)
|
res, height, err := cliCtx.QueryWithData(route, bz)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -26,22 +26,23 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
incentiveTxCmd.AddCommand(flags.PostCommands(
|
incentiveTxCmd.AddCommand(flags.PostCommands(
|
||||||
getCmdClaim(cdc),
|
getCmdClaimCdp(cdc),
|
||||||
|
getCmdClaimHard(cdc),
|
||||||
)...)
|
)...)
|
||||||
|
|
||||||
return incentiveTxCmd
|
return incentiveTxCmd
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCmdClaim(cdc *codec.Codec) *cobra.Command {
|
func getCmdClaimCdp(cdc *codec.Codec) *cobra.Command {
|
||||||
return &cobra.Command{
|
return &cobra.Command{
|
||||||
Use: "claim [owner] [multiplier]",
|
Use: "claim-cdp [owner] [multiplier]",
|
||||||
Short: "claim rewards for cdp owner and collateral-type",
|
Short: "claim CDP rewards for cdp owner and collateral-type",
|
||||||
Long: strings.TrimSpace(
|
Long: strings.TrimSpace(
|
||||||
fmt.Sprintf(`Claim any outstanding rewards owned by owner for the input collateral-type and multiplier,
|
fmt.Sprintf(`Claim any outstanding CDP rewards owned by owner for the input collateral-type and multiplier,
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
$ %s tx %s claim kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw large
|
$ %s tx %s claim-cdp kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw large
|
||||||
`, version.ClientName, types.ModuleName),
|
`, version.ClientName, types.ModuleName),
|
||||||
),
|
),
|
||||||
Args: cobra.ExactArgs(2),
|
Args: cobra.ExactArgs(2),
|
||||||
@ -63,3 +64,34 @@ func getCmdClaim(cdc *codec.Codec) *cobra.Command {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCmdClaimHard(cdc *codec.Codec) *cobra.Command {
|
||||||
|
return &cobra.Command{
|
||||||
|
Use: "claim-hard [owner] [multiplier]",
|
||||||
|
Short: "claim Hard rewards for deposit/borrow and delegating",
|
||||||
|
Long: strings.TrimSpace(
|
||||||
|
fmt.Sprintf(`Claim owner's outstanding Hard rewards using given multiplier multiplier,
|
||||||
|
|
||||||
|
Example:
|
||||||
|
$ %s tx %s claim-hard kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw large
|
||||||
|
`, version.ClientName, types.ModuleName),
|
||||||
|
),
|
||||||
|
Args: cobra.ExactArgs(2),
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||||
|
cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithCodec(cdc)
|
||||||
|
txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
|
||||||
|
owner, err := sdk.AccAddressFromBech32(args[0])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := types.NewMsgClaimHardLiquidityProviderReward(owner, args[1])
|
||||||
|
err = msg.ValidateBasic()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -15,11 +15,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) {
|
func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) {
|
||||||
r.HandleFunc(fmt.Sprintf("/%s/claims", types.ModuleName), queryClaimsHandlerFn(cliCtx)).Methods("GET")
|
r.HandleFunc(fmt.Sprintf("/%s/cdp-claims", types.ModuleName), queryCdpClaimsHandlerFn(cliCtx)).Methods("GET")
|
||||||
|
r.HandleFunc(fmt.Sprintf("/%s/hard-claims", types.ModuleName), queryHardClaimsHandlerFn(cliCtx)).Methods("GET")
|
||||||
r.HandleFunc(fmt.Sprintf("/%s/parameters", types.ModuleName), queryParamsHandlerFn(cliCtx)).Methods("GET")
|
r.HandleFunc(fmt.Sprintf("/%s/parameters", types.ModuleName), queryParamsHandlerFn(cliCtx)).Methods("GET")
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryClaimsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
func queryCdpClaimsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
_, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 0)
|
_, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -41,14 +42,54 @@ func queryClaimsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
queryParams := types.NewQueryClaimsParams(page, limit, owner)
|
queryParams := types.NewQueryCdpClaimsParams(page, limit, owner)
|
||||||
bz, err := cliCtx.Codec.MarshalJSON(queryParams)
|
bz, err := cliCtx.Codec.MarshalJSON(queryParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err))
|
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetClaims), bz)
|
res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetCdpClaims), bz)
|
||||||
|
if err != nil {
|
||||||
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cliCtx = cliCtx.WithHeight(height)
|
||||||
|
rest.PostProcessResponse(w, cliCtx, res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func queryHardClaimsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 0)
|
||||||
|
if err != nil {
|
||||||
|
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var owner sdk.AccAddress
|
||||||
|
if x := r.URL.Query().Get(types.RestClaimOwner); len(x) != 0 {
|
||||||
|
ownerStr := strings.ToLower(strings.TrimSpace(x))
|
||||||
|
owner, err = sdk.AccAddressFromBech32(ownerStr)
|
||||||
|
if err != nil {
|
||||||
|
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("cannot parse address from claim owner %s", ownerStr))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
queryParams := types.NewQueryHardClaimsParams(page, limit, owner)
|
||||||
|
bz, err := cliCtx.Codec.MarshalJSON(queryParams)
|
||||||
|
if err != nil {
|
||||||
|
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetHardClaims), bz)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
|
@ -16,10 +16,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) {
|
func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) {
|
||||||
r.HandleFunc("/incentive/claim", postClaimHandlerFn(cliCtx)).Methods("POST")
|
r.HandleFunc("/incentive/claim-cdp", postClaimCdpHandlerFn(cliCtx)).Methods("POST")
|
||||||
|
r.HandleFunc("/incentive/claim-hard", postClaimHardHandlerFn(cliCtx)).Methods("POST")
|
||||||
}
|
}
|
||||||
|
|
||||||
func postClaimHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
func postClaimCdpHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
var requestBody types.PostClaimReq
|
var requestBody types.PostClaimReq
|
||||||
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &requestBody) {
|
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &requestBody) {
|
||||||
@ -51,3 +52,36 @@ func postClaimHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
|||||||
utils.WriteGenerateStdTxResponse(w, cliCtx, requestBody.BaseReq, []sdk.Msg{msg})
|
utils.WriteGenerateStdTxResponse(w, cliCtx, requestBody.BaseReq, []sdk.Msg{msg})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func postClaimHardHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var requestBody types.PostClaimReq
|
||||||
|
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &requestBody) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
requestBody.BaseReq = requestBody.BaseReq.Sanitize()
|
||||||
|
if !requestBody.BaseReq.ValidateBasic(w) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fromAddr, err := sdk.AccAddressFromBech32(requestBody.BaseReq.From)
|
||||||
|
if err != nil {
|
||||||
|
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(fromAddr, requestBody.Sender) {
|
||||||
|
rest.WriteErrorResponse(w, http.StatusUnauthorized, fmt.Sprintf("expected: %s, got: %s", fromAddr, requestBody.Sender))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := types.NewMsgClaimHardLiquidityProviderReward(requestBody.Sender, requestBody.MultiplierName)
|
||||||
|
if err := msg.ValidateBasic(); err != nil {
|
||||||
|
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.WriteGenerateStdTxResponse(w, cliCtx, requestBody.BaseReq, []sdk.Msg{msg})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -15,6 +15,8 @@ func NewHandler(k keeper.Keeper) sdk.Handler {
|
|||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case types.MsgClaimUSDXMintingReward:
|
case types.MsgClaimUSDXMintingReward:
|
||||||
return handleMsgClaimUSDXMintingReward(ctx, k, msg)
|
return handleMsgClaimUSDXMintingReward(ctx, k, msg)
|
||||||
|
case types.MsgClaimHardLiquidityProviderReward:
|
||||||
|
return handleMsgClaimHardLiquidityProviderReward(ctx, k, msg)
|
||||||
default:
|
default:
|
||||||
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg)
|
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg)
|
||||||
}
|
}
|
||||||
@ -23,7 +25,18 @@ func NewHandler(k keeper.Keeper) sdk.Handler {
|
|||||||
|
|
||||||
func handleMsgClaimUSDXMintingReward(ctx sdk.Context, k keeper.Keeper, msg types.MsgClaimUSDXMintingReward) (*sdk.Result, error) {
|
func handleMsgClaimUSDXMintingReward(ctx sdk.Context, k keeper.Keeper, msg types.MsgClaimUSDXMintingReward) (*sdk.Result, error) {
|
||||||
|
|
||||||
err := k.ClaimReward(ctx, msg.Sender, types.MultiplierName(msg.MultiplierName))
|
err := k.ClaimUSDXMintingReward(ctx, msg.Sender, types.MultiplierName(msg.MultiplierName))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &sdk.Result{
|
||||||
|
Events: ctx.EventManager().Events(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleMsgClaimHardLiquidityProviderReward(ctx sdk.Context, k keeper.Keeper, msg types.MsgClaimHardLiquidityProviderReward) (*sdk.Result, error) {
|
||||||
|
|
||||||
|
err := k.ClaimHardReward(ctx, msg.Sender, types.MultiplierName(msg.MultiplierName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,34 @@ func (suite *HandlerTestSuite) SetupTest() {
|
|||||||
suite.ctx = ctx
|
suite.ctx = ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *HandlerTestSuite) addClaim() {
|
func (suite *HandlerTestSuite) TestMsgUSDXMintingClaimReward() {
|
||||||
|
suite.addUSDXMintingClaim()
|
||||||
|
msg := incentive.NewMsgClaimUSDXMintingReward(suite.addrs[0], "small")
|
||||||
|
res, err := suite.handler(suite.ctx, msg)
|
||||||
|
suite.NoError(err)
|
||||||
|
suite.Require().NotNil(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *HandlerTestSuite) TestMsgHardLiquidityProviderClaimReward() {
|
||||||
|
suite.addHardLiquidityProviderClaim()
|
||||||
|
msg := incentive.NewMsgClaimHardLiquidityProviderReward(suite.addrs[0], "small")
|
||||||
|
res, err := suite.handler(suite.ctx, msg)
|
||||||
|
suite.NoError(err)
|
||||||
|
suite.Require().NotNil(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *HandlerTestSuite) addHardLiquidityProviderClaim() {
|
||||||
|
sk := suite.app.GetSupplyKeeper()
|
||||||
|
err := sk.MintCoins(suite.ctx, kavadist.ModuleName, cs(c("ukava", 1000000000000)))
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
rewardPeriod := types.RewardIndexes{types.NewRewardIndex("bnb-s", sdk.ZeroDec())}
|
||||||
|
c1 := incentive.NewHardLiquidityProviderClaim(suite.addrs[0], c("ukava", 1000000), rewardPeriod, rewardPeriod, rewardPeriod)
|
||||||
|
suite.NotPanics(func() {
|
||||||
|
suite.keeper.SetHardLiquidityProviderClaim(suite.ctx, c1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *HandlerTestSuite) addUSDXMintingClaim() {
|
||||||
sk := suite.app.GetSupplyKeeper()
|
sk := suite.app.GetSupplyKeeper()
|
||||||
err := sk.MintCoins(suite.ctx, kavadist.ModuleName, cs(c("ukava", 1000000000000)))
|
err := sk.MintCoins(suite.ctx, kavadist.ModuleName, cs(c("ukava", 1000000000000)))
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
@ -73,13 +100,6 @@ func (suite *HandlerTestSuite) addClaim() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *HandlerTestSuite) TestMsgClaimReward() {
|
|
||||||
suite.addClaim()
|
|
||||||
msg := incentive.NewMsgClaimUSDXMintingReward(suite.addrs[0], "small")
|
|
||||||
res, err := suite.handler(suite.ctx, msg)
|
|
||||||
suite.NoError(err)
|
|
||||||
suite.Require().NotNil(res)
|
|
||||||
}
|
|
||||||
func TestHandlerTestSuite(t *testing.T) {
|
func TestHandlerTestSuite(t *testing.T) {
|
||||||
suite.Run(t, new(HandlerTestSuite))
|
suite.Run(t, new(HandlerTestSuite))
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,8 @@ import (
|
|||||||
validatorvesting "github.com/kava-labs/kava/x/validator-vesting"
|
validatorvesting "github.com/kava-labs/kava/x/validator-vesting"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ClaimReward sends the reward amount to the input address and zero's out the claim in the store
|
// ClaimUSDXMintingReward sends the reward amount to the input address and zero's out the claim in the store
|
||||||
func (k Keeper) ClaimReward(ctx sdk.Context, addr sdk.AccAddress, multiplierName types.MultiplierName) error {
|
func (k Keeper) ClaimUSDXMintingReward(ctx sdk.Context, addr sdk.AccAddress, multiplierName types.MultiplierName) error {
|
||||||
claim, found := k.GetUSDXMintingClaim(ctx, addr)
|
claim, found := k.GetUSDXMintingClaim(ctx, addr)
|
||||||
if !found {
|
if !found {
|
||||||
return sdkerrors.Wrapf(types.ErrClaimNotFound, "address: %s", addr)
|
return sdkerrors.Wrapf(types.ErrClaimNotFound, "address: %s", addr)
|
||||||
@ -30,7 +30,7 @@ func (k Keeper) ClaimReward(ctx sdk.Context, addr sdk.AccAddress, multiplierName
|
|||||||
return sdkerrors.Wrapf(types.ErrClaimExpired, "block time %s > claim end time %s", ctx.BlockTime(), claimEnd)
|
return sdkerrors.Wrapf(types.ErrClaimExpired, "block time %s > claim end time %s", ctx.BlockTime(), claimEnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
claim, err := k.SynchronizeClaim(ctx, claim)
|
claim, err := k.SynchronizeUSDXMintingClaim(ctx, claim)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -47,13 +47,64 @@ func (k Keeper) ClaimReward(ctx sdk.Context, addr sdk.AccAddress, multiplierName
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
k.ZeroClaim(ctx, claim)
|
k.ZeroUSDXMintingClaim(ctx, claim)
|
||||||
|
|
||||||
ctx.EventManager().EmitEvent(
|
ctx.EventManager().EmitEvent(
|
||||||
sdk.NewEvent(
|
sdk.NewEvent(
|
||||||
types.EventTypeClaim,
|
types.EventTypeClaim,
|
||||||
sdk.NewAttribute(types.AttributeKeyClaimedBy, addr.String()),
|
sdk.NewAttribute(types.AttributeKeyClaimedBy, claim.GetOwner().String()),
|
||||||
sdk.NewAttribute(types.AttributeKeyClaimAmount, claim.Reward.String()),
|
sdk.NewAttribute(types.AttributeKeyClaimAmount, claim.GetReward().String()),
|
||||||
|
sdk.NewAttribute(types.AttributeKeyClaimAmount, claim.GetType()),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClaimHardReward sends the reward amount to the input address and zero's out the claim in the store
|
||||||
|
func (k Keeper) ClaimHardReward(ctx sdk.Context, addr sdk.AccAddress, multiplierName types.MultiplierName) error {
|
||||||
|
_, found := k.GetHardLiquidityProviderClaim(ctx, addr)
|
||||||
|
if !found {
|
||||||
|
return sdkerrors.Wrapf(types.ErrClaimNotFound, "address: %s", addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
multiplier, found := k.GetMultiplier(ctx, multiplierName)
|
||||||
|
if !found {
|
||||||
|
return sdkerrors.Wrapf(types.ErrInvalidMultiplier, string(multiplierName))
|
||||||
|
}
|
||||||
|
|
||||||
|
claimEnd := k.GetClaimEnd(ctx)
|
||||||
|
|
||||||
|
if ctx.BlockTime().After(claimEnd) {
|
||||||
|
return sdkerrors.Wrapf(types.ErrClaimExpired, "block time %s > claim end time %s", ctx.BlockTime(), claimEnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
k.SynchronizeHardLiquidityProviderClaim(ctx, addr)
|
||||||
|
|
||||||
|
claim, found := k.GetHardLiquidityProviderClaim(ctx, addr)
|
||||||
|
if !found {
|
||||||
|
return sdkerrors.Wrapf(types.ErrClaimNotFound, "address: %s", addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
rewardAmount := claim.Reward.Amount.ToDec().Mul(multiplier.Factor).RoundInt()
|
||||||
|
if rewardAmount.IsZero() {
|
||||||
|
return types.ErrZeroClaim
|
||||||
|
}
|
||||||
|
rewardCoin := sdk.NewCoin(claim.Reward.Denom, rewardAmount)
|
||||||
|
length := ctx.BlockTime().AddDate(0, int(multiplier.MonthsLockup), 0).Unix() - ctx.BlockTime().Unix()
|
||||||
|
|
||||||
|
err := k.SendTimeLockedCoinsToAccount(ctx, types.IncentiveMacc, addr, sdk.NewCoins(rewardCoin), length)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
k.ZeroHardLiquidityProviderClaim(ctx, claim)
|
||||||
|
|
||||||
|
ctx.EventManager().EmitEvent(
|
||||||
|
sdk.NewEvent(
|
||||||
|
types.EventTypeClaim,
|
||||||
|
sdk.NewAttribute(types.AttributeKeyClaimedBy, claim.GetOwner().String()),
|
||||||
|
sdk.NewAttribute(types.AttributeKeyClaimAmount, claim.GetReward().String()),
|
||||||
|
sdk.NewAttribute(types.AttributeKeyClaimType, claim.GetType()),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
return nil
|
return nil
|
||||||
|
@ -14,12 +14,13 @@ import (
|
|||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
"github.com/kava-labs/kava/app"
|
"github.com/kava-labs/kava/app"
|
||||||
cdptypes "github.com/kava-labs/kava/x/cdp/types"
|
cdptypes "github.com/kava-labs/kava/x/cdp/types"
|
||||||
|
"github.com/kava-labs/kava/x/hard"
|
||||||
"github.com/kava-labs/kava/x/incentive/types"
|
"github.com/kava-labs/kava/x/incentive/types"
|
||||||
"github.com/kava-labs/kava/x/kavadist"
|
"github.com/kava-labs/kava/x/kavadist"
|
||||||
validatorvesting "github.com/kava-labs/kava/x/validator-vesting"
|
validatorvesting "github.com/kava-labs/kava/x/validator-vesting"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (suite *KeeperTestSuite) TestPayoutClaim() {
|
func (suite *KeeperTestSuite) TestPayoutUSDXMintingClaim() {
|
||||||
type args struct {
|
type args struct {
|
||||||
ctype string
|
ctype string
|
||||||
rewardsPerSecond sdk.Coin
|
rewardsPerSecond sdk.Coin
|
||||||
@ -129,7 +130,7 @@ func (suite *KeeperTestSuite) TestPayoutClaim() {
|
|||||||
err = suite.keeper.AccumulateUSDXMintingRewards(suite.ctx, rewardPeriod)
|
err = suite.keeper.AccumulateUSDXMintingRewards(suite.ctx, rewardPeriod)
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
err = suite.keeper.ClaimReward(suite.ctx, suite.addrs[0], tc.args.multiplier)
|
err = suite.keeper.ClaimUSDXMintingReward(suite.ctx, suite.addrs[0], tc.args.multiplier)
|
||||||
|
|
||||||
if tc.errArgs.expectPass {
|
if tc.errArgs.expectPass {
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
@ -155,6 +156,173 @@ func (suite *KeeperTestSuite) TestPayoutClaim() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaim() {
|
||||||
|
type args struct {
|
||||||
|
deposit sdk.Coins
|
||||||
|
borrow sdk.Coins
|
||||||
|
rewardsPerSecond sdk.Coin
|
||||||
|
initialTime time.Time
|
||||||
|
multipliers types.Multipliers
|
||||||
|
multiplier types.MultiplierName
|
||||||
|
timeElapsed int64
|
||||||
|
expectedReward sdk.Coin
|
||||||
|
expectedPeriods vesting.Periods
|
||||||
|
isPeriodicVestingAccount bool
|
||||||
|
}
|
||||||
|
type errArgs struct {
|
||||||
|
expectPass bool
|
||||||
|
contains string
|
||||||
|
}
|
||||||
|
type test struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
errArgs errArgs
|
||||||
|
}
|
||||||
|
testCases := []test{
|
||||||
|
{
|
||||||
|
"valid 1 day",
|
||||||
|
args{
|
||||||
|
deposit: cs(c("bnb", 10000000000)),
|
||||||
|
borrow: cs(c("bnb", 5000000000)),
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))},
|
||||||
|
multiplier: types.MultiplierName("large"),
|
||||||
|
timeElapsed: 86400,
|
||||||
|
expectedReward: c("hard", 21142771200), // 10571385600 (deposit reward) + 10571385600 (borrow reward)
|
||||||
|
expectedPeriods: vesting.Periods{vesting.Period{Length: 31536000, Amount: cs(c("hard", 21142771200))}},
|
||||||
|
isPeriodicVestingAccount: true,
|
||||||
|
},
|
||||||
|
errArgs{
|
||||||
|
expectPass: true,
|
||||||
|
contains: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"invalid zero rewards",
|
||||||
|
args{
|
||||||
|
deposit: cs(c("bnb", 10000000000)),
|
||||||
|
borrow: cs(c("bnb", 5000000000)),
|
||||||
|
rewardsPerSecond: c("hard", 0),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))},
|
||||||
|
multiplier: types.MultiplierName("large"),
|
||||||
|
timeElapsed: 86400,
|
||||||
|
expectedReward: sdk.Coin{},
|
||||||
|
expectedPeriods: vesting.Periods{},
|
||||||
|
isPeriodicVestingAccount: false,
|
||||||
|
},
|
||||||
|
errArgs{
|
||||||
|
expectPass: false,
|
||||||
|
contains: "claim amount rounds to zero",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
suite.Run(tc.name, func() {
|
||||||
|
suite.SetupWithGenState()
|
||||||
|
suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime)
|
||||||
|
|
||||||
|
// setup kavadist state
|
||||||
|
sk := suite.app.GetSupplyKeeper()
|
||||||
|
err := sk.MintCoins(suite.ctx, kavadist.ModuleName, cs(c("hard", 1000000000000)))
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// Set up generic reward periods
|
||||||
|
var rewardPeriods types.RewardPeriods
|
||||||
|
for _, coin := range tc.args.deposit {
|
||||||
|
rewardPeriod := types.NewRewardPeriod(true, coin.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)
|
||||||
|
rewardPeriods = append(rewardPeriods, rewardPeriod)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up incentive state
|
||||||
|
params := types.NewParams(
|
||||||
|
rewardPeriods, rewardPeriods, rewardPeriods, rewardPeriods,
|
||||||
|
tc.args.multipliers,
|
||||||
|
tc.args.initialTime.Add(time.Hour*24*365*5),
|
||||||
|
)
|
||||||
|
suite.keeper.SetParams(suite.ctx, params)
|
||||||
|
|
||||||
|
// Set each denom's previous accrual time and supply reward factor
|
||||||
|
for _, coin := range tc.args.deposit {
|
||||||
|
suite.keeper.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, coin.Denom, tc.args.initialTime)
|
||||||
|
suite.keeper.SetHardSupplyRewardFactor(suite.ctx, coin.Denom, sdk.ZeroDec())
|
||||||
|
}
|
||||||
|
for _, coin := range tc.args.borrow {
|
||||||
|
suite.keeper.SetPreviousHardBorrowRewardAccrualTime(suite.ctx, coin.Denom, tc.args.initialTime)
|
||||||
|
suite.keeper.SetHardBorrowRewardFactor(suite.ctx, coin.Denom, sdk.ZeroDec())
|
||||||
|
}
|
||||||
|
|
||||||
|
hardKeeper := suite.app.GetHardKeeper()
|
||||||
|
userAddr := suite.addrs[3]
|
||||||
|
|
||||||
|
// User deposits
|
||||||
|
err = hardKeeper.Deposit(suite.ctx, userAddr, tc.args.deposit)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// User borrows
|
||||||
|
err = hardKeeper.Borrow(suite.ctx, userAddr, tc.args.borrow)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// Check that Hard hooks initialized a HardLiquidityProviderClaim that has 0 rewards
|
||||||
|
claim, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3])
|
||||||
|
suite.Require().True(found)
|
||||||
|
suite.Require().Equal(sdk.ZeroInt(), claim.Reward.Amount)
|
||||||
|
|
||||||
|
// Set up future runtime context
|
||||||
|
runAtTime := time.Unix(suite.ctx.BlockTime().Unix()+(tc.args.timeElapsed), 0)
|
||||||
|
runCtx := suite.ctx.WithBlockTime(runAtTime)
|
||||||
|
|
||||||
|
// Run Hard begin blocker
|
||||||
|
hard.BeginBlocker(runCtx, suite.hardKeeper)
|
||||||
|
|
||||||
|
// Accumulate supply rewards for each deposit denom
|
||||||
|
for _, coin := range tc.args.deposit {
|
||||||
|
rewardPeriod, found := suite.keeper.GetHardSupplyRewardPeriod(runCtx, coin.Denom)
|
||||||
|
suite.Require().True(found)
|
||||||
|
err = suite.keeper.AccumulateHardSupplyRewards(runCtx, rewardPeriod)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accumulate borrow rewards for each deposit denom
|
||||||
|
for _, coin := range tc.args.borrow {
|
||||||
|
rewardPeriod, found := suite.keeper.GetHardBorrowRewardPeriod(runCtx, coin.Denom)
|
||||||
|
suite.Require().True(found)
|
||||||
|
err = suite.keeper.AccumulateHardBorrowRewards(runCtx, rewardPeriod)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch pre-claim balances
|
||||||
|
ak := suite.app.GetAccountKeeper()
|
||||||
|
preClaimAcc := ak.GetAccount(runCtx, suite.addrs[3])
|
||||||
|
|
||||||
|
err = suite.keeper.ClaimHardReward(runCtx, suite.addrs[3], tc.args.multiplier)
|
||||||
|
if tc.errArgs.expectPass {
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// Check that user's balance has increased by expected reward amount
|
||||||
|
postClaimAcc := ak.GetAccount(suite.ctx, suite.addrs[3])
|
||||||
|
suite.Require().Equal(preClaimAcc.GetCoins().Add(tc.args.expectedReward), postClaimAcc.GetCoins())
|
||||||
|
|
||||||
|
if tc.args.isPeriodicVestingAccount {
|
||||||
|
vacc, ok := postClaimAcc.(*vesting.PeriodicVestingAccount)
|
||||||
|
suite.Require().True(ok)
|
||||||
|
suite.Require().Equal(tc.args.expectedPeriods, vacc.VestingPeriods)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the claim's reward amount has been reset to 0
|
||||||
|
claim, found := suite.keeper.GetHardLiquidityProviderClaim(runCtx, suite.addrs[3])
|
||||||
|
suite.Require().True(found)
|
||||||
|
suite.Require().Equal(c("hard", 0), claim.Reward)
|
||||||
|
} else {
|
||||||
|
suite.Require().Error(err)
|
||||||
|
suite.Require().True(strings.Contains(err.Error(), tc.errArgs.contains))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (suite *KeeperTestSuite) TestSendCoinsToPeriodicVestingAccount() {
|
func (suite *KeeperTestSuite) TestSendCoinsToPeriodicVestingAccount() {
|
||||||
type accountArgs struct {
|
type accountArgs struct {
|
||||||
periods vesting.Periods
|
periods vesting.Periods
|
||||||
|
@ -17,8 +17,10 @@ func NewQuerier(k Keeper) sdk.Querier {
|
|||||||
switch path[0] {
|
switch path[0] {
|
||||||
case types.QueryGetParams:
|
case types.QueryGetParams:
|
||||||
return queryGetParams(ctx, req, k)
|
return queryGetParams(ctx, req, k)
|
||||||
case types.QueryGetClaims:
|
case types.QueryGetCdpClaims:
|
||||||
return queryGetClaims(ctx, req, k)
|
return queryGetCdpClaims(ctx, req, k)
|
||||||
|
case types.QueryGetHardClaims:
|
||||||
|
return queryGetHardClaims(ctx, req, k)
|
||||||
default:
|
default:
|
||||||
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint", types.ModuleName)
|
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint", types.ModuleName)
|
||||||
}
|
}
|
||||||
@ -38,8 +40,8 @@ func queryGetParams(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, e
|
|||||||
return bz, nil
|
return bz, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryGetClaims(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
|
func queryGetCdpClaims(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
|
||||||
var requestParams types.QueryClaimsParams
|
var requestParams types.QueryCdpClaimsParams
|
||||||
err := k.cdc.UnmarshalJSON(req.Data, &requestParams)
|
err := k.cdc.UnmarshalJSON(req.Data, &requestParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
|
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
|
||||||
@ -67,3 +69,33 @@ func queryGetClaims(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, e
|
|||||||
}
|
}
|
||||||
return bz, nil
|
return bz, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func queryGetHardClaims(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
|
||||||
|
var requestParams types.QueryHardClaimsParams
|
||||||
|
err := k.cdc.UnmarshalJSON(req.Data, &requestParams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
|
||||||
|
}
|
||||||
|
var claims types.HardLiquidityProviderClaims
|
||||||
|
if len(requestParams.Owner) > 0 {
|
||||||
|
claim, _ := k.GetHardLiquidityProviderClaim(ctx, requestParams.Owner)
|
||||||
|
claims = append(claims, claim)
|
||||||
|
} else {
|
||||||
|
claims = k.GetAllHardLiquidityProviderClaims(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
var paginatedClaims types.HardLiquidityProviderClaims
|
||||||
|
|
||||||
|
start, end := client.Paginate(len(claims), requestParams.Page, requestParams.Limit, 100)
|
||||||
|
if start < 0 || end < 0 {
|
||||||
|
paginatedClaims = types.HardLiquidityProviderClaims{}
|
||||||
|
} else {
|
||||||
|
paginatedClaims = claims[start:end]
|
||||||
|
}
|
||||||
|
|
||||||
|
bz, err := codec.MarshalJSONIndent(k.cdc, paginatedClaims)
|
||||||
|
if err != nil {
|
||||||
|
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
|
||||||
|
}
|
||||||
|
return bz, nil
|
||||||
|
}
|
||||||
|
@ -518,16 +518,16 @@ func (k Keeper) InitializeHardDelegatorReward(ctx sdk.Context, delegator sdk.Acc
|
|||||||
k.SetHardLiquidityProviderClaim(ctx, claim)
|
k.SetHardLiquidityProviderClaim(ctx, claim)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZeroClaim zeroes out the claim object's rewards and returns the updated claim object
|
// ZeroUSDXMintingClaim zeroes out the claim object's rewards and returns the updated claim object
|
||||||
func (k Keeper) ZeroClaim(ctx sdk.Context, claim types.USDXMintingClaim) types.USDXMintingClaim {
|
func (k Keeper) ZeroUSDXMintingClaim(ctx sdk.Context, claim types.USDXMintingClaim) types.USDXMintingClaim {
|
||||||
claim.Reward = sdk.NewCoin(claim.Reward.Denom, sdk.ZeroInt())
|
claim.Reward = sdk.NewCoin(claim.Reward.Denom, sdk.ZeroInt())
|
||||||
k.SetUSDXMintingClaim(ctx, claim)
|
k.SetUSDXMintingClaim(ctx, claim)
|
||||||
return claim
|
return claim
|
||||||
}
|
}
|
||||||
|
|
||||||
// SynchronizeClaim updates the claim object by adding any rewards that have accumulated.
|
// SynchronizeUSDXMintingClaim updates the claim object by adding any rewards that have accumulated.
|
||||||
// Returns the updated claim object
|
// Returns the updated claim object
|
||||||
func (k Keeper) SynchronizeClaim(ctx sdk.Context, claim types.USDXMintingClaim) (types.USDXMintingClaim, error) {
|
func (k Keeper) SynchronizeUSDXMintingClaim(ctx sdk.Context, claim types.USDXMintingClaim) (types.USDXMintingClaim, error) {
|
||||||
for _, ri := range claim.RewardIndexes {
|
for _, ri := range claim.RewardIndexes {
|
||||||
cdp, found := k.cdpKeeper.GetCdpByOwnerAndCollateralType(ctx, claim.Owner, ri.CollateralType)
|
cdp, found := k.cdpKeeper.GetCdpByOwnerAndCollateralType(ctx, claim.Owner, ri.CollateralType)
|
||||||
if !found {
|
if !found {
|
||||||
@ -546,6 +546,31 @@ func (k Keeper) synchronizeRewardAndReturnClaim(ctx sdk.Context, cdp cdptypes.CD
|
|||||||
return claim
|
return claim
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SynchronizeHardLiquidityProviderClaim adds any accumulated rewards
|
||||||
|
func (k Keeper) SynchronizeHardLiquidityProviderClaim(ctx sdk.Context, owner sdk.AccAddress) {
|
||||||
|
// Synchronize any hard liquidity supply-side rewards
|
||||||
|
deposit, foundDeposit := k.hardKeeper.GetDeposit(ctx, owner)
|
||||||
|
if foundDeposit {
|
||||||
|
k.SynchronizeHardSupplyReward(ctx, deposit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synchronize any hard liquidity borrow-side rewards
|
||||||
|
borrow, foundBorrow := k.hardKeeper.GetBorrow(ctx, owner)
|
||||||
|
if foundBorrow {
|
||||||
|
k.SynchronizeHardBorrowReward(ctx, borrow)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synchronize any hard delegator rewards
|
||||||
|
k.SynchronizeHardDelegatorRewards(ctx, owner)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZeroHardLiquidityProviderClaim zeroes out the claim object's rewards and returns the updated claim object
|
||||||
|
func (k Keeper) ZeroHardLiquidityProviderClaim(ctx sdk.Context, claim types.HardLiquidityProviderClaim) types.HardLiquidityProviderClaim {
|
||||||
|
claim.Reward = sdk.NewCoin(claim.Reward.Denom, sdk.ZeroInt())
|
||||||
|
k.SetHardLiquidityProviderClaim(ctx, claim)
|
||||||
|
return claim
|
||||||
|
}
|
||||||
|
|
||||||
// CalculateTimeElapsed calculates the number of reward-eligible seconds that have passed since the previous
|
// CalculateTimeElapsed calculates the number of reward-eligible seconds that have passed since the previous
|
||||||
// time rewards were accrued, taking into account the end time of the reward period
|
// time rewards were accrued, taking into account the end time of the reward period
|
||||||
func CalculateTimeElapsed(rewardPeriod types.RewardPeriod, blockTime time.Time, previousAccrualTime time.Time) sdk.Int {
|
func CalculateTimeElapsed(rewardPeriod types.RewardPeriod, blockTime time.Time, previousAccrualTime time.Time) sdk.Int {
|
||||||
|
@ -20,4 +20,5 @@ func RegisterCodec(cdc *codec.Codec) {
|
|||||||
|
|
||||||
// Register msgs
|
// Register msgs
|
||||||
cdc.RegisterConcrete(MsgClaimUSDXMintingReward{}, "incentive/MsgClaimUSDXMintingReward", nil)
|
cdc.RegisterConcrete(MsgClaimUSDXMintingReward{}, "incentive/MsgClaimUSDXMintingReward", nil)
|
||||||
|
cdc.RegisterConcrete(MsgClaimHardLiquidityProviderReward{}, "incentive/MsgClaimHardLiquidityProviderReward", nil)
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ const (
|
|||||||
AttributeValueCategory = ModuleName
|
AttributeValueCategory = ModuleName
|
||||||
AttributeKeyClaimedBy = "claimed_by"
|
AttributeKeyClaimedBy = "claimed_by"
|
||||||
AttributeKeyClaimAmount = "claim_amount"
|
AttributeKeyClaimAmount = "claim_amount"
|
||||||
|
AttributeKeyClaimType = "claim_type"
|
||||||
AttributeKeyRewardPeriod = "reward_period"
|
AttributeKeyRewardPeriod = "reward_period"
|
||||||
AttributeKeyClaimPeriod = "claim_period"
|
AttributeKeyClaimPeriod = "claim_period"
|
||||||
)
|
)
|
||||||
|
@ -33,6 +33,8 @@ type CdpKeeper interface {
|
|||||||
|
|
||||||
// HardKeeper defines the expected hard keeper for interacting with Hard protocol
|
// HardKeeper defines the expected hard keeper for interacting with Hard protocol
|
||||||
type HardKeeper interface {
|
type HardKeeper interface {
|
||||||
|
GetDeposit(ctx sdk.Context, depositor sdk.AccAddress) (hardtypes.Deposit, bool)
|
||||||
|
GetBorrow(ctx sdk.Context, borrower sdk.AccAddress) (hardtypes.Borrow, bool)
|
||||||
GetSupplyInterestFactor(ctx sdk.Context, denom string) (sdk.Dec, bool)
|
GetSupplyInterestFactor(ctx sdk.Context, denom string) (sdk.Dec, bool)
|
||||||
GetBorrowInterestFactor(ctx sdk.Context, denom string) (sdk.Dec, bool)
|
GetBorrowInterestFactor(ctx sdk.Context, denom string) (sdk.Dec, bool)
|
||||||
GetBorrowedCoins(ctx sdk.Context) (coins sdk.Coins, found bool)
|
GetBorrowedCoins(ctx sdk.Context) (coins sdk.Coins, found bool)
|
||||||
|
@ -9,8 +9,9 @@ import (
|
|||||||
|
|
||||||
// ensure Msg interface compliance at compile time
|
// ensure Msg interface compliance at compile time
|
||||||
var _ sdk.Msg = &MsgClaimUSDXMintingReward{}
|
var _ sdk.Msg = &MsgClaimUSDXMintingReward{}
|
||||||
|
var _ sdk.Msg = &MsgClaimHardLiquidityProviderReward{}
|
||||||
|
|
||||||
// MsgClaimUSDXMintingReward message type used to claim rewards
|
// MsgClaimUSDXMintingReward message type used to claim USDX minting rewards
|
||||||
type MsgClaimUSDXMintingReward struct {
|
type MsgClaimUSDXMintingReward struct {
|
||||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||||
MultiplierName string `json:"multiplier_name" yaml:"multiplier_name"`
|
MultiplierName string `json:"multiplier_name" yaml:"multiplier_name"`
|
||||||
@ -28,7 +29,7 @@ func NewMsgClaimUSDXMintingReward(sender sdk.AccAddress, multiplierName string)
|
|||||||
func (msg MsgClaimUSDXMintingReward) Route() string { return RouterKey }
|
func (msg MsgClaimUSDXMintingReward) Route() string { return RouterKey }
|
||||||
|
|
||||||
// Type returns a human-readable string for the message, intended for utilization within tags.
|
// Type returns a human-readable string for the message, intended for utilization within tags.
|
||||||
func (msg MsgClaimUSDXMintingReward) Type() string { return "claim_reward" }
|
func (msg MsgClaimUSDXMintingReward) Type() string { return "claim_usdx_minting_reward" }
|
||||||
|
|
||||||
// ValidateBasic does a simple validation check that doesn't require access to state.
|
// ValidateBasic does a simple validation check that doesn't require access to state.
|
||||||
func (msg MsgClaimUSDXMintingReward) ValidateBasic() error {
|
func (msg MsgClaimUSDXMintingReward) ValidateBasic() error {
|
||||||
@ -48,3 +49,44 @@ func (msg MsgClaimUSDXMintingReward) GetSignBytes() []byte {
|
|||||||
func (msg MsgClaimUSDXMintingReward) GetSigners() []sdk.AccAddress {
|
func (msg MsgClaimUSDXMintingReward) GetSigners() []sdk.AccAddress {
|
||||||
return []sdk.AccAddress{msg.Sender}
|
return []sdk.AccAddress{msg.Sender}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MsgClaimHardLiquidityProviderReward message type used to claim Hard liquidity provider rewards
|
||||||
|
type MsgClaimHardLiquidityProviderReward struct {
|
||||||
|
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||||
|
MultiplierName string `json:"multiplier_name" yaml:"multiplier_name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMsgClaimHardLiquidityProviderReward returns a new MsgClaimHardLiquidityProviderReward.
|
||||||
|
func NewMsgClaimHardLiquidityProviderReward(sender sdk.AccAddress, multiplierName string) MsgClaimHardLiquidityProviderReward {
|
||||||
|
return MsgClaimHardLiquidityProviderReward{
|
||||||
|
Sender: sender,
|
||||||
|
MultiplierName: multiplierName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Route return the message type used for routing the message.
|
||||||
|
func (msg MsgClaimHardLiquidityProviderReward) Route() string { return RouterKey }
|
||||||
|
|
||||||
|
// Type returns a human-readable string for the message, intended for utilization within tags.
|
||||||
|
func (msg MsgClaimHardLiquidityProviderReward) Type() string {
|
||||||
|
return "claim_hard_liquidity_provider_reward"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateBasic does a simple validation check that doesn't require access to state.
|
||||||
|
func (msg MsgClaimHardLiquidityProviderReward) ValidateBasic() error {
|
||||||
|
if msg.Sender.Empty() {
|
||||||
|
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be empty")
|
||||||
|
}
|
||||||
|
return MultiplierName(strings.ToLower(msg.MultiplierName)).IsValid()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSignBytes gets the canonical byte representation of the Msg.
|
||||||
|
func (msg MsgClaimHardLiquidityProviderReward) GetSignBytes() []byte {
|
||||||
|
bz := ModuleCdc.MustMarshalJSON(msg)
|
||||||
|
return sdk.MustSortJSON(bz)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSigners returns the addresses of signers that must sign.
|
||||||
|
func (msg MsgClaimHardLiquidityProviderReward) GetSigners() []sdk.AccAddress {
|
||||||
|
return []sdk.AccAddress{msg.Sender}
|
||||||
|
}
|
||||||
|
@ -7,7 +7,8 @@ import (
|
|||||||
|
|
||||||
// Querier routes for the incentive module
|
// Querier routes for the incentive module
|
||||||
const (
|
const (
|
||||||
QueryGetClaims = "claims"
|
QueryGetCdpClaims = "cdp-claims"
|
||||||
|
QueryGetHardClaims = "hard-claims"
|
||||||
RestClaimOwner = "owner"
|
RestClaimOwner = "owner"
|
||||||
RestClaimCollateralType = "collateral_type"
|
RestClaimCollateralType = "collateral_type"
|
||||||
QueryGetParams = "parameters"
|
QueryGetParams = "parameters"
|
||||||
@ -15,16 +16,32 @@ const (
|
|||||||
QueryGetClaimPeriods = "claim-periods"
|
QueryGetClaimPeriods = "claim-periods"
|
||||||
)
|
)
|
||||||
|
|
||||||
// QueryClaimsParams params for query /incentive/claims
|
// QueryCdpClaimsParams params for query /incentive/claims
|
||||||
type QueryClaimsParams struct {
|
type QueryCdpClaimsParams struct {
|
||||||
Page int `json:"page" yaml:"page"`
|
Page int `json:"page" yaml:"page"`
|
||||||
Limit int `json:"limit" yaml:"limit"`
|
Limit int `json:"limit" yaml:"limit"`
|
||||||
Owner sdk.AccAddress
|
Owner sdk.AccAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewQueryClaimsParams returns QueryClaimsParams
|
// NewQueryCdpClaimsParams returns QueryCdpClaimsParams
|
||||||
func NewQueryClaimsParams(page, limit int, owner sdk.AccAddress) QueryClaimsParams {
|
func NewQueryCdpClaimsParams(page, limit int, owner sdk.AccAddress) QueryCdpClaimsParams {
|
||||||
return QueryClaimsParams{
|
return QueryCdpClaimsParams{
|
||||||
|
Page: page,
|
||||||
|
Limit: limit,
|
||||||
|
Owner: owner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryHardClaimsParams params for query /incentive/claims
|
||||||
|
type QueryHardClaimsParams struct {
|
||||||
|
Page int `json:"page" yaml:"page"`
|
||||||
|
Limit int `json:"limit" yaml:"limit"`
|
||||||
|
Owner sdk.AccAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewQueryHardClaimsParams returns QueryHardClaimsParams
|
||||||
|
func NewQueryHardClaimsParams(page, limit int, owner sdk.AccAddress) QueryHardClaimsParams {
|
||||||
|
return QueryHardClaimsParams{
|
||||||
Page: page,
|
Page: page,
|
||||||
Limit: limit,
|
Limit: limit,
|
||||||
Owner: owner,
|
Owner: owner,
|
||||||
|
Loading…
Reference in New Issue
Block a user