# Staking

# Overview

The Staking contract hold and track the changes of all staked SQT Token, It provides entry for the indexers and delegators to stake/unstake, delegate/undelegate to available Indexers and withdraw their SQT Token. It also track the changes of the commission rate of each Indexer and make these changes always applied at two Eras later. We design this to allow time for the delegators to consider their delegation when an Indxer changes the commission rate.

# Terminology

stake -- Indexers must stake SQT Token to themself and not less than the minimumStakingAmount we set in IndexerRegistry contract delegate -- Delegators can delegate SQT Token to any indexer to share Indexer‘s Rewards. total staked amount -- indexer's stake amount + total delegate amount. The Indexer staked amount effects its max acceptable delegation amount. The total staked amount of an Indexer effects the maximum reward it can earn in an Era.

# Detail

Since The change of stake or delegate amount and commission rate affects the rewards distribution. So when users make these changes, we call onStakeChange()/onICRChnage() from rewardsStaking/rewardsPool contract to notify it to apply these changes for future distribution. In our design rewardsStaking contract apply the first stake change and commission rate change immediately when an Indexer make registration. Later on all the stake change apply at next Era, commission rate apply at two Eras later.

Since Indexers need to stake SQT Token at registration and the staked amount effects its max acceptable delegation amount. So the implementation of stake() is diffrernt with delegate().

  • stake() is for Indexers to stake on themself. There has no stake amount limitation.
  • delegate() is for delegators to delegate on an indexer and need to consider the indexer's delegation limitation.

Also in this contarct we has two entries to set commission rate for indexers. setInitialCommissionRate() is called by IndexrRegister contract when indexer register, this change need to take effect immediately. setCommissionRate() is called by Indexers to set their commission rate, and will be take effect after two Eras.

Since Indexer must keep the minimumStakingAmount, so the implementation of unstake() also different with undelegate().

  • unstake() is for Indexers to unstake their staking token. An indexer can not unstake all the token unless the indexer unregister from the network. Indexer need to keep the minimumStakingAmount staked on itself when it unstake.
  • undelegate() is for delegator to undelegate from an Indexer can be called by Delegators. Delegators can undelegate all their delegated tokens at one time. Tokens will transfer to user's account after the lockPeriod when users apply withdraw. Every widthdraw will cost a fix rate fees(unbondFeeRate), and these fees will be burned.

# settings

contract ISettings settings

# indexerLeverageLimit

The ratio of total stake amount to indexer self stake amount to limit the total delegation amount. Initial value is set to 10, which means the total stake amount cannot exceed 10 times the indexer self stake amount.

uint256 indexerLeverageLimit

# unbondFeeRate

uint256 unbondFeeRate

# lockPeriod

uint256 lockPeriod

# indexerLength

uint256 indexerLength

# maxUnbondingRequest

uint256 maxUnbondingRequest

# indexers

mapping(uint256 => address) indexers

# indexerNo

mapping(address => uint256) indexerNo

# totalStakingAmount

mapping(address => struct StakingAmount) totalStakingAmount

# unbondingAmount

mapping(address => mapping(uint256 => struct UnbondAmount)) unbondingAmount

# unbondingLength

mapping(address => uint256) unbondingLength

# withdrawnLength

mapping(address => uint256) withdrawnLength

# delegation

mapping(address => mapping(address => struct StakingAmount)) delegation

# lockedAmount

mapping(address => uint256) lockedAmount

# stakingIndexers

mapping(address => mapping(uint256 => address)) stakingIndexers

# stakingIndexerNos

mapping(address => mapping(address => uint256)) stakingIndexerNos

# stakingIndexerLengths

mapping(address => uint256) stakingIndexerLengths

Emitted when stake to an Indexer.

# DelegationAdded

event DelegationAdded(address source, address indexer, uint256 amount)

Emitted when unstake to an Indexer.

# DelegationRemoved

event DelegationRemoved(address source, address indexer, uint256 amount)

Emitted when request unbond.

# UnbondRequested

event UnbondRequested(address source, address indexer, uint256 amount, uint256 index, enum UnbondType _type)

Emitted when request withdraw.

# UnbondWithdrawn

event UnbondWithdrawn(address source, uint256 amount, uint256 fee, uint256 index)

Emitted when delegtor cancel unbond request.

# UnbondCancelled

event UnbondCancelled(address source, address indexer, uint256 amount, uint256 index)

# onlyStakingManager

modifier onlyStakingManager()

Initialize this contract.

# initialize

function initialize(contract ISettings _settings, uint256 _lockPeriod, uint256 _unbondFeeRate) external

# setSettings

function setSettings(contract ISettings _settings) external

# setLockPeriod

function setLockPeriod(uint256 _lockPeriod) external

# setIndexerLeverageLimit

function setIndexerLeverageLimit(uint256 _indexerLeverageLimit) external

# setUnbondFeeRateBP

function setUnbondFeeRateBP(uint256 _unbondFeeRate) external

# setMaxUnbondingRequest

function setMaxUnbondingRequest(uint256 maxNum) external

when Era update if valueAfter is the effective value, swap it to valueAt, so later on we can update valueAfter without change current value require it idempotent.

# reflectEraUpdate

function reflectEraUpdate(address _source, address _indexer) public

# _reflectStakingAmount

function _reflectStakingAmount(uint256 eraNumber, struct StakingAmount stakeAmount) private

# checkDelegateLimitation

function checkDelegateLimitation(address _indexer, uint256 _amount) external view

# addIndexer

function addIndexer(address _indexer) external

# removeIndexer

function removeIndexer(address _indexer) external

# removeUnbondingAmount

function removeUnbondingAmount(address _source, uint256 _unbondReqId) external

# addDelegation

function addDelegation(address _source, address _indexer, uint256 _amount) external

# delegateToIndexer

function delegateToIndexer(address _source, address _indexer, uint256 _amount) external

# removeDelegation

function removeDelegation(address _source, address _indexer, uint256 _amount) external

When the delegation change nodify rewardsStaking to deal with the change.

# _onDelegationChange

function _onDelegationChange(address _source, address _indexer) internal

# startUnbond

function startUnbond(address _source, address _indexer, uint256 _amount, enum UnbondType _type) external

Withdraw a single request. burn the withdrawn fees and transfer the rest to delegator.

# withdrawARequest

function withdrawARequest(address _source, uint256 _index) external

# slashIndexer

function slashIndexer(address _indexer, uint256 _amount) external

# unbondCommission

function unbondCommission(address _indexer, uint256 _amount) external

# isEmptyDelegation

function isEmptyDelegation(address _source, address _indexer) external view returns (bool)