Skip to content

Staking

This guide provides an overview of the key operations of staking, including creating validators, editing validator information, and performing delegation operations. For the general introduction of staking, please refer to Staking Mechanism.

Contract

The BSC staking mainly uses the smart contracts StakeHub for validator management and delegation management.

  • StakeHub: Manages validator creations, user delegations, and executs penalty for validator slash. (Address: 0x0000000000000000000000000000000000002002)

Creating a Validator

To create a validator, use the createValidator function with the following parameters:

  function createValidator(
    address consensusAddress,
    bytes calldata voteAddress,
    bytes calldata blsProof,
    Commission calldata commission,
    Description calldata description
) external payable
  • consensusAddress: The consensus address of the validator.
  • voteAddress: The vote address of the validator.
  • blsProof: The BLS signature as proof of the vote address.
  • commission: The commission structure, including rate, maxRate, and maxChangeRate.
  • description: The description of the validator, including moniker, identity, website, and details.

Note: Creating a validator requires locking 1 BNB, and the transaction must be sent with a sufficient BNB amount to cover this lock amount plus any self-delegation, in total 2001BNB.

Editing Validator Information

Edit Consensus Address

To change the consensus address of a validator, use the editConsensusAddress function with the following paramters:

function editConsensusAddress(address newConsensusAddress) external
  • newConsensusAddress: The new consensus address of the validator.

Edit Commission Rate

To update the commission rate of a validator, use the editCommissionRate function with the following paramters:

function editCommissionRate(uint64 newCommissionRate) external
  • newCommissionRate: The new commission structure, including rate, maxRate, and maxChangeRate.

Edit Description

To update the description of a validator, use the editDescription function with the following parameters:

function editDescription(Description memory newDescription) external
  • newDescription: The new description of the validator, including moniker, identity, website, and details.

Edit Vote Address

To change the vote address of a validator, use the editVoteAddress function with the following parameters:

function editVoteAddress(bytes calldata newVoteAddress, bytes calldata blsProof) external
  • newVoteAddress: The new vote address of the validator.
  • blsProof: The BLS signature as proof of the vote address.

Delegation Operations

Delegate

To delegate BNB to a validator, call the delegate function with the following parameters:

function delegate(address operatorAddress, bool delegateVotePower) external payable
  • operatorAddress: The operator address of the validator.
  • delegateVotePower: The flag to indicate whether the delegator would like to delegate his/her voting power to the validator for governance.

Undelegate

To undelegate BNB from a validator, use the undelegate function with the following parameters:

function undelegate(address operatorAddress, uint256 shares) external
  • operatorAddress: The operator address of the validator.
  • shares: The amount of shares to undelegate from the validator.

Redelegate

To redelegate BNB from one validator to another, use the redelegate function with the following parameters:

function redelegate(address srcValidator, address dstValidator, uint256 shares, bool delegateVotePower) external
  • srcValidator: The operator address of the source validator to redelegate from.
  • dstValidator: The operator address of the destination validator to redelegate to.
  • delegateVotePower: The flag to indicate whether the delegator would like to delegate his/her voting power to the destination validator for governance.

Claim

To claim undelegated BNB after the unbonding period, use the claim function for a single request or claimBatch for multiple requests:

function claim(address operatorAddress, uint256 requestNumber) external
  • operatorAddress: The operator address of the validator.
  • requestNumber: The number of unbonding requests to claim from. 0 means claiming from all unbonding requests.
function claimBatch(address[] calldata operatorAddresses, uint256[] calldata requestNumbers) external
  • operatorAddress: The operator addresses of the validatores.
  • requestNumber: The numbers of unbonding requests to claim from the validators.

FAQs

What are the functions/interfaces of each validator’s credit contract?

For each validator, there is a credit contract which will be automatically deployed when it is created. Meanwhile, the conctract cannot be upgraded or changed by any validator operator.

The credit contract is a BEP20 contract, and the ABI is the same as Stake Credit contract.

It provides functions for querying delegations, including:

  • balanceOf(address): Get the credit balance of a delegator.
  • getPooledBNB(address): Get the pooled BNB amount of a delegator.
  • getPooledBNBByShares(uint256): Get the pooled BNB amount for a specific amount of shares.
  • getSharesByPooledBNB(uint256): Get the shares for a specific amount of pooled BNB.
  • pendingUnbondingRequests(address): Get the count of unbonding requests for a delegator.
  • unbondRequest(address, uint256): Get the details of a unbond request for a delegator.
  • claimableUnbondRequest(address): Get the count of claimable unbonding requests for a delegator.
  • lockedBNBs(address, uint256): Get the locked BNBs for a delegator’s unbond queue.

How to get the shares/BNB amount for a delegator?

For any specific validator, please call the balanceOf function of the validator’s creat contract to get the delegator’s shares. To get the BNB amount instead of shares, the function getPooledBNB can be used.

To get the shares of all validators, please call the balanceOf function for each valiator and sum up the results. Please refer to the following to see how to get the information of all validators, and use a muticall contract to improve the efficiency.

How to calculte the BNB amount for a specific amount of shares?

The credit contract provides the getPooledBNBByShares function to calculate the BNB amount for some specific amount of shares.

To do the vice visa, please use the getSharesByPooledBNB function to calculate the shares for some specific BNB amount.

How to calculate the APR/APY of a validator?

Please be noted that each validator will have its own APR/APY, and the staking system will auto compound the rewards.

The reward is distributed to each validator’s BNB pool at 00:00:00 UTC time every day. To calculate the APR/APY of a validator, the total pooled BNB amount and the corresponding reward amount for the same day are needed.

The StakeHub contract provides the getValidatorTotalPooledBNBRecord(address,uint256)(uint256) and getValidatorRewardRecord(address,uint256)(uint256) for the purpose.

The following codes show how to calculate the APY at a given day:

// example code, do not use it in production

// stakehub is the instance of StakeHub contract
stakeHub, _ := contracts.NewStakeHub(ethcommon.HexToAddress("0x0000000000000000000000000000000000002002"), client.GetEthClient())

// get how many blocks are in a day
interval, _ := stakeHub.BREATHEBLOCKINTERVAL(nil)

// get the block time of a given block
header, _ := p.client.GetBlockHeader(blockHeight)

// calculate the index paramter to call the following functions
index := int64(header.Time) / interval.Int64()

// get the total pooled BNB amount and the corresponding reward amount for the given validator and index
totalPooledBNB, _ := stakeHub.GetValidatorTotalPooledBNBRecord(nil, validatorOperatorAddress, index)
reward, _ := stakeHub.GetValidatorRewardRecord(nil, validatorOperatorAddress, index)

// calculate the APY
rate, _ := big.NewFloat(0).Quo(big.NewFloat(0).SetInt(reward), big.NewFloat(0).SetInt(totalPooledBNB)).Float64()
apy := math.Pow(1+rate, 365) - 1.0

How to get the unbonding delegations of a delegator, and his/her unbonding requests which can be claimed?

The credit contract provides the pendingUnbondRequest function to get the unbonding delegation count for a delegator. To review the details of a unbond request, please call the unbondRequest function with a index parameter to define which unbond request will be returned.

To get the claimable unbonding requests, please call the claimableUnbondRequest function to get the count of claimable ones.

To get the locked BNBs for unbonding requests, please use the lockedBNBs function. It has the parameter number to define the sum of first number unbonding requests’ BNB locked in the delegator’s unbond queue. Set the number to 0 to get all the locked BNBs.

How to get the reward of a delegator?

The contracts does not save the initial delegation amount of a delegator. To get the accumulated reward, the following steps can be taken: 1) track the initial delegation amount in your system, 2) call the getPooledBNB of the credit contract of a validator, 3) do the math.

How to get the total staking address of a validator?

The contract does not provide a function to get the total staking address of a validator. It needs a offchain service to index Delegated, Redelegated, Undelegated events for the purpose. For example, you can consider building an indexer to crawl Delegated, Redelegated, Undelegated events on stakeHub contract first. Then sort the events according to your requirements.

How to get all validators’ information?

The StakeHub contract provides the getValidators function to get all validators’ information, including the operator addresses and credit contract addresses.

To get more information of a specific validator, please refer to the following functions:

  • getValidatorConsensusAddress
  • getValidatorCreditContract
  • getValidatorVoteAddress
  • getValidatorBasicInfo
  • getValidatorDescription
  • getValidatorCommission

Contract ABI

For the full interfaces of StakeHub, please refer to the ABI file.