Skip to main content

Stake with Code

This guide will show you how to stake ZCX by directly interacting with ZenChain's staking smart contracts.

Staking Smart Contracts

ZenChain supports staking through precompiled smart contracts. These precompiles expose the staking functionality as smart contracts that you can interact with, yet are more computationally efficient than a user-deployed smart contract.

Unless stated otherwise, the smart contract methods referenced in this document can be found in the NativeStaking precompile.

For more detail, see the section on Precompiled Smart Contracts.

ContractEthereum AddressSolidity Interface
NativeStaking0x0000000000000000000000000000000000000800GitHub
NativeFastUnstake0x0000000000000000000000000000000000000801GitHub

Stake

Staking involves two steps: bonding tokens and activating your stake.

Bond ZCX

To start staking, you first need to bond your tokens using one of two methods: bondWithRewardDestination or bondWithPayeeAddress. The choice of these two methods depends on where you want your rewards to go when they are claimed.

FunctionDescription
bondWithRewardDestination(value, dest)Stake tokens and set reward destination.
bondWithPayeeAddress(value, payee)Stake tokens and set a custom payee address for rewards.

The method bondWithRewardDestination requires you to supply a reward destination from the RewardDestination enum.

enum RewardDestination {
Staked,
Stash,
None
}

Let's say you want to stake 1,000 ZCX. You could do so with any of the following method calls.

  • To restake rewards for compounding gains: bondWithRewardDestination(1_000_000_000_000_000_000_000, 0)
  • To send rewards to your address: bondWithRewardDestination(1_000_000_000_000_000_000_000, 1)
  • To receive no rewards: bondWithRewardDestination(1_000_000_000_000_000_000_000, 2)
  • To send rewards to another account: bondWithPayeeAddress(1_000_000_000_000_000_000_000, 0x...)
info

To participate in consensus and earn rewards, you must bond a minimum amount of ZCX. Learn more about staking and the minimum amount of staked ZCX required for validators and nominators.

Activate Your Stake

Once you've bonded ZCX, you can declare your intention to participate in consensus, secure the blockchain, and earn rewards. To become a validator, you will call the validate method. To nominate validators, you will call the nominate method. You can only be either a nominator or a validator. You cannot do both simultaneously.

FunctionDescription
validate(commission, blocked)Declare intent to become a validator with specified commission and blocking status.
nominate(targets)As a nominator, select the validators you want to back.

The validate method takes two parameters. The commission parameter represented as parts per billion. The value can range from 0 to 1_000_000_000. For example, 10% is represented as 100_000_000 (0.1 * 10^9). The blocked parameter, if set to true, allows the validator to prevent new nominations.

  • To validate with a 0% commission rate: validate(0, false)
  • To validate with a 15% commission rate: validate(150_000_000, false)
  • To validate with a 100% commission rate and block nominations: validate(1_000_000_000, true)

The nominate method takes an array of validator addresses corresponding to the validators the caller wants to nominate. A nominator can select up to 16 targets. Each call to nominate will overwrite the values in the previous call, so you can update your nominations by calling nominate again with the full set of validators you want to support.

  • To nominate two validators: nominate(["0x46A148316EBA94539642f3fD6908dcAB10994D1A", "0x10e4f95a5655b932A724eaDea4766eb6671d0cA5"])
info

You cannot nominate and validate at the same time.

Claim Rewards

As explained in Staking, rewards are stored in pages, with up to 64 nominators' rewards stored on each page. If a page is claimed, rewards are distributed for the validator and all the nominators on the page.

FunctionDescription
payoutStakersByPage(validatorStash, era, page)Trigger payout of rewards for a specific validator, era, and page of nominators.

Let's say I am nominating the two validators used in the example above, and I want to claim rewards from era 42.

  • To claim the first page from the first validator: payoutStakersByPage("0x46A148316EBA94539642f3fD6908dcAB10994D1A", 42, 0)
  • To claim the first page from the second validator: payoutStakersByPage("0x10e4f95a5655b932A724eaDea4766eb6671d0cA5", 42, 0)

Increase Your Stake

You can increase your stake amount by calling bondExtra with the additional amount of ZCX you want to stake.

FunctionDescription
bondExtra(value)Add more tokens to your existing stake.

For example, if you are staking 1,000 ZCX and you want to stake an additional 500 ZCX, you can submit a transaction calling bondExtra(500_000_000_000_000_000_000).

Change Stake Configuration

Users can change their stake configuration using several methods. Here we highlight three important methods: chill, setPayee, and setRewardDestination.

FunctionDescription
setPayee(payee)Set a custom address to receive rewards.
setRewardDestination(dest)Set the reward destination (Staked, Stash, or None).

If your staking rewards are being distributed to another account, you can use setPayee to change the account to which your staking rewards are distributed.

You can call setRewardDestination to either restake (compound) rewards or have rewards distributed to your own account.

Calling either setPayee or setRewardDestination will overwrite the previous reward distribution configuration.

Unstake

To stop validating or nominating and unbond your staked tokens using the regular unbonding method, you will need to call two functions: chill and unbond. The process is simpler for those eligible for fast unstaking.

Regular Unbonding

FunctionDescription
chill()Stop validating or nominating.
unbond(value)Schedule a portion of your staked tokens for unbonding.
rebond(value)Re-stake a portion of your unbonding tokens.

To unstake your ZCX, you must first call chill. The chill function will pause validating or nominating without unbonding ZCX. This is useful to prevent slashing for a short period of time while a node is down, or to otherwise represent a state in which your ZCX is not exposed but still bonded. You will not earn rewards while your account is "chilled".

You can call unbond immediately after chilling (or call both together in a batch transaction). A call to unbond will start the "bonding duration", which lasts for 2 eras. Your ZCX cannot be withdrawn until after the bonding duration is completed. The ZCX will not be exposed, so it will not earn rewards or be slashed during this time. When the bonding duration is completed, you will need to submit a separate transaction to withdraw the tokens to your account.

If you change your mind about unbonding, you can call rebond at any time after the call to unbond (and before withdrawing your funds) to rebond all or a portion of your unbonding ZCX. After calling rebond, your ZCX will stop unlocking and become bonded once again. You will still be in the "chilled" state, so you will need to follow up with a call to either validate or nominate to continue earning rewards.

Fast Unstake

FunctionDescription
registerFastUnstake()Initiate a fast unstake request.
deregister()Cancel a fast unstake request and return to regular unbonding.

If your ZCX has not been "exposed", meaning you are not actively nominating or validating, for 2 eras (the bonding duration), you can unstake significantly more quickly using the FastUnstake precompile. A single call to registerFastUnstake will chill your account, fully unbond your ZCX, and add your account to a queue. When you reach the head of the queue--usually within a few blocks--your fast unstake eligibility will be validated and your ZCX will be withdrawn to your account with no further action required from you.

Fast unstaking requires submitting a modest deposit of 1 Gwei ZCX. The deposit will be returned to you when your ZCX is successfully unstaked.

If you are not eligible for fast unstaking and you register anyway, your deposit will be lost when your account is validated in the fast unstake queue. Your ZCX will remain locked for the bonding duration.

If you registered for fast unstaking but you have changed your mind--e.g. you realized you are ineligible--you can call deregister in the FastUnstake precompile to cancel the fast unstake request. If successful, your ZCX will continue unbonding through the normal unbonding process unless you take further action.

Withdraw

After you unbond your ZCX and waited the full bonding duration, you can call withdrawUnbonded to fully withdraw your ZCX into your account.

FunctionDescription
withdrawUnbonded(numSlashingSpans)Withdraw your unbonded tokens after the unbonding period.
historyDepth()Get the number of eras stored in history.

The withdrawUnbonded method takes one argument, which you can reliably fill in with the value returned by a call to the historyDepth view function.

  • To withdraw all unlocked ZCX: withdrawUnbonded(84)