mirror of
				https://github.com/0glabs/0g-chain.git
				synced 2025-10-31 18:27:26 +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 | ||||
| 	QuerierRoute               = types.QuerierRoute | ||||
| 	QueryGetClaimPeriods       = types.QueryGetClaimPeriods | ||||
| 	QueryGetClaims             = types.QueryGetClaims | ||||
| 	QueryGetCdpClaims          = types.QueryGetCdpClaims | ||||
| 	QueryGetHardClaims         = types.QueryGetHardClaims | ||||
| 	QueryGetParams             = types.QueryGetParams | ||||
| 	QueryGetRewardPeriods      = types.QueryGetRewardPeriods | ||||
| 	RestClaimCollateralType    = types.RestClaimCollateralType | ||||
| @ -35,24 +36,27 @@ const ( | ||||
| 
 | ||||
| var ( | ||||
| 	// function aliases
 | ||||
| 	CalculateTimeElapsed         = keeper.CalculateTimeElapsed | ||||
| 	NewKeeper                    = keeper.NewKeeper | ||||
| 	NewQuerier                   = keeper.NewQuerier | ||||
| 	DefaultGenesisState          = types.DefaultGenesisState | ||||
| 	DefaultParams                = types.DefaultParams | ||||
| 	GetTotalVestingPeriodLength  = types.GetTotalVestingPeriodLength | ||||
| 	NewGenesisAccumulationTime   = types.NewGenesisAccumulationTime | ||||
| 	NewGenesisState              = types.NewGenesisState | ||||
| 	NewMsgClaimUSDXMintingReward = types.NewMsgClaimUSDXMintingReward | ||||
| 	NewMultiplier                = types.NewMultiplier | ||||
| 	NewParams                    = types.NewParams | ||||
| 	NewPeriod                    = types.NewPeriod | ||||
| 	NewQueryClaimsParams         = types.NewQueryClaimsParams | ||||
| 	NewRewardIndex               = types.NewRewardIndex | ||||
| 	NewRewardPeriod              = types.NewRewardPeriod | ||||
| 	NewUSDXMintingClaim          = types.NewUSDXMintingClaim | ||||
| 	ParamKeyTable                = types.ParamKeyTable | ||||
| 	RegisterCodec                = types.RegisterCodec | ||||
| 	CalculateTimeElapsed                   = keeper.CalculateTimeElapsed | ||||
| 	NewKeeper                              = keeper.NewKeeper | ||||
| 	NewQuerier                             = keeper.NewQuerier | ||||
| 	DefaultGenesisState                    = types.DefaultGenesisState | ||||
| 	DefaultParams                          = types.DefaultParams | ||||
| 	GetTotalVestingPeriodLength            = types.GetTotalVestingPeriodLength | ||||
| 	NewGenesisAccumulationTime             = types.NewGenesisAccumulationTime | ||||
| 	NewGenesisState                        = types.NewGenesisState | ||||
| 	NewMsgClaimUSDXMintingReward           = types.NewMsgClaimUSDXMintingReward | ||||
| 	NewMsgClaimHardLiquidityProviderReward = types.NewMsgClaimHardLiquidityProviderReward | ||||
| 	NewMultiplier                          = types.NewMultiplier | ||||
| 	NewParams                              = types.NewParams | ||||
| 	NewPeriod                              = types.NewPeriod | ||||
| 	NewQueryCdpClaimsParams                = types.NewQueryCdpClaimsParams | ||||
| 	NewQueryHardClaimsParams               = types.NewQueryHardClaimsParams | ||||
| 	NewRewardIndex                         = types.NewRewardIndex | ||||
| 	NewRewardPeriod                        = types.NewRewardPeriod | ||||
| 	NewUSDXMintingClaim                    = types.NewUSDXMintingClaim | ||||
| 	NewHardLiquidityProviderClaim          = types.NewHardLiquidityProviderClaim | ||||
| 	ParamKeyTable                          = types.ParamKeyTable | ||||
| 	RegisterCodec                          = types.RegisterCodec | ||||
| 
 | ||||
| 	// variable aliases
 | ||||
| 	PreviousUSDXMintingRewardAccrualTimeKeyPrefix = types.PreviousUSDXMintingRewardAccrualTimeKeyPrefix | ||||
| @ -99,7 +103,8 @@ type ( | ||||
| 	Multipliers               = types.Multipliers | ||||
| 	Params                    = types.Params | ||||
| 	PostClaimReq              = types.PostClaimReq | ||||
| 	QueryClaimsParams         = types.QueryClaimsParams | ||||
| 	QueryCdpClaimsParams      = types.QueryCdpClaimsParams | ||||
| 	QueryHardClaimsParams     = types.QueryHardClaimsParams | ||||
| 	RewardIndex               = types.RewardIndex | ||||
| 	RewardIndexes             = types.RewardIndexes | ||||
| 	RewardPeriod              = types.RewardPeriod | ||||
|  | ||||
| @ -25,7 +25,8 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { | ||||
| 
 | ||||
| 	incentiveQueryCmd.AddCommand(flags.GetCommands( | ||||
| 		queryParamsCmd(queryRoute, cdc), | ||||
| 		queryClaimsCmd(queryRoute, cdc), | ||||
| 		queryCdpClaimsCmd(queryRoute, cdc), | ||||
| 		queryHardClaimsCmd(queryRoute, cdc), | ||||
| 	)...) | ||||
| 
 | ||||
| 	return incentiveQueryCmd | ||||
| @ -35,16 +36,16 @@ const ( | ||||
| 	flagOwner = "owner" | ||||
| ) | ||||
| 
 | ||||
| func queryClaimsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { | ||||
| func queryCdpClaimsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { | ||||
| 	cmd := &cobra.Command{ | ||||
| 		Use:   "claims ", | ||||
| 		Use:   "cdp-claims", | ||||
| 		Short: "query USDX minting claims", | ||||
| 		Long: strings.TrimSpace( | ||||
| 			fmt.Sprintf(`Query USDX minting claims with optional flag for finding claims for a specifc owner | ||||
| 
 | ||||
| 			Example: | ||||
| 			$ %s query %s claims | ||||
| 			$ %s query %s claims --owner kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw | ||||
| 			$ %s query %s cdp-claims | ||||
| 			$ %s query %s cdp-claims --owner kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw | ||||
| 			`, | ||||
| 				version.ClientName, types.ModuleName, version.ClientName, types.ModuleName)), | ||||
| 		Args: cobra.NoArgs, | ||||
| @ -60,14 +61,67 @@ func queryClaimsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			params := types.NewQueryClaimsParams(page, limit, owner) | ||||
| 			params := types.NewQueryCdpClaimsParams(page, limit, owner) | ||||
| 			bz, err := cdc.MarshalJSON(params) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			// 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) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
|  | ||||
| @ -26,22 +26,23 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command { | ||||
| 	} | ||||
| 
 | ||||
| 	incentiveTxCmd.AddCommand(flags.PostCommands( | ||||
| 		getCmdClaim(cdc), | ||||
| 		getCmdClaimCdp(cdc), | ||||
| 		getCmdClaimHard(cdc), | ||||
| 	)...) | ||||
| 
 | ||||
| 	return incentiveTxCmd | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| func getCmdClaim(cdc *codec.Codec) *cobra.Command { | ||||
| func getCmdClaimCdp(cdc *codec.Codec) *cobra.Command { | ||||
| 	return &cobra.Command{ | ||||
| 		Use:   "claim [owner] [multiplier]", | ||||
| 		Short: "claim rewards for cdp owner and collateral-type", | ||||
| 		Use:   "claim-cdp [owner] [multiplier]", | ||||
| 		Short: "claim CDP rewards for cdp owner and collateral-type", | ||||
| 		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: | ||||
| 			$ %s tx %s claim kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw large | ||||
| 			$ %s tx %s claim-cdp kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw large | ||||
| 		`, version.ClientName, types.ModuleName), | ||||
| 		), | ||||
| 		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) { | ||||
| 	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") | ||||
| } | ||||
| 
 | ||||
| func queryClaimsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { | ||||
| func queryCdpClaimsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { | ||||
| 	return func(w http.ResponseWriter, r *http.Request) { | ||||
| 		_, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 0) | ||||
| 		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) | ||||
| 		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.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 { | ||||
| 			rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) | ||||
| 			return | ||||
|  | ||||
| @ -16,10 +16,11 @@ import ( | ||||
| ) | ||||
| 
 | ||||
| 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) { | ||||
| 		var requestBody types.PostClaimReq | ||||
| 		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}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 		case types.MsgClaimUSDXMintingReward: | ||||
| 			return handleMsgClaimUSDXMintingReward(ctx, k, msg) | ||||
| 		case types.MsgClaimHardLiquidityProviderReward: | ||||
| 			return handleMsgClaimHardLiquidityProviderReward(ctx, k, msg) | ||||
| 		default: | ||||
| 			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) { | ||||
| 
 | ||||
| 	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 { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| @ -63,7 +63,34 @@ func (suite *HandlerTestSuite) SetupTest() { | ||||
| 	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() | ||||
| 	err := sk.MintCoins(suite.ctx, kavadist.ModuleName, cs(c("ukava", 1000000000000))) | ||||
| 	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) { | ||||
| 	suite.Run(t, new(HandlerTestSuite)) | ||||
| } | ||||
|  | ||||
| @ -12,8 +12,8 @@ import ( | ||||
| 	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
 | ||||
| func (k Keeper) ClaimReward(ctx sdk.Context, addr sdk.AccAddress, multiplierName types.MultiplierName) error { | ||||
| // ClaimUSDXMintingReward sends the reward amount to the input address and zero's out the claim in the store
 | ||||
| func (k Keeper) ClaimUSDXMintingReward(ctx sdk.Context, addr sdk.AccAddress, multiplierName types.MultiplierName) error { | ||||
| 	claim, found := k.GetUSDXMintingClaim(ctx, addr) | ||||
| 	if !found { | ||||
| 		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) | ||||
| 	} | ||||
| 
 | ||||
| 	claim, err := k.SynchronizeClaim(ctx, claim) | ||||
| 	claim, err := k.SynchronizeUSDXMintingClaim(ctx, claim) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @ -47,13 +47,64 @@ func (k Keeper) ClaimReward(ctx sdk.Context, addr sdk.AccAddress, multiplierName | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	k.ZeroClaim(ctx, claim) | ||||
| 	k.ZeroUSDXMintingClaim(ctx, claim) | ||||
| 
 | ||||
| 	ctx.EventManager().EmitEvent( | ||||
| 		sdk.NewEvent( | ||||
| 			types.EventTypeClaim, | ||||
| 			sdk.NewAttribute(types.AttributeKeyClaimedBy, addr.String()), | ||||
| 			sdk.NewAttribute(types.AttributeKeyClaimAmount, claim.Reward.String()), | ||||
| 			sdk.NewAttribute(types.AttributeKeyClaimedBy, claim.GetOwner().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 | ||||
|  | ||||
| @ -14,12 +14,13 @@ import ( | ||||
| 	"github.com/cosmos/cosmos-sdk/x/auth" | ||||
| 	"github.com/kava-labs/kava/app" | ||||
| 	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/kavadist" | ||||
| 	validatorvesting "github.com/kava-labs/kava/x/validator-vesting" | ||||
| ) | ||||
| 
 | ||||
| func (suite *KeeperTestSuite) TestPayoutClaim() { | ||||
| func (suite *KeeperTestSuite) TestPayoutUSDXMintingClaim() { | ||||
| 	type args struct { | ||||
| 		ctype                    string | ||||
| 		rewardsPerSecond         sdk.Coin | ||||
| @ -129,7 +130,7 @@ func (suite *KeeperTestSuite) TestPayoutClaim() { | ||||
| 			err = suite.keeper.AccumulateUSDXMintingRewards(suite.ctx, rewardPeriod) | ||||
| 			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 { | ||||
| 				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() { | ||||
| 	type accountArgs struct { | ||||
| 		periods          vesting.Periods | ||||
|  | ||||
| @ -17,8 +17,10 @@ func NewQuerier(k Keeper) sdk.Querier { | ||||
| 		switch path[0] { | ||||
| 		case types.QueryGetParams: | ||||
| 			return queryGetParams(ctx, req, k) | ||||
| 		case types.QueryGetClaims: | ||||
| 			return queryGetClaims(ctx, req, k) | ||||
| 		case types.QueryGetCdpClaims: | ||||
| 			return queryGetCdpClaims(ctx, req, k) | ||||
| 		case types.QueryGetHardClaims: | ||||
| 			return queryGetHardClaims(ctx, req, k) | ||||
| 		default: | ||||
| 			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 | ||||
| } | ||||
| 
 | ||||
| func queryGetClaims(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { | ||||
| 	var requestParams types.QueryClaimsParams | ||||
| func queryGetCdpClaims(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { | ||||
| 	var requestParams types.QueryCdpClaimsParams | ||||
| 	err := k.cdc.UnmarshalJSON(req.Data, &requestParams) | ||||
| 	if err != nil { | ||||
| 		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 | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| } | ||||
| 
 | ||||
| // ZeroClaim 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 { | ||||
| // ZeroUSDXMintingClaim zeroes out the claim object's rewards and returns the updated claim object
 | ||||
| func (k Keeper) ZeroUSDXMintingClaim(ctx sdk.Context, claim types.USDXMintingClaim) types.USDXMintingClaim { | ||||
| 	claim.Reward = sdk.NewCoin(claim.Reward.Denom, sdk.ZeroInt()) | ||||
| 	k.SetUSDXMintingClaim(ctx, 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
 | ||||
| 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 { | ||||
| 		cdp, found := k.cdpKeeper.GetCdpByOwnerAndCollateralType(ctx, claim.Owner, ri.CollateralType) | ||||
| 		if !found { | ||||
| @ -546,6 +546,31 @@ func (k Keeper) synchronizeRewardAndReturnClaim(ctx sdk.Context, cdp cdptypes.CD | ||||
| 	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
 | ||||
| // 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 { | ||||
|  | ||||
| @ -20,4 +20,5 @@ func RegisterCodec(cdc *codec.Codec) { | ||||
| 
 | ||||
| 	// Register msgs
 | ||||
| 	cdc.RegisterConcrete(MsgClaimUSDXMintingReward{}, "incentive/MsgClaimUSDXMintingReward", nil) | ||||
| 	cdc.RegisterConcrete(MsgClaimHardLiquidityProviderReward{}, "incentive/MsgClaimHardLiquidityProviderReward", nil) | ||||
| } | ||||
|  | ||||
| @ -10,6 +10,7 @@ const ( | ||||
| 	AttributeValueCategory   = ModuleName | ||||
| 	AttributeKeyClaimedBy    = "claimed_by" | ||||
| 	AttributeKeyClaimAmount  = "claim_amount" | ||||
| 	AttributeKeyClaimType    = "claim_type" | ||||
| 	AttributeKeyRewardPeriod = "reward_period" | ||||
| 	AttributeKeyClaimPeriod  = "claim_period" | ||||
| ) | ||||
|  | ||||
| @ -33,6 +33,8 @@ type CdpKeeper interface { | ||||
| 
 | ||||
| // HardKeeper defines the expected hard keeper for interacting with Hard protocol
 | ||||
| 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) | ||||
| 	GetBorrowInterestFactor(ctx sdk.Context, denom string) (sdk.Dec, bool) | ||||
| 	GetBorrowedCoins(ctx sdk.Context) (coins sdk.Coins, found bool) | ||||
|  | ||||
| @ -9,8 +9,9 @@ import ( | ||||
| 
 | ||||
| // ensure Msg interface compliance at compile time
 | ||||
| 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 { | ||||
| 	Sender         sdk.AccAddress `json:"sender" yaml:"sender"` | ||||
| 	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 } | ||||
| 
 | ||||
| // 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.
 | ||||
| func (msg MsgClaimUSDXMintingReward) ValidateBasic() error { | ||||
| @ -48,3 +49,44 @@ func (msg MsgClaimUSDXMintingReward) GetSignBytes() []byte { | ||||
| func (msg MsgClaimUSDXMintingReward) GetSigners() []sdk.AccAddress { | ||||
| 	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
 | ||||
| const ( | ||||
| 	QueryGetClaims          = "claims" | ||||
| 	QueryGetCdpClaims       = "cdp-claims" | ||||
| 	QueryGetHardClaims      = "hard-claims" | ||||
| 	RestClaimOwner          = "owner" | ||||
| 	RestClaimCollateralType = "collateral_type" | ||||
| 	QueryGetParams          = "parameters" | ||||
| @ -15,16 +16,32 @@ const ( | ||||
| 	QueryGetClaimPeriods    = "claim-periods" | ||||
| ) | ||||
| 
 | ||||
| // QueryClaimsParams params for query /incentive/claims
 | ||||
| type QueryClaimsParams struct { | ||||
| // QueryCdpClaimsParams params for query /incentive/claims
 | ||||
| type QueryCdpClaimsParams struct { | ||||
| 	Page  int `json:"page" yaml:"page"` | ||||
| 	Limit int `json:"limit" yaml:"limit"` | ||||
| 	Owner sdk.AccAddress | ||||
| } | ||||
| 
 | ||||
| // NewQueryClaimsParams returns QueryClaimsParams
 | ||||
| func NewQueryClaimsParams(page, limit int, owner sdk.AccAddress) QueryClaimsParams { | ||||
| 	return QueryClaimsParams{ | ||||
| // NewQueryCdpClaimsParams returns QueryCdpClaimsParams
 | ||||
| func NewQueryCdpClaimsParams(page, limit int, owner sdk.AccAddress) QueryCdpClaimsParams { | ||||
| 	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, | ||||
| 		Limit: limit, | ||||
| 		Owner: owner, | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Denali Marsh
						Denali Marsh