Beanstalk is a permissionless fiat stablecoin protocol built on Ethereum.
Technical documentation is a WIP. Current draft is available here.
A comprehensive list of contracts related to Beanstalk is available here.
| Contract | Address |
|---|---|
| Beanstalk | 0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5 |
| Bean | 0xBEA0000029AD1c77D3d5D23Ba2D8893dB9d1Efab |
| Curve BEAN:3CRV Metapool | 0xc9C32cd16Bf7eFB85Ff14e0c8603cc90F6F2eE49 |
| Unripe Bean ERC-20 token | 0x1BEA0050E63e05FBb5D8BA2f10cf5800B6224449 |
| Unripe BEAN:3CRV LP token | 0x1BEA3CcD22F4EBd3d37d731BA31Eeca95713716D |
| Fertilizer ERC-1155 token | 0x402c84de2ce49af88f5e2ef3710ff89bfed36cb6 |
| Fertilizer Admin | 0xfECB01359263C12Aa9eD838F878A596F0064aa6e |
| Fertilizer Implementation | 0x39cdAf9Dc6057Fd7Ae81Aaed64D7A062aAf452fD |
| Beanstalk Price Contract | 0xA57289161FF18D67A68841922264B317170b0b81 |
| Beanstalk Contract Owner (BCM) | 0xa9bA2C40b263843C04d344727b954A545c81D043 |
| Beanstalk Farms Multisig | 0x21DE18B6A8f78eDe6D16C50A167f6B222DC08DF7 |
| Bean Sprout Multisig | 0xb7ab3f0667eFF5e2299d39C23Aa0C956e8982235 |
| BeaNFT Genesis | 0xa755A670Aaf1FeCeF2bea56115E65e03F7722A79 |
| BeaNFT Winter | 0x459895483556dad32526efa461f75e33e458d9e9 |
The Beanstalk smart contract is a multi-facet proxy as it implements EIP-2535. Thus, the Beanstalk contract pulls in functions from a variety of different contracts (called facets in the EIP-2535 documentation) that are all capable of sharing the same state object.
The following are the different facets Beanstalk uses:
The following facets are part of the diamond functionality:
| Contract | Address |
|---|---|
| DiamondCutFacet | 0xDFeFF7592915bea8D040499E961E332BD453C249 |
| DiamondLoupeFacet | 0xB51D5C699B749E0382e257244610039dDB272Da0 |
| OwnershipFacet | 0x5D45283Ff53aabDb93693095039b489Af8b18Cf7 |
The Beanstalk DAO partnered with Immunefi to launch a bug bounty program with rewards up to 1.1M Beans.
You can find the bug bounty program and submit bug reports here.
- clone the repository
- run
cd protocolto enter the protocol repository - run
npm install - run
npx hardhat compile
We elect to use anvil instead of hardhat for local node forking as anvil is considerably faster than hardhat and properly caches the blockchain locally
- ensure you are in the
/protocolrepository - Install Foundry
curl -L https://foundry.paradigm.xyz | bash& reopen terminal - Run
foundryupto ensure latest version - Start a locally forked node with the following command:
anvil --fork-url <FORK_RPC> --fork-block-number <BLOCK_NUMBER> --chain-id 1337For <FORK_RPC>, use an Alchemy or Infura RPC URL.
For <BLOCK_NUMBER>, we currently use 15128715, but you are welcome to use any block after Replant2
It should be very clear if the node starts up properly.
Note: anvil will cache the blockchain provided that BLOCK_NUMBER does NOT change. Given this, we recommend picking a block and sticking to it.
- ensure that you have a localhost
- run
npx hardhat replant --network localhost
- make sure you are in the
protocolrepository - run
npm testto run all coverage tests - run
npx hardhat coverageto run all coverage tests and generate a coverage report
As Beanstalk implements EIP-2535, Beanstalk is upgraded through a diamondCut function call.
There are two different ways a diamondCut can apply code to Beanstalk:
- adding/replacing/removing functions
- Functions being added/replaced are implemented in smart contracts referred to as
facets. Facets are no different than a normal smart contract with callable functions. In order to share a state, Facets can only define 1 internal state variable: TheAppStoragestruct defined inAppStorage.sol.
- Functions being added/replaced are implemented in smart contracts referred to as
- calling the
initfunction of a smart contract- This is a one time action and will be called when the
diamondCutis executed. There can be 1initcall perdiamondCut.
- This is a one time action and will be called when the
For this tutorial, we are going to create a new facet called SampleFacet. In your own implementation replace iterations of the word Sample with the name of the Facet you want to create.
- make sure you are in the
protocolrepository - in
protocol/farm/facets/, create a new folder calledSampleFacet - within the
SampleFacetfolder create a file calledSampleFacet.sol. - implement your faucet. You can use
SampleFacet.solinprotocol/samplesas a template for a basis faucet. Note that facets can only haveAppStorageas an internal state variable or there will be issues with accessingAppStorage. - modify the
deployfunction inscripts/deployto include your new facet, so that thefaucetwill be deployed with the Beanstalk diamond.
There are a couple of steps that must be done before we can fork mainnet and upgrade Bips/test Bip upgrades
-
include the following code in the networks section of the hardhat.config.js, where ALCHEMY_URL is your mainnet url. We recommend using Alchemy for this. The blockNumber is optional, but we recommend to be one that is close to the current block number but not too close.
forking: { url: <RPC_URL>, blockNumber: <BLOCK_NUMBER> },localhost: { chainId: 1337, url: "http://127.0.0.1:8545", forking: { url: <RPC_URL>, blockNumber: <BLOCK_NUMBER> }, }, -
include as in imports section
const BEANSTALK = "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5"; const ownerFacet = await ethers.getContractAt('OwnershipFacet', BEANSTALK); const owner = await ownerFacet.owner(); const { upgradeWithNewFacets } = require('./scripts/diamond.js') -
Lastly, include the tasks required for upgrading above module.exports:
task("upgrade", "Commits a bip", async() => { await hre.network.provider.request({ method: "hardhat_impersonateAccount", params: [owner], }); const account = await ethers.getSigner(owner) await upgradeWithNewFacets({ diamondAddress: BEANSTALK, facetNames: [], initFacetName: 'InitEmpty', initArgs: [], bip: false, verbose: true, account: account }); }) -
(this is an example of what bip11 deployment looked like):
await upgradeWithNewFacets({ diamondAddress: BEANSTALK, initFacetName: 'InitBip11', facetNames: ['MarketplaceFacet'], libraryNames: ["LibClaim"], facetLibraries: { "MarketplaceFacet": ["LibClaim"], }, bip: false, verbose: true, account: account });
-
Spin up your mainnet fork node with:
npx hardhat node -
In another console, execute your tasks by running
npx hardhat upgrade --network localhostwhere
upgradeis where you put the name of your task, in the example above it was named upgrade. -
Now you can test your changes using your local blockchain node that should now have the latest version of beanstalk that you upgraded.
Code Version: 2.0.0
Whitepaper Version 2.0.0