Merge PR #3857: Remove Shares Concept from Unbond/Redelegate UX
* Remove shares concept from unbonding and redelegation * Remove redundant staking REST type declerations * Rename staking REST request types * Fix slashing tests * Fix staking tests * Fix integration tests * Add safety checks for when validator tokens are zero * Attempt to fix simulation * Add pending log entry * Update docs * Implement and use SharesFromTokens * Rename ShareTokens and ShareTokensTruncated * Rename Delegation to Amount in DelegateRequest * Implement and use SharesFromTokensTruncated * Update MsgDelegate to use Amount instead of Value * Use constructors in staking sim messages * Implement and use ValidateUnbondAmount
This commit is contained in:
parent
2788c2250d
commit
59765cecb1
|
@ -0,0 +1,2 @@
|
|||
#3516 Remove concept of shares from staking unbonding and redelegation UX;
|
||||
replaced by direct coin amount.
|
|
@ -533,7 +533,7 @@ func TestBonding(t *testing.T) {
|
|||
// this test takes a long time to run, eventually this second validator
|
||||
// will get slashed, meaning that it's exchange rate is no-longer 1-to-1,
|
||||
// hence we utilize the exchange rate in the following test
|
||||
delTokensAfterRedelegation := validator2.ShareTokens(delegatorDels[0].GetShares())
|
||||
delTokensAfterRedelegation := validator2.TokensFromShares(delegatorDels[0].GetShares())
|
||||
require.Equal(t, rdTokens.ToDec(), delTokensAfterRedelegation)
|
||||
|
||||
// verify balance after paying fees
|
||||
|
|
|
@ -815,11 +815,11 @@ func doDelegate(
|
|||
from := acc.GetAddress().String()
|
||||
|
||||
baseReq := rest.NewBaseReq(from, "", chainID, "", "", accnum, sequence, fees, nil, false)
|
||||
msg := msgDelegationsInput{
|
||||
msg := stakingrest.DelegateRequest{
|
||||
BaseReq: baseReq,
|
||||
DelegatorAddress: delAddr,
|
||||
ValidatorAddress: valAddr,
|
||||
Delegation: sdk.NewCoin(sdk.DefaultBondDenom, amount),
|
||||
Amount: sdk.NewCoin(sdk.DefaultBondDenom, amount),
|
||||
}
|
||||
|
||||
req, err := cdc.MarshalJSON(msg)
|
||||
|
@ -839,13 +839,6 @@ func doDelegate(
|
|||
return txResp
|
||||
}
|
||||
|
||||
type msgDelegationsInput struct {
|
||||
BaseReq rest.BaseReq `json:"base_req"`
|
||||
DelegatorAddress sdk.AccAddress `json:"delegator_address"` // in bech32
|
||||
ValidatorAddress sdk.ValAddress `json:"validator_address"` // in bech32
|
||||
Delegation sdk.Coin `json:"delegation"`
|
||||
}
|
||||
|
||||
// POST /staking/delegators/{delegatorAddr}/delegations Submit delegation
|
||||
func doUndelegate(
|
||||
t *testing.T, port, name, pwd string, delAddr sdk.AccAddress,
|
||||
|
@ -859,11 +852,11 @@ func doUndelegate(
|
|||
from := acc.GetAddress().String()
|
||||
|
||||
baseReq := rest.NewBaseReq(from, "", chainID, "", "", accnum, sequence, fees, nil, false)
|
||||
msg := msgUndelegateInput{
|
||||
msg := stakingrest.UndelegateRequest{
|
||||
BaseReq: baseReq,
|
||||
DelegatorAddress: delAddr,
|
||||
ValidatorAddress: valAddr,
|
||||
SharesAmount: amount.ToDec(),
|
||||
Amount: sdk.NewCoin(sdk.DefaultBondDenom, amount),
|
||||
}
|
||||
|
||||
req, err := cdc.MarshalJSON(msg)
|
||||
|
@ -882,13 +875,6 @@ func doUndelegate(
|
|||
return txResp
|
||||
}
|
||||
|
||||
type msgUndelegateInput struct {
|
||||
BaseReq rest.BaseReq `json:"base_req"`
|
||||
DelegatorAddress sdk.AccAddress `json:"delegator_address"` // in bech32
|
||||
ValidatorAddress sdk.ValAddress `json:"validator_address"` // in bech32
|
||||
SharesAmount sdk.Dec `json:"shares"`
|
||||
}
|
||||
|
||||
// POST /staking/delegators/{delegatorAddr}/delegations Submit delegation
|
||||
func doBeginRedelegation(
|
||||
t *testing.T, port, name, pwd string, delAddr sdk.AccAddress, valSrcAddr,
|
||||
|
@ -902,12 +888,12 @@ func doBeginRedelegation(
|
|||
from := acc.GetAddress().String()
|
||||
|
||||
baseReq := rest.NewBaseReq(from, "", chainID, "", "", accnum, sequence, fees, nil, false)
|
||||
msg := stakingrest.MsgBeginRedelegateInput{
|
||||
msg := stakingrest.RedelegateRequest{
|
||||
BaseReq: baseReq,
|
||||
DelegatorAddress: delAddr,
|
||||
ValidatorSrcAddress: valSrcAddr,
|
||||
ValidatorDstAddress: valDstAddr,
|
||||
SharesAmount: amount.ToDec(),
|
||||
Amount: sdk.NewCoin(sdk.DefaultBondDenom, amount),
|
||||
}
|
||||
|
||||
req, err := cdc.MarshalJSON(msg)
|
||||
|
@ -926,14 +912,6 @@ func doBeginRedelegation(
|
|||
return txResp
|
||||
}
|
||||
|
||||
type msgBeginRedelegateInput struct {
|
||||
BaseReq rest.BaseReq `json:"base_req"`
|
||||
DelegatorAddress sdk.AccAddress `json:"delegator_address"` // in bech32
|
||||
ValidatorSrcAddress sdk.ValAddress `json:"validator_src_address"` // in bech32
|
||||
ValidatorDstAddress sdk.ValAddress `json:"validator_dst_address"` // in bech32
|
||||
SharesAmount sdk.Dec `json:"shares"`
|
||||
}
|
||||
|
||||
// GET /staking/delegators/{delegatorAddr}/delegations Get all delegations from a delegator
|
||||
func getDelegatorDelegations(t *testing.T, port string, delegatorAddr sdk.AccAddress) []staking.Delegation {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/staking/delegators/%s/delegations", delegatorAddr), nil)
|
||||
|
|
|
@ -394,13 +394,13 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
|||
require.NotZero(t, validatorDelegations[0].Shares)
|
||||
|
||||
// unbond a single share
|
||||
unbondTokens := sdk.TokensFromTendermintPower(1)
|
||||
success = f.TxStakingUnbond(keyBar, unbondTokens.String(), barVal, "-y")
|
||||
unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromTendermintPower(1))
|
||||
success = f.TxStakingUnbond(keyBar, unbondAmt.String(), barVal, "-y")
|
||||
require.True(t, success)
|
||||
tests.WaitForNextNBlocksTM(1, f.Port)
|
||||
|
||||
// Ensure bonded staking is correct
|
||||
remainingTokens := newValTokens.Sub(unbondTokens)
|
||||
remainingTokens := newValTokens.Sub(unbondAmt.Amount)
|
||||
validator = f.QueryStakingValidator(barVal)
|
||||
require.Equal(t, remainingTokens, validator.Tokens)
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ When a validator wishes to withdraw their transaction fees it must send
|
|||
triggered each with any change in individual delegations, such as an unbond,
|
||||
redelegation, or delegation of additional tokens to a specific validator. This
|
||||
transaction withdraws the validators commission rewards, as well as any rewards
|
||||
earning on their self-delegation.
|
||||
earning on their self-delegation.
|
||||
|
||||
```golang
|
||||
type TxWithdrawValidator struct {
|
||||
|
|
|
@ -376,12 +376,13 @@ gaiacli query staking delegations <delegator_addr>
|
|||
|
||||
#### Unbond Tokens
|
||||
|
||||
If for any reason the validator misbehaves, or you just want to unbond a certain amount of tokens, use this following command. You can unbond a specific `shares-amount` (eg:`12.1`\) or a `shares-fraction` (eg:`0.25`) with the corresponding flags.
|
||||
If for any reason the validator misbehaves, or you just want to unbond a certain
|
||||
amount of tokens, use this following command.
|
||||
|
||||
```bash
|
||||
gaiacli tx staking unbond \
|
||||
--validator=<account_cosmosval> \
|
||||
--shares-fraction=0.5 \
|
||||
<validator_addr> \
|
||||
10atom \
|
||||
--from=<key_name> \
|
||||
--chain-id=<chain_id>
|
||||
```
|
||||
|
@ -414,9 +415,9 @@ A redelegation is a type delegation that allows you to bond illiquid tokens from
|
|||
|
||||
```bash
|
||||
gaiacli tx staking redelegate \
|
||||
--addr-validator-source=<account_cosmosval> \
|
||||
--addr-validator-dest=<account_cosmosval> \
|
||||
--shares-fraction=50 \
|
||||
<src-validator-operator-addr> \
|
||||
<dst-validator-operator-addr> \
|
||||
10atom \
|
||||
--from=<key_name> \
|
||||
--chain-id=<chain_id>
|
||||
```
|
||||
|
|
|
@ -375,13 +375,12 @@ gaiacli query staking delegation <delegator_addr(위임자 코스모스 주소)>
|
|||
|
||||
만약 특정 검증인이 악의적인 행동을 했거나 또는 본인이 개인적인 이유로 일부 토큰을 언본딩을 워하는 경우 다음 명령어를 통해 토큰을 언본딩 할 수 있습니다. 언본딩은 정확한 수량인 `shares-amount`(예시, `12.1`) 또는 언본딩을 원하는 물량의 비율인 `shares-fraction`(예시, `0.25`) 값으로 표현될 수 있습니다.
|
||||
|
||||
|
||||
```bash
|
||||
gaiacli tx staking unbond \
|
||||
--validator=<account_cosmosval(검증인 cosmosval 주소)> \
|
||||
--shares-fraction=0.5 \
|
||||
--from=<key_name(트랜잭션을 발생시킬 키/계정 이름)> \
|
||||
--chain-id=<chain_id(체인 아이디)>
|
||||
<validator_addr> \
|
||||
10atom \
|
||||
--from=<key_name> \
|
||||
--chain-id=<chain_id>
|
||||
```
|
||||
|
||||
언본딩은 언본딩 기간이 끝나는 대로 완료됩니다.
|
||||
|
@ -412,11 +411,11 @@ gaiacli query staking unbonding-delegations-from <account_cosmosval(검증인 co
|
|||
|
||||
```bash
|
||||
gaiacli tx staking redelegate \
|
||||
--addr-validator-source=<account_cosmosval(스테이킹을 취소할 검증인의 cosmosval 주소)> \
|
||||
--addr-validator-dest=<account_cosmosval(스테이킹을 받을 검증인의 cosmosval 주소)> \
|
||||
--shares-fraction=50 \
|
||||
--from=<key_name(트랜잭션을 발생시킬 키/계정 이름)> \
|
||||
--chain-id=<chain_id(체인 아이디)>
|
||||
<src-validator-operator-addr> \
|
||||
<dst-validator-operator-addr> \
|
||||
10atom \
|
||||
--from=<key_name> \
|
||||
--chain-id=<chain_id>
|
||||
```
|
||||
|
||||
위 예시와 같이 재위임될 토큰의 수량은 특정 수량(`shares-amount`) 또는 일정 비율(`shares-fraction`)로 표현될 수 있습니다.
|
||||
|
|
|
@ -61,20 +61,22 @@ func (b BondStatus) Equal(b2 BondStatus) bool {
|
|||
|
||||
// validator for a delegated proof of stake system
|
||||
type Validator interface {
|
||||
GetJailed() bool // whether the validator is jailed
|
||||
GetMoniker() string // moniker of the validator
|
||||
GetStatus() BondStatus // status of the validator
|
||||
GetOperator() ValAddress // operator address to receive/return validators coins
|
||||
GetConsPubKey() crypto.PubKey // validation consensus pubkey
|
||||
GetConsAddr() ConsAddress // validation consensus address
|
||||
GetTokens() Int // validation tokens
|
||||
GetBondedTokens() Int // validator bonded tokens
|
||||
GetTendermintPower() int64 // validation power in tendermint
|
||||
GetCommission() Dec // validator commission rate
|
||||
GetMinSelfDelegation() Int // validator minimum self delegation
|
||||
GetDelegatorShares() Dec // total outstanding delegator shares
|
||||
ShareTokens(Dec) Dec // token worth of provided delegator shares
|
||||
ShareTokensTruncated(Dec) Dec // token worth of provided delegator shares, truncated
|
||||
GetJailed() bool // whether the validator is jailed
|
||||
GetMoniker() string // moniker of the validator
|
||||
GetStatus() BondStatus // status of the validator
|
||||
GetOperator() ValAddress // operator address to receive/return validators coins
|
||||
GetConsPubKey() crypto.PubKey // validation consensus pubkey
|
||||
GetConsAddr() ConsAddress // validation consensus address
|
||||
GetTokens() Int // validation tokens
|
||||
GetBondedTokens() Int // validator bonded tokens
|
||||
GetTendermintPower() int64 // validation power in tendermint
|
||||
GetCommission() Dec // validator commission rate
|
||||
GetMinSelfDelegation() Int // validator minimum self delegation
|
||||
GetDelegatorShares() Dec // total outstanding delegator shares
|
||||
TokensFromShares(Dec) Dec // token worth of provided delegator shares
|
||||
TokensFromSharesTruncated(Dec) Dec // token worth of provided delegator shares, truncated
|
||||
SharesFromTokens(amt Int) (Dec, Error) // shares worth of delegator's bond
|
||||
SharesFromTokensTruncated(amt Int) (Dec, Error) // truncated shares worth of delegator's bond
|
||||
}
|
||||
|
||||
// validator which fulfills abci validator interface for use in Tendermint
|
||||
|
|
|
@ -22,7 +22,7 @@ func (k Keeper) initializeDelegation(ctx sdk.Context, val sdk.ValAddress, del sd
|
|||
// calculate delegation stake in tokens
|
||||
// we don't store directly, so multiply delegation shares * (tokens per share)
|
||||
// note: necessary to truncate so we don't allow withdrawing more rewards than owed
|
||||
stake := validator.ShareTokensTruncated(delegation.GetShares())
|
||||
stake := validator.TokensFromSharesTruncated(delegation.GetShares())
|
||||
k.SetDelegatorStartingInfo(ctx, val, del, types.NewDelegatorStartingInfo(previousPeriod, stake, uint64(ctx.BlockHeight())))
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,7 @@ func (k Keeper) calculateDelegationRewards(ctx sdk.Context, val sdk.Validator, d
|
|||
// a stake sanity check - recalculated final stake should be less than or equal to current stake
|
||||
// here we cannot use Equals because stake is truncated when multiplied by slash fractions
|
||||
// we could only use equals if we had arbitrary-precision rationals
|
||||
currentStake := val.ShareTokens(del.GetShares())
|
||||
currentStake := val.TokensFromShares(del.GetShares())
|
||||
if stake.GT(currentStake) {
|
||||
panic(fmt.Sprintf("calculated final stake for delegator %s greater than current stake: %s, %s",
|
||||
del.GetDelegatorAddr(), stake, currentStake))
|
||||
|
|
|
@ -31,7 +31,7 @@ func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) sdk.Result {
|
|||
return ErrMissingSelfDelegation(k.codespace).Result()
|
||||
}
|
||||
|
||||
if validator.ShareTokens(selfDel.GetShares()).TruncateInt().LT(validator.GetMinSelfDelegation()) {
|
||||
if validator.TokensFromShares(selfDel.GetShares()).TruncateInt().LT(validator.GetMinSelfDelegation()) {
|
||||
return ErrSelfDelegationTooLowToUnjail(k.codespace).Result()
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,8 @@ func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) {
|
|||
sdk.Coins{sdk.NewCoin(sk.GetParams(ctx).BondDenom, initCoins.Sub(amt))},
|
||||
)
|
||||
|
||||
undelegateMsg := staking.NewMsgUndelegate(sdk.AccAddress(addr), addr, sdk.OneDec())
|
||||
unbondAmt := sdk.NewCoin(sk.GetParams(ctx).BondDenom, sdk.OneInt())
|
||||
undelegateMsg := staking.NewMsgUndelegate(sdk.AccAddress(addr), addr, unbondAmt)
|
||||
got = staking.NewHandler(sk)(ctx, undelegateMsg)
|
||||
|
||||
require.True(t, sk.Validator(ctx, addr).GetJailed())
|
||||
|
@ -92,10 +93,10 @@ func TestJailedValidatorDelegations(t *testing.T) {
|
|||
got = staking.NewHandler(stakingKeeper)(ctx, msgDelegate)
|
||||
require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got)
|
||||
|
||||
unbondShares := bondAmount.ToDec()
|
||||
unbondAmt := sdk.NewCoin(stakingKeeper.GetParams(ctx).BondDenom, bondAmount)
|
||||
|
||||
// unbond validator total self-delegations (which should jail the validator)
|
||||
msgUndelegate := staking.NewMsgUndelegate(sdk.AccAddress(valAddr), valAddr, unbondShares)
|
||||
msgUndelegate := staking.NewMsgUndelegate(sdk.AccAddress(valAddr), valAddr, unbondAmt)
|
||||
got = staking.NewHandler(stakingKeeper)(ctx, msgUndelegate)
|
||||
require.True(t, got.IsOK(), "expected begin unbonding validator msg to be ok, got: %v", got)
|
||||
|
||||
|
|
|
@ -73,7 +73,10 @@ func TestHandleDoubleSign(t *testing.T) {
|
|||
|
||||
// Should be able to unbond now
|
||||
del, _ := sk.GetDelegation(ctx, sdk.AccAddress(operatorAddr), operatorAddr)
|
||||
msgUnbond := staking.NewMsgUndelegate(sdk.AccAddress(operatorAddr), operatorAddr, del.GetShares())
|
||||
validator, _ := sk.GetValidator(ctx, operatorAddr)
|
||||
|
||||
totalBond := validator.TokensFromShares(del.GetShares()).TruncateInt()
|
||||
msgUnbond := staking.NewMsgUndelegate(sdk.AccAddress(operatorAddr), operatorAddr, sdk.NewCoin(sk.GetParams(ctx).BondDenom, totalBond))
|
||||
res = staking.NewHandler(sk)(ctx, msgUnbond)
|
||||
require.True(t, res.IsOK())
|
||||
}
|
||||
|
|
|
@ -157,7 +157,7 @@ func TestStakingMsgs(t *testing.T) {
|
|||
checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), true, bondTokens.ToDec())
|
||||
|
||||
// begin unbonding
|
||||
beginUnbondingMsg := NewMsgUndelegate(addr2, sdk.ValAddress(addr1), bondTokens.ToDec())
|
||||
beginUnbondingMsg := NewMsgUndelegate(addr2, sdk.ValAddress(addr1), bondCoin)
|
||||
header = abci.Header{Height: mApp.LastBlockHeight() + 1}
|
||||
mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, header, []sdk.Msg{beginUnbondingMsg}, []uint64{1}, []uint64{1}, true, true, priv2)
|
||||
|
||||
|
|
|
@ -153,7 +153,7 @@ func GetCmdRedelegate(storeName string, cdc *codec.Codec) *cobra.Command {
|
|||
Args: cobra.ExactArgs(3),
|
||||
Long: strings.TrimSpace(`Redelegate an amount of illiquid staking tokens from one validator to another:
|
||||
|
||||
$ gaiacli tx staking redelegate cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 100 --from mykey
|
||||
$ gaiacli tx staking redelegate cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 100stake --from mykey
|
||||
`),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
txBldr := authtxb.NewTxBuilderFromCLI().WithTxEncoder(auth.DefaultTxEncoder(cdc))
|
||||
|
@ -161,8 +161,6 @@ $ gaiacli tx staking redelegate cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmq
|
|||
WithCodec(cdc).
|
||||
WithAccountDecoder(cdc)
|
||||
|
||||
// var err error
|
||||
|
||||
delAddr := cliCtx.GetFromAddress()
|
||||
valSrcAddr, err := sdk.ValAddressFromBech32(args[0])
|
||||
if err != nil {
|
||||
|
@ -174,13 +172,12 @@ $ gaiacli tx staking redelegate cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmq
|
|||
return err
|
||||
}
|
||||
|
||||
// get the shares amount
|
||||
sharesAmount, err := getShares(args[2], delAddr, valSrcAddr)
|
||||
amount, err := sdk.ParseCoin(args[2])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := staking.NewMsgBeginRedelegate(delAddr, valSrcAddr, valDstAddr, sharesAmount)
|
||||
msg := staking.NewMsgBeginRedelegate(delAddr, valSrcAddr, valDstAddr, amount)
|
||||
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}, false)
|
||||
},
|
||||
}
|
||||
|
@ -194,7 +191,7 @@ func GetCmdUnbond(storeName string, cdc *codec.Codec) *cobra.Command {
|
|||
Args: cobra.ExactArgs(2),
|
||||
Long: strings.TrimSpace(`Unbond an amount of bonded shares from a validator:
|
||||
|
||||
$ gaiacli tx staking unbond cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100 --from mykey
|
||||
$ gaiacli tx staking unbond cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100stake --from mykey
|
||||
`),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
txBldr := authtxb.NewTxBuilderFromCLI().WithTxEncoder(auth.DefaultTxEncoder(cdc))
|
||||
|
@ -208,13 +205,12 @@ $ gaiacli tx staking unbond cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj
|
|||
return err
|
||||
}
|
||||
|
||||
// get the shares amount
|
||||
sharesAmount, err := getShares(args[1], delAddr, valAddr)
|
||||
amount, err := sdk.ParseCoin(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := staking.NewMsgUndelegate(delAddr, valAddr, sharesAmount)
|
||||
msg := staking.NewMsgUndelegate(delAddr, valAddr, amount)
|
||||
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}, false)
|
||||
},
|
||||
}
|
||||
|
|
|
@ -7,19 +7,6 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
)
|
||||
|
||||
func getShares(sharesAmountStr string, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (sharesAmount sdk.Dec, err error) {
|
||||
sharesAmount, err = sdk.NewDecFromStr(sharesAmountStr)
|
||||
if err != nil {
|
||||
return sharesAmount, err
|
||||
}
|
||||
|
||||
if !sharesAmount.GT(sdk.ZeroDec()) {
|
||||
return sharesAmount, errors.New("shares amount must be positive number (ex. 123, 1.23456789)")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func buildCommissionMsg(rateStr, maxRateStr, maxChangeRateStr string) (commission types.CommissionMsg, err error) {
|
||||
if rateStr == "" || maxRateStr == "" || maxChangeRateStr == "" {
|
||||
return commission, errors.New("must specify all validator commission parameters")
|
||||
|
|
|
@ -31,35 +31,35 @@ func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec
|
|||
}
|
||||
|
||||
type (
|
||||
// MsgBeginRedelegateInput defines the properties of a delegation request's body.
|
||||
MsgDelegationsInput struct {
|
||||
// DelegateRequest defines the properties of a delegation request's body.
|
||||
DelegateRequest struct {
|
||||
BaseReq rest.BaseReq `json:"base_req"`
|
||||
DelegatorAddress sdk.AccAddress `json:"delegator_address"` // in bech32
|
||||
ValidatorAddress sdk.ValAddress `json:"validator_address"` // in bech32
|
||||
Delegation sdk.Coin `json:"delegation"`
|
||||
Amount sdk.Coin `json:"amount"`
|
||||
}
|
||||
|
||||
// MsgBeginRedelegateInput defines the properties of a redelegate request's body.
|
||||
MsgBeginRedelegateInput struct {
|
||||
// RedelegateRequest defines the properties of a redelegate request's body.
|
||||
RedelegateRequest struct {
|
||||
BaseReq rest.BaseReq `json:"base_req"`
|
||||
DelegatorAddress sdk.AccAddress `json:"delegator_address"` // in bech32
|
||||
ValidatorSrcAddress sdk.ValAddress `json:"validator_src_address"` // in bech32
|
||||
ValidatorDstAddress sdk.ValAddress `json:"validator_dst_address"` // in bech32
|
||||
SharesAmount sdk.Dec `json:"shares"`
|
||||
Amount sdk.Coin `json:"amount"`
|
||||
}
|
||||
|
||||
// MsgUndelegateInput defines the properties of a undelegate request's body.
|
||||
MsgUndelegateInput struct {
|
||||
// UndelegateRequest defines the properties of a undelegate request's body.
|
||||
UndelegateRequest struct {
|
||||
BaseReq rest.BaseReq `json:"base_req"`
|
||||
DelegatorAddress sdk.AccAddress `json:"delegator_address"` // in bech32
|
||||
ValidatorAddress sdk.ValAddress `json:"validator_address"` // in bech32
|
||||
SharesAmount sdk.Dec `json:"shares"`
|
||||
Amount sdk.Coin `json:"amount"`
|
||||
}
|
||||
)
|
||||
|
||||
func postDelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req MsgDelegationsInput
|
||||
var req DelegateRequest
|
||||
|
||||
if !rest.ReadRESTReq(w, r, cdc, &req) {
|
||||
return
|
||||
|
@ -70,7 +70,7 @@ func postDelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.
|
|||
return
|
||||
}
|
||||
|
||||
msg := staking.NewMsgDelegate(req.DelegatorAddress, req.ValidatorAddress, req.Delegation)
|
||||
msg := staking.NewMsgDelegate(req.DelegatorAddress, req.ValidatorAddress, req.Amount)
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
|
@ -93,7 +93,7 @@ func postDelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.
|
|||
|
||||
func postRedelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req MsgBeginRedelegateInput
|
||||
var req RedelegateRequest
|
||||
|
||||
if !rest.ReadRESTReq(w, r, cdc, &req) {
|
||||
return
|
||||
|
@ -104,7 +104,7 @@ func postRedelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx contex
|
|||
return
|
||||
}
|
||||
|
||||
msg := staking.NewMsgBeginRedelegate(req.DelegatorAddress, req.ValidatorSrcAddress, req.ValidatorDstAddress, req.SharesAmount)
|
||||
msg := staking.NewMsgBeginRedelegate(req.DelegatorAddress, req.ValidatorSrcAddress, req.ValidatorDstAddress, req.Amount)
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
|
@ -127,7 +127,7 @@ func postRedelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx contex
|
|||
|
||||
func postUnbondingDelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req MsgUndelegateInput
|
||||
var req UndelegateRequest
|
||||
|
||||
if !rest.ReadRESTReq(w, r, cdc, &req) {
|
||||
return
|
||||
|
@ -138,7 +138,7 @@ func postUnbondingDelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx
|
|||
return
|
||||
}
|
||||
|
||||
msg := staking.NewMsgUndelegate(req.DelegatorAddress, req.ValidatorAddress, req.SharesAmount)
|
||||
msg := staking.NewMsgUndelegate(req.DelegatorAddress, req.ValidatorAddress, req.Amount)
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
|
|
|
@ -209,11 +209,11 @@ func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper)
|
|||
return ErrNoValidatorFound(k.Codespace()).Result()
|
||||
}
|
||||
|
||||
if msg.Value.Denom != k.GetParams(ctx).BondDenom {
|
||||
if msg.Amount.Denom != k.GetParams(ctx).BondDenom {
|
||||
return ErrBadDenom(k.Codespace()).Result()
|
||||
}
|
||||
|
||||
_, err := k.Delegate(ctx, msg.DelegatorAddress, msg.Value.Amount, validator, true)
|
||||
_, err := k.Delegate(ctx, msg.DelegatorAddress, msg.Amount.Amount, validator, true)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
@ -229,7 +229,14 @@ func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper)
|
|||
}
|
||||
|
||||
func handleMsgUndelegate(ctx sdk.Context, msg types.MsgUndelegate, k keeper.Keeper) sdk.Result {
|
||||
completionTime, err := k.Undelegate(ctx, msg.DelegatorAddress, msg.ValidatorAddress, msg.SharesAmount)
|
||||
shares, err := k.ValidateUnbondAmount(
|
||||
ctx, msg.DelegatorAddress, msg.ValidatorAddress, msg.Amount.Amount,
|
||||
)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
||||
completionTime, err := k.Undelegate(ctx, msg.DelegatorAddress, msg.ValidatorAddress, shares)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
@ -245,8 +252,16 @@ func handleMsgUndelegate(ctx sdk.Context, msg types.MsgUndelegate, k keeper.Keep
|
|||
}
|
||||
|
||||
func handleMsgBeginRedelegate(ctx sdk.Context, msg types.MsgBeginRedelegate, k keeper.Keeper) sdk.Result {
|
||||
completionTime, err := k.BeginRedelegation(ctx, msg.DelegatorAddress, msg.ValidatorSrcAddress,
|
||||
msg.ValidatorDstAddress, msg.SharesAmount)
|
||||
shares, err := k.ValidateUnbondAmount(
|
||||
ctx, msg.DelegatorAddress, msg.ValidatorSrcAddress, msg.Amount.Amount,
|
||||
)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
||||
completionTime, err := k.BeginRedelegation(
|
||||
ctx, msg.DelegatorAddress, msg.ValidatorSrcAddress, msg.ValidatorDstAddress, shares,
|
||||
)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@ func TestValidatorByPowerIndex(t *testing.T) {
|
|||
keeper.Slash(ctx, consAddr0, 0, initPower, sdk.NewDecWithPrec(5, 1))
|
||||
keeper.Jail(ctx, consAddr0)
|
||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
validator, found = keeper.GetValidator(ctx, validatorAddr)
|
||||
require.True(t, found)
|
||||
require.Equal(t, sdk.Unbonding, validator.Status) // ensure is unbonding
|
||||
|
@ -91,14 +92,18 @@ func TestValidatorByPowerIndex(t *testing.T) {
|
|||
require.Equal(t, power2, power3)
|
||||
|
||||
// unbond self-delegation
|
||||
msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, initBond.ToDec())
|
||||
totalBond := validator.TokensFromShares(bond.GetShares()).TruncateInt()
|
||||
unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, totalBond)
|
||||
msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt)
|
||||
|
||||
got = handleMsgUndelegate(ctx, msgUndelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
|
||||
var finishTime time.Time
|
||||
types.MsgCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime)
|
||||
|
||||
ctx = ctx.WithBlockTime(finishTime)
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
// verify that by power key nolonger exists
|
||||
|
@ -215,8 +220,8 @@ func TestLegacyValidatorDelegations(t *testing.T) {
|
|||
require.Equal(t, bondAmount.MulRaw(2), validator.BondedTokens())
|
||||
|
||||
// unbond validator total self-delegations (which should jail the validator)
|
||||
unbondShares := sdk.TokensFromTendermintPower(10)
|
||||
msgUndelegate := NewMsgUndelegate(sdk.AccAddress(valAddr), valAddr, unbondShares.ToDec())
|
||||
unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, bondAmount)
|
||||
msgUndelegate := NewMsgUndelegate(sdk.AccAddress(valAddr), valAddr, unbondAmt)
|
||||
|
||||
got = handleMsgUndelegate(ctx, msgUndelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected begin unbonding validator msg to be ok, got %v", got)
|
||||
|
@ -437,8 +442,8 @@ func TestIncrementsMsgUnbond(t *testing.T) {
|
|||
|
||||
// just send the same msgUnbond multiple times
|
||||
// TODO use decimals here
|
||||
unbondShares := sdk.NewDec(10)
|
||||
msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondShares)
|
||||
unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10))
|
||||
msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt)
|
||||
numUnbonds := int64(5)
|
||||
for i := int64(0); i < numUnbonds; i++ {
|
||||
|
||||
|
@ -455,8 +460,8 @@ func TestIncrementsMsgUnbond(t *testing.T) {
|
|||
bond, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr)
|
||||
require.True(t, found)
|
||||
|
||||
expBond := initBond.Sub(unbondShares.MulInt64(i + 1).RoundInt())
|
||||
expDelegatorShares := (initBond.MulRaw(2)).Sub(unbondShares.MulInt64(i + 1).RoundInt())
|
||||
expBond := initBond.Sub(unbondAmt.Amount.Mul(sdk.NewInt(i + 1)))
|
||||
expDelegatorShares := initBond.MulRaw(2).Sub(unbondAmt.Amount.Mul(sdk.NewInt(i + 1)))
|
||||
expDelegatorAcc := initBond.Sub(expBond)
|
||||
|
||||
gotBond := bond.Shares.RoundInt()
|
||||
|
@ -482,28 +487,22 @@ func TestIncrementsMsgUnbond(t *testing.T) {
|
|||
sdk.TokensFromTendermintPower(1 << 31),
|
||||
initBond,
|
||||
}
|
||||
|
||||
for i, c := range errorCases {
|
||||
unbondShares := c.ToDec()
|
||||
msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondShares)
|
||||
unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, c)
|
||||
msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt)
|
||||
got = handleMsgUndelegate(ctx, msgUndelegate, keeper)
|
||||
require.False(t, got.IsOK(), "expected unbond msg to fail, index: %v", i)
|
||||
}
|
||||
|
||||
leftBonded := initBond.Sub(unbondShares.MulInt64(numUnbonds).RoundInt())
|
||||
leftBonded := initBond.Sub(unbondAmt.Amount.Mul(sdk.NewInt(numUnbonds)))
|
||||
|
||||
// should be unable to unbond one more than we have
|
||||
unbondShares = leftBonded.AddRaw(1).ToDec()
|
||||
msgUndelegate = NewMsgUndelegate(delegatorAddr, validatorAddr, unbondShares)
|
||||
got = handleMsgUndelegate(ctx, msgUndelegate, keeper)
|
||||
require.False(t, got.IsOK(),
|
||||
"got: %v\nmsgUnbond: %v\nshares: %v\nleftBonded: %v\n", got, msgUndelegate, unbondShares.String(), leftBonded)
|
||||
|
||||
// should be able to unbond just what we have
|
||||
unbondShares = leftBonded.ToDec()
|
||||
msgUndelegate = NewMsgUndelegate(delegatorAddr, validatorAddr, unbondShares)
|
||||
// should be able to unbond remaining
|
||||
unbondAmt = sdk.NewCoin(sdk.DefaultBondDenom, leftBonded)
|
||||
msgUndelegate = NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt)
|
||||
got = handleMsgUndelegate(ctx, msgUndelegate, keeper)
|
||||
require.True(t, got.IsOK(),
|
||||
"got: %v\nmsgUnbond: %v\nshares: %v\nleftBonded: %v\n", got, msgUndelegate, unbondShares, leftBonded)
|
||||
"got: %v\nmsgUnbond: %v\nshares: %s\nleftBonded: %s\n", got.Log, msgUndelegate, unbondAmt, leftBonded)
|
||||
}
|
||||
|
||||
func TestMultipleMsgCreateValidator(t *testing.T) {
|
||||
|
@ -548,14 +547,18 @@ func TestMultipleMsgCreateValidator(t *testing.T) {
|
|||
for i, validatorAddr := range validatorAddrs {
|
||||
_, found := keeper.GetValidator(ctx, validatorAddr)
|
||||
require.True(t, found)
|
||||
unbondingTokens := sdk.TokensFromTendermintPower(10)
|
||||
msgUndelegate := NewMsgUndelegate(delegatorAddrs[i], validatorAddr, unbondingTokens.ToDec()) // remove delegation
|
||||
|
||||
unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromTendermintPower(10))
|
||||
msgUndelegate := NewMsgUndelegate(delegatorAddrs[i], validatorAddr, unbondAmt) // remove delegation
|
||||
got := handleMsgUndelegate(ctx, msgUndelegate, keeper)
|
||||
|
||||
require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got)
|
||||
var finishTime time.Time
|
||||
|
||||
// Jump to finishTime for unbonding period and remove from unbonding queue
|
||||
types.MsgCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime)
|
||||
ctx = ctx.WithBlockTime(finishTime)
|
||||
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
// Check that the validator is deleted from state
|
||||
|
@ -576,7 +579,7 @@ func TestMultipleMsgDelegate(t *testing.T) {
|
|||
validatorAddr, delegatorAddrs := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1:]
|
||||
_ = setInstantUnbondPeriod(keeper, ctx)
|
||||
|
||||
//first make a validator
|
||||
// first make a validator
|
||||
msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10))
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
|
@ -587,7 +590,7 @@ func TestMultipleMsgDelegate(t *testing.T) {
|
|||
got := handleMsgDelegate(ctx, msgDelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got)
|
||||
|
||||
//Check that the account is bonded
|
||||
// check that the account is bonded
|
||||
bond, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr)
|
||||
require.True(t, found)
|
||||
require.NotNil(t, bond, "expected delegatee bond %d to exist", bond)
|
||||
|
@ -595,15 +598,19 @@ func TestMultipleMsgDelegate(t *testing.T) {
|
|||
|
||||
// unbond them all
|
||||
for i, delegatorAddr := range delegatorAddrs {
|
||||
msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, sdk.NewDec(10))
|
||||
unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10))
|
||||
msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt)
|
||||
|
||||
got := handleMsgUndelegate(ctx, msgUndelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got)
|
||||
|
||||
var finishTime time.Time
|
||||
types.MsgCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime)
|
||||
|
||||
ctx = ctx.WithBlockTime(finishTime)
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
//Check that the account is unbonded
|
||||
// check that the account is unbonded
|
||||
_, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr)
|
||||
require.False(t, found)
|
||||
}
|
||||
|
@ -625,11 +632,14 @@ func TestJailValidator(t *testing.T) {
|
|||
require.True(t, got.IsOK(), "expected ok, got %v", got)
|
||||
|
||||
// unbond the validators bond portion
|
||||
msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, sdk.NewDec(10))
|
||||
unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10))
|
||||
msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt)
|
||||
got = handleMsgUndelegate(ctx, msgUndelegateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error: %v", got)
|
||||
|
||||
var finishTime time.Time
|
||||
types.MsgCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime)
|
||||
|
||||
ctx = ctx.WithBlockTime(finishTime)
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
|
@ -638,10 +648,12 @@ func TestJailValidator(t *testing.T) {
|
|||
require.True(t, validator.Jailed, "%v", validator)
|
||||
|
||||
// test that the delegator can still withdraw their bonds
|
||||
msgUndelegateDelegator := NewMsgUndelegate(delegatorAddr, validatorAddr, sdk.NewDec(10))
|
||||
msgUndelegateDelegator := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt)
|
||||
|
||||
got = handleMsgUndelegate(ctx, msgUndelegateDelegator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error")
|
||||
types.MsgCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime)
|
||||
|
||||
ctx = ctx.WithBlockTime(finishTime)
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
|
@ -674,14 +686,17 @@ func TestValidatorQueue(t *testing.T) {
|
|||
EndBlocker(ctx, keeper)
|
||||
|
||||
// unbond the all self-delegation to put validator in unbonding state
|
||||
msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr),
|
||||
validatorAddr, delTokens.ToDec())
|
||||
unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, delTokens)
|
||||
msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt)
|
||||
got = handleMsgUndelegate(ctx, msgUndelegateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error: %v", got)
|
||||
|
||||
var finishTime time.Time
|
||||
types.MsgCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime)
|
||||
|
||||
ctx = ctx.WithBlockTime(finishTime)
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
origHeader := ctx.BlockHeader()
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, validatorAddr)
|
||||
|
@ -691,6 +706,7 @@ func TestValidatorQueue(t *testing.T) {
|
|||
// should still be unbonding at time 6 seconds later
|
||||
ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6))
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
validator, found = keeper.GetValidator(ctx, validatorAddr)
|
||||
require.True(t, found)
|
||||
require.True(t, validator.GetStatus() == sdk.Unbonding, "%v", validator)
|
||||
|
@ -698,6 +714,7 @@ func TestValidatorQueue(t *testing.T) {
|
|||
// should be in unbonded state at time 7 seconds later
|
||||
ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7))
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
validator, found = keeper.GetValidator(ctx, validatorAddr)
|
||||
require.True(t, found)
|
||||
require.True(t, validator.GetStatus() == sdk.Unbonded, "%v", validator)
|
||||
|
@ -721,11 +738,11 @@ func TestUnbondingPeriod(t *testing.T) {
|
|||
EndBlocker(ctx, keeper)
|
||||
|
||||
// begin unbonding
|
||||
unbondingTokens := sdk.TokensFromTendermintPower(10)
|
||||
msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr),
|
||||
validatorAddr, unbondingTokens.ToDec())
|
||||
unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromTendermintPower(10))
|
||||
msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt)
|
||||
got = handleMsgUndelegate(ctx, msgUndelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error")
|
||||
|
||||
origHeader := ctx.BlockHeader()
|
||||
|
||||
_, found := keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr)
|
||||
|
@ -764,7 +781,8 @@ func TestUnbondingFromUnbondingValidator(t *testing.T) {
|
|||
require.True(t, got.IsOK(), "expected ok, got %v", got)
|
||||
|
||||
// unbond the validators bond portion
|
||||
msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, sdk.NewDec(10))
|
||||
unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10))
|
||||
msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt)
|
||||
got = handleMsgUndelegate(ctx, msgUndelegateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error")
|
||||
|
||||
|
@ -774,7 +792,7 @@ func TestUnbondingFromUnbondingValidator(t *testing.T) {
|
|||
ctx = ctx.WithBlockTime(finishTime.Add(time.Second * -1))
|
||||
|
||||
// unbond the delegator from the validator
|
||||
msgUndelegateDelegator := NewMsgUndelegate(delegatorAddr, validatorAddr, sdk.NewDec(10))
|
||||
msgUndelegateDelegator := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt)
|
||||
got = handleMsgUndelegate(ctx, msgUndelegateDelegator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error")
|
||||
|
||||
|
@ -820,7 +838,8 @@ func TestRedelegationPeriod(t *testing.T) {
|
|||
bal1 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins()
|
||||
|
||||
// begin redelegate
|
||||
msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, sdk.NewDec(10))
|
||||
redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10))
|
||||
msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt)
|
||||
got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error, %v", got)
|
||||
|
||||
|
@ -873,12 +892,13 @@ func TestTransitiveRedelegation(t *testing.T) {
|
|||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
// begin redelegate
|
||||
msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, sdk.NewDec(10))
|
||||
redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10))
|
||||
msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt)
|
||||
got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error, %v", got)
|
||||
|
||||
// cannot redelegation to next validator while first delegation exists
|
||||
msgBeginRedelegate = NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr2, validatorAddr3, sdk.NewDec(10))
|
||||
msgBeginRedelegate = NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr2, validatorAddr3, redAmt)
|
||||
got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper)
|
||||
require.True(t, !got.IsOK(), "expected an error, msg: %v", msgBeginRedelegate)
|
||||
|
||||
|
@ -915,8 +935,8 @@ func TestMultipleRedelegationAtSameTime(t *testing.T) {
|
|||
|
||||
// begin a redelegate
|
||||
selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator)
|
||||
msgBeginRedelegate := NewMsgBeginRedelegate(selfDelAddr,
|
||||
valAddr, valAddr2, valTokens.QuoRaw(2).ToDec())
|
||||
redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2))
|
||||
msgBeginRedelegate := NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt)
|
||||
got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error, %v", got)
|
||||
|
||||
|
@ -967,8 +987,8 @@ func TestMultipleRedelegationAtUniqueTimes(t *testing.T) {
|
|||
|
||||
// begin a redelegate
|
||||
selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator)
|
||||
msgBeginRedelegate := NewMsgBeginRedelegate(selfDelAddr,
|
||||
valAddr, valAddr2, valTokens.QuoRaw(2).ToDec())
|
||||
redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2))
|
||||
msgBeginRedelegate := NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt)
|
||||
got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error, %v", got)
|
||||
|
||||
|
@ -1016,7 +1036,8 @@ func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) {
|
|||
|
||||
// begin an unbonding delegation
|
||||
selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator)
|
||||
msgUndelegate := NewMsgUndelegate(selfDelAddr, valAddr, valTokens.QuoRaw(2).ToDec())
|
||||
unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2))
|
||||
msgUndelegate := NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt)
|
||||
got = handleMsgUndelegate(ctx, msgUndelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error, %v", got)
|
||||
|
||||
|
@ -1062,7 +1083,8 @@ func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) {
|
|||
|
||||
// begin an unbonding delegation
|
||||
selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator)
|
||||
msgUndelegate := NewMsgUndelegate(selfDelAddr, valAddr, valTokens.QuoRaw(2).ToDec())
|
||||
unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2))
|
||||
msgUndelegate := NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt)
|
||||
got = handleMsgUndelegate(ctx, msgUndelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error, %v", got)
|
||||
|
||||
|
@ -1132,8 +1154,9 @@ func TestUnbondingWhenExcessValidators(t *testing.T) {
|
|||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 2, len(keeper.GetLastValidators(ctx)))
|
||||
|
||||
// unbond the valdator-2
|
||||
msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr2), validatorAddr2, valTokens2.ToDec())
|
||||
// unbond the validator-2
|
||||
unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens2)
|
||||
msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr2), validatorAddr2, unbondAmt)
|
||||
got = handleMsgUndelegate(ctx, msgUndelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgUndelegate")
|
||||
|
||||
|
@ -1177,21 +1200,21 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) {
|
|||
ctx = ctx.WithBlockHeight(1)
|
||||
|
||||
// begin unbonding 4 stake
|
||||
ubdTokens := sdk.TokensFromTendermintPower(4)
|
||||
msgUndelegate := NewMsgUndelegate(del, valA, ubdTokens.ToDec())
|
||||
unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromTendermintPower(4))
|
||||
msgUndelegate := NewMsgUndelegate(del, valA, unbondAmt)
|
||||
got = handleMsgUndelegate(ctx, msgUndelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgUndelegate")
|
||||
|
||||
// begin redelegate 6 stake
|
||||
rdTokens := sdk.TokensFromTendermintPower(6)
|
||||
msgBeginRedelegate := NewMsgBeginRedelegate(del, valA, valB, rdTokens.ToDec())
|
||||
redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromTendermintPower(6))
|
||||
msgBeginRedelegate := NewMsgBeginRedelegate(del, valA, valB, redAmt)
|
||||
got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgBeginRedelegate")
|
||||
|
||||
// destination delegation should have 6 shares
|
||||
delegation, found := keeper.GetDelegation(ctx, del, valB)
|
||||
require.True(t, found)
|
||||
require.Equal(t, rdTokens.ToDec(), delegation.Shares)
|
||||
require.Equal(t, sdk.NewDecFromInt(redAmt.Amount), delegation.Shares)
|
||||
|
||||
// must apply validator updates
|
||||
updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
@ -1204,7 +1227,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) {
|
|||
ubd, found := keeper.GetUnbondingDelegation(ctx, del, valA)
|
||||
require.True(t, found)
|
||||
require.Len(t, ubd.Entries, 1)
|
||||
require.Equal(t, ubdTokens.QuoRaw(2), ubd.Entries[0].Balance)
|
||||
require.Equal(t, unbondAmt.Amount.QuoRaw(2), ubd.Entries[0].Balance)
|
||||
|
||||
// redelegation should have been slashed by half
|
||||
redelegation, found := keeper.GetRedelegation(ctx, del, valA, valB)
|
||||
|
@ -1214,7 +1237,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) {
|
|||
// destination delegation should have been slashed by half
|
||||
delegation, found = keeper.GetDelegation(ctx, del, valB)
|
||||
require.True(t, found)
|
||||
require.Equal(t, rdTokens.QuoRaw(2).ToDec(), delegation.Shares)
|
||||
require.Equal(t, sdk.NewDecFromInt(redAmt.Amount.QuoRaw(2)), delegation.Shares)
|
||||
|
||||
// validator power should have been reduced by half
|
||||
validator, found := keeper.GetValidator(ctx, valA)
|
||||
|
@ -1229,7 +1252,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) {
|
|||
ubd, found = keeper.GetUnbondingDelegation(ctx, del, valA)
|
||||
require.True(t, found)
|
||||
require.Len(t, ubd.Entries, 1)
|
||||
require.Equal(t, ubdTokens.QuoRaw(2), ubd.Entries[0].Balance)
|
||||
require.Equal(t, unbondAmt.Amount.QuoRaw(2), ubd.Entries[0].Balance)
|
||||
|
||||
// redelegation should be unchanged
|
||||
redelegation, found = keeper.GetRedelegation(ctx, del, valA, valB)
|
||||
|
@ -1239,7 +1262,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) {
|
|||
// destination delegation should be unchanged
|
||||
delegation, found = keeper.GetDelegation(ctx, del, valB)
|
||||
require.True(t, found)
|
||||
require.Equal(t, rdTokens.QuoRaw(2).ToDec(), delegation.Shares)
|
||||
require.Equal(t, sdk.NewDecFromInt(redAmt.Amount.QuoRaw(2)), delegation.Shares)
|
||||
|
||||
// end blocker
|
||||
EndBlocker(ctx, keeper)
|
||||
|
|
|
@ -518,7 +518,7 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA
|
|||
// if the delegation is the operator of the validator and undelegating will decrease the validator's self delegation below their minimum
|
||||
// trigger a jail validator
|
||||
if isValidatorOperator && !validator.Jailed &&
|
||||
validator.ShareTokens(delegation.Shares).TruncateInt().LT(validator.MinSelfDelegation) {
|
||||
validator.TokensFromShares(delegation.Shares).TruncateInt().LT(validator.MinSelfDelegation) {
|
||||
|
||||
k.jailValidator(ctx, validator)
|
||||
validator = k.mustGetValidator(ctx, validator.OperatorAddress)
|
||||
|
@ -726,3 +726,46 @@ func (k Keeper) CompleteRedelegation(ctx sdk.Context, delAddr sdk.AccAddress,
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateUnbondAmount validates that a given unbond or redelegation amount is
|
||||
// valied based on upon the converted shares. If the amount is valid, the total
|
||||
// amount of respective shares is returned, otherwise an error is returned.
|
||||
func (k Keeper) ValidateUnbondAmount(
|
||||
ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, amt sdk.Int,
|
||||
) (shares sdk.Dec, err sdk.Error) {
|
||||
|
||||
validator, found := k.GetValidator(ctx, valAddr)
|
||||
if !found {
|
||||
return shares, types.ErrNoValidatorFound(k.Codespace())
|
||||
}
|
||||
|
||||
del, found := k.GetDelegation(ctx, delAddr, valAddr)
|
||||
if !found {
|
||||
return shares, types.ErrNoDelegation(k.Codespace())
|
||||
}
|
||||
|
||||
shares, err = validator.SharesFromTokens(amt)
|
||||
if err != nil {
|
||||
return shares, err
|
||||
}
|
||||
|
||||
sharesTruncated, err := validator.SharesFromTokensTruncated(amt)
|
||||
if err != nil {
|
||||
return shares, err
|
||||
}
|
||||
|
||||
delShares := del.GetShares()
|
||||
if sharesTruncated.GT(delShares) {
|
||||
return shares, types.ErrBadSharesAmount(k.Codespace())
|
||||
}
|
||||
|
||||
// Cap the shares at the delegation's shares. Shares being greater could occur
|
||||
// due to rounding, however we don't want to truncate the shares or take the
|
||||
// minimum because we want to allow for the full withdraw of shares from a
|
||||
// delegation.
|
||||
if shares.GT(delShares) {
|
||||
shares = delShares
|
||||
}
|
||||
|
||||
return shares, nil
|
||||
}
|
||||
|
|
|
@ -148,24 +148,31 @@ func SimulateMsgUndelegate(m auth.AccountKeeper, k staking.Keeper) simulation.Op
|
|||
}
|
||||
delegation := delegations[r.Intn(len(delegations))]
|
||||
|
||||
numShares := simulation.RandomDecAmount(r, delegation.Shares)
|
||||
if numShares.Equal(sdk.ZeroDec()) {
|
||||
validator, found := k.GetValidator(ctx, delegation.GetValidatorAddr())
|
||||
if !found {
|
||||
return simulation.NoOpMsg(), nil, nil
|
||||
}
|
||||
msg := staking.MsgUndelegate{
|
||||
DelegatorAddress: delegatorAddress,
|
||||
ValidatorAddress: delegation.ValidatorAddress,
|
||||
SharesAmount: numShares,
|
||||
|
||||
totalBond := validator.TokensFromShares(delegation.GetShares()).TruncateInt()
|
||||
unbondAmt := simulation.RandomAmount(r, totalBond)
|
||||
if unbondAmt.Equal(sdk.ZeroInt()) {
|
||||
return simulation.NoOpMsg(), nil, nil
|
||||
}
|
||||
|
||||
msg := staking.NewMsgDelegate(
|
||||
delegatorAddress, delegation.ValidatorAddress, sdk.NewCoin(k.GetParams(ctx).BondDenom, unbondAmt),
|
||||
)
|
||||
if msg.ValidateBasic() != nil {
|
||||
return simulation.NoOpMsg(), nil, fmt.Errorf("expected msg to pass ValidateBasic: %s, got error %v",
|
||||
msg.GetSignBytes(), msg.ValidateBasic())
|
||||
}
|
||||
|
||||
ctx, write := ctx.CacheContext()
|
||||
ok := handler(ctx, msg).IsOK()
|
||||
if ok {
|
||||
write()
|
||||
}
|
||||
|
||||
opMsg = simulation.NewOperationMsg(msg, ok, "")
|
||||
return opMsg, nil, nil
|
||||
}
|
||||
|
@ -195,20 +202,20 @@ func SimulateMsgBeginRedelegate(m auth.AccountKeeper, k staking.Keeper) simulati
|
|||
if amount.Equal(sdk.ZeroInt()) {
|
||||
return simulation.NoOpMsg(), nil, nil
|
||||
}
|
||||
msg := staking.MsgBeginRedelegate{
|
||||
DelegatorAddress: delegatorAddress,
|
||||
ValidatorSrcAddress: srcValidatorAddress,
|
||||
ValidatorDstAddress: destValidatorAddress,
|
||||
SharesAmount: amount.ToDec(),
|
||||
}
|
||||
|
||||
msg := staking.NewMsgBeginRedelegate(
|
||||
delegatorAddress, srcValidatorAddress, destValidatorAddress, sdk.NewCoin(denom, amount),
|
||||
)
|
||||
if msg.ValidateBasic() != nil {
|
||||
return simulation.NoOpMsg(), nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
||||
}
|
||||
|
||||
ctx, write := ctx.CacheContext()
|
||||
ok := handler(ctx, msg).IsOK()
|
||||
if ok {
|
||||
write()
|
||||
}
|
||||
|
||||
opMsg = simulation.NewOperationMsg(msg, ok, "")
|
||||
return opMsg, nil, nil
|
||||
}
|
||||
|
|
|
@ -212,14 +212,14 @@ func (msg MsgEditValidator) ValidateBasic() sdk.Error {
|
|||
type MsgDelegate struct {
|
||||
DelegatorAddress sdk.AccAddress `json:"delegator_address"`
|
||||
ValidatorAddress sdk.ValAddress `json:"validator_address"`
|
||||
Value sdk.Coin `json:"value"`
|
||||
Amount sdk.Coin `json:"amount"`
|
||||
}
|
||||
|
||||
func NewMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, value sdk.Coin) MsgDelegate {
|
||||
func NewMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount sdk.Coin) MsgDelegate {
|
||||
return MsgDelegate{
|
||||
DelegatorAddress: delAddr,
|
||||
ValidatorAddress: valAddr,
|
||||
Value: value,
|
||||
Amount: amount,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,7 +244,7 @@ func (msg MsgDelegate) ValidateBasic() sdk.Error {
|
|||
if msg.ValidatorAddress.Empty() {
|
||||
return ErrNilValidatorAddr(DefaultCodespace)
|
||||
}
|
||||
if msg.Value.Amount.LTE(sdk.ZeroInt()) {
|
||||
if msg.Amount.Amount.LTE(sdk.ZeroInt()) {
|
||||
return ErrBadDelegationAmount(DefaultCodespace)
|
||||
}
|
||||
return nil
|
||||
|
@ -257,17 +257,17 @@ type MsgBeginRedelegate struct {
|
|||
DelegatorAddress sdk.AccAddress `json:"delegator_address"`
|
||||
ValidatorSrcAddress sdk.ValAddress `json:"validator_src_address"`
|
||||
ValidatorDstAddress sdk.ValAddress `json:"validator_dst_address"`
|
||||
SharesAmount sdk.Dec `json:"shares_amount"`
|
||||
Amount sdk.Coin `json:"amount"`
|
||||
}
|
||||
|
||||
func NewMsgBeginRedelegate(delAddr sdk.AccAddress, valSrcAddr,
|
||||
valDstAddr sdk.ValAddress, sharesAmount sdk.Dec) MsgBeginRedelegate {
|
||||
valDstAddr sdk.ValAddress, amount sdk.Coin) MsgBeginRedelegate {
|
||||
|
||||
return MsgBeginRedelegate{
|
||||
DelegatorAddress: delAddr,
|
||||
ValidatorSrcAddress: valSrcAddr,
|
||||
ValidatorDstAddress: valDstAddr,
|
||||
SharesAmount: sharesAmount,
|
||||
Amount: amount,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -295,7 +295,7 @@ func (msg MsgBeginRedelegate) ValidateBasic() sdk.Error {
|
|||
if msg.ValidatorDstAddress.Empty() {
|
||||
return ErrNilValidatorAddr(DefaultCodespace)
|
||||
}
|
||||
if msg.SharesAmount.LTE(sdk.ZeroDec()) {
|
||||
if msg.Amount.Amount.LTE(sdk.ZeroInt()) {
|
||||
return ErrBadSharesAmount(DefaultCodespace)
|
||||
}
|
||||
return nil
|
||||
|
@ -305,14 +305,14 @@ func (msg MsgBeginRedelegate) ValidateBasic() sdk.Error {
|
|||
type MsgUndelegate struct {
|
||||
DelegatorAddress sdk.AccAddress `json:"delegator_address"`
|
||||
ValidatorAddress sdk.ValAddress `json:"validator_address"`
|
||||
SharesAmount sdk.Dec `json:"shares_amount"`
|
||||
Amount sdk.Coin `json:"amount"`
|
||||
}
|
||||
|
||||
func NewMsgUndelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, sharesAmount sdk.Dec) MsgUndelegate {
|
||||
func NewMsgUndelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount sdk.Coin) MsgUndelegate {
|
||||
return MsgUndelegate{
|
||||
DelegatorAddress: delAddr,
|
||||
ValidatorAddress: valAddr,
|
||||
SharesAmount: sharesAmount,
|
||||
Amount: amount,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,7 +335,7 @@ func (msg MsgUndelegate) ValidateBasic() sdk.Error {
|
|||
if msg.ValidatorAddress.Empty() {
|
||||
return ErrNilValidatorAddr(DefaultCodespace)
|
||||
}
|
||||
if msg.SharesAmount.LTE(sdk.ZeroDec()) {
|
||||
if msg.Amount.Amount.LTE(sdk.ZeroInt()) {
|
||||
return ErrBadSharesAmount(DefaultCodespace)
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -110,19 +110,18 @@ func TestMsgBeginRedelegate(t *testing.T) {
|
|||
delegatorAddr sdk.AccAddress
|
||||
validatorSrcAddr sdk.ValAddress
|
||||
validatorDstAddr sdk.ValAddress
|
||||
sharesAmount sdk.Dec
|
||||
amount sdk.Coin
|
||||
expectPass bool
|
||||
}{
|
||||
{"regular", sdk.AccAddress(addr1), addr2, addr3, sdk.NewDecWithPrec(1, 1), true},
|
||||
{"negative decimal", sdk.AccAddress(addr1), addr2, addr3, sdk.NewDecWithPrec(-1, 1), false},
|
||||
{"zero amount", sdk.AccAddress(addr1), addr2, addr3, sdk.ZeroDec(), false},
|
||||
{"empty delegator", sdk.AccAddress(emptyAddr), addr1, addr3, sdk.NewDecWithPrec(1, 1), false},
|
||||
{"empty source validator", sdk.AccAddress(addr1), emptyAddr, addr3, sdk.NewDecWithPrec(1, 1), false},
|
||||
{"empty destination validator", sdk.AccAddress(addr1), addr2, emptyAddr, sdk.NewDecWithPrec(1, 1), false},
|
||||
{"regular", sdk.AccAddress(addr1), addr2, addr3, sdk.NewInt64Coin(sdk.DefaultBondDenom, 1), true},
|
||||
{"zero amount", sdk.AccAddress(addr1), addr2, addr3, sdk.NewInt64Coin(sdk.DefaultBondDenom, 0), false},
|
||||
{"empty delegator", sdk.AccAddress(emptyAddr), addr1, addr3, sdk.NewInt64Coin(sdk.DefaultBondDenom, 1), false},
|
||||
{"empty source validator", sdk.AccAddress(addr1), emptyAddr, addr3, sdk.NewInt64Coin(sdk.DefaultBondDenom, 1), false},
|
||||
{"empty destination validator", sdk.AccAddress(addr1), addr2, emptyAddr, sdk.NewInt64Coin(sdk.DefaultBondDenom, 1), false},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
msg := NewMsgBeginRedelegate(tc.delegatorAddr, tc.validatorSrcAddr, tc.validatorDstAddr, tc.sharesAmount)
|
||||
msg := NewMsgBeginRedelegate(tc.delegatorAddr, tc.validatorSrcAddr, tc.validatorDstAddr, tc.amount)
|
||||
if tc.expectPass {
|
||||
require.Nil(t, msg.ValidateBasic(), "test: %v", tc.name)
|
||||
} else {
|
||||
|
@ -137,18 +136,17 @@ func TestMsgUndelegate(t *testing.T) {
|
|||
name string
|
||||
delegatorAddr sdk.AccAddress
|
||||
validatorAddr sdk.ValAddress
|
||||
sharesAmount sdk.Dec
|
||||
amount sdk.Coin
|
||||
expectPass bool
|
||||
}{
|
||||
{"regular", sdk.AccAddress(addr1), addr2, sdk.NewDecWithPrec(1, 1), true},
|
||||
{"negative decimal", sdk.AccAddress(addr1), addr2, sdk.NewDecWithPrec(-1, 1), false},
|
||||
{"zero amount", sdk.AccAddress(addr1), addr2, sdk.ZeroDec(), false},
|
||||
{"empty delegator", sdk.AccAddress(emptyAddr), addr1, sdk.NewDecWithPrec(1, 1), false},
|
||||
{"empty validator", sdk.AccAddress(addr1), emptyAddr, sdk.NewDecWithPrec(1, 1), false},
|
||||
{"regular", sdk.AccAddress(addr1), addr2, sdk.NewInt64Coin(sdk.DefaultBondDenom, 1), true},
|
||||
{"zero amount", sdk.AccAddress(addr1), addr2, sdk.NewInt64Coin(sdk.DefaultBondDenom, 0), false},
|
||||
{"empty delegator", sdk.AccAddress(emptyAddr), addr1, sdk.NewInt64Coin(sdk.DefaultBondDenom, 1), false},
|
||||
{"empty validator", sdk.AccAddress(addr1), emptyAddr, sdk.NewInt64Coin(sdk.DefaultBondDenom, 1), false},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
msg := NewMsgUndelegate(tc.delegatorAddr, tc.validatorAddr, tc.sharesAmount)
|
||||
msg := NewMsgUndelegate(tc.delegatorAddr, tc.validatorAddr, tc.amount)
|
||||
if tc.expectPass {
|
||||
require.Nil(t, msg.ValidateBasic(), "test: %v", tc.name)
|
||||
} else {
|
||||
|
|
|
@ -354,7 +354,12 @@ func (v Validator) AddTokensFromDel(pool Pool, amount sdk.Int) (Validator, Pool,
|
|||
// the first delegation to a validator sets the exchange rate to one
|
||||
issuedShares = amount.ToDec()
|
||||
} else {
|
||||
issuedShares = v.DelegatorShares.MulInt(amount).QuoInt(v.Tokens)
|
||||
shares, err := v.SharesFromTokens(amount)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
issuedShares = shares
|
||||
}
|
||||
|
||||
if v.Status == sdk.Bonded {
|
||||
|
@ -384,7 +389,7 @@ func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Dec) (Validator, Poo
|
|||
|
||||
// leave excess tokens in the validator
|
||||
// however fully use all the delegator shares
|
||||
issuedTokens = v.ShareTokens(delShares).TruncateInt()
|
||||
issuedTokens = v.TokensFromShares(delShares).TruncateInt()
|
||||
v.Tokens = v.Tokens.Sub(issuedTokens)
|
||||
if v.Tokens.IsNegative() {
|
||||
panic("attempting to remove more tokens than available in validator")
|
||||
|
@ -407,15 +412,35 @@ func (v Validator) InvalidExRate() bool {
|
|||
}
|
||||
|
||||
// calculate the token worth of provided shares
|
||||
func (v Validator) ShareTokens(shares sdk.Dec) sdk.Dec {
|
||||
func (v Validator) TokensFromShares(shares sdk.Dec) sdk.Dec {
|
||||
return (shares.MulInt(v.Tokens)).Quo(v.DelegatorShares)
|
||||
}
|
||||
|
||||
// calculate the token worth of provided shares, truncated
|
||||
func (v Validator) ShareTokensTruncated(shares sdk.Dec) sdk.Dec {
|
||||
func (v Validator) TokensFromSharesTruncated(shares sdk.Dec) sdk.Dec {
|
||||
return (shares.MulInt(v.Tokens)).QuoTruncate(v.DelegatorShares)
|
||||
}
|
||||
|
||||
// SharesFromTokens returns the shares of a delegation given a bond amount. It
|
||||
// returns an error if the validator has no tokens.
|
||||
func (v Validator) SharesFromTokens(amt sdk.Int) (sdk.Dec, sdk.Error) {
|
||||
if v.Tokens.IsZero() {
|
||||
return sdk.ZeroDec(), ErrInsufficientShares(DefaultCodespace)
|
||||
}
|
||||
|
||||
return v.GetDelegatorShares().MulInt(amt).QuoInt(v.GetTokens()), nil
|
||||
}
|
||||
|
||||
// SharesFromTokensTruncated returns the truncated shares of a delegation given
|
||||
// a bond amount. It returns an error if the validator has no tokens.
|
||||
func (v Validator) SharesFromTokensTruncated(amt sdk.Int) (sdk.Dec, sdk.Error) {
|
||||
if v.Tokens.IsZero() {
|
||||
return sdk.ZeroDec(), ErrInsufficientShares(DefaultCodespace)
|
||||
}
|
||||
|
||||
return v.GetDelegatorShares().MulInt(amt).QuoTruncate(v.GetTokens().ToDec()), nil
|
||||
}
|
||||
|
||||
// get the bonded tokens which the validator holds
|
||||
func (v Validator) BondedTokens() sdk.Int {
|
||||
if v.Status == sdk.Bonded {
|
||||
|
|
|
@ -77,11 +77,11 @@ func TestShareTokens(t *testing.T) {
|
|||
Tokens: sdk.NewInt(100),
|
||||
DelegatorShares: sdk.NewDec(100),
|
||||
}
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(50), validator.ShareTokens(sdk.NewDec(50))))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(50), validator.TokensFromShares(sdk.NewDec(50))))
|
||||
|
||||
validator.Tokens = sdk.NewInt(50)
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(25), validator.ShareTokens(sdk.NewDec(50))))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(5), validator.ShareTokens(sdk.NewDec(10))))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(25), validator.TokensFromShares(sdk.NewDec(50))))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(5), validator.TokensFromShares(sdk.NewDec(10))))
|
||||
}
|
||||
|
||||
func TestRemoveTokens(t *testing.T) {
|
||||
|
|
Loading…
Reference in New Issue