Skip to content

Commit

Permalink
feat: add vesting vote (#234)
Browse files Browse the repository at this point in the history
* add vesting vote

* cleanup (keeper Keeper) to (k Keeper)

* apply audit comments
  • Loading branch information
beer-1 authored Aug 13, 2024
1 parent b5195f4 commit 9f195bd
Show file tree
Hide file tree
Showing 30 changed files with 1,405 additions and 150 deletions.
2 changes: 1 addition & 1 deletion app/keepers/keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ func NewAppKeeper(
govConfig := govtypes.DefaultConfig()
appKeepers.GovKeeper = govkeeper.NewKeeper(
appCodec, runtime.NewKVStoreService(appKeepers.keys[govtypes.StoreKey]), appKeepers.AccountKeeper, appKeepers.BankKeeper,
appKeepers.StakingKeeper, appKeepers.DistrKeeper, bApp.MsgServiceRouter(), govConfig, authorityAddr,
appKeepers.StakingKeeper, appKeepers.DistrKeeper, movekeeper.NewVestingKeeper(appKeepers.MoveKeeper), bApp.MsgServiceRouter(), govConfig, authorityAddr,
)

return appKeepers
Expand Down
19 changes: 19 additions & 0 deletions proto/initia/gov/v1/gov.proto
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,25 @@ message Params {
// These are Move function identifiers and can only be applied
// for Move execute messages.
repeated string low_threshold_functions = 93;

// Vesting is the vesting contract info for tally.
Vesting vesting = 94 [(gogoproto.nullable) = true, (amino.dont_omitempty) = false];
}

// Vesting defines the vesting contract info for MsgVestingVote.
// At tally time, gov module would check vesting token amount.
message Vesting {
option (gogoproto.equal) = true;
option (gogoproto.goproto_stringer) = false;

// module_addr is the address of the vesting module.
string module_addr = 1;

// module_name is the name of the vesting module.
string module_name = 2;

// creator_addr is the address of the creator of the vesting contract.
string creator_addr = 3;
}

// Proposal defines the core field members of a governance proposal.
Expand Down
1 change: 1 addition & 0 deletions x/bank/keeper/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ func _createTestInput(
bankKeeper,
stakingKeeper,
distKeeper,
movekeeper.NewVestingKeeper(moveKeeper),
msgRouter,
govConfig,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
Expand Down
1 change: 1 addition & 0 deletions x/distribution/keeper/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ func _createTestInput(
bankKeeper,
stakingKeeper,
distKeeper,
movekeeper.NewVestingKeeper(moveKeeper),
msgRouter,
govConfig,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
Expand Down
4 changes: 2 additions & 2 deletions x/distribution/keeper/custom_msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ type customMsgServer struct {

// NewMsgServerImpl returns an implementation of the distribution MsgServer interface
// for the provided Keeper.
func NewCustomMsgServerImpl(keeper Keeper) customtypes.MsgServer {
return &customMsgServer{Keeper: keeper}
func NewCustomMsgServerImpl(k Keeper) customtypes.MsgServer {
return &customMsgServer{Keeper: k}
}

var _ customtypes.MsgServer = customMsgServer{}
Expand Down
6 changes: 3 additions & 3 deletions x/distribution/keeper/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package keeper

// Migrator is a struct for handling in-place store migrations.
type Migrator struct {
keeper Keeper
k Keeper
}

// NewMigrator returns a new Migrator.
func NewMigrator(keeper Keeper) Migrator {
return Migrator{keeper: keeper}
func NewMigrator(k Keeper) Migrator {
return Migrator{k: k}
}
4 changes: 2 additions & 2 deletions x/distribution/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ type msgServer struct {

// NewMsgServerImpl returns an implementation of the distribution MsgServer interface
// for the provided Keeper.
func NewMsgServerImpl(keeper Keeper) types.MsgServer {
return &msgServer{Keeper: keeper}
func NewMsgServerImpl(k Keeper) types.MsgServer {
return &msgServer{Keeper: k}
}

var _ types.MsgServer = msgServer{}
Expand Down
4 changes: 2 additions & 2 deletions x/evidence/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ type msgServer struct {

// NewMsgServerImpl returns an implementation of the bank MsgServer interface
// for the provided Keeper.
func NewMsgServerImpl(keeper Keeper) types.MsgServer {
return &msgServer{Keeper: keeper}
func NewMsgServerImpl(k Keeper) types.MsgServer {
return &msgServer{Keeper: k}
}

var _ types.MsgServer = msgServer{}
Expand Down
33 changes: 25 additions & 8 deletions x/gov/keeper/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper_test

import (
"encoding/binary"
"os"
"testing"
"time"

Expand Down Expand Up @@ -424,6 +425,7 @@ func _createTestInput(
bankKeeper,
stakingKeeper,
distKeeper,
movekeeper.NewVestingKeeper(moveKeeper),
msgRouter,
govConfig,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
Expand Down Expand Up @@ -454,11 +456,11 @@ func _createTestInput(
return ctx, keepers
}

func createValidatorWithBalance(
func createValidatorWithCoin(
ctx sdk.Context,
input TestKeepers,
balance int64,
delBalance int64,
balance sdk.Coins,
delBalance sdk.Coins,
index int,
) sdk.ValAddress {
valPubKey := testutilsims.CreateTestPubKeys(index)[index-1]
Expand All @@ -467,10 +469,10 @@ func createValidatorWithBalance(
accAddr := sdk.AccAddress(sdk.AccAddress(pubKey.Address()))
valAddr := sdk.ValAddress(sdk.AccAddress(pubKey.Address()))

input.Faucet.Fund(ctx, accAddr, sdk.NewCoin(bondDenom, math.NewInt(balance)))
input.Faucet.Fund(ctx, accAddr, balance...)

sh := stakingkeeper.NewMsgServerImpl(input.StakingKeeper)
_, err := sh.CreateValidator(ctx, newTestMsgCreateValidator(valAddr, valPubKey, math.NewInt(delBalance)))
_, err := sh.CreateValidator(ctx, newTestMsgCreateValidator(valAddr, valPubKey, delBalance...))
if err != nil {
panic(err)
}
Expand All @@ -485,11 +487,26 @@ func createValidatorWithBalance(
}

// newTestMsgCreateValidator test msg creator
func newTestMsgCreateValidator(address sdk.ValAddress, pubKey cryptotypes.PubKey, amt math.Int) *stakingtypes.MsgCreateValidator {
commission := stakingtypes.NewCommissionRates(math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDec(0))
func newTestMsgCreateValidator(address sdk.ValAddress, pubKey cryptotypes.PubKey, amt ...sdk.Coin) *stakingtypes.MsgCreateValidator {
commission := stakingtypes.NewCommissionRates(math.LegacyNewDecWithPrec(1, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDec(0))
msg, _ := stakingtypes.NewMsgCreateValidator(
address.String(), pubKey, sdk.NewCoins(sdk.NewCoin(bondDenom, amt)),
address.String(), pubKey, amt,
stakingtypes.NewDescription("homeDir", "", "", "", ""), commission,
)
return msg
}

var vestingModule []byte

func init() {
vestingModule = ReadMoveFile("Vesting")
}

func ReadMoveFile(filename string) []byte {
path := "../../move/keeper/binaries/" + filename + ".mv"
b, err := os.ReadFile(path)
if err != nil {
panic(err)
}
return b
}
10 changes: 6 additions & 4 deletions x/gov/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ import (

// Keeper defines the governance module Keeper
type Keeper struct {
authKeeper types.AccountKeeper
bankKeeper types.BankKeeper
distrKeeper types.DistributionKeeper
authKeeper types.AccountKeeper
bankKeeper types.BankKeeper
distrKeeper types.DistributionKeeper
vestingKeeper customtypes.VestingKeeper

// The reference to the DelegationSet and ValidatorSet to get information about validators and delegators
sk customtypes.StakingKeeper
Expand Down Expand Up @@ -73,7 +74,7 @@ type Keeper struct {
func NewKeeper(
cdc codec.Codec, storeService corestoretypes.KVStoreService, authKeeper types.AccountKeeper,
bankKeeper types.BankKeeper, sk customtypes.StakingKeeper, distrKeeper types.DistributionKeeper,
router baseapp.MessageRouter, config types.Config, authority string,
vestingKeeper customtypes.VestingKeeper, router baseapp.MessageRouter, config types.Config, authority string,
) *Keeper {
// ensure governance module account is set
if addr := authKeeper.GetModuleAddress(types.ModuleName); addr == nil {
Expand All @@ -96,6 +97,7 @@ func NewKeeper(
authKeeper: authKeeper,
bankKeeper: bankKeeper,
distrKeeper: distrKeeper,
vestingKeeper: vestingKeeper,
sk: sk,
router: router,
config: config,
Expand Down
41 changes: 41 additions & 0 deletions x/gov/keeper/tally.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,27 @@ func (k Keeper) Tally(ctx context.Context, params customtypes.Params, proposal c
return false, false, false, tallyResults, err
}

// fetch vesting table handle if vesting params are provided
var vestingHandle *sdk.AccAddress
if params.Vesting != nil {
vesting := *params.Vesting
moduleAddr, err := k.authKeeper.AddressCodec().StringToBytes(vesting.ModuleAddr)
if err != nil {
return false, false, false, tallyResults, err
}

creatorAddr, err := k.authKeeper.AddressCodec().StringToBytes(vesting.CreatorAddr)
if err != nil {
return false, false, false, tallyResults, err
}

// base denom validation will be done in vesting keeper
vestingHandle, err = k.vestingKeeper.GetVestingHandle(ctx, moduleAddr, vesting.ModuleName, creatorAddr)
if err != nil {
return false, false, false, tallyResults, err
}
}

rng := collections.NewPrefixedPairRange[uint64, sdk.AccAddress](proposal.Id)
err = k.Votes.Walk(ctx, rng, func(key collections.Pair[uint64, sdk.AccAddress], vote v1.Vote) (bool, error) {
// if validator, just record it in the map
Expand All @@ -70,6 +91,26 @@ func (k Keeper) Tally(ctx context.Context, params customtypes.Params, proposal c
currValidators[valAddrStr] = val
}

// add vesting voting power if vesting params are provided
if vestingHandle != nil {
amount, err := k.vestingKeeper.GetUnclaimedVestedAmount(ctx, *vestingHandle, voter)
if err != nil {
return false, err
}

if !amount.IsZero() {
// `the vesting token == the base denom`` check is done in vesting keeper,
// so we can safely convert the amount to voting power
votingPower := math.LegacyNewDecFromInt(amount)
for _, option := range vote.Options {
subPower := votingPower.Mul(math.LegacyMustNewDecFromStr(option.Weight))
results[option.Option] = results[option.Option].Add(subPower)
}
totalVotingPower = totalVotingPower.Add(votingPower)
stakedVotingPower = stakedVotingPower.Add(amount)
}
}

// iterate over all delegations from voter, deduct from any delegated-to validators
err = k.sk.IterateDelegations(ctx, voter, func(delegation stakingtypes.DelegationI) (stop bool, err error) {
valAddrStr := delegation.GetValidatorAddr()
Expand Down
Loading

0 comments on commit 9f195bd

Please sign in to comment.