Skip to main content

How Does It Work?

Reward Streams operates in two modes of rewards distribution: staking and balance-tracking. Each mode has a separate contract implementation.

Reward Streams Mechanism

Tracking Reward Distribution

The balance-tracking TrackingRewardStreams implementation inherits from the BaseRewardStreams contract. It defines the IBalanceTracker.balanceTrackerHook function, which is required to be called on every transfer of the rewarded token if a user opted in for the hook to be called. Provided that the account opted in for their balance to be tracked, on every balance change of the account which is a result of the deposit, withdrawal, shares transfer etc., the credit vault contract calls the balanceTrackerHook function. Once the hook is called, the contract updates the account's balance and all the enabled rewards distribution data in order to track the rewards accrual.

The already deployed TrackingRewardStreams (referred to as BalanceTracker in the deployed contract addresses section) can be used by any other newly developed ERC20-like contract. Assuming that one wants to embed the reward distribution mechanism into their own contract, it is enough that the token contract calls the balanceTrackerHook function on every balance change of the account. For inspiration, one can take a look at the mock ERC20 token contract here.

Staking Reward Distribution

The staking StakingRewardStreams implementation also inherits from the BaseRewardStreams contract. It defines two functions: stake and unstake, which are used to stake and unstake the rewarded token. This contract has been audited but haven't been yet deployed. If you are interested in using it, please reach out to us so we can deploy it for you.

Internal Mechanics

In both modes, each distributor contract defines an EPOCH_DURATION constant, which is the duration of a single epoch. This duration cannot be less than 1 week and more than 10 weeks. The currently deployed TrackingRewardStreams instance used by the EVK vaults has an epoch duration of 2 weeks.

When registering a new reward stream for the rewarded token, one must specify the startEpoch number when the new stream will come into effect. To protect users from obvious mistakes, the distributor contract enforces a soft requirement that ensures the startEpoch is not more than 5 epochs into the future. Moreover, one must specify the rewardAmounts array, which instructs the contract how much reward one wants to distribute in each epoch starting from startEpoch. The rewardAmounts array must have a length of at most 25 for one function call.

If rewarded epochs of multiple reward streams overlap, the amounts will be combined and the effective distribution will be the sum of the amounts in the overlapping epochs.

Permissionless Reward

Unlike other permissioned distributors based on the billion-dollar algorithm, Reward Streams distributors do not have an owner or admin meaning that none of the assets can be directly recovered from them. This property is required in order for the system to work in a permissionless manner, allowing anyone to transfer rewards token to a distributor and register a new reward stream. The drawback of this approach is that reward tokens may get lost if nobody earns them at the given moment (i.e. nobody stakes required assets or nobody enabled earning those rewards). In order to prevent reward tokens from being lost when nobody earns them at the moment, the rewards get virtually accrued by address(0) and, in exchange for updating given distribution data, are claimable by anyone with use of updateReward function.