Merge PR #1944: Piggy-bank distribution spec
This commit is contained in:
commit
1039388207
|
@ -84,6 +84,7 @@ IMPROVEMENTS
|
||||||
* [x/stake] Improve speed of GetValidator, which was shown to be a performance bottleneck. [#2046](https://github.com/tendermint/tendermint/pull/2200)
|
* [x/stake] Improve speed of GetValidator, which was shown to be a performance bottleneck. [#2046](https://github.com/tendermint/tendermint/pull/2200)
|
||||||
* SDK
|
* SDK
|
||||||
* [tools] Make get_vendor_deps deletes `.vendor-new` directories, in case scratch files are present.
|
* [tools] Make get_vendor_deps deletes `.vendor-new` directories, in case scratch files are present.
|
||||||
|
* [spec] Added simple piggy bank distribution spec
|
||||||
* [cli] \#1632 Add integration tests to ensure `basecoind init && basecoind` start sequences run successfully for both `democoin` and `basecoin` examples.
|
* [cli] \#1632 Add integration tests to ensure `basecoind init && basecoind` start sequences run successfully for both `democoin` and `basecoin` examples.
|
||||||
* [store] Speedup IAVL iteration, and consequently everything that requires IAVL iteration. [#2143](https://github.com/cosmos/cosmos-sdk/issues/2143)
|
* [store] Speedup IAVL iteration, and consequently everything that requires IAVL iteration. [#2143](https://github.com/cosmos/cosmos-sdk/issues/2143)
|
||||||
* [simulation] Make timestamps randomized [#2153](https://github.com/cosmos/cosmos-sdk/pull/2153)
|
* [simulation] Make timestamps randomized [#2153](https://github.com/cosmos/cosmos-sdk/pull/2153)
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Please note that this folder is a WIP specification for an advanced fee distribution
|
||||||
|
mechanism which is not set to be implemented.
|
|
@ -0,0 +1,36 @@
|
||||||
|
# End Block
|
||||||
|
|
||||||
|
At each endblock, the fees received are sorted to the proposer, community fund,
|
||||||
|
and global pool. When the validator is the proposer of the round, that
|
||||||
|
validator (and their delegators) receives between 1% and 5% of fee rewards, the
|
||||||
|
reserve tax is then charged, then the remainder is distributed proportionally
|
||||||
|
by voting power to all bonded validators independent of whether they voted
|
||||||
|
(social distribution). Note the social distribution is applied to proposer
|
||||||
|
validator in addition to the proposer reward.
|
||||||
|
|
||||||
|
The amount of proposer reward is calculated from pre-commits Tendermint
|
||||||
|
messages in order to incentivize validators to wait and include additional
|
||||||
|
pre-commits in the block. All provision rewards are added to a provision reward
|
||||||
|
pool which validator holds individually
|
||||||
|
(`ValidatorDistribution.ProvisionsRewardPool`).
|
||||||
|
|
||||||
|
```
|
||||||
|
func SortFees(feesCollected sdk.Coins, global Global, proposer ValidatorDistribution,
|
||||||
|
sumPowerPrecommitValidators, totalBondedTokens, communityTax sdk.Dec)
|
||||||
|
|
||||||
|
feesCollectedDec = MakeDecCoins(feesCollected)
|
||||||
|
proposerReward = feesCollectedDec * (0.01 + 0.04
|
||||||
|
* sumPowerPrecommitValidators / totalBondedTokens)
|
||||||
|
proposer.ProposerPool += proposerReward
|
||||||
|
|
||||||
|
communityFunding = feesCollectedDec * communityTax
|
||||||
|
global.CommunityFund += communityFunding
|
||||||
|
|
||||||
|
poolReceived = feesCollectedDec - proposerReward - communityFunding
|
||||||
|
global.Pool += poolReceived
|
||||||
|
global.EverReceivedPool += poolReceived
|
||||||
|
global.LastReceivedPool = poolReceived
|
||||||
|
|
||||||
|
SetValidatorDistribution(proposer)
|
||||||
|
SetGlobal(global)
|
||||||
|
```
|
|
@ -0,0 +1,54 @@
|
||||||
|
# Distribution
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Collected fees are pooled globally and divided out passively to validators and
|
||||||
|
delegators. Each validator has the opportunity to charge commission to the
|
||||||
|
delegators on the fees collected on behalf of the delegators by the validators.
|
||||||
|
Fees are paid directly into a global fee pool, and validator proposer-reward
|
||||||
|
pool. Due to the nature of passive accounting whenever changes to parameters
|
||||||
|
which affect the rate of fee distribution occurs, withdrawal of fees must also
|
||||||
|
occur when:
|
||||||
|
|
||||||
|
- withdrawing one must withdrawal the maximum amount they are entitled
|
||||||
|
too, leaving nothing in the pool,
|
||||||
|
- bonding, unbonding, or re-delegating tokens to an existing account a
|
||||||
|
full withdrawal of the fees must occur (as the rules for lazy accounting
|
||||||
|
change),
|
||||||
|
- a validator chooses to change the commission on fees, all accumulated
|
||||||
|
commission fees must be simultaneously withdrawn.
|
||||||
|
|
||||||
|
The above scenarios are covered in `triggers.md`.
|
||||||
|
|
||||||
|
The distribution mechanism outlines herein is used to lazily distribute the
|
||||||
|
following between validators and associated delegators:
|
||||||
|
- multi-token fees to be socially distributed,
|
||||||
|
- proposer reward pool,
|
||||||
|
- inflated atom provisions, and
|
||||||
|
- validator commission on all rewards earned by their delegators stake
|
||||||
|
|
||||||
|
Fees are pooled within a global pool, as well as validator specific
|
||||||
|
proposer-reward pools. The mechanisms used allow for validators and delegators
|
||||||
|
to independently and lazily withdrawn their rewards. As a part of the lazy
|
||||||
|
computations adjustment factors must be maintained for each validator and
|
||||||
|
delegator to determine the true proportion of fees in each pool which they are
|
||||||
|
entitled too. Adjustment factors are updated every time a validator or
|
||||||
|
delegator's voting power changes. Validators and delegators must withdraw all
|
||||||
|
fees they are entitled too before they can change their portion of bonded
|
||||||
|
Atoms.
|
||||||
|
|
||||||
|
## Affect on Staking
|
||||||
|
|
||||||
|
|
||||||
|
Charging commission on Atom provisions while also allowing for Atom-provisions
|
||||||
|
to be auto-bonded (distributed directly to the validators bonded stake) is
|
||||||
|
problematic within DPoS. Fundamentally these two mechnisms are mutually
|
||||||
|
exclusive. If there are atoms commissions and auto-bonding Atoms, the portion
|
||||||
|
of Atoms the fee distribution calculation would become very large as the Atom
|
||||||
|
portion for each delegator would change each block making a withdrawal of fees
|
||||||
|
for a delegator require a calculation for every single block since the last
|
||||||
|
withdrawal. In conclusion we can only have atom commission and unbonded atoms
|
||||||
|
provisions, or bonded atom provisions with no Atom commission, and we elect to
|
||||||
|
implement the former. Stakeholders wishing to rebond their provisions may elect
|
||||||
|
to set up a script to periodically withdraw and rebond fees.
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
## State
|
||||||
|
|
||||||
|
### Global
|
||||||
|
|
||||||
|
All globally tracked parameters for distribution are stored within
|
||||||
|
`Global`. Rewards are collected and added to the reward pool and
|
||||||
|
distributed to validators/delegators from here.
|
||||||
|
|
||||||
|
Note that the reward pool holds decimal coins (`DecCoins`) to allow
|
||||||
|
for fractions of coins to be received from operations like inflation.
|
||||||
|
When coins are distributed from the pool they are truncated back to
|
||||||
|
`sdk.Coins` which are non-decimal.
|
||||||
|
|
||||||
|
- Global: `0x00 -> amino(global)`
|
||||||
|
|
||||||
|
```golang
|
||||||
|
// coins with decimal
|
||||||
|
type DecCoins []DecCoin
|
||||||
|
|
||||||
|
type DecCoin struct {
|
||||||
|
Amount sdk.Dec
|
||||||
|
Denom string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Global struct {
|
||||||
|
PrevBondedTokens sdk.Dec // bonded token amount for the global pool on the previous block
|
||||||
|
Adjustment sdk.Dec // global adjustment factor for lazy calculations
|
||||||
|
Pool DecCoins // funds for all validators which have yet to be withdrawn
|
||||||
|
PrevReceivedPool DecCoins // funds added to the pool on the previous block
|
||||||
|
EverReceivedPool DecCoins // total funds ever added to the pool
|
||||||
|
CommunityFund DecCoins // pool for community funds yet to be spent
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Validator Distribution
|
||||||
|
|
||||||
|
Validator distribution information for the relevant validator is updated each time:
|
||||||
|
1. delegation amount to a validator are updated,
|
||||||
|
2. a validator successfully proposes a block and receives a reward,
|
||||||
|
3. any delegator withdraws from a validator, or
|
||||||
|
4. the validator withdraws it's commission.
|
||||||
|
|
||||||
|
- ValidatorDistribution: `0x02 | ValOwnerAddr -> amino(validatorDistribution)`
|
||||||
|
|
||||||
|
```golang
|
||||||
|
type ValidatorDistribution struct {
|
||||||
|
CommissionWithdrawalHeight int64 // last time this validator withdrew commission
|
||||||
|
Adjustment sdk.Dec // global pool adjustment factor
|
||||||
|
ProposerAdjustment DecCoins // proposer pool adjustment factor
|
||||||
|
ProposerPool DecCoins // reward pool collected from being the proposer
|
||||||
|
EverReceivedProposerReward DecCoins // all rewards ever collected from being the proposer
|
||||||
|
PrevReceivedProposerReward DecCoins // previous rewards collected from being the proposer
|
||||||
|
PrevBondedTokens sdk.Dec // bonded token amount on the previous block
|
||||||
|
PrevDelegatorShares sdk.Dec // amount of delegator shares for the validator on the previous block
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Delegation Distribution
|
||||||
|
|
||||||
|
Each delegation holds multiple adjustment factors to specify its entitlement to
|
||||||
|
the rewards from a validator. `AdjustmentPool` is used to passively calculate
|
||||||
|
each bonds entitled fees from the `RewardPool`. `AdjustmentPool` is used to
|
||||||
|
passively calculate each bonds entitled fees from
|
||||||
|
`ValidatorDistribution.ProposerRewardPool`
|
||||||
|
|
||||||
|
- DelegatorDistribution: ` 0x02 | DelegatorAddr | ValOwnerAddr -> amino(delegatorDist)`
|
||||||
|
|
||||||
|
```golang
|
||||||
|
type DelegatorDist struct {
|
||||||
|
WithdrawalHeight int64 // last time this delegation withdrew rewards
|
||||||
|
Adjustment sdk.Dec // fee provisioning adjustment factor
|
||||||
|
AdjustmentProposer DecCoins // proposers pool adjustment factor
|
||||||
|
PrevTokens sdk.Dec // bonded tokens held by the delegation on the previous block
|
||||||
|
PrevShares sdk.Dec // delegator shares held by the delegation on the previous block
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Power Change
|
||||||
|
|
||||||
|
Every instance that the voting power changes, information about the state of
|
||||||
|
the validator set during the change must be recorded as a `PowerChange` for
|
||||||
|
other validators to run through. Each power change is indexed by its block
|
||||||
|
height.
|
||||||
|
|
||||||
|
- PowerChange: `0x03 | amino(Height) -> amino(validatorDist)`
|
||||||
|
|
||||||
|
```golang
|
||||||
|
type PowerChange struct {
|
||||||
|
Height int64 // block height at change
|
||||||
|
ValidatorBondedTokens sdk.Dec // following used to create distribution scenarios
|
||||||
|
ValidatorDelegatorShares sdk.Dec
|
||||||
|
ValidatorDelegatorShareExRate sdk.Dec
|
||||||
|
ValidatorCommission sdk.Dec
|
||||||
|
PoolBondedTokens sdk.Dec
|
||||||
|
Global Global
|
||||||
|
ValDistr ValidatorDistribution
|
||||||
|
DelegationShares sdk.Dec
|
||||||
|
DelDistr DelegatorDistribution
|
||||||
|
}
|
||||||
|
```
|
|
@ -0,0 +1,399 @@
|
||||||
|
# Transactions
|
||||||
|
|
||||||
|
## TxWithdrawDelegation
|
||||||
|
|
||||||
|
When a delegator wishes to withdraw their transaction fees it must send
|
||||||
|
`TxWithdrawDelegation`. Note that parts of this transaction logic are also
|
||||||
|
triggered each with any change in individual delegations, such as an unbond,
|
||||||
|
redelegation, or delegation of additional tokens to a specific validator.
|
||||||
|
|
||||||
|
Each time a withdrawal is made by a recipient the adjustment term must be
|
||||||
|
modified for each block with a change in distributors shares since the time of
|
||||||
|
last withdrawal. This is accomplished by iterating over all relevant
|
||||||
|
`PowerChange`'s stored in distribution state.
|
||||||
|
|
||||||
|
|
||||||
|
```golang
|
||||||
|
type TxWithdrawDelegation struct {
|
||||||
|
delegatorAddr sdk.AccAddress
|
||||||
|
withdrawAddr sdk.AccAddress // address to make the withdrawal to
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithdrawDelegator(delegatorAddr, withdrawAddr sdk.AccAddress)
|
||||||
|
entitlement = GetDelegatorEntitlement(delegatorAddr)
|
||||||
|
AddCoins(withdrawAddr, totalEntitlment.TruncateDecimal())
|
||||||
|
|
||||||
|
func GetDelegatorEntitlement(delegatorAddr sdk.AccAddress) DecCoins
|
||||||
|
|
||||||
|
// compile all the distribution scenarios
|
||||||
|
delegations = GetDelegations(delegatorAddr)
|
||||||
|
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
|
||||||
|
delegation.ValidatorAddr)
|
||||||
|
pcs = GetPowerChanges(DelDistr.WithdrawalHeight)
|
||||||
|
|
||||||
|
// update all adjustment factors for each delegation since last withdrawal
|
||||||
|
for pc = range pcs
|
||||||
|
for delegation = range delegations
|
||||||
|
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
|
||||||
|
delegation.ValidatorAddr)
|
||||||
|
pc.ProcessPowerChangeDelegation(delegation, DelDistr)
|
||||||
|
|
||||||
|
// collect all entitled fees
|
||||||
|
entitlement = 0
|
||||||
|
for delegation = range delegations
|
||||||
|
global = GetGlobal()
|
||||||
|
pool = GetPool()
|
||||||
|
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
|
||||||
|
delegation.ValidatorAddr)
|
||||||
|
ValDistr = GetValidatorDistribution(delegation.ValidatorAddr)
|
||||||
|
validator = GetValidator(delegation.ValidatorAddr)
|
||||||
|
|
||||||
|
scenerio1 = NewDelegationFromGlobalPool(delegation, validator,
|
||||||
|
pool, global, ValDistr, DelDistr)
|
||||||
|
scenerio2 = NewDelegationFromProvisionPool(delegation, validator,
|
||||||
|
ValDistr, DelDistr)
|
||||||
|
entitlement += scenerio1.WithdrawalEntitlement()
|
||||||
|
entitlement += scenerio2.WithdrawalEntitlement()
|
||||||
|
|
||||||
|
return entitlement
|
||||||
|
|
||||||
|
func (pc PowerChange) ProcessPowerChangeDelegation(delegation sdk.Delegation,
|
||||||
|
DelDistr DelegationDistribution)
|
||||||
|
|
||||||
|
// get the historical scenarios
|
||||||
|
scenario1 = pc.DelegationFromGlobalPool(delegation, DelDistr)
|
||||||
|
scenario2 = pc.DelegationFromProvisionPool(delegation, DelDistr)
|
||||||
|
|
||||||
|
// process the adjustment factors
|
||||||
|
scenario1.UpdateAdjustmentForPowerChange(pc.Height)
|
||||||
|
scenario2.UpdateAdjustmentForPowerChange(pc.Height)
|
||||||
|
```
|
||||||
|
|
||||||
|
## TxWithdrawValidator
|
||||||
|
|
||||||
|
When a validator wishes to withdraw their transaction fees it must send
|
||||||
|
`TxWithdrawDelegation`. Note that parts of this transaction logic is also
|
||||||
|
triggered each with any change in individual delegations, such as an unbond,
|
||||||
|
redelegation, or delegation of additional tokens to a specific validator. This
|
||||||
|
transaction withdraws the validators commission rewards, as well as any rewards
|
||||||
|
earning on their self-delegation.
|
||||||
|
|
||||||
|
```golang
|
||||||
|
type TxWithdrawValidator struct {
|
||||||
|
ownerAddr sdk.AccAddress // validator address to withdraw from
|
||||||
|
withdrawAddr sdk.AccAddress // address to make the withdrawal to
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithdrawalValidator(ownerAddr, withdrawAddr sdk.AccAddress)
|
||||||
|
|
||||||
|
// update the delegator adjustment factors and also withdrawal delegation fees
|
||||||
|
entitlement = GetDelegatorEntitlement(ownerAddr)
|
||||||
|
|
||||||
|
// update the validator adjustment factors for commission
|
||||||
|
ValDistr = GetValidatorDistribution(ownerAddr.ValidatorAddr)
|
||||||
|
pcs = GetPowerChanges(ValDistr.CommissionWithdrawalHeight)
|
||||||
|
for pc = range pcs
|
||||||
|
pc.ProcessPowerChangeCommission()
|
||||||
|
|
||||||
|
// withdrawal validator commission rewards
|
||||||
|
global = GetGlobal()
|
||||||
|
pool = GetPool()
|
||||||
|
ValDistr = GetValidatorDistribution(delegation.ValidatorAddr)
|
||||||
|
validator = GetValidator(delegation.ValidatorAddr)
|
||||||
|
|
||||||
|
scenerio1 = NewCommissionFromGlobalPool(validator,
|
||||||
|
pool, global, ValDistr)
|
||||||
|
scenerio2 = CommissionFromProposerPool(validator, ValDistr)
|
||||||
|
entitlement += scenerio1.WithdrawalEntitlement()
|
||||||
|
entitlement += scenerio2.WithdrawalEntitlement()
|
||||||
|
|
||||||
|
AddCoins(withdrawAddr, totalEntitlment.TruncateDecimal())
|
||||||
|
|
||||||
|
func (pc PowerChange) ProcessPowerChangeCommission()
|
||||||
|
|
||||||
|
// get the historical scenarios
|
||||||
|
scenario1 = pc.CommissionFromGlobalPool()
|
||||||
|
scenario2 = pc.CommissionFromProposerPool()
|
||||||
|
|
||||||
|
// process the adjustment factors
|
||||||
|
scenario1.UpdateAdjustmentForPowerChange(pc.Height)
|
||||||
|
scenario2.UpdateAdjustmentForPowerChange(pc.Height)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Calculations
|
||||||
|
|
||||||
|
### Distribution scenario
|
||||||
|
|
||||||
|
A common form of abstracted calculations exists between validators and
|
||||||
|
delegations attempting to withdrawal their rewards, either from `Global.Pool`
|
||||||
|
or from `ValidatorDistribution.ProposerPool`. With the following interface
|
||||||
|
fulfilled the entitled fees for the various scenarios can be calculated.
|
||||||
|
|
||||||
|
```golang
|
||||||
|
type DistributionScenario interface {
|
||||||
|
DistributorTokens() DecCoins // current tokens from distributor
|
||||||
|
DistributorCumulativeTokens() DecCoins // total tokens ever received
|
||||||
|
DistributorPrevReceivedTokens() DecCoins // last value of tokens received
|
||||||
|
DistributorShares() sdk.Dec // current shares
|
||||||
|
DistributorPrevShares() sdk.Dec // shares last block
|
||||||
|
|
||||||
|
RecipientAdjustment() sdk.Dec
|
||||||
|
RecipientShares() sdk.Dec // current shares
|
||||||
|
RecipientPrevShares() sdk.Dec // shares last block
|
||||||
|
|
||||||
|
ModifyAdjustments(withdrawal sdk.Dec) // proceedure to modify adjustment factors
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Entitled reward from distribution scenario
|
||||||
|
|
||||||
|
The entitlement to the distributor's tokens held can be accounted for lazily.
|
||||||
|
To begin this calculation we must determine the recipient's _simple pool_ and
|
||||||
|
_projected pool_. The simple pool represents a lazy accounting of what a
|
||||||
|
recipient's entitlement to the distributor's tokens would be if all recipients
|
||||||
|
for that distributor had static shares (equal to the current shares), and no
|
||||||
|
recipients had ever withdrawn their entitled rewards. The projected pool
|
||||||
|
represents the anticipated recipient's entitlement to the distributors tokens
|
||||||
|
based on the current blocks token input (for example fees reward received) to
|
||||||
|
the distributor, and the distributor's tokens and shares of the previous block
|
||||||
|
assuming that neither had changed in the current block. Using the simple and
|
||||||
|
projected pools we can determine all cumulative changes which have taken place
|
||||||
|
outside of the recipient and adjust the recipient's _adjustment factor_ to
|
||||||
|
account for these changes and ultimately keep track of the correct entitlement
|
||||||
|
to the distributors tokens.
|
||||||
|
|
||||||
|
```
|
||||||
|
func (d DistributionScenario) RecipientCount(height int64) sdk.Dec
|
||||||
|
return v.RecipientShares() * height
|
||||||
|
|
||||||
|
func (d DistributionScenario) GlobalCount(height int64) sdk.Dec
|
||||||
|
return d.DistributorShares() * height
|
||||||
|
|
||||||
|
func (d DistributionScenario) SimplePool() DecCoins
|
||||||
|
return d.RecipientCount() / d.GlobalCount() * d.DistributorCumulativeTokens
|
||||||
|
|
||||||
|
func (d DistributionScenario) ProjectedPool(height int64) DecCoins
|
||||||
|
return d.RecipientPrevShares() * (height-1)
|
||||||
|
/ (d.DistributorPrevShares() * (height-1))
|
||||||
|
* d.DistributorCumulativeTokens
|
||||||
|
+ d.RecipientShares() / d.DistributorShares()
|
||||||
|
* d.DistributorPrevReceivedTokens()
|
||||||
|
```
|
||||||
|
|
||||||
|
The `DistributionScenario` _adjustment_ terms account for changes in
|
||||||
|
recipient/distributor shares and recipient withdrawals. The adjustment factor
|
||||||
|
must be modified whenever the recipient withdraws from the distributor or the
|
||||||
|
distributor's/recipient's shares are changed.
|
||||||
|
- When the shares of the recipient is changed the adjustment factor is
|
||||||
|
increased/decreased by the difference between the _simple_ and _projected_
|
||||||
|
pools. In other words, the cumulative difference in the shares if the shares
|
||||||
|
has been the new shares as opposed to the old shares for the entire duration of
|
||||||
|
the blockchain up the previous block.
|
||||||
|
- When a recipient makes a withdrawal the adjustment factor is increased by the
|
||||||
|
withdrawal amount.
|
||||||
|
|
||||||
|
```
|
||||||
|
func (d DistributionScenario) UpdateAdjustmentForPowerChange(height int64)
|
||||||
|
simplePool = d.SimplePool()
|
||||||
|
projectedPool = d.ProjectedPool(height)
|
||||||
|
AdjustmentChange = simplePool - projectedPool
|
||||||
|
if AdjustmentChange > 0
|
||||||
|
d.ModifyAdjustments(AdjustmentChange)
|
||||||
|
|
||||||
|
func (d DistributionScenario) WithdrawalEntitlement() DecCoins
|
||||||
|
entitlement = d.SimplePool() - d.RecipientAdjustment()
|
||||||
|
d.ModifyAdjustments(entitlement)
|
||||||
|
return entitlement
|
||||||
|
```
|
||||||
|
|
||||||
|
### Distribution scenarios
|
||||||
|
|
||||||
|
Note that the distribution scenario structures are found in `state.md`.
|
||||||
|
|
||||||
|
#### Delegation's entitlement to Global.Pool
|
||||||
|
|
||||||
|
For delegations (including validator's self-delegation) all fees from fee pool
|
||||||
|
are subject to commission rate from the owner of the validator. The global
|
||||||
|
shares should be taken as true number of global bonded shares. The recipients
|
||||||
|
shares should be taken as the bonded tokens less the validator's commission.
|
||||||
|
|
||||||
|
```
|
||||||
|
type DelegationFromGlobalPool struct {
|
||||||
|
DelegationShares sdk.Dec
|
||||||
|
ValidatorCommission sdk.Dec
|
||||||
|
ValidatorBondedTokens sdk.Dec
|
||||||
|
ValidatorDelegatorShareExRate sdk.Dec
|
||||||
|
PoolBondedTokens sdk.Dec
|
||||||
|
Global Global
|
||||||
|
ValDistr ValidatorDistribution
|
||||||
|
DelDistr DelegatorDistribution
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d DelegationFromGlobalPool) DistributorTokens() DecCoins
|
||||||
|
return d.Global.Pool
|
||||||
|
|
||||||
|
func (d DelegationFromGlobalPool) DistributorCumulativeTokens() DecCoins
|
||||||
|
return d.Global.EverReceivedPool
|
||||||
|
|
||||||
|
func (d DelegationFromGlobalPool) DistributorPrevReceivedTokens() DecCoins
|
||||||
|
return d.Global.PrevReceivedPool
|
||||||
|
|
||||||
|
func (d DelegationFromGlobalPool) DistributorShares() sdk.Dec
|
||||||
|
return d.PoolBondedTokens
|
||||||
|
|
||||||
|
func (d DelegationFromGlobalPool) DistributorPrevShares() sdk.Dec
|
||||||
|
return d.Global.PrevBondedTokens
|
||||||
|
|
||||||
|
func (d DelegationFromGlobalPool) RecipientShares() sdk.Dec
|
||||||
|
return d.DelegationShares * d.ValidatorDelegatorShareExRate() *
|
||||||
|
d.ValidatorBondedTokens() * (1 - d.ValidatorCommission)
|
||||||
|
|
||||||
|
func (d DelegationFromGlobalPool) RecipientPrevShares() sdk.Dec
|
||||||
|
return d.DelDistr.PrevTokens
|
||||||
|
|
||||||
|
func (d DelegationFromGlobalPool) RecipientAdjustment() sdk.Dec
|
||||||
|
return d.DelDistr.Adjustment
|
||||||
|
|
||||||
|
func (d DelegationFromGlobalPool) ModifyAdjustments(withdrawal sdk.Dec)
|
||||||
|
d.ValDistr.Adjustment += withdrawal
|
||||||
|
d.DelDistr.Adjustment += withdrawal
|
||||||
|
d.global.Adjustment += withdrawal
|
||||||
|
SetValidatorDistribution(d.ValDistr)
|
||||||
|
SetDelegatorDistribution(d.DelDistr)
|
||||||
|
SetGlobal(d.Global)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Delegation's entitlement to ValidatorDistribution.ProposerPool
|
||||||
|
|
||||||
|
Delegations (including validator's self-delegation) are still subject
|
||||||
|
commission on the rewards gained from the proposer pool. Global shares in this
|
||||||
|
context is actually the validators total delegations shares. The recipient's
|
||||||
|
shares is taken as the effective delegation shares less the validator's
|
||||||
|
commission.
|
||||||
|
|
||||||
|
```
|
||||||
|
type DelegationFromProposerPool struct {
|
||||||
|
DelegationShares sdk.Dec
|
||||||
|
ValidatorCommission sdk.Dec
|
||||||
|
ValidatorDelegatorShares sdk.Dec
|
||||||
|
ValDistr ValidatorDistribution
|
||||||
|
DelDistr DelegatorDistribution
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d DelegationFromProposerPool) DistributorTokens() DecCoins
|
||||||
|
return d.ValDistr.ProposerPool
|
||||||
|
|
||||||
|
func (d DelegationFromProposerPool) DistributorCumulativeTokens() DecCoins
|
||||||
|
return d.ValDistr.EverReceivedProposerReward
|
||||||
|
|
||||||
|
func (d DelegationFromProposerPool) DistributorPrevReceivedTokens() DecCoins
|
||||||
|
return d.ValDistr.PrevReceivedProposerReward
|
||||||
|
|
||||||
|
func (d DelegationFromProposerPool) DistributorShares() sdk.Dec
|
||||||
|
return d.ValidatorDelegatorShares
|
||||||
|
|
||||||
|
func (d DelegationFromProposerPool) DistributorPrevShares() sdk.Dec
|
||||||
|
return d.ValDistr.PrevDelegatorShares
|
||||||
|
|
||||||
|
func (d DelegationFromProposerPool) RecipientShares() sdk.Dec
|
||||||
|
return d.DelegationShares * (1 - d.ValidatorCommission)
|
||||||
|
|
||||||
|
func (d DelegationFromProposerPool) RecipientPrevShares() sdk.Dec
|
||||||
|
return d.DelDistr.PrevShares
|
||||||
|
|
||||||
|
func (d DelegationFromProposerPool) RecipientAdjustment() sdk.Dec
|
||||||
|
return d.DelDistr.AdjustmentProposer
|
||||||
|
|
||||||
|
func (d DelegationFromProposerPool) ModifyAdjustments(withdrawal sdk.Dec)
|
||||||
|
d.ValDistr.AdjustmentProposer += withdrawal
|
||||||
|
d.DelDistr.AdjustmentProposer += withdrawal
|
||||||
|
SetValidatorDistribution(d.ValDistr)
|
||||||
|
SetDelegatorDistribution(d.DelDistr)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Validators's commission entitlement to Global.Pool
|
||||||
|
|
||||||
|
Similar to a delegator's entitlement, but with recipient shares based on the
|
||||||
|
commission portion of bonded tokens.
|
||||||
|
|
||||||
|
```
|
||||||
|
type CommissionFromGlobalPool struct {
|
||||||
|
ValidatorBondedTokens sdk.Dec
|
||||||
|
ValidatorCommission sdk.Dec
|
||||||
|
PoolBondedTokens sdk.Dec
|
||||||
|
Global Global
|
||||||
|
ValDistr ValidatorDistribution
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c CommissionFromGlobalPool) DistributorTokens() DecCoins
|
||||||
|
return c.Global.Pool
|
||||||
|
|
||||||
|
func (c CommissionFromGlobalPool) DistributorCumulativeTokens() DecCoins
|
||||||
|
return c.Global.EverReceivedPool
|
||||||
|
|
||||||
|
func (c CommissionFromGlobalPool) DistributorPrevReceivedTokens() DecCoins
|
||||||
|
return c.Global.PrevReceivedPool
|
||||||
|
|
||||||
|
func (c CommissionFromGlobalPool) DistributorShares() sdk.Dec
|
||||||
|
return c.PoolBondedTokens
|
||||||
|
|
||||||
|
func (c CommissionFromGlobalPool) DistributorPrevShares() sdk.Dec
|
||||||
|
return c.Global.PrevBondedTokens
|
||||||
|
|
||||||
|
func (c CommissionFromGlobalPool) RecipientShares() sdk.Dec
|
||||||
|
return c.ValidatorBondedTokens() * c.ValidatorCommission
|
||||||
|
|
||||||
|
func (c CommissionFromGlobalPool) RecipientPrevShares() sdk.Dec
|
||||||
|
return c.ValDistr.PrevBondedTokens * c.ValidatorCommission
|
||||||
|
|
||||||
|
func (c CommissionFromGlobalPool) RecipientAdjustment() sdk.Dec
|
||||||
|
return c.ValDistr.Adjustment
|
||||||
|
|
||||||
|
func (c CommissionFromGlobalPool) ModifyAdjustments(withdrawal sdk.Dec)
|
||||||
|
c.ValDistr.Adjustment += withdrawal
|
||||||
|
c.Global.Adjustment += withdrawal
|
||||||
|
SetValidatorDistribution(c.ValDistr)
|
||||||
|
SetGlobal(c.Global)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Validators's commission entitlement to ValidatorDistribution.ProposerPool
|
||||||
|
|
||||||
|
Similar to a delegators entitlement to the proposer pool, but with recipient
|
||||||
|
shares based on the commission portion of the total delegator shares.
|
||||||
|
|
||||||
|
```
|
||||||
|
type CommissionFromProposerPool struct {
|
||||||
|
ValidatorDelegatorShares sdk.Dec
|
||||||
|
ValidatorCommission sdk.Dec
|
||||||
|
ValDistr ValidatorDistribution
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c CommissionFromProposerPool) DistributorTokens() DecCoins
|
||||||
|
return c.ValDistr.ProposerPool
|
||||||
|
|
||||||
|
func (c CommissionFromProposerPool) DistributorCumulativeTokens() DecCoins
|
||||||
|
return c.ValDistr.EverReceivedProposerReward
|
||||||
|
|
||||||
|
func (c CommissionFromProposerPool) DistributorPrevReceivedTokens() DecCoins
|
||||||
|
return c.ValDistr.PrevReceivedProposerReward
|
||||||
|
|
||||||
|
func (c CommissionFromProposerPool) DistributorShares() sdk.Dec
|
||||||
|
return c.ValidatorDelegatorShares
|
||||||
|
|
||||||
|
func (c CommissionFromProposerPool) DistributorPrevShares() sdk.Dec
|
||||||
|
return c.ValDistr.PrevDelegatorShares
|
||||||
|
|
||||||
|
func (c CommissionFromProposerPool) RecipientShares() sdk.Dec
|
||||||
|
return c.ValidatorDelegatorShares * (c.ValidatorCommission)
|
||||||
|
|
||||||
|
func (c CommissionFromProposerPool) RecipientPrevShares() sdk.Dec
|
||||||
|
return c.ValDistr.PrevDelegatorShares * (c.ValidatorCommission)
|
||||||
|
|
||||||
|
func (c CommissionFromProposerPool) RecipientAdjustment() sdk.Dec
|
||||||
|
return c.ValDistr.AdjustmentProposer
|
||||||
|
|
||||||
|
func (c CommissionFromProposerPool) ModifyAdjustments(withdrawal sdk.Dec)
|
||||||
|
c.ValDistr.AdjustmentProposer += withdrawal
|
||||||
|
SetValidatorDistribution(c.ValDistr)
|
||||||
|
```
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
# End Block
|
# End Block
|
||||||
|
|
||||||
At each endblock, the fees received are sorted to the proposer, community fund,
|
At each endblock, the fees received are allocated to the proposer, community fund,
|
||||||
and global pool. When the validator is the proposer of the round, that
|
and global pool. When the validator is the proposer of the round, that
|
||||||
validator (and their delegators) receives between 1% and 5% of fee rewards, the
|
validator (and their delegators) receives between 1% and 5% of fee rewards, the
|
||||||
reserve tax is then charged, then the remainder is distributed proportionally
|
reserve community tax is then charged, then the remainder is distributed
|
||||||
by voting power to all bonded validators independent of whether they voted
|
proportionally by voting power to all bonded validators independent of whether
|
||||||
(social distribution). Note the social distribution is applied to proposer
|
they voted (social distribution). Note the social distribution is applied to
|
||||||
validator in addition to the proposer reward.
|
proposer validator in addition to the proposer reward.
|
||||||
|
|
||||||
The amount of proposer reward is calculated from pre-commits Tendermint
|
The amount of proposer reward is calculated from pre-commits Tendermint
|
||||||
messages in order to incentivize validators to wait and include additional
|
messages in order to incentivize validators to wait and include additional
|
||||||
|
@ -15,13 +15,17 @@ pool which validator holds individually
|
||||||
(`ValidatorDistribution.ProvisionsRewardPool`).
|
(`ValidatorDistribution.ProvisionsRewardPool`).
|
||||||
|
|
||||||
```
|
```
|
||||||
func SortFees(feesCollected sdk.Coins, global Global, proposer ValidatorDistribution,
|
func AllocateFees(feesCollected sdk.Coins, global Global, proposer ValidatorDistribution,
|
||||||
sumPowerPrecommitValidators, totalBondedTokens, communityTax sdk.Dec)
|
sumPowerPrecommitValidators, totalBondedTokens, communityTax,
|
||||||
|
proposerCommissionRate sdk.Dec)
|
||||||
|
|
||||||
feesCollectedDec = MakeDecCoins(feesCollected)
|
feesCollectedDec = MakeDecCoins(feesCollected)
|
||||||
proposerReward = feesCollectedDec * (0.01 + 0.04
|
proposerReward = feesCollectedDec * (0.01 + 0.04
|
||||||
* sumPowerPrecommitValidators / totalBondedTokens)
|
* sumPowerPrecommitValidators / totalBondedTokens)
|
||||||
proposer.ProposerPool += proposerReward
|
|
||||||
|
commission = proposerReward * proposerCommissionRate
|
||||||
|
proposer.PoolCommission += commission
|
||||||
|
proposer.Pool += proposerReward - commission
|
||||||
|
|
||||||
communityFunding = feesCollectedDec * communityTax
|
communityFunding = feesCollectedDec * communityTax
|
||||||
global.CommunityFund += communityFunding
|
global.CommunityFund += communityFunding
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
# Hooks
|
||||||
|
|
||||||
|
## Create or modify delegation distribution
|
||||||
|
|
||||||
|
- triggered-by: `stake.TxDelegate`, `stake.TxBeginRedelegate`, `stake.TxBeginUnbonding`
|
||||||
|
|
||||||
|
The pool of a new delegator bond will be 0 for the height at which the bond was
|
||||||
|
added, or the withdrawal has taken place. This is achieved by setting
|
||||||
|
`DelegatorDistInfo.WithdrawalHeight` to the height of the triggering transaction.
|
||||||
|
|
||||||
|
## Commission rate change
|
||||||
|
|
||||||
|
- triggered-by: `stake.TxEditValidator`
|
||||||
|
|
||||||
|
If a validator changes its commission rate, all commission on fees must be
|
||||||
|
simultaneously withdrawn using the transaction `TxWithdrawValidator`.
|
||||||
|
Additionally the change and associated height must be recorded in a
|
||||||
|
`ValidatorUpdate` state record.
|
||||||
|
|
||||||
|
## Change in Validator State
|
||||||
|
|
||||||
|
- triggered-by: `stake.Slash`, `stake.UpdateValidator`
|
||||||
|
|
||||||
|
Whenever a validator is slashed or enters/leaves the validator group all of the
|
||||||
|
validator entitled reward tokens must be simultaneously withdrawn from
|
||||||
|
`Global.Pool` and added to `ValidatorDistInfo.Pool`.
|
|
@ -2,53 +2,71 @@
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
Collected fees are pooled globally and divided out passively to validators and
|
This _simple_ distribution mechanism describes a functional way to passively
|
||||||
delegators. Each validator has the opportunity to charge commission to the
|
distribute rewards between validator and delegators. Note that this mechanism does
|
||||||
delegators on the fees collected on behalf of the delegators by the validators.
|
not distribute funds in as precisely as active reward distribution and will therefore
|
||||||
Fees are paid directly into a global fee pool, and validator proposer-reward
|
be upgraded in the future.
|
||||||
pool. Due to the nature of passive accounting whenever changes to parameters
|
|
||||||
which affect the rate of fee distribution occurs, withdrawal of fees must also
|
|
||||||
occur when:
|
|
||||||
|
|
||||||
- withdrawing one must withdrawal the maximum amount they are entitled
|
|
||||||
too, leaving nothing in the pool,
|
|
||||||
- bonding, unbonding, or re-delegating tokens to an existing account a
|
|
||||||
full withdrawal of the fees must occur (as the rules for lazy accounting
|
|
||||||
change),
|
|
||||||
- a validator chooses to change the commission on fees, all accumulated
|
|
||||||
commission fees must be simultaneously withdrawn.
|
|
||||||
|
|
||||||
The above scenarios are covered in `triggers.md`.
|
The mechanism operates as follows. Collected rewards are pooled globally and
|
||||||
|
divided out passively to validators and delegators. Each validator has the
|
||||||
|
opportunity to charge commission to the delegators on the rewards collected on
|
||||||
|
behalf of the delegators by the validators. Fees are paid directly into a
|
||||||
|
global reward pool, and validator proposer-reward pool. Due to the nature of
|
||||||
|
passive accounting, whenever changes to parameters which affect the rate of reward
|
||||||
|
distribution occurs, withdrawal of rewards must also occur.
|
||||||
|
|
||||||
|
- Whenever withdrawing, one must withdraw the maximum amount they are entitled
|
||||||
|
too, leaving nothing in the pool.
|
||||||
|
- Whenever bonding, unbonding, or re-delegating tokens to an existing account, a
|
||||||
|
full withdrawal of the rewards must occur (as the rules for lazy accounting
|
||||||
|
change).
|
||||||
|
- Whenever a validator chooses to change the commission on rewards, all accumulated
|
||||||
|
commission rewards must be simultaneously withdrawn.
|
||||||
|
|
||||||
|
The above scenarios are covered in `hooks.md`.
|
||||||
|
|
||||||
The distribution mechanism outlines herein is used to lazily distribute the
|
The distribution mechanism outlines herein is used to lazily distribute the
|
||||||
following between validators and associated delegators:
|
following rewards between validators and associated delegators:
|
||||||
- multi-token fees to be socially distributed,
|
- multi-token fees to be socially distributed,
|
||||||
- proposer reward pool,
|
- proposer reward pool,
|
||||||
- inflated atom provisions, and
|
- inflated atom provisions, and
|
||||||
- validator commission on all rewards earned by their delegators stake
|
- validator commission on all rewards earned by their delegators stake
|
||||||
|
|
||||||
Fees are pooled within a global pool, as well as validator specific
|
Fees are pooled within a global pool, as well as validator specific
|
||||||
proposer-reward pools. The mechanisms used allow for validators and delegators
|
proposer-reward pools. The mechanisms used allow for validators and delegators
|
||||||
to independently and lazily withdrawn their rewards. As a part of the lazy
|
to independently and lazily withdraw their rewards.
|
||||||
computations adjustment factors must be maintained for each validator and
|
|
||||||
delegator to determine the true proportion of fees in each pool which they are
|
## Shortcomings
|
||||||
entitled too. Adjustment factors are updated every time a validator or
|
|
||||||
delegator's voting power changes. Validators and delegators must withdraw all
|
As a part of the lazy computations, each delegator holds an accumulation term
|
||||||
fees they are entitled too before they can change their portion of bonded
|
specific to each validator which is used to estimate what their approximate
|
||||||
Atoms.
|
fair portion of tokens held in the global pool is owed to them.
|
||||||
|
|
||||||
|
```
|
||||||
|
entitlement = delegator-accumulation / all-delegators-accumulation
|
||||||
|
```
|
||||||
|
|
||||||
|
Under the circumstance that there were constant and equal flow of incoming
|
||||||
|
reward tokens every block, this distribution mechanism would be equal to the
|
||||||
|
active distribution (distribute individually to all delegators each block).
|
||||||
|
However this is unrealistic so deviations from the active distribution will
|
||||||
|
occur based on fluctuations of incoming reward tokens as well as timing of
|
||||||
|
reward withdrawal by other delegators.
|
||||||
|
|
||||||
|
If you happen to know that incoming rewards are about significantly move up,
|
||||||
|
you are incentivized to not withdraw until after this event, increasing the
|
||||||
|
worth of your existing _accum_.
|
||||||
|
|
||||||
## Affect on Staking
|
## Affect on Staking
|
||||||
|
|
||||||
|
|
||||||
Charging commission on Atom provisions while also allowing for Atom-provisions
|
Charging commission on Atom provisions while also allowing for Atom-provisions
|
||||||
to be auto-bonded (distributed directly to the validators bonded stake) is
|
to be auto-bonded (distributed directly to the validators bonded stake) is
|
||||||
problematic within DPoS. Fundamentally these two mechnisms are mutually
|
problematic within DPoS. Fundamentally these two mechanisms are mutually
|
||||||
exclusive. If there are atoms commissions and auto-bonding Atoms, the portion
|
exclusive. If there are Atom commissions and auto-bonding Atoms, the portion
|
||||||
of Atoms the fee distribution calculation would become very large as the Atom
|
of Atoms the reward distribution calculation would become very large as the Atom
|
||||||
portion for each delegator would change each block making a withdrawal of fees
|
portion for each delegator would change each block making a withdrawal of rewards
|
||||||
for a delegator require a calculation for every single block since the last
|
for a delegator require a calculation for every single block since the last
|
||||||
withdrawal. In conclusion we can only have atom commission and unbonded atoms
|
withdrawal. In conclusion, we can only have Atom commission and unbonded atoms
|
||||||
provisions, or bonded atom provisions with no Atom commission, and we elect to
|
provisions or bonded atom provisions with no Atom commission, and we elect to
|
||||||
implement the former. Stakeholders wishing to rebond their provisions may elect
|
implement the former. Stakeholders wishing to rebond their provisions may elect
|
||||||
to set up a script to periodically withdraw and rebond fees.
|
to set up a script to periodically withdraw and rebond rewards.
|
||||||
|
|
||||||
|
|
|
@ -23,78 +23,46 @@ type DecCoin struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Global struct {
|
type Global struct {
|
||||||
PrevBondedTokens sdk.Dec // bonded token amount for the global pool on the previous block
|
TotalValAccumUpdateHeight int64 // last height which the total validator accum was updated
|
||||||
Adjustment sdk.Dec // global adjustment factor for lazy calculations
|
TotalValAccum sdk.Dec // total valdator accum held by validators
|
||||||
Pool DecCoins // funds for all validators which have yet to be withdrawn
|
Pool DecCoins // funds for all validators which have yet to be withdrawn
|
||||||
PrevReceivedPool DecCoins // funds added to the pool on the previous block
|
CommunityPool DecCoins // pool for community funds yet to be spent
|
||||||
EverReceivedPool DecCoins // total funds ever added to the pool
|
|
||||||
CommunityFund DecCoins // pool for community funds yet to be spent
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Validator Distribution
|
### Validator Distribution
|
||||||
|
|
||||||
Validator distribution information for the relevant validator is updated each time:
|
Validator distribution information for the relevant validator is updated each time:
|
||||||
1. delegation amount to a validator are updated,
|
1. delegation amount to a validator is updated,
|
||||||
2. a validator successfully proposes a block and receives a reward,
|
2. a validator successfully proposes a block and receives a reward,
|
||||||
3. any delegator withdraws from a validator, or
|
3. any delegator withdraws from a validator, or
|
||||||
4. the validator withdraws it's commission.
|
4. the validator withdraws it's commission.
|
||||||
|
|
||||||
- ValidatorDistribution: `0x02 | ValOwnerAddr -> amino(validatorDistribution)`
|
- ValidatorDistInfo: `0x02 | ValOperatorAddr -> amino(validatorDistribution)`
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
type ValidatorDistribution struct {
|
type ValidatorDistInfo struct {
|
||||||
CommissionWithdrawalHeight int64 // last time this validator withdrew commission
|
GlobalWithdrawalHeight int64 // last height this validator withdrew from the global pool
|
||||||
Adjustment sdk.Dec // global pool adjustment factor
|
Pool DecCoins // rewards owed to delegators, commission has already been charged (includes proposer reward)
|
||||||
ProposerAdjustment DecCoins // proposer pool adjustment factor
|
PoolCommission DecCoins // commission collected by this validator (pending withdrawal)
|
||||||
ProposerPool DecCoins // reward pool collected from being the proposer
|
|
||||||
EverReceivedProposerReward DecCoins // all rewards ever collected from being the proposer
|
TotalDelAccumUpdateHeight int64 // last height which the total delegator accum was updated
|
||||||
PrevReceivedProposerReward DecCoins // previous rewards collected from being the proposer
|
TotalDelAccum sdk.Dec // total proposer pool accumulation factor held by delegators
|
||||||
PrevBondedTokens sdk.Dec // bonded token amount on the previous block
|
|
||||||
PrevDelegatorShares sdk.Dec // amount of delegator shares for the validator on the previous block
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Delegation Distribution
|
### Delegation Distribution
|
||||||
|
|
||||||
Each delegation holds multiple adjustment factors to specify its entitlement to
|
Each delegation distribution only needs to record the height at which it last
|
||||||
the rewards from a validator. `AdjustmentPool` is used to passively calculate
|
withdrew fees. Because a delegation must withdraw fees each time it's
|
||||||
each bonds entitled fees from the `RewardPool`. `AdjustmentPool` is used to
|
properties change (aka bonded tokens etc.) its properties will remain constant
|
||||||
passively calculate each bonds entitled fees from
|
and the delegator's _accumulation_ factor can be calculated passively knowing
|
||||||
`ValidatorDistribution.ProposerRewardPool`
|
only the height of the last withdrawal and its current properties.
|
||||||
|
|
||||||
- DelegatorDistribution: ` 0x02 | DelegatorAddr | ValOwnerAddr -> amino(delegatorDist)`
|
- DelegatorDistInfo: ` 0x02 | DelegatorAddr | ValOperatorAddr -> amino(delegatorDist)`
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
type DelegatorDist struct {
|
type DelegatorDistInfo struct {
|
||||||
WithdrawalHeight int64 // last time this delegation withdrew rewards
|
WithdrawalHeight int64 // last time this delegation withdrew rewards
|
||||||
Adjustment sdk.Dec // fee provisioning adjustment factor
|
|
||||||
AdjustmentProposer DecCoins // proposers pool adjustment factor
|
|
||||||
PrevTokens sdk.Dec // bonded tokens held by the delegation on the previous block
|
|
||||||
PrevShares sdk.Dec // delegator shares held by the delegation on the previous block
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Power Change
|
|
||||||
|
|
||||||
Every instance that the voting power changes, information about the state of
|
|
||||||
the validator set during the change must be recorded as a `PowerChange` for
|
|
||||||
other validators to run through. Each power change is indexed by its block
|
|
||||||
height.
|
|
||||||
|
|
||||||
- PowerChange: `0x03 | amino(Height) -> amino(validatorDist)`
|
|
||||||
|
|
||||||
```golang
|
|
||||||
type PowerChange struct {
|
|
||||||
Height int64 // block height at change
|
|
||||||
ValidatorBondedTokens sdk.Dec // following used to create distribution scenarios
|
|
||||||
ValidatorDelegatorShares sdk.Dec
|
|
||||||
ValidatorDelegatorShareExRate sdk.Dec
|
|
||||||
ValidatorCommission sdk.Dec
|
|
||||||
PoolBondedTokens sdk.Dec
|
|
||||||
Global Global
|
|
||||||
ValDistr ValidatorDistribution
|
|
||||||
DelegationShares sdk.Dec
|
|
||||||
DelDistr DelegatorDistribution
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,399 +1,213 @@
|
||||||
# Transactions
|
# Transactions
|
||||||
|
|
||||||
## TxWithdrawDelegation
|
## TxWithdrawDelegationRewardsAll
|
||||||
|
|
||||||
When a delegator wishes to withdraw their transaction fees it must send
|
When a delegator wishes to withdraw their rewards it must send
|
||||||
`TxWithdrawDelegation`. Note that parts of this transaction logic are also
|
`TxWithdrawDelegationRewardsAll`. Note that parts of this transaction logic are also
|
||||||
triggered each with any change in individual delegations, such as an unbond,
|
triggered each with any change in individual delegations, such as an unbond,
|
||||||
redelegation, or delegation of additional tokens to a specific validator.
|
redelegation, or delegation of additional tokens to a specific validator.
|
||||||
|
|
||||||
Each time a withdrawal is made by a recipient the adjustment term must be
|
|
||||||
modified for each block with a change in distributors shares since the time of
|
|
||||||
last withdrawal. This is accomplished by iterating over all relevant
|
|
||||||
`PowerChange`'s stored in distribution state.
|
|
||||||
|
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
type TxWithdrawDelegation struct {
|
type TxWithdrawDelegationRewardsAll struct {
|
||||||
delegatorAddr sdk.AccAddress
|
delegatorAddr sdk.AccAddress
|
||||||
withdrawAddr sdk.AccAddress // address to make the withdrawal to
|
withdrawAddr sdk.AccAddress // address to make the withdrawal to
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithdrawDelegator(delegatorAddr, withdrawAddr sdk.AccAddress)
|
func WithdrawDelegationRewardsAll(delegatorAddr, withdrawAddr sdk.AccAddress)
|
||||||
entitlement = GetDelegatorEntitlement(delegatorAddr)
|
height = GetHeight()
|
||||||
AddCoins(withdrawAddr, totalEntitlment.TruncateDecimal())
|
withdraw = GetDelegatorRewardsAll(delegatorAddr, height)
|
||||||
|
AddCoins(withdrawAddr, withdraw.TruncateDecimal())
|
||||||
|
|
||||||
func GetDelegatorEntitlement(delegatorAddr sdk.AccAddress) DecCoins
|
func GetDelegatorRewardsAll(delegatorAddr sdk.AccAddress, height int64) DecCoins
|
||||||
|
|
||||||
// compile all the distribution scenarios
|
// get all distribution scenarios
|
||||||
delegations = GetDelegations(delegatorAddr)
|
delegations = GetDelegations(delegatorAddr)
|
||||||
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
|
|
||||||
delegation.ValidatorAddr)
|
|
||||||
pcs = GetPowerChanges(DelDistr.WithdrawalHeight)
|
|
||||||
|
|
||||||
// update all adjustment factors for each delegation since last withdrawal
|
// collect all entitled rewards
|
||||||
for pc = range pcs
|
withdraw = 0
|
||||||
for delegation = range delegations
|
pool = stake.GetPool()
|
||||||
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
|
global = GetGlobal()
|
||||||
delegation.ValidatorAddr)
|
|
||||||
pc.ProcessPowerChangeDelegation(delegation, DelDistr)
|
|
||||||
|
|
||||||
// collect all entitled fees
|
|
||||||
entitlement = 0
|
|
||||||
for delegation = range delegations
|
for delegation = range delegations
|
||||||
global = GetGlobal()
|
delInfo = GetDelegationDistInfo(delegation.DelegatorAddr,
|
||||||
pool = GetPool()
|
|
||||||
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
|
|
||||||
delegation.ValidatorAddr)
|
delegation.ValidatorAddr)
|
||||||
ValDistr = GetValidatorDistribution(delegation.ValidatorAddr)
|
valInfo = GetValidatorDistInfo(delegation.ValidatorAddr)
|
||||||
validator = GetValidator(delegation.ValidatorAddr)
|
validator = GetValidator(delegation.ValidatorAddr)
|
||||||
|
|
||||||
scenerio1 = NewDelegationFromGlobalPool(delegation, validator,
|
global, diWithdraw = delInfo.WithdrawRewards(global, valInfo, height, pool.BondedTokens,
|
||||||
pool, global, ValDistr, DelDistr)
|
validator.Tokens, validator.DelegatorShares, validator.Commission)
|
||||||
scenerio2 = NewDelegationFromProvisionPool(delegation, validator,
|
withdraw += diWithdraw
|
||||||
ValDistr, DelDistr)
|
|
||||||
entitlement += scenerio1.WithdrawalEntitlement()
|
|
||||||
entitlement += scenerio2.WithdrawalEntitlement()
|
|
||||||
|
|
||||||
return entitlement
|
|
||||||
|
|
||||||
func (pc PowerChange) ProcessPowerChangeDelegation(delegation sdk.Delegation,
|
SetGlobal(global)
|
||||||
DelDistr DelegationDistribution)
|
return withdraw
|
||||||
|
|
||||||
// get the historical scenarios
|
|
||||||
scenario1 = pc.DelegationFromGlobalPool(delegation, DelDistr)
|
|
||||||
scenario2 = pc.DelegationFromProvisionPool(delegation, DelDistr)
|
|
||||||
|
|
||||||
// process the adjustment factors
|
|
||||||
scenario1.UpdateAdjustmentForPowerChange(pc.Height)
|
|
||||||
scenario2.UpdateAdjustmentForPowerChange(pc.Height)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## TxWithdrawValidator
|
## TxWithdrawDelegationReward
|
||||||
|
|
||||||
When a validator wishes to withdraw their transaction fees it must send
|
under special circumstances a delegator may wish to withdraw rewards from only
|
||||||
`TxWithdrawDelegation`. Note that parts of this transaction logic is also
|
a single validator.
|
||||||
triggered each with any change in individual delegations, such as an unbond,
|
|
||||||
redelegation, or delegation of additional tokens to a specific validator. This
|
|
||||||
transaction withdraws the validators commission rewards, as well as any rewards
|
|
||||||
earning on their self-delegation.
|
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
type TxWithdrawValidator struct {
|
type TxWithdrawDelegationReward struct {
|
||||||
ownerAddr sdk.AccAddress // validator address to withdraw from
|
delegatorAddr sdk.AccAddress
|
||||||
|
validatorAddr sdk.AccAddress
|
||||||
|
withdrawAddr sdk.AccAddress // address to make the withdrawal to
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithdrawDelegationReward(delegatorAddr, validatorAddr, withdrawAddr sdk.AccAddress)
|
||||||
|
height = GetHeight()
|
||||||
|
|
||||||
|
// get all distribution scenarios
|
||||||
|
pool = stake.GetPool()
|
||||||
|
global = GetGlobal()
|
||||||
|
delInfo = GetDelegationDistInfo(delegatorAddr,
|
||||||
|
validatorAddr)
|
||||||
|
valInfo = GetValidatorDistInfo(validatorAddr)
|
||||||
|
validator = GetValidator(validatorAddr)
|
||||||
|
|
||||||
|
global, withdraw = delInfo.WithdrawRewards(global, valInfo, height, pool.BondedTokens,
|
||||||
|
validator.Tokens, validator.DelegatorShares, validator.Commission)
|
||||||
|
|
||||||
|
SetGlobal(global)
|
||||||
|
AddCoins(withdrawAddr, withdraw.TruncateDecimal())
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## TxWithdrawValidatorRewardsAll
|
||||||
|
|
||||||
|
When a validator wishes to withdraw their rewards it must send
|
||||||
|
`TxWithdrawValidatorRewardsAll`. Note that parts of this transaction logic are also
|
||||||
|
triggered each with any change in individual delegations, such as an unbond,
|
||||||
|
redelegation, or delegation of additional tokens to a specific validator. This
|
||||||
|
transaction withdraws the validators commission fee, as well as any rewards
|
||||||
|
earning on their self-delegation.
|
||||||
|
|
||||||
|
```
|
||||||
|
type TxWithdrawValidatorRewardsAll struct {
|
||||||
|
operatorAddr sdk.AccAddress // validator address to withdraw from
|
||||||
withdrawAddr sdk.AccAddress // address to make the withdrawal to
|
withdrawAddr sdk.AccAddress // address to make the withdrawal to
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithdrawalValidator(ownerAddr, withdrawAddr sdk.AccAddress)
|
func WithdrawValidatorRewardsAll(operatorAddr, withdrawAddr sdk.AccAddress)
|
||||||
|
|
||||||
// update the delegator adjustment factors and also withdrawal delegation fees
|
height = GetHeight()
|
||||||
entitlement = GetDelegatorEntitlement(ownerAddr)
|
|
||||||
|
|
||||||
// update the validator adjustment factors for commission
|
|
||||||
ValDistr = GetValidatorDistribution(ownerAddr.ValidatorAddr)
|
|
||||||
pcs = GetPowerChanges(ValDistr.CommissionWithdrawalHeight)
|
|
||||||
for pc = range pcs
|
|
||||||
pc.ProcessPowerChangeCommission()
|
|
||||||
|
|
||||||
// withdrawal validator commission rewards
|
|
||||||
global = GetGlobal()
|
global = GetGlobal()
|
||||||
pool = GetPool()
|
pool = GetPool()
|
||||||
ValDistr = GetValidatorDistribution(delegation.ValidatorAddr)
|
ValInfo = GetValidatorDistInfo(delegation.ValidatorAddr)
|
||||||
validator = GetValidator(delegation.ValidatorAddr)
|
validator = GetValidator(delegation.ValidatorAddr)
|
||||||
|
|
||||||
scenerio1 = NewCommissionFromGlobalPool(validator,
|
// withdraw self-delegation
|
||||||
pool, global, ValDistr)
|
withdraw = GetDelegatorRewardsAll(validator.OperatorAddr, height)
|
||||||
scenerio2 = CommissionFromProposerPool(validator, ValDistr)
|
|
||||||
entitlement += scenerio1.WithdrawalEntitlement()
|
// withdrawal validator commission rewards
|
||||||
entitlement += scenerio2.WithdrawalEntitlement()
|
global, commission = valInfo.WithdrawCommission(global, valInfo, height, pool.BondedTokens,
|
||||||
|
validator.Tokens, validator.Commission)
|
||||||
|
withdraw += commission
|
||||||
|
SetGlobal(global)
|
||||||
|
|
||||||
|
AddCoins(withdrawAddr, withdraw.TruncateDecimal())
|
||||||
|
```
|
||||||
|
|
||||||
AddCoins(withdrawAddr, totalEntitlment.TruncateDecimal())
|
## Common calculations
|
||||||
|
|
||||||
func (pc PowerChange) ProcessPowerChangeCommission()
|
### Update total validator accum
|
||||||
|
|
||||||
// get the historical scenarios
|
The total amount of validator accum must be calculated in order to determine
|
||||||
scenario1 = pc.CommissionFromGlobalPool()
|
the amount of pool tokens which a validator is entitled to at a particular
|
||||||
scenario2 = pc.CommissionFromProposerPool()
|
block. The accum is always additive to the existing accum. This term is to be
|
||||||
|
updated each time rewards are withdrawn from the system.
|
||||||
|
|
||||||
// process the adjustment factors
|
```
|
||||||
scenario1.UpdateAdjustmentForPowerChange(pc.Height)
|
func (g Global) UpdateTotalValAccum(height int64, totalBondedTokens Dec) Global
|
||||||
scenario2.UpdateAdjustmentForPowerChange(pc.Height)
|
blocks = height - g.TotalValAccumUpdateHeight
|
||||||
|
g.TotalValAccum += totalDelShares * blocks
|
||||||
|
g.TotalValAccumUpdateHeight = height
|
||||||
|
return g
|
||||||
```
|
```
|
||||||
|
|
||||||
## Common Calculations
|
### Update validator's accums
|
||||||
|
|
||||||
### Distribution scenario
|
The total amount of delegator accum must be updated in order to determine the
|
||||||
|
amount of pool tokens which each delegator is entitled to, relative to the
|
||||||
|
other delegators for that validator. The accum is always additive to
|
||||||
|
the existing accum. This term is to be updated each time a
|
||||||
|
withdrawal is made from a validator.
|
||||||
|
|
||||||
A common form of abstracted calculations exists between validators and
|
```
|
||||||
delegations attempting to withdrawal their rewards, either from `Global.Pool`
|
func (vi ValidatorDistInfo) UpdateTotalDelAccum(height int64, totalDelShares Dec) ValidatorDistInfo
|
||||||
or from `ValidatorDistribution.ProposerPool`. With the following interface
|
blocks = height - vi.TotalDelAccumUpdateHeight
|
||||||
fulfilled the entitled fees for the various scenarios can be calculated.
|
vi.TotalDelAccum += totalDelShares * blocks
|
||||||
|
vi.TotalDelAccumUpdateHeight = height
|
||||||
```golang
|
return vi
|
||||||
type DistributionScenario interface {
|
|
||||||
DistributorTokens() DecCoins // current tokens from distributor
|
|
||||||
DistributorCumulativeTokens() DecCoins // total tokens ever received
|
|
||||||
DistributorPrevReceivedTokens() DecCoins // last value of tokens received
|
|
||||||
DistributorShares() sdk.Dec // current shares
|
|
||||||
DistributorPrevShares() sdk.Dec // shares last block
|
|
||||||
|
|
||||||
RecipientAdjustment() sdk.Dec
|
|
||||||
RecipientShares() sdk.Dec // current shares
|
|
||||||
RecipientPrevShares() sdk.Dec // shares last block
|
|
||||||
|
|
||||||
ModifyAdjustments(withdrawal sdk.Dec) // proceedure to modify adjustment factors
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Entitled reward from distribution scenario
|
### Global pool to validator pool
|
||||||
|
|
||||||
The entitlement to the distributor's tokens held can be accounted for lazily.
|
Every time a validator or delegator executes a withdrawal or the validator is
|
||||||
To begin this calculation we must determine the recipient's _simple pool_ and
|
the proposer and receives new tokens, the relevant validator must move tokens
|
||||||
_projected pool_. The simple pool represents a lazy accounting of what a
|
from the passive global pool to their own pool. It is at this point that the
|
||||||
recipient's entitlement to the distributor's tokens would be if all recipients
|
commission is withdrawn
|
||||||
for that distributor had static shares (equal to the current shares), and no
|
|
||||||
recipients had ever withdrawn their entitled rewards. The projected pool
|
|
||||||
represents the anticipated recipient's entitlement to the distributors tokens
|
|
||||||
based on the current blocks token input (for example fees reward received) to
|
|
||||||
the distributor, and the distributor's tokens and shares of the previous block
|
|
||||||
assuming that neither had changed in the current block. Using the simple and
|
|
||||||
projected pools we can determine all cumulative changes which have taken place
|
|
||||||
outside of the recipient and adjust the recipient's _adjustment factor_ to
|
|
||||||
account for these changes and ultimately keep track of the correct entitlement
|
|
||||||
to the distributors tokens.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
func (d DistributionScenario) RecipientCount(height int64) sdk.Dec
|
func (vi ValidatorDistInfo) TakeAccum(g Global, height int64, totalBonded, vdTokens, commissionRate Dec) (
|
||||||
return v.RecipientShares() * height
|
vi ValidatorDistInfo, g Global)
|
||||||
|
|
||||||
func (d DistributionScenario) GlobalCount(height int64) sdk.Dec
|
g.UpdateTotalValAccum(height, totalBondedShares)
|
||||||
return d.DistributorShares() * height
|
|
||||||
|
|
||||||
func (d DistributionScenario) SimplePool() DecCoins
|
|
||||||
return d.RecipientCount() / d.GlobalCount() * d.DistributorCumulativeTokens
|
|
||||||
|
|
||||||
func (d DistributionScenario) ProjectedPool(height int64) DecCoins
|
|
||||||
return d.RecipientPrevShares() * (height-1)
|
|
||||||
/ (d.DistributorPrevShares() * (height-1))
|
|
||||||
* d.DistributorCumulativeTokens
|
|
||||||
+ d.RecipientShares() / d.DistributorShares()
|
|
||||||
* d.DistributorPrevReceivedTokens()
|
|
||||||
```
|
|
||||||
|
|
||||||
The `DistributionScenario` _adjustment_ terms account for changes in
|
|
||||||
recipient/distributor shares and recipient withdrawals. The adjustment factor
|
|
||||||
must be modified whenever the recipient withdraws from the distributor or the
|
|
||||||
distributor's/recipient's shares are changed.
|
|
||||||
- When the shares of the recipient is changed the adjustment factor is
|
|
||||||
increased/decreased by the difference between the _simple_ and _projected_
|
|
||||||
pools. In other words, the cumulative difference in the shares if the shares
|
|
||||||
has been the new shares as opposed to the old shares for the entire duration of
|
|
||||||
the blockchain up the previous block.
|
|
||||||
- When a recipient makes a withdrawal the adjustment factor is increased by the
|
|
||||||
withdrawal amount.
|
|
||||||
|
|
||||||
```
|
|
||||||
func (d DistributionScenario) UpdateAdjustmentForPowerChange(height int64)
|
|
||||||
simplePool = d.SimplePool()
|
|
||||||
projectedPool = d.ProjectedPool(height)
|
|
||||||
AdjustmentChange = simplePool - projectedPool
|
|
||||||
if AdjustmentChange > 0
|
|
||||||
d.ModifyAdjustments(AdjustmentChange)
|
|
||||||
|
|
||||||
func (d DistributionScenario) WithdrawalEntitlement() DecCoins
|
|
||||||
entitlement = d.SimplePool() - d.RecipientAdjustment()
|
|
||||||
d.ModifyAdjustments(entitlement)
|
|
||||||
return entitlement
|
|
||||||
```
|
|
||||||
|
|
||||||
### Distribution scenarios
|
|
||||||
|
|
||||||
Note that the distribution scenario structures are found in `state.md`.
|
|
||||||
|
|
||||||
#### Delegation's entitlement to Global.Pool
|
|
||||||
|
|
||||||
For delegations (including validator's self-delegation) all fees from fee pool
|
|
||||||
are subject to commission rate from the owner of the validator. The global
|
|
||||||
shares should be taken as true number of global bonded shares. The recipients
|
|
||||||
shares should be taken as the bonded tokens less the validator's commission.
|
|
||||||
|
|
||||||
```
|
|
||||||
type DelegationFromGlobalPool struct {
|
|
||||||
DelegationShares sdk.Dec
|
|
||||||
ValidatorCommission sdk.Dec
|
|
||||||
ValidatorBondedTokens sdk.Dec
|
|
||||||
ValidatorDelegatorShareExRate sdk.Dec
|
|
||||||
PoolBondedTokens sdk.Dec
|
|
||||||
Global Global
|
|
||||||
ValDistr ValidatorDistribution
|
|
||||||
DelDistr DelegatorDistribution
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d DelegationFromGlobalPool) DistributorTokens() DecCoins
|
|
||||||
return d.Global.Pool
|
|
||||||
|
|
||||||
func (d DelegationFromGlobalPool) DistributorCumulativeTokens() DecCoins
|
|
||||||
return d.Global.EverReceivedPool
|
|
||||||
|
|
||||||
func (d DelegationFromGlobalPool) DistributorPrevReceivedTokens() DecCoins
|
|
||||||
return d.Global.PrevReceivedPool
|
|
||||||
|
|
||||||
func (d DelegationFromGlobalPool) DistributorShares() sdk.Dec
|
// update the validators pool
|
||||||
return d.PoolBondedTokens
|
blocks = height - vi.GlobalWithdrawalHeight
|
||||||
|
vi.GlobalWithdrawalHeight = height
|
||||||
func (d DelegationFromGlobalPool) DistributorPrevShares() sdk.Dec
|
accum = blocks * vdTokens
|
||||||
return d.Global.PrevBondedTokens
|
withdrawalTokens := g.Pool * accum / g.TotalValAccum
|
||||||
|
commission := withdrawalTokens * commissionRate
|
||||||
func (d DelegationFromGlobalPool) RecipientShares() sdk.Dec
|
|
||||||
return d.DelegationShares * d.ValidatorDelegatorShareExRate() *
|
|
||||||
d.ValidatorBondedTokens() * (1 - d.ValidatorCommission)
|
|
||||||
|
|
||||||
func (d DelegationFromGlobalPool) RecipientPrevShares() sdk.Dec
|
|
||||||
return d.DelDistr.PrevTokens
|
|
||||||
|
|
||||||
func (d DelegationFromGlobalPool) RecipientAdjustment() sdk.Dec
|
|
||||||
return d.DelDistr.Adjustment
|
|
||||||
|
|
||||||
func (d DelegationFromGlobalPool) ModifyAdjustments(withdrawal sdk.Dec)
|
|
||||||
d.ValDistr.Adjustment += withdrawal
|
|
||||||
d.DelDistr.Adjustment += withdrawal
|
|
||||||
d.global.Adjustment += withdrawal
|
|
||||||
SetValidatorDistribution(d.ValDistr)
|
|
||||||
SetDelegatorDistribution(d.DelDistr)
|
|
||||||
SetGlobal(d.Global)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Delegation's entitlement to ValidatorDistribution.ProposerPool
|
|
||||||
|
|
||||||
Delegations (including validator's self-delegation) are still subject
|
|
||||||
commission on the rewards gained from the proposer pool. Global shares in this
|
|
||||||
context is actually the validators total delegations shares. The recipient's
|
|
||||||
shares is taken as the effective delegation shares less the validator's
|
|
||||||
commission.
|
|
||||||
|
|
||||||
```
|
|
||||||
type DelegationFromProposerPool struct {
|
|
||||||
DelegationShares sdk.Dec
|
|
||||||
ValidatorCommission sdk.Dec
|
|
||||||
ValidatorDelegatorShares sdk.Dec
|
|
||||||
ValDistr ValidatorDistribution
|
|
||||||
DelDistr DelegatorDistribution
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d DelegationFromProposerPool) DistributorTokens() DecCoins
|
|
||||||
return d.ValDistr.ProposerPool
|
|
||||||
|
|
||||||
func (d DelegationFromProposerPool) DistributorCumulativeTokens() DecCoins
|
|
||||||
return d.ValDistr.EverReceivedProposerReward
|
|
||||||
|
|
||||||
func (d DelegationFromProposerPool) DistributorPrevReceivedTokens() DecCoins
|
|
||||||
return d.ValDistr.PrevReceivedProposerReward
|
|
||||||
|
|
||||||
func (d DelegationFromProposerPool) DistributorShares() sdk.Dec
|
|
||||||
return d.ValidatorDelegatorShares
|
|
||||||
|
|
||||||
func (d DelegationFromProposerPool) DistributorPrevShares() sdk.Dec
|
|
||||||
return d.ValDistr.PrevDelegatorShares
|
|
||||||
|
|
||||||
func (d DelegationFromProposerPool) RecipientShares() sdk.Dec
|
|
||||||
return d.DelegationShares * (1 - d.ValidatorCommission)
|
|
||||||
|
|
||||||
func (d DelegationFromProposerPool) RecipientPrevShares() sdk.Dec
|
|
||||||
return d.DelDistr.PrevShares
|
|
||||||
|
|
||||||
func (d DelegationFromProposerPool) RecipientAdjustment() sdk.Dec
|
|
||||||
return d.DelDistr.AdjustmentProposer
|
|
||||||
|
|
||||||
func (d DelegationFromProposerPool) ModifyAdjustments(withdrawal sdk.Dec)
|
|
||||||
d.ValDistr.AdjustmentProposer += withdrawal
|
|
||||||
d.DelDistr.AdjustmentProposer += withdrawal
|
|
||||||
SetValidatorDistribution(d.ValDistr)
|
|
||||||
SetDelegatorDistribution(d.DelDistr)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Validators's commission entitlement to Global.Pool
|
|
||||||
|
|
||||||
Similar to a delegator's entitlement, but with recipient shares based on the
|
|
||||||
commission portion of bonded tokens.
|
|
||||||
|
|
||||||
```
|
|
||||||
type CommissionFromGlobalPool struct {
|
|
||||||
ValidatorBondedTokens sdk.Dec
|
|
||||||
ValidatorCommission sdk.Dec
|
|
||||||
PoolBondedTokens sdk.Dec
|
|
||||||
Global Global
|
|
||||||
ValDistr ValidatorDistribution
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c CommissionFromGlobalPool) DistributorTokens() DecCoins
|
|
||||||
return c.Global.Pool
|
|
||||||
|
|
||||||
func (c CommissionFromGlobalPool) DistributorCumulativeTokens() DecCoins
|
|
||||||
return c.Global.EverReceivedPool
|
|
||||||
|
|
||||||
func (c CommissionFromGlobalPool) DistributorPrevReceivedTokens() DecCoins
|
|
||||||
return c.Global.PrevReceivedPool
|
|
||||||
|
|
||||||
func (c CommissionFromGlobalPool) DistributorShares() sdk.Dec
|
g.TotalValAccum -= accumm
|
||||||
return c.PoolBondedTokens
|
vi.PoolCommission += commission
|
||||||
|
vi.PoolCommissionFree += withdrawalTokens - commission
|
||||||
|
g.Pool -= withdrawalTokens
|
||||||
|
|
||||||
func (c CommissionFromGlobalPool) DistributorPrevShares() sdk.Dec
|
return vi, g
|
||||||
return c.Global.PrevBondedTokens
|
|
||||||
|
|
||||||
func (c CommissionFromGlobalPool) RecipientShares() sdk.Dec
|
|
||||||
return c.ValidatorBondedTokens() * c.ValidatorCommission
|
|
||||||
|
|
||||||
func (c CommissionFromGlobalPool) RecipientPrevShares() sdk.Dec
|
|
||||||
return c.ValDistr.PrevBondedTokens * c.ValidatorCommission
|
|
||||||
|
|
||||||
func (c CommissionFromGlobalPool) RecipientAdjustment() sdk.Dec
|
|
||||||
return c.ValDistr.Adjustment
|
|
||||||
|
|
||||||
func (c CommissionFromGlobalPool) ModifyAdjustments(withdrawal sdk.Dec)
|
|
||||||
c.ValDistr.Adjustment += withdrawal
|
|
||||||
c.Global.Adjustment += withdrawal
|
|
||||||
SetValidatorDistribution(c.ValDistr)
|
|
||||||
SetGlobal(c.Global)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Validators's commission entitlement to ValidatorDistribution.ProposerPool
|
|
||||||
|
|
||||||
Similar to a delegators entitlement to the proposer pool, but with recipient
|
### Delegation reward withdrawal
|
||||||
shares based on the commission portion of the total delegator shares.
|
|
||||||
|
For delegations (including validator's self-delegation) all rewards from reward
|
||||||
|
pool have already had the validator's commission taken away.
|
||||||
|
|
||||||
```
|
```
|
||||||
type CommissionFromProposerPool struct {
|
func (di DelegatorDistInfo) WithdrawRewards(g Global, vi ValidatorDistInfo,
|
||||||
ValidatorDelegatorShares sdk.Dec
|
height int64, totalBonded, vdTokens, totalDelShares, commissionRate Dec) (
|
||||||
ValidatorCommission sdk.Dec
|
di DelegatorDistInfo, g Global, withdrawn DecCoins)
|
||||||
ValDistr ValidatorDistribution
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c CommissionFromProposerPool) DistributorTokens() DecCoins
|
vi.UpdateTotalDelAccum(height, totalDelShares)
|
||||||
return c.ValDistr.ProposerPool
|
g = vi.TakeAccum(g, height, totalBonded, vdTokens, commissionRate)
|
||||||
|
|
||||||
|
blocks = height - di.WithdrawalHeight
|
||||||
|
di.WithdrawalHeight = height
|
||||||
|
accum = delegatorShares * blocks
|
||||||
|
|
||||||
|
withdrawalTokens := vi.Pool * accum / vi.TotalDelAccum
|
||||||
|
vi.TotalDelAccum -= accum
|
||||||
|
|
||||||
func (c CommissionFromProposerPool) DistributorCumulativeTokens() DecCoins
|
vi.Pool -= withdrawalTokens
|
||||||
return c.ValDistr.EverReceivedProposerReward
|
vi.TotalDelAccum -= accum
|
||||||
|
return di, g, withdrawalTokens
|
||||||
|
|
||||||
func (c CommissionFromProposerPool) DistributorPrevReceivedTokens() DecCoins
|
|
||||||
return c.ValDistr.PrevReceivedProposerReward
|
|
||||||
|
|
||||||
func (c CommissionFromProposerPool) DistributorShares() sdk.Dec
|
|
||||||
return c.ValidatorDelegatorShares
|
|
||||||
|
|
||||||
func (c CommissionFromProposerPool) DistributorPrevShares() sdk.Dec
|
|
||||||
return c.ValDistr.PrevDelegatorShares
|
|
||||||
|
|
||||||
func (c CommissionFromProposerPool) RecipientShares() sdk.Dec
|
|
||||||
return c.ValidatorDelegatorShares * (c.ValidatorCommission)
|
|
||||||
|
|
||||||
func (c CommissionFromProposerPool) RecipientPrevShares() sdk.Dec
|
|
||||||
return c.ValDistr.PrevDelegatorShares * (c.ValidatorCommission)
|
|
||||||
|
|
||||||
func (c CommissionFromProposerPool) RecipientAdjustment() sdk.Dec
|
|
||||||
return c.ValDistr.AdjustmentProposer
|
|
||||||
|
|
||||||
func (c CommissionFromProposerPool) ModifyAdjustments(withdrawal sdk.Dec)
|
|
||||||
c.ValDistr.AdjustmentProposer += withdrawal
|
|
||||||
SetValidatorDistribution(c.ValDistr)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Validator commission withdrawal
|
||||||
|
|
||||||
|
Commission is calculated each time rewards enter into the validator.
|
||||||
|
|
||||||
|
```
|
||||||
|
func (vi ValidatorDistInfo) WithdrawCommission(g Global, height int64,
|
||||||
|
totalBonded, vdTokens, commissionRate Dec) (
|
||||||
|
vi ValidatorDistInfo, g Global, withdrawn DecCoins)
|
||||||
|
|
||||||
|
g = vi.TakeAccum(g, height, totalBonded, vdTokens, commissionRate)
|
||||||
|
|
||||||
|
withdrawalTokens := vi.PoolCommission
|
||||||
|
vi.PoolCommission = 0
|
||||||
|
|
||||||
|
return vi, g, withdrawalTokens
|
||||||
|
```
|
||||||
|
|
Loading…
Reference in New Issue