Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: claimable protocol commission #46

Merged
merged 9 commits into from
May 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@

## [Unreleased]

### Improvements

- (`x/stakers`) [#46](https://github.com/KYVENetwork/chain/pull/46) Allow protocol validator commission rewards to be claimed.

### Client Breaking

- (`x/stakers`) [#46](https://github.com/KYVENetwork/chain/pull/46) Include `MsgClaimCommissionRewards` for claiming commission rewards.

### API Breaking

<!-- TODO: Switch this link to the release tag. -->
- (`x/stakers`) [#46](https://github.com/KYVENetwork/chain/pull/46) Emit an [event](https://github.com/KYVENetwork/chain/blob/main/x/stakers/spec/05_events.md#eventclaimcommissionrewards) when claiming protocol validator commission rewards.

## [v1.2.1](https://github.com/KYVENetwork/chain/releases/tag/v1.2.1) - 2023-05-25

### Bug Fixes
Expand Down
9 changes: 9 additions & 0 deletions proto/kyve/stakers/v1beta1/events.proto
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ message EventUpdateCommission {
];
}

// EventClaimCommissionRewards ...
// emitted_by: MsgClaimCommissionRewards
message EventClaimCommissionRewards {
// staker is the account address of the protocol node.
string staker = 1;
// amount ...
uint64 amount = 2;
}

// EventJoinPool ...
// emitted_by: MsgJoinPool
message EventJoinPool {
Expand Down
2 changes: 2 additions & 0 deletions proto/kyve/stakers/v1beta1/stakers.proto
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ message Staker {
string security_contact = 6;
// details are some additional notes the staker finds important
string details = 7;
// commission_rewards are the rewards in $KYVE earned through commission
uint64 commission_rewards = 8;
}

// Valaccount gets authorized by a staker to
Expand Down
13 changes: 13 additions & 0 deletions proto/kyve/stakers/v1beta1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ service Msg {
rpc UpdateMetadata(MsgUpdateMetadata) returns (MsgUpdateMetadataResponse);
// UpdateCommission ...
rpc UpdateCommission(MsgUpdateCommission) returns (MsgUpdateCommissionResponse);
// ClaimCommissionRewards ...
rpc ClaimCommissionRewards(MsgClaimCommissionRewards) returns (MsgClaimCommissionRewardsResponse);
// JoinPool ...
rpc JoinPool(MsgJoinPool) returns (MsgJoinPoolResponse);
// LeavePool ...
Expand Down Expand Up @@ -75,6 +77,17 @@ message MsgUpdateCommission {
// MsgUpdateCommissionResponse ...
message MsgUpdateCommissionResponse {}

// MsgClaimCommissionRewards ...
message MsgClaimCommissionRewards {
// creator ...
string creator = 1;
// amount ...
uint64 amount = 2;
}

// MsgClaimCommissionRewardsResponse ...
message MsgClaimCommissionRewardsResponse {}

// MsgJoinPool ...
message MsgJoinPool {
// creator ...
Expand Down
24 changes: 13 additions & 11 deletions testutil/integration/checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/KYVENetwork/chain/x/pool"
querytypes "github.com/KYVENetwork/chain/x/query/types"
"github.com/KYVENetwork/chain/x/stakers"
stakertypes "github.com/KYVENetwork/chain/x/stakers/types"
"github.com/KYVENetwork/chain/x/team"
"github.com/cosmos/cosmos-sdk/types/query"
. "github.com/onsi/gomega"
Expand Down Expand Up @@ -56,6 +57,7 @@ func (suite *KeeperTestSuite) VerifyPoolModuleAssetsIntegrity() {
actualBalance := uint64(0)

for _, pool := range suite.App().PoolKeeper.GetAllPools(suite.Ctx()) {
// pool funds should be in pool module
for _, funder := range pool.Funders {
expectedBalance += funder.Amount
}
Expand Down Expand Up @@ -166,17 +168,17 @@ func (suite *KeeperTestSuite) VerifyPoolGenesisImportExport() {
// =====================

func (suite *KeeperTestSuite) VerifyStakersModuleAssetsIntegrity() {
//expectedBalance := uint64(0)
//actualBalance := uint64(0)
//
//for _, staker := range suite.App().StakersKeeper.GetAllStakers(suite.Ctx()) {
// expectedBalance += suite.App().DelegationKeeper
//}
//
//moduleAcc := suite.App().AccountKeeper.GetModuleAccount(suite.Ctx(), stakerstypes.ModuleName).GetAddress()
//actualBalance = suite.App().BankKeeper.GetBalance(suite.Ctx(), moduleAcc, globalTypes.Denom).Amount.Uint64()
//
//Expect(actualBalance).To(Equal(expectedBalance))
expectedBalance := uint64(0)
actualBalance := uint64(0)

for _, staker := range suite.App().StakersKeeper.GetAllStakers(suite.Ctx()) {
expectedBalance += staker.CommissionRewards
}

moduleAcc := suite.App().AccountKeeper.GetModuleAccount(suite.Ctx(), stakertypes.ModuleName).GetAddress()
actualBalance = suite.App().BankKeeper.GetBalance(suite.Ctx(), moduleAcc, globalTypes.Denom).Amount.Uint64()

Expect(actualBalance).To(Equal(expectedBalance))
}

func (suite *KeeperTestSuite) VerifyPoolTotalStake() {
Expand Down
4 changes: 3 additions & 1 deletion x/bundles/keeper/keeper_suite_stakers_leave_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,9 @@ var _ = Describe("stakers leave", Ordered, func() {
uploaderDelegationReward := totalUploaderReward - uploaderPayoutReward

// assert payout transfer
Expect(balanceUploader).To(Equal(initialBalanceStaker0 + uploaderPayoutReward))
Expect(balanceUploader).To(Equal(initialBalanceStaker0))
// assert commission rewards
Expect(uploader.CommissionRewards).To(Equal(uploaderPayoutReward))
// assert uploader self delegation rewards
Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(uploaderDelegationReward))
})
Expand Down
47 changes: 24 additions & 23 deletions x/bundles/keeper/keeper_suite_valid_bundles_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,9 @@ var _ = Describe("valid bundles", Ordered, func() {
uploaderDelegationReward := totalUploaderReward - uploaderPayoutReward

// assert payout transfer
Expect(balanceUploader).To(Equal(initialBalanceStaker0 + uploaderPayoutReward))
Expect(balanceUploader).To(Equal(initialBalanceStaker0))
// assert commission rewards
Expect(uploader.CommissionRewards).To(Equal(uploaderPayoutReward))
// assert uploader self delegation rewards
Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(uploaderDelegationReward))

Expand Down Expand Up @@ -307,7 +309,9 @@ var _ = Describe("valid bundles", Ordered, func() {
delegatorDelegationReward := uint64(sdk.NewDec(int64(totalDelegationReward)).Quo(sdk.NewDec(4)).Mul(sdk.NewDec(3)).TruncateInt64())

// assert payout transfer
Expect(balanceUploader).To(Equal(initialBalanceStaker0 + uploaderPayoutReward))
Expect(balanceUploader).To(Equal(initialBalanceStaker0))
// assert commission rewards
Expect(uploader.CommissionRewards).To(Equal(uploaderPayoutReward))
// assert uploader self delegation rewards
Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(uploaderDelegationReward))
// assert delegator delegation rewards
Expand Down Expand Up @@ -451,7 +455,9 @@ var _ = Describe("valid bundles", Ordered, func() {
uploaderDelegationReward := totalUploaderReward - uploaderPayoutReward

// assert payout transfer
Expect(balanceUploader).To(Equal(initialBalanceStaker0 + uploaderPayoutReward))
Expect(balanceUploader).To(Equal(initialBalanceStaker0))
// assert commission rewards
Expect(uploader.CommissionRewards).To(Equal(uploaderPayoutReward))
// assert uploader self delegation rewards
Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(uploaderDelegationReward))

Expand Down Expand Up @@ -609,7 +615,9 @@ var _ = Describe("valid bundles", Ordered, func() {
delegatorDelegationReward := uint64(sdk.NewDec(int64(totalDelegationReward)).Quo(sdk.NewDec(3)).Mul(sdk.NewDec(2)).TruncateInt64())

// assert payout transfer
Expect(balanceUploader).To(Equal(initialBalanceStaker0 + uploaderPayoutReward))
Expect(balanceUploader).To(Equal(initialBalanceStaker0))
// assert commission rewards
Expect(uploader.CommissionRewards).To(Equal(uploaderPayoutReward))
// assert uploader self delegation rewards
Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(uploaderDelegationReward))
// assert delegator delegation rewards
Expand All @@ -619,7 +627,9 @@ var _ = Describe("valid bundles", Ordered, func() {
Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_1, i.BOB)).To(BeZero())

// assert payout transfer
Expect(balanceUploader).To(Equal(initialBalanceStaker0 + uploaderPayoutReward))
Expect(balanceUploader).To(Equal(initialBalanceStaker0))
// assert commission rewards
Expect(uploader.CommissionRewards).To(Equal(uploaderPayoutReward))
// assert uploader self delegation rewards
Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(uploaderDelegationReward))

Expand Down Expand Up @@ -768,7 +778,9 @@ var _ = Describe("valid bundles", Ordered, func() {
delegatorDelegationReward := uint64(sdk.NewDec(int64(totalDelegationReward)).Quo(sdk.NewDec(4)).Mul(sdk.NewDec(3)).TruncateInt64())

// assert payout transfer
Expect(balanceUploader).To(Equal(initialBalanceStaker0 + uploaderPayoutReward))
Expect(balanceUploader).To(Equal(initialBalanceStaker0))
// assert commission rewards
Expect(uploader.CommissionRewards).To(Equal(uploaderPayoutReward))
// assert uploader self delegation rewards
Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(uploaderDelegationReward))
// assert delegator delegation rewards
Expand All @@ -777,11 +789,6 @@ var _ = Describe("valid bundles", Ordered, func() {
// check voter rewards
Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_1, i.BOB)).To(BeZero())

// assert payout transfer
Expect(balanceUploader).To(Equal(initialBalanceStaker0 + uploaderPayoutReward))
// assert uploader self delegation rewards
Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(uploaderDelegationReward))

// check pool funds
pool, _ = s.App().PoolKeeper.GetPool(s.Ctx(), 0)

Expand Down Expand Up @@ -935,7 +942,9 @@ var _ = Describe("valid bundles", Ordered, func() {
delegatorDelegationReward := uint64(sdk.NewDec(int64(totalDelegationReward)).Quo(sdk.NewDec(4)).Mul(sdk.NewDec(3)).TruncateInt64())

// assert payout transfer
Expect(balanceUploader).To(Equal(initialBalanceStaker0 + uploaderPayoutReward))
Expect(balanceUploader).To(Equal(initialBalanceStaker0))
// assert commission rewards
Expect(uploader.CommissionRewards).To(Equal(uploaderPayoutReward))
// assert uploader self delegation rewards
Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(uploaderDelegationReward))
// assert delegator delegation rewards
Expand All @@ -944,11 +953,6 @@ var _ = Describe("valid bundles", Ordered, func() {
// check voter rewards
Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_1, i.BOB)).To(BeZero())

// assert payout transfer
Expect(balanceUploader).To(Equal(initialBalanceStaker0 + uploaderPayoutReward))
// assert uploader self delegation rewards
Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(uploaderDelegationReward))

// check pool funds
pool, _ = s.App().PoolKeeper.GetPool(s.Ctx(), 0)

Expand Down Expand Up @@ -1112,7 +1116,9 @@ var _ = Describe("valid bundles", Ordered, func() {
delegatorDelegationReward := uint64(sdk.NewDec(int64(totalDelegationReward)).Quo(sdk.NewDec(4)).Mul(sdk.NewDec(3)).TruncateInt64())

// assert payout transfer
Expect(balanceUploader).To(Equal(initialBalanceStaker0 + uploaderPayoutReward))
Expect(balanceUploader).To(Equal(initialBalanceStaker0))
// assert commission rewards
Expect(uploader.CommissionRewards).To(Equal(uploaderPayoutReward))
// assert uploader self delegation rewards
Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(uploaderDelegationReward))
// assert delegator delegation rewards
Expand All @@ -1121,11 +1127,6 @@ var _ = Describe("valid bundles", Ordered, func() {
// check voter rewards
Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_1, i.BOB)).To(BeZero())

// assert payout transfer
Expect(balanceUploader).To(Equal(initialBalanceStaker0 + uploaderPayoutReward))
// assert uploader self delegation rewards
Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(Equal(uploaderDelegationReward))

// check pool funds
pool, _ = s.App().PoolKeeper.GetPool(s.Ctx(), 0)

Expand Down
6 changes: 5 additions & 1 deletion x/bundles/keeper/keeper_suite_zero_delegation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,8 +390,12 @@ var _ = Describe("valid bundles", Ordered, func() {
treasuryReward := uint64(sdk.NewDec(int64(totalReward)).Mul(networkFee).TruncateInt64())
totalUploaderReward := totalReward - treasuryReward

uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), i.STAKER_0)

// assert payout transfer
Expect(balanceUploader).To(Equal(initialBalanceStaker0 + totalUploaderReward))
Expect(balanceUploader).To(Equal(initialBalanceStaker0))
// assert commission rewards
Expect(uploader.CommissionRewards).To(Equal(totalUploaderReward))
// assert uploader self delegation rewards
Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0)).To(BeZero())

Expand Down
23 changes: 15 additions & 8 deletions x/bundles/keeper/msg_server_submit_bundle_proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ package keeper
import (
"context"

delegationTypes "github.com/KYVENetwork/chain/x/delegation/types"

"github.com/KYVENetwork/chain/util"
"github.com/KYVENetwork/chain/x/bundles/types"
pooltypes "github.com/KYVENetwork/chain/x/pool/types"
sdk "github.com/cosmos/cosmos-sdk/types"

// Delegation
delegationTypes "github.com/KYVENetwork/chain/x/delegation/types"
// Pool
poolTypes "github.com/KYVENetwork/chain/x/pool/types"
// Stakers
stakersTypes "github.com/KYVENetwork/chain/x/stakers/types"
)

// SubmitBundleProposal handles the logic of an SDK message that allows protocol nodes to submit a new bundle proposal.
Expand Down Expand Up @@ -73,7 +77,7 @@ func (k msgServer) SubmitBundleProposal(
k.SetBundleProposal(ctx, bundleProposal)

// emit event which indicates that pool has run out of funds
_ = ctx.EventManager().EmitTypedEvent(&pooltypes.EventPoolOutOfFunds{
_ = ctx.EventManager().EmitTypedEvent(&poolTypes.EventPoolOutOfFunds{
PoolId: msg.PoolId,
})

Expand All @@ -85,19 +89,22 @@ func (k msgServer) SubmitBundleProposal(

uploaderPayout := bundleReward.Uploader

delegationPayoutSuccessful := k.delegationKeeper.PayoutRewards(ctx, bundleProposal.Uploader, bundleReward.Delegation, pooltypes.ModuleName)
delegationPayoutSuccessful := k.delegationKeeper.PayoutRewards(ctx, bundleProposal.Uploader, bundleReward.Delegation, poolTypes.ModuleName)
// If staker has no delegators add all delegation rewards to the staker rewards
if !delegationPayoutSuccessful {
uploaderPayout += bundleReward.Delegation
}

// send commission to uploader
if err := util.TransferFromModuleToAddress(k.bankKeeper, ctx, pooltypes.ModuleName, bundleProposal.Uploader, uploaderPayout); err != nil {
// transfer funds from pool to stakers module
if err := util.TransferFromModuleToModule(k.bankKeeper, ctx, poolTypes.ModuleName, stakersTypes.ModuleName, uploaderPayout); err != nil {
return nil, err
}

// increase commission rewards of uploader
k.stakerKeeper.IncreaseStakerCommissionRewards(ctx, bundleProposal.Uploader, uploaderPayout)

// send network fee to treasury
if err := util.TransferFromModuleToTreasury(k.accountKeeper, k.distrkeeper, ctx, pooltypes.ModuleName, bundleReward.Treasury); err != nil {
if err := util.TransferFromModuleToTreasury(k.accountKeeper, k.distrkeeper, ctx, poolTypes.ModuleName, bundleReward.Treasury); err != nil {
return nil, err
}

Expand Down
1 change: 1 addition & 0 deletions x/bundles/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type PoolKeeper interface {
type StakerKeeper interface {
GetAllStakerAddressesOfPool(ctx sdk.Context, poolId uint64) (stakers []string)
GetCommission(ctx sdk.Context, stakerAddress string) sdk.Dec
IncreaseStakerCommissionRewards(ctx sdk.Context, address string, amount uint64)
AssertValaccountAuthorized(ctx sdk.Context, poolId uint64, stakerAddress string, valaddress string) error

DoesStakerExist(ctx sdk.Context, staker string) bool
Expand Down
1 change: 1 addition & 0 deletions x/stakers/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func GetTxCmd() *cobra.Command {
cmd.AddCommand(CmdJoinPool())
cmd.AddCommand(CmdLeavePool())
cmd.AddCommand(CmdUpdateCommission())
cmd.AddCommand(CmdClaimCommissionRewards())
cmd.AddCommand(CmdUpdateMetadata())

return cmd
Expand Down
44 changes: 44 additions & 0 deletions x/stakers/client/cli/tx_claim_commission_rewards.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package cli

import (
"github.com/KYVENetwork/chain/x/stakers/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/spf13/cast"
"github.com/spf13/cobra"
)

func CmdClaimCommissionRewards() *cobra.Command {
cmd := &cobra.Command{
Use: "claim-commission-rewards [amount]",
Short: "Broadcast message claim-commission-rewards",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) (err error) {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

argAmount, err := cast.ToUint64E(args[0])
if err != nil {
return err
}

msg := types.MsgClaimCommissionRewards{
Creator: clientCtx.GetFromAddress().String(),
Amount: argAmount,
}

if err := msg.ValidateBasic(); err != nil {
return err
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
},
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}
9 changes: 9 additions & 0 deletions x/stakers/keeper/getters_staker.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ func (k Keeper) UpdateStakerCommission(ctx sdk.Context, address string, commissi
}
}

// IncreaseStakerCommissionRewards ...
func (k Keeper) IncreaseStakerCommissionRewards(ctx sdk.Context, address string, amount uint64) {
staker, found := k.GetStaker(ctx, address)
if found {
staker.CommissionRewards += amount
k.setStaker(ctx, staker)
}
}

// AddValaccountToPool adds a valaccount to a pool.
// If valaccount already belongs to pool, nothing happens.
func (k Keeper) AddValaccountToPool(ctx sdk.Context, poolId uint64, stakerAddress string, valaddress string) {
Expand Down
Loading