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

increased validator bond shares during delegation #24

Merged
merged 3 commits into from
Aug 10, 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
7 changes: 7 additions & 0 deletions x/staking/keeper/liquid_stake.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,13 @@ func (k Keeper) DecreaseValidatorLiquidShares(ctx sdk.Context, validator types.V
return nil
}

// Increase validator bond shares increments the validator's self bond
// in the event that the delegation amount on a validator bond delegation is increased
func (k Keeper) IncreaseValidatorBondShares(ctx sdk.Context, validator types.Validator, shares sdk.Dec) {
validator.ValidatorBondShares = validator.ValidatorBondShares.Add(shares)
k.SetValidator(ctx, validator)
}

// SafelyDecreaseValidatorBond decrements the validator's self bond
// so long as it will not cause the current delegations to exceed the threshold
// set by validator bond factor
Expand Down
28 changes: 19 additions & 9 deletions x/staking/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,15 @@ func (k msgServer) Delegate(goCtx context.Context, msg *types.MsgDelegate) (*typ
return nil, err
}

// If the delegation is a validator bond, increment the validator bond shares
delegation, found := k.Keeper.GetDelegation(ctx, delegatorAddress, valAddr)
if !found {
return nil, types.ErrNoDelegation
}
if delegation.ValidatorBond {
k.IncreaseValidatorBondShares(ctx, validator, newShares)
}

if tokens.IsInt64() {
defer func() {
telemetry.IncrCounter(1, types.ModuleName, "delegate")
Expand Down Expand Up @@ -300,12 +309,9 @@ func (k msgServer) BeginRedelegate(goCtx context.Context, msg *types.MsgBeginRed
if err != nil {
return nil, err
}
dstShares, err := dstValidator.SharesFromTokensTruncated(msg.Amount.Amount)
if err != nil {
return nil, err
}

// if this is a validator self-bond, the new liquid delegation cannot fall below the self-bond * bond factor
// If this is a validator self-bond, the new liquid delegation cannot fall below the self-bond * bond factor
// The delegation on the new validator will not a validator bond
if delegation.ValidatorBond {
if err := k.SafelyDecreaseValidatorBond(ctx, srcValidator, srcShares); err != nil {
return nil, err
Expand All @@ -322,6 +328,10 @@ func (k msgServer) BeginRedelegate(goCtx context.Context, msg *types.MsgBeginRed
// cannot exceed that validator's self-bond cap
// The liquid shares from the source validator should get moved to the destination validator
if k.DelegatorIsLiquidStaker(delegatorAddress) {
dstShares, err := dstValidator.SharesFromTokensTruncated(msg.Amount.Amount)
if err != nil {
return nil, err
}
if err := k.SafelyIncreaseValidatorLiquidShares(ctx, dstValidator, dstShares); err != nil {
return nil, err
}
Expand Down Expand Up @@ -547,11 +557,11 @@ func (k msgServer) CancelUnbondingDelegation(goCtx context.Context, msg *types.M
// if this undelegation was from a liquid staking provider (identified if the delegator
// is an ICA account), the global and validator liquid totals should be incremented
tokens := msg.Amount.Amount
shares, err := validator.SharesFromTokens(tokens)
if err != nil {
return nil, err
}
if k.DelegatorIsLiquidStaker(delegatorAddress) {
shares, err := validator.SharesFromTokens(tokens)
if err != nil {
return nil, err
}
if err := k.SafelyIncreaseTotalLiquidStakedTokens(ctx, tokens, false); err != nil {
return nil, err
}
Expand Down
100 changes: 100 additions & 0 deletions x/staking/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -993,6 +993,106 @@ func TestValidatorBond(t *testing.T) {
}
}

func TestChangeValidatorBond(t *testing.T) {
_, app, ctx := createTestInput()
msgServer := keeper.NewMsgServerImpl(app.StakingKeeper)

checkValidatorBondShares := func(validatorAddress sdk.ValAddress, expectedShares sdk.Int) {
validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddress)
require.True(t, found, "validator should have been found")
require.Equal(t, expectedShares.Int64(), validator.ValidatorBondShares.TruncateInt64(), "validator bond shares")
}

// Create a delegator and 2 validators
addresses := simapp.AddTestAddrs(app, ctx, 3, sdk.NewInt(1_000_000))
pubKeys := simapp.CreateTestPubKeys(3)

validatorAPubKey := pubKeys[1]
validatorBPubKey := pubKeys[2]

delegatorAddress := addresses[0]
validatorAAddress := sdk.ValAddress(validatorAPubKey.Address())
validatorBAddress := sdk.ValAddress(validatorBPubKey.Address())

validatorA := teststaking.NewValidator(t, validatorAAddress, validatorAPubKey)
validatorB := teststaking.NewValidator(t, validatorBAddress, validatorBPubKey)

validatorA.Tokens = sdk.NewInt(1_000_000)
validatorB.Tokens = sdk.NewInt(1_000_000)
validatorA.DelegatorShares = sdk.NewDec(1_000_000)
validatorB.DelegatorShares = sdk.NewDec(1_000_000)

app.StakingKeeper.SetValidator(ctx, validatorA)
app.StakingKeeper.SetValidator(ctx, validatorB)

// The test will go through Delegate/Redelegate/Undelegate messages with the following
delegation1Amount := sdk.NewInt(1000)
delegation2Amount := sdk.NewInt(1000)
redelegateAmount := sdk.NewInt(500)
undelegateAmount := sdk.NewInt(500)

delegate1Coin := sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), delegation1Amount)
delegate2Coin := sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), delegation2Amount)
redelegateCoin := sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), redelegateAmount)
undelegateCoin := sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), undelegateAmount)

// Delegate to validator A - validator bond shares should not change
_, err := msgServer.Delegate(sdk.WrapSDKContext(ctx), &types.MsgDelegate{
DelegatorAddress: delegatorAddress.String(),
ValidatorAddress: validatorAAddress.String(),
Amount: delegate1Coin,
})
require.NoError(t, err, "no error expected during first delegation")

checkValidatorBondShares(validatorAAddress, sdk.ZeroInt())
checkValidatorBondShares(validatorBAddress, sdk.ZeroInt())

// Flag the delegation as a validator bond
_, err = msgServer.ValidatorBond(sdk.WrapSDKContext(ctx), &types.MsgValidatorBond{
DelegatorAddress: delegatorAddress.String(),
ValidatorAddress: validatorAAddress.String(),
})
require.NoError(t, err, "no error expected during validator bond")

checkValidatorBondShares(validatorAAddress, delegation1Amount)
checkValidatorBondShares(validatorBAddress, sdk.ZeroInt())

// Delegate more - it should increase the validator bond shares
_, err = msgServer.Delegate(sdk.WrapSDKContext(ctx), &types.MsgDelegate{
DelegatorAddress: delegatorAddress.String(),
ValidatorAddress: validatorAAddress.String(),
Amount: delegate2Coin,
})
require.NoError(t, err, "no error expected during second delegation")

checkValidatorBondShares(validatorAAddress, delegation1Amount.Add(delegation2Amount))
checkValidatorBondShares(validatorBAddress, sdk.ZeroInt())

// Redelegate partially from A to B - it should remove the bond shares from the source validator
_, err = msgServer.BeginRedelegate(sdk.WrapSDKContext(ctx), &types.MsgBeginRedelegate{
DelegatorAddress: delegatorAddress.String(),
ValidatorSrcAddress: validatorAAddress.String(),
ValidatorDstAddress: validatorBAddress.String(),
Amount: redelegateCoin,
})
require.NoError(t, err, "no error expected during redelegation")

checkValidatorBondShares(validatorAAddress, delegation1Amount.Add(delegation2Amount).Sub(redelegateAmount))
checkValidatorBondShares(validatorBAddress, sdk.ZeroInt())

// Undelegate from validator A - it should have removed the shares
_, err = msgServer.Undelegate(sdk.WrapSDKContext(ctx), &types.MsgUndelegate{
DelegatorAddress: delegatorAddress.String(),
ValidatorAddress: validatorAAddress.String(),
Amount: undelegateCoin,
})
require.NoError(t, err, "no error expected during undelegation")

expectedBondShares := delegation1Amount.Add(delegation2Amount).Sub(redelegateAmount).Sub(undelegateAmount)
checkValidatorBondShares(validatorAAddress, expectedBondShares)
checkValidatorBondShares(validatorBAddress, sdk.ZeroInt())
}

func TestEnableDisableTokenizeShares(t *testing.T) {
_, app, ctx := createTestInput()
msgServer := keeper.NewMsgServerImpl(app.StakingKeeper)
Expand Down
Loading