Skip to content

Commit

Permalink
feat: allow KYVE protocol voting
Browse files Browse the repository at this point in the history
  • Loading branch information
johnletey committed Oct 19, 2022
1 parent 26786a0 commit b36d676
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 13 deletions.
2 changes: 1 addition & 1 deletion simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ func NewSimApp(
*/
govKeeper := govkeeper.NewKeeper(
appCodec, keys[govtypes.StoreKey], app.GetSubspace(govtypes.ModuleName), app.AccountKeeper, app.BankKeeper,
&stakingKeeper, govRouter, app.MsgServiceRouter(), govConfig,
&stakingKeeper, nil, govRouter, app.MsgServiceRouter(), govConfig,
)

app.GovKeeper = *govKeeper.SetHooks(
Expand Down
24 changes: 14 additions & 10 deletions x/gov/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ type Keeper struct {
// The reference to the DelegationSet and ValidatorSet to get information about validators and delegators
sk types.StakingKeeper

protocolStakingKeeper types.ProtocolStakingKeeper

// GovHooks
hooks types.GovHooks

Expand Down Expand Up @@ -54,7 +56,8 @@ type Keeper struct {
// CONTRACT: the parameter Subspace must have the param key table already initialized
func NewKeeper(
cdc codec.BinaryCodec, key storetypes.StoreKey, paramSpace types.ParamSubspace,
authKeeper types.AccountKeeper, bankKeeper types.BankKeeper, sk types.StakingKeeper,
authKeeper types.AccountKeeper, bankKeeper types.BankKeeper,
sk types.StakingKeeper, protocolStakingKeeper types.ProtocolStakingKeeper,
legacyRouter v1beta1.Router, router *baseapp.MsgServiceRouter,
config types.Config,
) Keeper {
Expand All @@ -74,15 +77,16 @@ func NewKeeper(
}

return Keeper{
storeKey: key,
paramSpace: paramSpace,
authKeeper: authKeeper,
bankKeeper: bankKeeper,
sk: sk,
cdc: cdc,
legacyRouter: legacyRouter,
router: router,
config: config,
storeKey: key,
paramSpace: paramSpace,
authKeeper: authKeeper,
bankKeeper: bankKeeper,
sk: sk,
protocolStakingKeeper: protocolStakingKeeper,
cdc: cdc,
legacyRouter: legacyRouter,
router: router,
config: config,
}
}

Expand Down
49 changes: 47 additions & 2 deletions x/gov/keeper/tally.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (

// TODO: Break into several smaller functions for clarity

// NOTE: We have to check if the KYVE Protocol staking keeper is defined to ensure minimal changes.

// Tally iterates over the votes and updates the tally of a proposal based on the voting power of the
// voters
func (keeper Keeper) Tally(ctx sdk.Context, proposal v1.Proposal) (passes bool, burnDeposits bool, tallyResults v1.TallyResult) {
Expand All @@ -33,6 +35,18 @@ func (keeper Keeper) Tally(ctx sdk.Context, proposal v1.Proposal) (passes bool,
return false
})

// Fetch and insert all KYVE Protocol validators into list of current validators.
// NOTE: The key used is a normal "kyve1blah" address.
if keeper.protocolStakingKeeper != nil {
for _, rawVal := range keeper.protocolStakingKeeper.GetActiveValidators(ctx) {
// NOTE: We have to typecast to avoid creating import cycles when defining the function interfaces.
if val, ok := rawVal.(v1.ValidatorGovInfo); ok {
address := sdk.AccAddress(val.Address).String()
currValidators[address] = val
}
}
}

keeper.IterateVotes(ctx, proposal.Id, func(vote v1.Vote) bool {
// if validator, just record it in the map
voter := sdk.MustAccAddressFromBech32(vote.Voter)
Expand All @@ -42,6 +56,11 @@ func (keeper Keeper) Tally(ctx sdk.Context, proposal v1.Proposal) (passes bool,
val.Vote = vote.Options
currValidators[valAddrStr] = val
}
// Check if the voter is a KYVE Protocol validator.
if val, ok := currValidators[voter.String()]; ok {
val.Vote = vote.Options
currValidators[valAddrStr] = val
}

// iterate over all delegations from voter, deduct from any delegated-to validators
keeper.sk.IterateDelegations(ctx, voter, func(index int64, delegation stakingtypes.DelegationI) (stop bool) {
Expand All @@ -67,6 +86,25 @@ func (keeper Keeper) Tally(ctx sdk.Context, proposal v1.Proposal) (passes bool,
return false
})

if keeper.protocolStakingKeeper != nil {
validators, amounts := keeper.protocolStakingKeeper.GetDelegations(ctx, voter.String())
for idx, address := range validators {
if val, ok := currValidators[address]; ok {
val.DelegatorDeductions = val.DelegatorDeductions.Add(amounts[idx])
currValidators[address] = val

votingPower := amounts[idx].Quo(val.DelegatorShares)

for _, option := range vote.Options {
weight, _ := sdk.NewDecFromStr(option.Weight)
subPower := votingPower.Mul(weight)
results[option.Option] = results[option.Option].Add(subPower)
}
totalVotingPower = totalVotingPower.Add(votingPower)
}
}
}

keeper.deleteVote(ctx, vote.ProposalId, voter)
return false
})
Expand All @@ -91,14 +129,21 @@ func (keeper Keeper) Tally(ctx sdk.Context, proposal v1.Proposal) (passes bool,
tallyParams := keeper.GetTallyParams(ctx)
tallyResults = v1.NewTallyResultFromMap(results)

totalBondedTokens := keeper.sk.TotalBondedTokens(ctx)
if keeper.protocolStakingKeeper != nil {
totalBondedTokens = totalBondedTokens.Add(
keeper.protocolStakingKeeper.TotalBondedTokens(ctx),
)
}

// TODO: Upgrade the spec to cover all of these cases & remove pseudocode.
// If there is no staked coins, the proposal fails
if keeper.sk.TotalBondedTokens(ctx).IsZero() {
if totalBondedTokens.IsZero() {
return false, false, tallyResults
}

// If there is not enough quorum of votes, the proposal fails
percentVoting := totalVotingPower.Quo(sdk.NewDecFromInt(keeper.sk.TotalBondedTokens(ctx)))
percentVoting := totalVotingPower.Quo(sdk.NewDecFromInt(totalBondedTokens))
quorum, _ := sdk.NewDecFromStr(tallyParams.Quorum)
if percentVoting.LT(quorum) {
return false, false, tallyResults
Expand Down
8 changes: 8 additions & 0 deletions x/gov/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ type StakingKeeper interface {
)
}

// ProtocolStakingKeeper expected KYVE protocol staking keeper (Protocol Validator and Delegator sets) (noalias)
type ProtocolStakingKeeper interface {
GetActiveValidators(sdk.Context) []interface{}

TotalBondedTokens(sdk.Context) math.Int
GetDelegations(sdk.Context, string) ([]string, []sdk.Dec)
}

// AccountKeeper defines the expected account keeper (noalias)
type AccountKeeper interface {
GetAccount(ctx sdk.Context, addr sdk.AccAddress) types.AccountI
Expand Down

0 comments on commit b36d676

Please sign in to comment.