- BEP-153: Introduce Native Staking on BSC
This BEP introduces a native staking protocol onto BNB Smart Chain. With this BEP, individual or institution delegators can stake BNB to specified validators and get staking rewards on the BSC side directly.
This BEP introduces a new staking system contract on the BSC side, all staking-related operations on the BSC side should be initiated through this contract, and then applied across-chain to BNB Beacon Chain through the native cross-chain communication mechanism. The cross-chain staking APP on the BNB Beacon Chain side reuses the previous staking mechanism to handle these staking-related operations.
The goals of this BEP is:
- For decentralized applications (dApps), they can launch their own staking services on the BSC side base on this protocol;
- For individuals, they can either directly stake their BNB through the staking system contract , or stake through the staking services provided by dApps on the BSC side.
This BEP is already implemented.
Before this BEP, the BNB holders can only stake their assets on the BNB Beacon Chain. It means that if their assets are on the BNB Smart Chain, they have to transfer their assets across-chain to the BNB Beacon Chain first, which is not user-friendly enough.
With this BEP, the BNB holders can stake on the BSC directly, and dApps can launch their staking service based on the protocol introduced by this BEP, which can diversify the BSC ecosystem.
There are mainly four components:
- Staking System Contract: A newly designed system contract in charge of handling staking requests on BSC.
- Cross-Chain Communication: Existing cross-chain infrastructures including cross chain contract, relayer and oracle module on BC.
- Cross-Chain Staking APP: A newly designed app on BC in charge of handling cross-chain staking requests.
- Staking Module on BC: Existing infrastructure in charge of BC’s staking delegation.
This is a new system contract deployed on BSC. It fulfills all the basic functionalities of staking service including delegation, undelegation, claiming reward and redelegation. It receives requests, encapsulates data and sends cross-chain packages. Specifically, the cross-chain package is normalized as a Cross-Chain Stake Event as below.
The Cross-chain stake event will be emitted once a cross-chain stake transaction happens on BSC. It is mainly composed of channel ID, sequence ID and payload data.
The payload data is a sequence of RLP encoded bytes of {eventType, params}.
-
eventType: uint8, will determine the corresponding handler that handles staking requests, and also determine how to decode the data. It includes the following types.
Among them,
distribute reward
anddistribute undelegated
events will be emitted initially on BC.
Code | 0x01 | 0x02 | 0x03 | 0x04 | 0x05 |
---|---|---|---|---|---|
Event | Delegate | Undelegate | Redelegate | Distribute reward | Distribute undelegated |
- params: different requests have different parameters including but not limited to delegator address, staking amount, validator operator address and so on.
To keep track of delegators staking funds, we adopt multiple mappings to record data.
mapping(address => uint256) delegated
mapping(address => mapping(address => uint256)) delegatedOfValidator
mapping(address => uint256) distributedReward
mapping(address => mapping(address => uint256)) pendingUndelegateTime
mapping(address => uint256) undelegated
mapping(address => mapping(address => mapping(address => uint256))) pendingRedelegateTime
delegated
records every delegator’s total staked amount. When a delegator submits undelegation, his/her delegated amount will decrease and after undelegation finishes, the undelegated increase the same number.
delegatedOfValidator
records every delegator’s staked amount to a specific validator.
distributedReward
records every delegator’s reward that is already distributed to BSC.
pendingUndelegateTime
and pendingRedelegateTime
records the estimated finish time of undelegation/redelegation. A new operation must wait until the previous operation is closed(until the time is up or receive an ack/failack package). Please be noted that this record will not always be accurate. The previous operation may end early.
undelegated
records every delegator’s unlocked undelegate funds that is already distributed to BSC.
-
delegate(address validator, uint256 amount) payable
This method will handle the cross-chain delegating requests. Here, the
validator
represents the BC operator address of the validator to be delegated to. Cross-chain relayer fee should be included in the msg.value. The following graph represents the workflow of delegation on BSC:
-
undelegate(address validator, uint256 amount) payable
This method will handle the cross-chain undelegating requests. The staked BNBs on BC will be unlocked after 7 days and transferred to the staking contract on BSC automatically. Delegators could claim undelegated BNBs by
claimUndelegated
(see below). Thevalidator
represents the BC operator address of the validator delegated to. Cross-chain relayer fee should be included in the msg.value. -
redelegate(address validatorSrc, address validatorDst, uint256 amount) payable
Undelegate amount BNBs from
validatorSrc
and delegate tovalidatorDst
. -
claimReward() returns(uint256 amount)
Delegators can claim their distributed reward by this method. The returned amount is the number of funds that
msg.sender
received. -
claimUndelegated() returns(uint256 amount)
Delegators can claim their undelegated funds by this method. The returned amount is the number of funds that
msg.sender
received. -
getDelegated(address delegator, address validator) external view returns(uint256 amount)
This function allows the delegator to query how much he/she has delegated to the specific validator.
-
getTotalDelegated(address delegator) external view returns(uint256 amount)
This function allows the delegator to query how much he/she has delegated in all.
-
getDistributedReward(address delegator) external view returns(uint256 amount)
This function allows the delegator to view the amount of the distributed rewards.
-
getPendingRedelegateTime(address delegator, address valSrc, address valDst) external view returns(uint256 amount)
This function allows the delegator to view the estimated finish time of redelegation from
valSrc
tovalDst
. -
getPendingUndelegateTime(address delegator, address validator) external view returns(uint256 amount)
This function allows the delegator to view the estimated finish time of undelegation from
validator
. -
getUndelegated(address delegator) external view returns(uint256 amount)
This function allows the delegator to view the amount of the undelegated funds.
This is a new cross-chain app on BC side. It will be called by the BC’s bridge once it receives cross-chain staking packages. The main function of this app is to parse the data and do the staking related tasks.
The native staking mechanism on the BC will stay almost the same as before. The only change is that the delegation will be tagged as native or none-native(cross-chain). The Cross-Chain Staking app will decode the cross-chain package depending on the event type code and call corresponding functions.
The delegator’s corresponding address on the BC will be the XOR result between a map hash of a specific constant string and its BSC address. So no one could control it except for the cross-chain app.
- The delegate CAoB is calculated by sha256("Staking Delegate Address Anchor") ^ BSC Address. This address is the counterpart of normal delegation’s delegator address. It’s used to hold the delegator’s staking funds.
- The reward CAoB is calculated by sha256("Staking Reward Address Anchor") ^ delegate CAoB. This address is used to hold the delegator’s reward. For convenience we add this extra address comparing to normal delegation.
The delegation reward will be released at each breath block to the reward CAoB, once the balance of the reward CAoB is larger than a threshold. The reward will be cross-chain transferred to the staking system contract on the BSC side automatically. Please note that a proper cross chain relay fee will be charged so that the received reward on BSC will be slightly different.
When undelegation finishes, the undelegated funds will be released to the stake CAoB address, and the funds of the stake CAoB will be cross-chain transferred to the staking system contract on the BSC side automatically in the next breath block. Please note that a proper cross chain relay fee will be charged so that the received undelegated BNB on BSC will be slightly different.
The fees charged for the relevant transactions are based on the following principles:
- For normal cross-chain communication, the gas and relayer fee shall be paid by the msg sender at once;
- For the failed transactions, there may be extra gas and relayer fee as extra cross-chain communication is needed. This part will be covered by the system reward contract.
- For reward and undelegated distribution, the relayer fee will be deducted from users' funds.
This BEP will reuse the existing cross-chain infrastructure as much as possible. This includes and is not limited to the separation of application and communication protocol layers, uniform error handling principle and cross-chain application coding principle. As the new system contract BSC and new app on BC are all parts of the application layer, the error handling of the communication layer will remain the same as before.
Normal errors means anticipated errors. For transactions that cross-chain communication is involved, all normal errors will be relayed back. So no errors will be missed. For this type of errors, we recommend that developers should check the returned reason for failure, modify the parameters and retry the transaction. All anticipated errors and success scenarios are listed below.
Function | Error | BSC result | BC result | Feedback |
---|---|---|---|---|
Delegate | Any errors happened on BSC | Transaction reverted | N/A | Error message |
Delegate | Validator jailed/not exist | Success | AckPackage | Event with error message emitted |
Delegate | N/A (Success) | Success | N/A | N/A |
Undelegate | Any errors happened on BSC | Transaction reverted | N/A | Error message |
Undelegate | Amount greater than delegated shares/Validator not found/No delegation to the validator/Undelegate amount is too small | Success | AckPackage | Event with error message emitted |
Undelegate | N/A (Success) | Success | N/A | N/A |
Redelegate | Any errors happened on BSC | Transaction reverted | N/A | Error message |
Redelegate | Validator jailed/not exist | Success | AckPackage | Event with error message emitted |
Redelegate | N/A (Success) | Success | N/A | N/A |
Therefore, if any errors happen on BSC, the transaction will be reverted and the msg sender will know it at once. But if an error happens on BC, the msg sender will not get feedback immediately. So we recommend dApp developers run some robots to monitor related events to get informed.
The communication layer will catch the crash error of the application, record it in store or emit an event for debugging. The crash error will use the FAIL_ACK type of package if needed, and the payload of FAIL_ACK is the same as the payload of the SYNC package.
For contracts in BSC, the crash of Application will revert state change automatically, but for Application on BC we need to build another sandbox for it, only commit store after it did not crash.
When receiving the FAIL_ACK package, the communication layer will invoke a different method of Application, like handleFailAckPackage or ExecuteFailAckClaim. We will ensure the safety of users’ assets(see 5.5.4).
Communication layer only plays around with these inputs: Type, Sequence, ChannelId, RelayerFee. The simplicity of these inputs helps us build a robust system.
However, once an error happens, the communication of a channel may be blocked. We have to hard fork the chain when errors occur in the communication layer.
It is very important to protect the safety of actors’ funds. As funds need to be transferred across the chain, this BEP will reuse the cross-chain transfer design as before. The key points are that funds transferred from BSC to BC will be locked in the tokenHub system contract and funds transferred from BC to BSC will be locked in the pegAccount. Necessary mechanism is employed to ensure the cross-chain reconciliation.
When a delegation request fails, an extra cross-chain package will be sent back to BSC. The funds will be unlocked from the tokenhub system contract, transferred to the staking system contract and be recorded as a part of the delegator’s pending undelegated. The delegator can get his/her funds back by claimUndelegated later. However, if the msg sender is a contract without a receive/fallback method, the transfer will fail and the funds may be lost forever. So make sure your dApp implements the receive/fallback method.