/multi-rewards

A modified version of the SNX staking rewards contract, allowing for multiple reward tokens. Designed for use with Curve.fi liquidity gauges.

Primary LanguagePythonMIT LicenseMIT

multi-rewards

A modified version of the Synthetix staking rewards contract, allowing for multiple rewards tokens. Designed for use with Curve.fi liquidity gauges.

Overview

The MultiRewards contract in this repository enables distribution of multiple reward tokens for staked users. It is a flattened and modified version of the SNX staking rewards contract.

How it Works

As an example, assume we desire users to stake an ERC20 Token Base Token ($BASE). As a reward for staking their token, we may wish to offer users multiple different tokens. For the sake of this example, we'll assume we have two different amount of governance tokens, Reward Token 1 ($ONE) and Reward Token 2 ($TWO), which we want to release over different schedules.

  • We begin by deploying the MultiReward contract with a link to $BASE as our staking token.
  • For both token $ONE and $TWO the contract's Owner calls addReward
    • When calling addReward, Owner also specifies the duration of the reward period (in seconds)
    • The addReward function also authorizes a Distributor to further manage the reward token.
  • To begin the reward period, Distributor will call notifyRewardAmount, which transfers the specified amount of reward tokens from their address to the contract and begins the reward cycle.
  • Users can stake the $BASE token by calling stake, and will then accrue $ONE and $TWO throughout the duration of the rewards period.
  • Users can claim their rewards at any time by calling getReward.
  • Users can also withdraw their $BASE token at any point by calling withdraw. At this point they can still claim any accumulated unclaimed $ONE and $TWO rewards through the getReward endpoint but will not longer accrue rewards.

Considerations

Keep the following in mind when using the MultiReward contract:

  • The duration and amounts of $ONE and $TWO may be different, and the contract will support any number of additional tokens you may wish to provide.
  • The Distributor may update the duration of the reward schedule by calling setRewardsDuration only after the active reward cycle has completed.
  • The Owner may assign a new Distributor to a reward token at any time.
  • Calling exit combines both getReward and withdraw in one endpoint.
  • While the rewards period is active, the contract will automatically update all reward balances anytime most mutative functions are called (stake, withdraw, exit, getReward, or notifyRewardAmount)
  • The Owner may call recoverERC20 to transfer reward tokens, but not the staking token. Claiming rewards may fail if this function drains the balance.
  • In order to transfer ERC20 tokens to the contract, you must first call the approve function on the token's contract and authorize MultiRewards to transfer the correct amount.

Dependencies

Testing

The test suite is broadly split between unit and integration tests.

To run the unit tests:

brownie test tests/unitary

To run the integration tests:

brownie test tests/integration

Deployment

To deploy the contracts, first modify the deployment script to unlock the account you wish to deploy from. Then:

brownie run deploy --network mainnet

License

The smart contract within this repository is forked from Synthetixio/synthetix which is licensed under the MIT License.

This repository is licensed under the MIT License.