Code Version: 2.3.1
Whitepaper Version: 2.3.0
This repository contains the code base for the Beanstalk protocol, all of its facets and related contracts in the Beanstalk ecosystem.
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
- git
- You'll know you did it right if you can run
git --version
and you see a response likegit version x.x.x
- You'll know you did it right if you can run
- Nodejs
- You'll know you've installed nodejs right if you can run
node --version
and get an ouput like:vx.x.x
- You'll know you've installed nodejs right if you can run
- Yarn
- You'll know you've installed yarn right if you can run
yarn --version
And get an output like:x.x.x
- You'll know you've installed yarn right if you can run
- Rosetta (Apple Silicon)
- You'll know you've installed Rosetta right if you can execute the solc 0.7.6 binary
.../solc-macosx-amd64-v0.7.6+commit.7338295f --version
- You'll know you've installed Rosetta right if you can execute the solc 0.7.6 binary
The latest Node.js and NPM versions are known to be incompatible with some parts of the Foundry toolchain. We recommend using Node.js v18.12.0
and npm v8.19.2
.
Note: The Beanstalk repo is a monorepo with induvidual projects inside it. See the DEVELOPER.md
in the root directory for more information.
- Clone the repository and install dependencies
git clone https://github.com/BeanstalkFarms/Beanstalk
cd Beanstalk/protocol
yarn
- Compile the contracts
yarn hardhat compile
- Ensure you are in the
protocol
directory - Have a FORKING_RPC as an environment variable pointing to ETH Mainnet.
- We fork ETH Mainnet to run our test suite locally. Note, this will make a large number of API calls to your
FORKING_RPC
- We fork ETH Mainnet to run our test suite locally. Note, this will make a large number of API calls to your
- Run all tests
yarn test
- Generate coverage report
yarn hardhat coverage
- Ensure you are in the
protocol
directory - Install foundry with
foundryup
- instructions here forge install foundry-rs/forge-std --no-commit
forge test
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
# Be sure to use the official docs linked above if this doesn't work
curl -L https://foundry.paradigm.xyz | bash
- Close and re-open your terminal to ensure foundry is installed correctly
- You may need to update your path.
- Run
foundryup
to ensure you have downloaded the latest version - Start a locally forked node with the following command:
anvil --fork-url <FORKING_RPC> --fork-block-number <BLOCK_NUMBER> --chain-id 1337
For <FORKING_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.
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, whereRPC_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:
yarn hardhat node
-
In another console, execute your tasks against your mainnet fork by running:
yarn 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.