State Transitions
The Alliance module uses an EndBlocker which performs the following tasks at the end of every block.
- Complete redelegations by reading from the redelegations queue.
- Complete undelegations by reading from the undelegations queue.
- Redistribute rewards based on the block time.
- Rebalance the bonded tokens if an
AssetRebalanceQueueKey
event has been produced.
For more details on the EndBlocker, please refer to the x/alliance
module code on @terra-money/alliance.
Delegate​
When a delegation occurs the Alliance coin, validator, and delegation objects are affected.
The basic delegation sequence is as follows.
- Check to see if the Alliance asset exists.
- If the Alliance exists, send the delegated coins to the Alliance module.
- Claim existing delegation rewards.
- Create or update the delegation.
- Update the validator shares,
- Queue the rebalance assets event.
Because the delegating sequence does not require rewards to be claimed, it is not called directly by the EndBlocker
. Instead, delegations are set in the rebalance queue, which is then called by the EndBlocker
. For more details on delegation, visit the Delegate function from delegation.go. For more information on rebalancing, visit the concepts section.
Redelegate​
Redelegations affect the delegation, the source validator, and the destination validator.
The basic redelegation sequence is as follows.
- Check if the asset exists.
- Check if the delegation exists.
- Claim the delegation rewards from the source validator and query the delegation to get the updated values.
- Claim the delegation rewards from the destination validator and query the delegation again to get the updated values.
- Calculate how many delegation shares are to be redelegated.
- Iterate over re-delegations to prevent transitive re-delegations.
- Remove the redelegated coins and shares from the source validator.
- Add the coins and shares to the destination validator.
- Queue the redelegations to be executed based on the unbonding time.
- Queue the rebalance assets event.
For more details on redelegation, visit the Redelegate function from delegation.go. For more information on rebalancing, visit the concepts section.
Undelegate​
Undelegations affect the validator and the delegations pool.
The basic sequence is as follows.
- Check if the Alliance exists.
- Check if the account has delegations.
- Claim delegation rewards.
- Calculate how many shares need to be subtracted from the validator.
- Reduce the validator’s delegation shares.
- Queue the undelegation to be executed based on the unbonding time.
- Queue the rebalance assets event.
For more details on undelegating, visit the Undelegate function from delegation.go. For more information on rebalancing, visit the concepts section.
Queues​
The Alliance module has three queues that are checked at the end of every block, along with the reward weight decay:
- Redelegation: Iterate over the queue and delete all completed redelegations to enable the user redelegation again.
- Undelegation: Iterate over the queue and send coins from the Alliance module to the delegator’s account if the unbonding time has been completed,
- Rebalance: Works like a semaphore that is checked at the end of each block. If the value is true, it rebalances the assets from the different Alliance pools. This semaphore is enabled when a user Delegates, Undelegates, or Redelegates, or when one of the following
StakingHooks
are triggered:AfterValidatorRemoved
AfterValidatorBonded
AfterValidatorBeginUnbonding
AfterDelegationModified
BeforeValidatorSlashed
- Reward Weight Decay: Iterate all mature events and update the reward weight for the Alliance asset.
Rebalancing​
Reward power is rebalanced at the end of a block whenever the block contains an event that triggers a reward power change.
The events that trigger rebalancing are:
- Native coin delegations and undelegations.
- The slashing of a validator.
- Alliance coin delegations, redelegations, and undelegations.
For more information on rebalancing, visit the concepts section.
Because redelegating a native coin does not change the supply of the native coin, and because the reward power of native coins is always equal to the staked amount, the redelegation of native assets does not trigger a rebalance of reward power.
Whenever a rebalancing is requested, the following happens:
-
If it is the end of the block:
-
Consume the rebalancing request so that rebalancing does not stay queued.
-
Query the amount of native coins that are bonded.
-
Query the amount of native coins staked by the
x/alliance
module. -
Query the list of all validators with staked Alliance assets.
-
Filter for validators that are bonded
-
For each bonded validator:
- Query the current amount of native coins that the
x/alliance
module staked with the validator. These coins represent the reward power of staked Alliance coins.
- Query the current amount of native coins that the
-
For each Alliance asset:
- Calculate the expected native coins (reward power) that the validator should have based on the asset's reward weight and the amount of the asset. This amount should be the rebalanced reward power, as it takes into account the changes made during the block.
- Take the difference between the expected amount and the current amount of native coins staked. This is the amount that needs to be rebalanced.
-
If the expected amount is more than the current amount:
- Unbond the difference from the validator.
- Burn all leftover native coins that exist on the
x/alliance
module account.
-
If the expected amount is less than the current amount:
- Mint and delegate more native coins to the validator.
Reward Calculation and Distribution​
Rewards Pool​
A new module account is introduced to store all rewards that have not been claimed by a delegator. When adding rewards to the pool for a given validator, the validator’s global RewardHistories
data structure will be updated.
For more general information on rewards, visit the rewards section.
Reward Histories​
The RewardHistories
data structure is used to track the amount of rewards eligible for delegations and the amount of rewards claimed by delegators without having to iterate through all delegations every block. RewardHistories
track the rewards that a unit of reward power is eligible for.
Reward Histories Snapshot​
Whenever the reward weights of Alliance assets are updated, a snapshot of the current reward history is taken. This snapshot is used to provide historical data to calculate the rewards due before and after the reward weight update. When calculating rewards, the snapshots are iterated to accumulate rewards. The entire logic for this process is documented in the Claiming Delegation Rewards section.
Adding Assets to the Rewards Pool​
When assets are requested to be added to the rewards pool, the following sequence occurs:
- Get the current asset weight of all delegations in the
x/alliance
module.- This is calculated by multiplying the asset amounts by the sum of their reward weights.
- Query the latest
RewardHistories
for a validator. - For each asset added to the pool:
- Update the
RewardHistories
to account for the newly added assets.
- Update the
- Move the tokens from the source account into the
RewardsPool
module account.
Claiming Delegation Rewards​
When delegators claim rewards, the following sequence occurs:
- Initialize a
totalRewards
variable set to zero. - Query all the relevant snapshots for the given validator.
- For each snapshot iterated by ascending blockheight:
- Compare the delegator’s
RewardHistories
with the snapshot’s records to determine how many rewards to claim. - Accumulate the amount into totalRewards.
- Compare the delegator’s
- Query the latest
RewardHistories
and compare the delegator’s values to determine how many rewards to claim. - The delegator’s
RewardHistories
is then updated to match the global value to signify that the latest rewards have been claimed. - Return totalRewards as the amount that a delegator can claim.
For more information about rewards, visit the rewards section.
Take Rate Deduction​
The TakeRate
is deducted at an interval defined in the module parameters as Params.RewardClaimInterval
. The previous time this deduction was executed is saved in Params.LastRewardClaimTime
. At the end of every block, the Alliance module will check to see if the current block time minus the LastRewardClaimTime
is greater than the RewardsClaimInterval
.
If true, it will apply the TakeRate
to the assets and send the deducted tokens to the fee collector module account to be redistributed among stakers. For more information about the TakeRate
, visit the rewards section.
Slashing​
Slashing is based on the BeforeValidatorSlashed
hook from the Cosmos SDK’s StakingHooks. When the hook is executed, the Alliance module will subtract a proportional amount of shares of each delegator from the slashed validators. Undelegations and redelegations are affected by the slashing event if they are not completed before the block time of the slashing event. After the slashing is completed, an asset rebalance event is queued. For more information on slashing and shares, visit the Delegations and Validator Shares page.
Alliance coins slashed from validators are redistributed among the rest of the validators. For more on validator shares, visit the Delegations and validator shares section