Note: This article was originally published on our blog in March of 2022 and SushiSwap has since changed the mechanics of their token emissions.
In this smart contract review, we will be digging into the reward mechanisms of SushiSwap's MasterChef. Specifically, we will be looking at how rewards are distributed across pools. This smart contract is one of the most popular in DeFi and is designed to incentivize users for staking their tokens into a protocol. The rewards are typically a native token for protocol that may provide governance rights or fee revenue. You can find the contract code here on the SushiSwap GitHub: MasterChef.sol. We will also be interacting with a MasterChef contract deployed on Ethereum, which you can find at this address: 0xc2EdaD668740f1aA35E4D8f227fB8E17dcA888Cd.
When interacting with the contract, we will be using eth-brownie. Brownie is a Python-based development and testing framework for EVM smart contracts.
There is a V2 of the Masterchef contract that improves upon efficiency and allows for multiple rewards. You can read about the improvements of the V2 contract here: MasterChef V2. The primary reason that we are not looking at V2 is that there is more value locked into the original at the time of writing. We may do a future write up of the improved reward harvesting mechanisms of V2.
Setup
Because this is not a brownie tutorial, I won't go too deep on the setup. I have a brownie project that uses an Infura API key to connect to the Ethereuem Mainnet. I also have a contract interface that uses MasterChef ABI. You can grab the ABI from Etherscan: 0xc2EdaD668740f1aA35E4D8f227fB8E17dcA888Cd.
There are multiple tools for interacting with contracts, you can even execute these functions directly from this implementation's Etherscan page.
Interaction
sushiPerBlock()
In this implementation, there are 100 sushi generated per block. We get to this number by calling the sushiPerBlock()
function and applying the correct decimal place. Sushi token has 18 decimals, so the response of 100000000000000000000
would be 100 tokens.
At the time of writing, one Sushi is worth around $3 and Ethereum block times are averaging about 13 seconds. In hourly terms, there are around 28,000 Sushi, or $84,000, created for participants in this MasterChef contract.
totalAllocPoint()
In order to split out the rewards by pool, we use the concept of allocation points. Each pool has a set number of allocation points and the MasterChef contract maintains a total number of allocations points. This implementation has 822655
allocation points. To get the amount of rewards that a pool would receive, you just divide the pool's allocation points by the total allocations points in the contract.
poolInfo()
To request data from the contract for a specific pool, you will need to provide a pool id to the poolInfo()
function. The pool id will be a number between 0 and the value of poolLength() - 1. Currently, the contract we are working with has 354 pools, so the pool id can range between 0 and 353. The results of this call tell us what token is staked in the pool, how much of the Masterchef rewards are allocated to the pool, when the last rewards were distributed, and how many rewards have been accumulated per share of the pool.
As an example, pool 1 is the USDC/ETH pool. You can check this by taking the LP token address and looking it up on Etherscan: 0x397FF1542f962076d0BFE58eA045FfA2d347ACa0
This pool gets 4185
allocation points, or ~0.5% of the total Sushi rewards. If the hourly amount of rewards is around $84,000, then this pool gets $427 per hour. With 8760 hours in a year, this would be around $3,740,520. The current value locked into this pool is around $200,000,000, and annual rewards divided by the TVL results in about 1.85% annual reward APR. This number is consistent with what we see in the SushiSwap UI, taking into account that we have done a lot of rounding so far.
Disclaimer
We, Digital Opportunities Group, LLC, are not providing investment or other advice. Nothing that we post on Substack should be construed as personalized investment advice or a recommendation that you buy, sell, or hold any security or other investment or that you pursue any investment style or strategy.
Case studies may be included for informational purposes only and are provided as a general overview of our general investment process. We have compiled our research in good faith and use reasonable efforts to include accurate and up-to-date information. In no event should we be responsible or liable for the correctness of any such research or for any damage or lost opportunities resulting from use of our data.
We are not responsible for the content of any third-party websites and we do not endorse the products, services, or investment recommendations described or offered in third-party social media posts and websites.
Nothing we post on Substack should be construed as, and may not be used in connection with, an offer to sell, or a solicitation of an offer to buy or hold, an interest in any security or investment product.