Skip to main content

Staking Module (x/staking)

Overview

The x/staking module enables Cosmos SDK-based blockchains to support an advanced Proof-of-Stake (PoS) system where token holders can become validators or delegate tokens to validators. Purpose: Manage validator set, handle delegations, and facilitate the Proof-of-Stake consensus mechanism.

Key Features

  • Validator Management: Create, edit, and track validators
  • Delegation: Delegate tokens to validators for staking rewards
  • Unbonding: Safely unbond tokens with time delay
  • Redelegation: Move delegations between validators instantly
  • Slashing Integration: Penalize validator misbehavior
  • Dynamic Validator Set: Automatically update active validators

Validator States

Validators can be in one of three states:

Unbonded

  • Not in active set
  • Cannot sign blocks
  • Do not earn rewards
  • Can receive delegations

Bonded

  • In active set
  • Sign blocks and receive rewards
  • Can be slashed for misbehavior
  • Delegations have unbonding period

Unbonding

  • Leaving active set
  • All delegations begin unbonding
  • Still slashable during unbonding period
  • Duration defined by UnbondingTime parameter

State

Pool

Tracks bonded and not-bonded token supply:
  • BondedPool: Tokens from bonded validators
  • NotBondedPool: Tokens from unbonding/unbonded validators

Validators

Storage Keys:
0x21 | OperatorAddr -> ProtocolBuffer(validator)
0x22 | ConsAddr -> OperatorAddr
0x23 | BigEndian(Power) | OperatorAddr -> OperatorAddr
0x11 | OperatorAddr -> ProtocolBuffer(Power)
message Validator {
    string operator_address = 1;
    google.protobuf.Any consensus_pubkey = 2;
    bool jailed = 3;
    BondStatus status = 4;
    string tokens = 5;
    string delegator_shares = 6;
    Description description = 7;
    int64 unbonding_height = 8;
    google.protobuf.Timestamp unbonding_time = 9;
    Commission commission = 10;
    string min_self_delegation = 11;
}

Delegation

Storage: 0x31 | DelegatorAddr | ValidatorAddr -> ProtocolBuffer(delegation)
message Delegation {
    string delegator_address = 1;
    string validator_address = 2;
    string shares = 3;
}

Delegator Shares

Shares are issued based on exchange rate:
SharesPerToken = validator.TotalShares() / validator.Tokens()
TokensPerShare = validator.Tokens() / validator.TotalShares()

UnbondingDelegation

Storage: 0x32 | DelegatorAddr | ValidatorAddr -> ProtocolBuffer(unbondingDelegation)
message UnbondingDelegation {
    string delegator_address = 1;
    string validator_address = 2;
    repeated UnbondingDelegationEntry entries = 3;
}

message UnbondingDelegationEntry {
    int64 creation_height = 1;
    google.protobuf.Timestamp completion_time = 2;
    string initial_balance = 3;
    string balance = 4;
    uint64 unbonding_id = 5;
}

Redelegation

Storage: 0x34 | DelegatorAddr | ValidatorSrcAddr | ValidatorDstAddr -> ProtocolBuffer(redelegation)
message Redelegation {
    string delegator_address = 1;
    string validator_src_address = 2;
    string validator_dst_address = 3;
    repeated RedelegationEntry entries = 4;
}

message RedelegationEntry {
    int64 creation_height = 1;
    google.protobuf.Timestamp completion_time = 2;
    string initial_balance = 3;
    string shares_dst = 4;
    uint64 unbonding_id = 5;
}

Parameters

ParameterTypeDefaultDescription
UnbondingTimeDuration1814400s (21 days)Time for unbonding completion
MaxValidatorsuint32100Maximum active validators
MaxEntriesuint327Max unbonding/redelegation entries
HistoricalEntriesuint3210000Historical info entries to persist
BondDenomstring”stake”Denomination for staking
MinCommissionRateDec”0”Minimum validator commission rate

Messages

MsgCreateValidator

Create a new validator:
message MsgCreateValidator {
    Description description = 1;
    CommissionRates commission = 2;
    string min_self_delegation = 3;
    string delegator_address = 4;
    string validator_address = 5;
    google.protobuf.Any pubkey = 6;
    Coin value = 7;
}
Usage:
simd tx staking create-validator \
    --amount=1000000stake \
    --pubkey=$(simd tendermint show-validator) \
    --moniker="my-validator" \
    --commission-rate="0.10" \
    --commission-max-rate="0.20" \
    --commission-max-change-rate="0.01" \
    --min-self-delegation="1" \
    --from=mykey

MsgEditValidator

Edit validator description and commission:
message MsgEditValidator {
    Description description = 1;
    string validator_address = 2;
    string commission_rate = 3;
    string min_self_delegation = 4;
}
Usage:
simd tx staking edit-validator \
    --moniker="updated-moniker" \
    --commission-rate="0.15" \
    --from=mykey

MsgDelegate

Delegate tokens to a validator:
message MsgDelegate {
    string delegator_address = 1;
    string validator_address = 2;
    Coin amount = 3;
}
Usage:
simd tx staking delegate cosmosvaloper1... 1000000stake --from=mykey

MsgUndelegate

Unbond delegation from validator:
message MsgUndelegate {
    string delegator_address = 1;
    string validator_address = 2;
    Coin amount = 3;
}
Usage:
simd tx staking unbond cosmosvaloper1... 1000000stake --from=mykey

MsgBeginRedelegate

Redelegate tokens to different validator:
message MsgBeginRedelegate {
    string delegator_address = 1;
    string validator_src_address = 2;
    string validator_dst_address = 3;
    Coin amount = 4;
}
Usage:
simd tx staking redelegate \
    cosmosvaloper1... \
    cosmosvaloper2... \
    1000000stake \
    --from=mykey

MsgCancelUnbondingDelegation

Cancel unbonding and re-delegate:
message MsgCancelUnbondingDelegation {
    string delegator_address = 1;
    string validator_address = 2;
    Coin amount = 3;
    int64 creation_height = 4;
}

Queries

Query Validator

simd query staking validator cosmosvaloper1...

Query Validators

simd query staking validators

Query Delegation

simd query staking delegation cosmos1... cosmosvaloper1...

Query Delegations

# All delegations for delegator
simd query staking delegations cosmos1...

# All delegations to validator
simd query staking delegations-to cosmosvaloper1...

Query Unbonding Delegation

simd query staking unbonding-delegation cosmos1... cosmosvaloper1...

Query Redelegation

simd query staking redelegation cosmos1... cosmosvaloper1... cosmosvaloper2...

Query Pool

simd query staking pool
Example output:
bonded_tokens: "10000000"
not_bonded_tokens: "0"

Query Parameters

simd query staking params

Query Historical Info

simd query staking historical-info 100

gRPC Endpoints

Validator

grpcurl -plaintext \
    -d '{"validator_addr":"cosmosvaloper1.."}' \
    localhost:9090 \
    cosmos.staking.v1beta1.Query/Validator

Validators

grpcurl -plaintext \
    localhost:9090 \
    cosmos.staking.v1beta1.Query/Validators

Delegation

grpcurl -plaintext \
    -d '{"delegator_addr":"cosmos1..","validator_addr":"cosmosvaloper1.."}' \
    localhost:9090 \
    cosmos.staking.v1beta1.Query/Delegation

Pool

grpcurl -plaintext \
    localhost:9090 \
    cosmos.staking.v1beta1.Query/Pool

Events

MsgCreateValidator

TypeAttribute KeyAttribute Value
create_validatorvalidator
create_validatoramount
messagemodulestaking
messageactioncreate_validator
messagesender

MsgDelegate

TypeAttribute KeyAttribute Value
delegatevalidator
delegateamount
messagemodulestaking
messageactiondelegate
messagesender

EndBlocker

TypeAttribute KeyAttribute Value
complete_unbondingamount
complete_unbondingvalidator
complete_unbondingdelegator
complete_redelegationamount
complete_redelegationsource_validator
complete_redelegationdestination_validator

Code Examples

Create Validator

// Create validator
valAddr := sdk.ValAddress(operatorAddr)
pubKey := ed25519.GenPrivKey().PubKey()

commission := stakingtypes.NewCommissionRates(
    sdk.NewDecWithPrec(10, 2), // 10% rate
    sdk.NewDecWithPrec(20, 2), // 20% max rate  
    sdk.NewDecWithPrec(1, 2),  // 1% max change
)

description := stakingtypes.Description{
    Moniker:  "My Validator",
    Identity: "keybase-id",
    Website:  "https://example.com",
    Details:  "Validator details",
}

msg := stakingtypes.NewMsgCreateValidator(
    valAddr,
    pubKey,
    sdk.NewCoin("stake", sdk.NewInt(1000000)),
    description,
    commission,
    sdk.OneInt(),
)

Delegate Tokens

// Delegate to validator
delAddr := sdk.AccAddress([]byte("delegator"))
valAddr := sdk.ValAddress([]byte("validator"))
amount := sdk.NewCoin("stake", sdk.NewInt(100000))

msg := stakingtypes.NewMsgDelegate(delAddr, valAddr, amount)

Query Delegation

// Get delegation
del, found := stakingKeeper.GetDelegation(ctx, delAddr, valAddr)
if !found {
    return fmt.Errorf("delegation not found")
}

// Get delegation tokens
val := stakingKeeper.Validator(ctx, valAddr)
tokens := val.TokensFromShares(del.Shares)
fmt.Printf("Delegated tokens: %s\n", tokens)

Unbond Delegation

// Unbond from validator
amount := sdk.NewCoin("stake", sdk.NewInt(50000))
msg := stakingtypes.NewMsgUndelegate(delAddr, valAddr, amount)

// Process unbonding
completionTime, err := stakingKeeper.Undelegate(ctx, delAddr, valAddr, shares)
if err != nil {
    return err
}

fmt.Printf("Unbonding completes at: %s\n", completionTime)

Redelegate

// Redelegate to new validator
srcValAddr := sdk.ValAddress([]byte("source"))
dstValAddr := sdk.ValAddress([]byte("destination"))
amount := sdk.NewCoin("stake", sdk.NewInt(50000))

msg := stakingtypes.NewMsgBeginRedelegate(
    delAddr,
    srcValAddr,
    dstValAddr,
    amount,
)

Hooks

The staking module provides hooks for other modules:
type StakingHooks interface {
    AfterValidatorCreated(ctx context.Context, valAddr sdk.ValAddress) error
    BeforeValidatorModified(ctx context.Context, valAddr sdk.ValAddress) error
    AfterValidatorRemoved(ctx context.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) error
    AfterValidatorBonded(ctx context.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) error
    AfterValidatorBeginUnbonding(ctx context.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) error
    BeforeDelegationCreated(ctx context.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error
    BeforeDelegationSharesModified(ctx context.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error
    BeforeDelegationRemoved(ctx context.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error
    AfterDelegationModified(ctx context.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error
    BeforeValidatorSlashed(ctx context.Context, valAddr sdk.ValAddress, fraction sdk.Dec) error
    AfterUnbondingInitiated(ctx context.Context, id uint64) error
}

CLI Commands Reference

CommandDescription
simd query staking validator [addr]Query validator
simd query staking validatorsQuery all validators
simd query staking delegation [del] [val]Query delegation
simd query staking delegations [delegator]Query delegations
simd query staking unbonding-delegation [del] [val]Query unbonding
simd query staking poolQuery staking pool
simd query staking paramsQuery parameters
simd tx staking create-validatorCreate validator
simd tx staking edit-validatorEdit validator
simd tx staking delegate [val] [amount]Delegate tokens
simd tx staking unbond [val] [amount]Unbond delegation
simd tx staking redelegate [src] [dst] [amount]Redelegate tokens

Integration Guide

// Initialize staking keeper
app.StakingKeeper = stakingkeeper.NewKeeper(
    appCodec,
    runtime.NewKVStoreService(keys[stakingtypes.StoreKey]),
    app.AccountKeeper,
    app.BankKeeper,
    authtypes.NewModuleAddress(govtypes.ModuleName).String(),
    authcodec.NewBech32Codec(sdk.Bech32PrefixValAddr),
    authcodec.NewBech32Codec(sdk.Bech32PrefixConsAddr),
)

// Register module
app.ModuleManager = module.NewManager(
    staking.NewAppModule(appCodec, &app.StakingKeeper, app.AccountKeeper, app.BankKeeper),
    // other modules...
)

// Set hooks
app.StakingKeeper.SetHooks(
    stakingtypes.NewMultiStakingHooks(
        app.DistrKeeper.Hooks(),
        app.SlashingKeeper.Hooks(),
    ),
)

Build docs developers (and LLMs) love