Code Version: 2.3.1
Whitepaper Version: 2.3.0
Beanstalk is a permissionless fiat stablecoin protocol built on Ethereum.
This repository contains the code base for the Beanstalk protocol, all of its facets and related contracts in the Beanstalk ecosystem.
- Documentation
- Audits
- Bug Bounty Program
- Contracts
- EIP-2535 Diamond
- Setup
- Developing
- Testing a BIP
- License
Conceptual documentation on Beanstalk can be found in the Farmers' Almanac.
Technical documentation on Beanstalk can be found in the Agronomics Handbook.
The latest version of the Beanstalk Whitepaper is available here (version history can be found here).
Read more about Beanstalk audits here.
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.
A comprehensive list of contract addresses related to Beanstalk is available here.
Contract | Address |
---|---|
Beanstalk | 0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5 |
Bean | 0xBEA0000029AD1c77D3d5D23Ba2D8893dB9d1Efab |
BEAN:3CRV LP token | 0xc9C32cd16Bf7eFB85Ff14e0c8603cc90F6F2eE49 |
Unripe Bean token | 0x1BEA0050E63e05FBb5D8BA2f10cf5800B6224449 |
Unripe BEAN:3CRV LP token | 0x1BEA3CcD22F4EBd3d37d731BA31Eeca95713716D |
Fertilizer ERC-1155 token | 0x402c84de2ce49af88f5e2ef3710ff89bfed36cb6 |
Beanstalk Community Multisig | 0xa9bA2C40b263843C04d344727b954A545c81D043 |
The Beanstalk contract is a multi-facet proxy that implements EIP-2535. Thus, the Beanstalk contract implements functionality from multiple different Facet contracts that all share a common storage.
- Beanstalk EIP-2535 Diamond Documentation
- Current Beanstalk Facets
- Beanstalk on Louper, The Ethereum Diamond Inspector
- Clone the repository
- Run
cd protocol
to 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
/protocol
repository - Install Foundry with
curl -L https://foundry.paradigm.xyz | bash
and reopen your terminal - Run
foundryup
to ensure you have downloaded the latest version - Start a locally forked node with the following command:
anvil --fork-url <FORK_RPC> --fork-block-number <BLOCK_NUMBER> --chain-id 1337
For <FORK_RPC>
, use an Alchemy or Infura RPC URL. 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 you are in the
protocol
directory - Run
npm test
to run all coverage tests - Run
npx hardhat coverage
to 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 execute code:
- Adding, replacing and/or removing functions
- Functions in Beanstalk are implemented in contracts known as
facets
. Facets are no different than normal smart contract with callable functions. In order to share a state, Facets can only define 1 internal state variable: TheAppStorage
struct defined inAppStorage.sol
. Read more here.
- Functions in Beanstalk are implemented in contracts known as
- Calling the
init
function of a contract- This is a one time action and will be called when the
diamondCut
is executed. There can be 1init
call perdiamondCut
.
- This is a one time action and will be called when the
For this tutorial, we will create a new Facet called SampleFacet
.
- Ensure you are in the
protocol
directory - In
protocol/farm/facets/
, create a new folder calledSampleFacet
- Within the
SampleFacet
folder create a file calledSampleFacet.sol
. - Implement your Facet. You can use
SampleFacet.sol
inprotocol/samples
as a template. Note that Facets can only haveAppStorage
as an internal state variable. - Modify the
deploy
function inscripts/deploy
to include your new Facet, so that the Facet will be deployed with the Beanstalk Diamond.
There are a couple of steps that must be done before forking mainnet and testing a BIP.
-
Include the following code in the
networks
section of the hardhat.config.js, whereALCHEMY_URL
is your RPC url. We recommend using Alchemy for this. TheBLOCK_NUMBER
is optional, but we recommend choosing a block number close to the current block.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 imports:
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 }); })
-
Here is an example of what BIP-11 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 against your mainnet fork by running:
npx hardhat upgrade --network localhost
Where
upgrade
is 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 mainnet fork that should now have the latest version of Beanstalk that you upgraded.