--- eip: 4000 title: ERC-4000 Staking-Reward Pool Standard author: Dotta <https://twitter.com/cryppadotta>, vfat <https://twitter.com/vfat12>, DkNinja <https://twitter.com/DkNinja21>, ... you? type: Standards Track category: ERC status: Idea created: 2021-04-15 --- # ERC-4000 Staking-Reward Pool Standard | eip | 4000 (*unofficial) | | ------ | ---- | | title | ERC-4000 Staking-Reward Pool Standard | | authors | [Dotta](https://twitter.com/cryppadotta), [vfat](https://twitter.com/vfat12), [DkNinja](https://twitter.com/DkNinja21)| |type | Standards Track | |category| ERC | |status | Idea | |created | 2021-04-15 | ## :sparkles: Join the Discussion: :sparkles: - [ERC-4000 Staking-Reward Pool Standard (request for comments) - EIPs - Fellowship of Ethereum Magicians](https://ethereum-magicians.org/t/erc-4000-staking-reward-pool-standard-request-for-comments/6004) > ## Context > > Below is a draft EIP for a staking-reward pool standard. The goal is to define an easy-to-use convention for staking-reward pools. > > Staking-reward pools are a common way for projects to incentivize desired behaviors like providing liquidity, bonding, token distribution, or loan origination. > > The popularity of the staking-reward pool mechanism can be seen on websites like [vfat.tools](https://vfat.tools/) and [apy.vision](https://apy.vision/) which track hundreds of reward pools across the ecosystem. > > Nearly every new project launches reward pool contracts and nearly every project implements the interface differently. > > The standard below is based on the author's interactions with hundreds of "Masterchef-" and "Synthetix-"style staking-rewards pools. > > Adoption of a standard for staking-reward pools will benefit the ecosystem by composibility, similar to that seen with ERC20 tokens. > > ## Request for Comments > > The authors request your comments and feedback on this document before submitting for official EIP consideration in late-April 2021. > > Blockquotes indicate thoughts and open questions and will be removed from the final EIP draft > [name=Dotta] > April 15, 2021 ## Simple Summary A standard interface for staking pools with rewards. ## Abstract The following standard allows for the implementation of a standard API for staking-rewards pools within smart contracts. This standard provides basic functionality to stake tokens in smart contracts with multiple pools and inspect the rewards for doing so. ## Motivation Staking-reward pools are a common way for projects to incentivize desired behaviors such as providing liquidity, bonding, token distribution, or loan origination. This document specifies a standard interface that allows any staking-reward pools on Ethereum to be re-used by other applications such as wallets, user interfaces, yield aggregators, and other smart contracts. ## Specification ## Pool ### Methods **NOTES**: - The following specifications use syntax from Solidity `0.8.3` (or above) #### poolLength Returns the total number of pools ``` js function poolLength() public view returns (uint256) ``` #### poolInfo Returns the information about a pool. ```js poolInfo(uint256 poolIdx) public view returns ( address stakingToken, address rewardToken, uint256 stakedAmount, uint256 rewardAmount, uint256 rewardPerBlock, uint256 startBlock ) ``` Where: * `stakingToken` is the address of the token to be staked in `poolIdx` * `rewardToken` is the address of the token which is rewarded for staking in `poolIdx` * `stakedAmount` is the total number of tokens currently staked in `poolIdx` * `rewardAmount` is the total number of tokens currently allocated as rewards to the pool at `poolIdx` * `rewardPerBlock` is the sum total of reward tokens accrued to all stakers in `poolIdx` for the current block * `startBlock` is the first block number at which rewards will accrue for the pool at `poolIdx` #### userInfo Returns the information about `userAddress` at `poolIdx` ```js userInfo(uint256 poolIdx, address userAddress) public view returns ( uint256 stakedAmount, uint256 rewardAmount ) ``` Where: * `stakedAmount` is the number of tokens `userAddress` has staked in `poolIdx` * `rewardAmount` is the number of tokens credited to `userAddress` in `poolIdx` that have not yet been withdrawn #### rewardForBlock Returns the sum total of reward tokens accrued to all stakers in `poolIdx` at `blockNum`. OPTIONAL - This method can be used to improve usability, but interfaces and other contracts MUST NOT expect these values to be present. ```js rewardForBlock(uint256 poolIdx, uint256 blockNum) public view returns (uint256) ``` *Note* - The purpose of this optional method is to allow for calculation of non-linear reward accrual curves. #### deposit * Transfers `amount` of staking tokens from the calling user to the pool at `poolIdx` and * MUST fire the `Deposit` event and * Transfers all claimable reward tokens from the pool at `poolIdx` to the calling user and * MUST fire the `Claim` event. ```js deposit(uint256 poolIdx, uint256 amount) public nonpayable ``` *Note* - `amount` of 0 MUST be allowed, which has the effect of withdrawing all claimable rewards. #### withdraw * Transfers `amount` of staking tokens from the pool at `poolIdx` to the calling user and * MUST fire the `Withdraw` event and * Transfers all claimable reward tokens from the pool at `poolIdx` to the calling user and * MUST fire the `Claim` event. ```js withdraw(uint256 poolIdx, uint256 amount) public nonpayable ``` *Note* - `amount` of 0 MUST be allowed, which has the effect of withdrawing all claimable rewards. #### claim * Transfers all claimable reward tokens from the pool at `poolIdx` to the calling user and * MUST fire the `Claim` event. ```js claim(uint256 poolIdx) public nonpayable ``` ### Events #### Deposit MUST trigger when staking tokens are deposited, including zero value deposits. ```js event Deposit(address indexed user, uint256 indexed poolIdx, uint256 stakeAmount); ``` Where: * `user` is the address of the depositing user * `poolIdx` is the index of the pool * `stakeAmount` is the amount of the stake token deposited #### Withdraw MUST trigger when staking tokens are withdrawn, including zero value withdrawals. ```js event Withdraw(address indexed user, uint256 indexed poolIdx, uint256 stakeAmount); ``` Where: * `user` is the address of the depositing user * `poolIdx` is the index of the pool * `stakeAmount` is the amount of the stake token withdrawn #### Claim MUST trigger when reward tokens are withdrawn, including zero value withdrawals. ```js event Claim(address indexed user, uint256 indexed poolIdx, uint256 rewardAmount); ``` Where: * `user` is the address of the depositing user * `poolIdx` is the index of the pool * `rewardAmount` is the amount of the reward token withdrawn ## Open Questions > > Q: Should we specify ERC20 as part of this standard? > A: Probably not because this ERC might be useful for other sorts of tokens e.g. ERC-721 NFTs > > Q: What about `allocPoint`, `getMultiplier`, `lastRewardBlock`, `rewardDebt` etc? > A: While commonly exposed in "Masterchef" contracts, these values are internals that don't need to be exposed in the standard. A contract can expose them if they desire. > > Q: What about a global `rewardPerBlock` that shows the total emission per block for the entire contract? > A: This standard allows for differnt reward tokens to be emitted for each pool, so a global `rewardPerBlock` would not be useful > > Q: What about vesting and locking both stake and rewards? > A: This standard doesn't address those issues. > > Q: What about legacy staking-reward pool contracts that don't conform to this standard? > A: It should be straightforward to write a Masterchef-to-ERC-4000 proxy-adapter contract (cf. multicall) that adapts the values for any standard Masterchef- or Synthetix-style pool. ## Implementation #### Example implementations are available at - TODO - any takers? ## History Historical links related to this standard: - [EIP-900: Simple Staking Interface (DRAFT)](https://eips.ethereum.org/EIPS/eip-900) is an earlier attempt at defining a staking interface - [Masterchef TODO](#TODO) - _What was the very first Masterchef contract? If you know, please comment here_ ## Copyright Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).