Skip to content

Commit

Permalink
Merge pull request irisnet#14 from terra-money/feat/reward-rate-update
Browse files Browse the repository at this point in the history
feat: update voting power after reward rate update
  • Loading branch information
javiersuweijie authored Oct 20, 2022
2 parents 05e9dac + bd03235 commit e011fd6
Show file tree
Hide file tree
Showing 21 changed files with 907 additions and 218 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ require (
github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
github.com/gtank/merlin v0.1.1 // indirect
github.com/gtank/ristretto255 v0.1.2 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0 h1:kr3j8iIMR4ywO/O0rvksXaJvauGGCMg2zAZIiNZ9uIQ=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0/go.mod h1:ummNFgdgLhhX7aIiy35vVmQNS0rWXknfPE0qe6fmFXg=
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU=
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0=
github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s=
Expand Down
12 changes: 12 additions & 0 deletions proto/alliance/alliance.proto
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ message AllianceAsset {
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string total_validator_shares = 5 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}

message AddAssetProposal {
Expand Down Expand Up @@ -64,6 +68,14 @@ message UpdateAssetProposal {
AllianceAsset asset = 3;
}

message QueuedRewardRateChange {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

string denom = 1;
string prev_reward_rate = 2;
}

message RewardRateChangeSnapshot {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
Expand Down
4 changes: 2 additions & 2 deletions proto/alliance/delegations.proto
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ message Validator {
repeated RewardIndex reward_indices = 2 [
(gogoproto.nullable) = false
];
repeated cosmos.base.v1beta1.Coin total_tokens = 3 [
repeated cosmos.base.v1beta1.DecCoin total_shares = 4 [
(gogoproto.nullable) = false
];
repeated cosmos.base.v1beta1.DecCoin total_shares = 4 [
repeated cosmos.base.v1beta1.DecCoin validator_shares = 5 [
(gogoproto.nullable) = false
];
}
15 changes: 15 additions & 0 deletions testutil/keeper/mocks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 57 additions & 1 deletion x/alliance/keeper/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,67 @@ package keeper

import (
"alliance/x/alliance/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"

sdk "github.com/cosmos/cosmos-sdk/types"
)

// setAsset Does not check if the asset already exists and overwrites it
func (k Keeper) UpdateAllianceAsset(ctx sdk.Context, newAsset types.AllianceAsset) error {
prevAsset, found := k.GetAssetByDenom(ctx, newAsset.Denom)
if !found {
return types.ErrUnknownAsset
}
moduleAddr := k.accountKeeper.GetModuleAddress(types.ModuleName)

if prevAsset.RewardWeight != newAsset.RewardWeight {
iter := k.GetAllValidators(ctx)
for ; iter.Valid(); iter.Next() {
b := iter.Value()
var aVal types.Validator
k.cdc.MustUnmarshal(b, &aVal)
if !aVal.TotalTokensWithAsset(prevAsset).IsPositive() {
continue
}
valAddr, _ := sdk.ValAddressFromBech32(aVal.ValidatorAddress)
val, _ := k.stakingKeeper.GetValidator(ctx, valAddr)
delegation, found := k.stakingKeeper.GetDelegation(ctx, moduleAddr, valAddr)
if !found {
return types.ErrZeroDelegations
}
currentTokens := types.ConvertNewShareToToken(val.Tokens, val.DelegatorShares, delegation.Shares)
expectedTokens := newAsset.RewardWeight.MulInt(prevAsset.TotalTokens).TruncateInt()
if currentTokens.GT(expectedTokens) {
tokensToRemove := currentTokens.Sub(expectedTokens)
shares, err := k.stakingKeeper.ValidateUnbondAmount(ctx, moduleAddr, valAddr, tokensToRemove)
if err != nil {
return err
}
_, err = k.stakingKeeper.Unbond(ctx, moduleAddr, valAddr, shares)
if err != nil {
return err
}
} else {
tokensToAdd := expectedTokens.Sub(currentTokens)
err := k.bankKeeper.MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), tokensToAdd)))
if err != nil {
return err
}
_, err = k.stakingKeeper.Delegate(ctx, moduleAddr, tokensToAdd, stakingtypes.Unbonded, val, true)
}
}
}

// Add a snapshot to help with rewards calculation

// Only allow updating of certain values
prevAsset.TakeRate = newAsset.TakeRate
prevAsset.RewardWeight = newAsset.RewardWeight

k.SetAsset(ctx, prevAsset)
return nil
}

// SetAsset Does not check if the asset already exists and overwrites it
func (k Keeper) SetAsset(ctx sdk.Context, asset types.AllianceAsset) {
store := ctx.KVStore(k.storeKey)
b := k.cdc.MustMarshal(&asset)
Expand Down
113 changes: 113 additions & 0 deletions x/alliance/keeper/asset_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package keeper_test

import (
test_helpers "alliance/app"
"alliance/x/alliance/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/staking/teststaking"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/stretchr/testify/require"
"testing"
"time"
)

func TestUpdateRewardRates(t *testing.T) {
app, ctx := createTestContext(t)
startTime := time.Now()
ctx.WithBlockTime(startTime)
app.AllianceKeeper.InitGenesis(ctx, &types.GenesisState{
Params: types.DefaultParams(),
Assets: []types.AllianceAsset{
types.NewAsset(ALLIANCE_TOKEN_DENOM, sdk.NewDec(2), sdk.ZeroDec()),
types.NewAsset(ALLIANCE_2_TOKEN_DENOM, sdk.NewDec(10), sdk.ZeroDec()),
},
})

// remove genesis validator delegations
delegations := app.StakingKeeper.GetAllDelegations(ctx)
require.Len(t, delegations, 1)
err := app.StakingKeeper.RemoveDelegation(ctx, stakingtypes.Delegation{
ValidatorAddress: delegations[0].ValidatorAddress,
DelegatorAddress: delegations[0].DelegatorAddress,
})
require.NoError(t, err)

// Set tax and rewards to be zero for easier calculation
distParams := app.DistrKeeper.GetParams(ctx)
distParams.CommunityTax = sdk.ZeroDec()
distParams.BaseProposerReward = sdk.ZeroDec()
distParams.BonusProposerReward = sdk.ZeroDec()
app.DistrKeeper.SetParams(ctx, distParams)

// Accounts
//mintPoolAddr := app.AccountKeeper.GetModuleAddress(minttypes.ModuleName)
//rewardsPoolAddr := app.AccountKeeper.GetModuleAddress(types.RewardsPoolName)
addrs := test_helpers.AddTestAddrsIncremental(app, ctx, 4, sdk.NewCoins(
sdk.NewCoin(ALLIANCE_TOKEN_DENOM, sdk.NewInt(1000_000)),
sdk.NewCoin(ALLIANCE_2_TOKEN_DENOM, sdk.NewInt(1000_000)),
))
pks := test_helpers.CreateTestPubKeys(2)
powerReduction := app.StakingKeeper.PowerReduction(ctx)

// Creating two validators: 1 with 0% commission, 1 with 100% commission
valAddr1 := sdk.ValAddress(addrs[0])
val1 := teststaking.NewValidator(t, valAddr1, pks[0])
val1.Commission = stakingtypes.Commission{
CommissionRates: stakingtypes.CommissionRates{
Rate: sdk.NewDec(0),
MaxRate: sdk.NewDec(0),
MaxChangeRate: sdk.NewDec(0),
},
UpdateTime: time.Now(),
}
val1.Status = stakingtypes.Bonded
test_helpers.RegisterNewValidator(t, app, ctx, val1)

valAddr2 := sdk.ValAddress(addrs[1])
val2 := teststaking.NewValidator(t, valAddr2, pks[1])
val2.Commission = stakingtypes.Commission{
CommissionRates: stakingtypes.CommissionRates{
Rate: sdk.NewDec(1),
MaxRate: sdk.NewDec(1),
MaxChangeRate: sdk.NewDec(0),
},
UpdateTime: time.Now(),
}
test_helpers.RegisterNewValidator(t, app, ctx, val2)

user1 := addrs[2]
//user2 := addrs[3]

// Start by delegating
_, err = app.AllianceKeeper.Delegate(ctx, user1, val1, sdk.NewCoin(ALLIANCE_TOKEN_DENOM, sdk.NewInt(1000_000)))
require.NoError(t, err)

// Expecting voting power for the alliance module
val, found := app.StakingKeeper.GetValidator(ctx, valAddr1)
require.True(t, found)
require.Equal(t, int64(2), val.ConsensusPower(powerReduction))

err = app.AllianceKeeper.UpdateAllianceAsset(ctx, types.AllianceAsset{
Denom: ALLIANCE_TOKEN_DENOM,
RewardWeight: sdk.NewDec(20),
TakeRate: sdk.NewDec(0),
})
require.NoError(t, err)

// Expecting voting power to increase
val, found = app.StakingKeeper.GetValidator(ctx, valAddr1)
require.True(t, found)
require.Equal(t, int64(20), val.ConsensusPower(powerReduction))

err = app.AllianceKeeper.UpdateAllianceAsset(ctx, types.AllianceAsset{
Denom: ALLIANCE_TOKEN_DENOM,
RewardWeight: sdk.NewDec(1),
TakeRate: sdk.NewDec(0),
})
require.NoError(t, err)

// Expecting voting power to decrease
val, found = app.StakingKeeper.GetValidator(ctx, valAddr1)
require.True(t, found)
require.Equal(t, int64(1), val.ConsensusPower(powerReduction))
}
Loading

0 comments on commit e011fd6

Please sign in to comment.