As mentioned in the spec, many actions taken by a user will involve redistributing some funds as rewards to "all other stakers". To accomplish this, an algorithm has been developed which works as follows:
Assume n
number of users (denoted as u1, u2, ... un
) have deposited a total amount of CAW denoted as totalDepositedCaw
When an arbitrary user, ui
, removes X
caw from their balance and distributes this amount as rewards to all other users,
the amount added to the account of any arbitrary user (uj
, where j ≠ i
) will be X
multiplied by percentOwnership(uj)
,
where percentOwnership(uj)
is the ratio of the balance of uj
to the total amount of CAW which has been deposited by all users aside from ui
.
percentOwnership(uj) = balanceOf(uj) / (totalDepositedCaw - balanceOf(ui))
The balanceAfterReward
of uj
can be denoted as follows:
balanceAfterReward(uj) = balanceOf(uj) + X * percentOwnership(uj)
i.e.
balanceAfterReward(uj) = balanceOf(uj) + X * balanceOf(uj) / (totalDepositedCaw - balanceOf(ui))
therefore
balanceAfterReward(uj) = balanceOf(uj) * (1 + X / (totalDepositedCaw - balanceOf(ui))
if we refer to the multiplier of the balance before the rewards as r
, where
r = (1 + X / (totalDepositedCaw - balanceOf(ui))
then
balanceAfterReward(uj) = balanceOf(uj) * r
Since each amount distributed as rewards can be different, we can denote each amount as Xn
, and
rn = (1 + Xn / (totalDepositedCawn - balancen(ui))
and therefore
balanceOf(n+1)(uj) = balanceOfn(uj) * rn
...
balanceOf3(uj) = balanceOf2(uj) * r2
balanceOf2(uj) = balanceOf1(uj) * r1
balanceOf1(uj) = balanceOf0(uj) * r0
and by substitution, we can compute balance3
as:
balanceOf3(uj) = balanceOf2(uj) * r2
balanceOf3(uj) = balanceOf1(uj) * r1 * r2
balanceOf3(uj) = balanceOf0(uj) * r0 * r1 * r2
To compute the current value of any user at any time,
we just need to multiply it's initial balance by the product of all r0...rn
.
In the solidity contract, we are only ever interested in the current balance,
so we can persist a value, rewardMultiplern
, which is overwritten with with each reward distribution n
as
rewardMultipliern = rewardMultiplier(n-1) * rn
which is equivalent to
rewardMultiplern = r0 * r1 * ... * rn
and therefore, at any time
balanceOfn(uj) = balanceOf0(uj) * rewardMultiplern
--
The one other piece of this algorithm that needs to be considered is the balance of ui
,
after ui
distributes X
from it's balance, it should receive no part of X
, and must be
overwritten as it's pre-distribution balance minus X
. Since the current balance of each un
is computed by multiplying rewardMultipler
, we must overwrite the initial balance of ui
to be in terms of rewardMultiplern
. Namely,
balanceOf0(ui) = (balanceOfn-1(ui) - Xn) / rewardMultiplern
Since the spec requires several transactions to move funds between users while simultaneously redistributing
rewards to all other stakers, the contract uses this process of overwriting balanceOf0
in terms of rewardMultiplern
anytime a user receives, spends, deposits, or withdraws
any CAW from their balance.
QED
...
...
(p.s. I dedicate this proof to my grlfren, who not only endured me writing it, but also helped)