Staking - Second Type of Staking Contracts
Distributing rewards to a specific group of stakeholders of the protocol

1. Introduction

The StakingRewards allows to stake an ERC20 token to receive as a reward another ERC20 token. The contract used at Angle was forked from SetProtocol, some functions were added to it by Angle Core team.
This contract is the second type of contract used by Angle Protocol to distribute rewards. It is the staking contract used on other chains to incentivize LPs of pools involving agEUR for instance. Contrarily to the first type of staking contract, boosts do not apply for people staking in this contract and owning veANGLE tokens.
The contract is managed by the AngleDistributor contract and implements the IStakingRewards interface. Note that PerpetualManager contracts also implement this interface which means that it is the logic of this contract that is used to distribute rewards to HAs.
In very few terms, the way the contract works is that it stores a rewardRate that is a reward per second given to the staking contract. The way the reward is distributed is that it is split among all the stakers in the contract depending on how much they staked.
The rewardRate is computed based on the reward given by the AngleDistributor and on the rewardsDuration parameter of the contract. The rewardsDuration parameter has currently been set to a week for all staking contracts.
These contracts work with any token given as a reward. They work however with only one reward token.

2. Contract Details


Implements IStakingRewards, ReentrancyGuard and AccessControl.


References to Contracts

  • rewardToken : Token used as a reward
  • stakingToken: ERC20 token used for staking
  • rewardsDistribution: Rewards Distribution contract associated to this staking contract
  • stakingBase: Base of the staked token. It is mostly going to be useful in the case of sanTokens which are not in base 10^18

Staking Parameters

  • periodFinish: Time at which rewards distribution ends for this staking contract. It is updated each time new rewards are given to the contract
  • rewardRate: Reward per second given to the staking contract, split among the staked tokens
  • rewardsDuration: Duration of the reward distribution
  • lastUpdateTime: Last time rewardPerTokenStored was updated
  • rewardPerTokenStored: Helps to compute the amount earned by someone. Cumulates rewards accumulated for one token since the beginning


  • userRewardPerTokenPaid: Stores for each account the rewardPerToken: we do the difference between the current and the old value to compute what has been earned by an account
  • rewards: Stores for each account the accumulated rewards

Access Control

We did not introduce in this contract OpenZeppelin's Access Control logic. The reason was that we would just have needed a REWARD_DISTRIBUTOR_ROLE and that defining a simple modifier is easier.

3. Key Mechanisms & Concepts

SetProtocol and Synthetix Functions

Most of key functions of this contract are detailed on Synthetix website. Some were slightly modified to take into account the fact that the staked token could have a different base than 10^18
StakingRewards - Synthetix System Documentation

Functions Added By Angle Core Team

The following functions were added to the base version of the contract forked from SetProtocol:


function stakeOnBehalf(uint256 amount, address onBehalf) external;
Allows to stake on behalf of another address, meaning the staking tokens are brought by the msg.sender but the staking rewards go to the onBehalf address
  • amount: Amount to stake
  • onBehalf: Address to stake onBehalf of


function setNewRewardsDistributor(address _rewardsDistribution) external;
Changes the rewards distributor associated to this contract. This function can only be called by the AngleDistributor contract and the governor. Before this function is called by the current rewardsDistribution address, a compatibility check is made to see if the reward token associated to the new reward distribution address is the same.