- The strategy swaps/stakes WETH to wstETH (according to maximum output) to collateralize it on Maker and mints DAI. The DAI is then deposited part in yvDAI and part in swapping/staking more wstETH to collateralize in Maker further.
- Advantages: Leveraged yield from staking rewards according & leveraged yield of underlying ETH if ETH price increases. In addition, depositors into the yearn vault will have exposure to this strategy without the necessary minimum Maker DAI debt requirement of 15kUSD.
- APR yield scenario: - Aim for 1.5x leverage (300% collateralization ratio) with 200% initial collateralization ratio and 100% reinvestment ratio into wstETH. Staking yield is leveraged by 1.5x to ~6.75% ETH APR (assuming 4.5% APR for stETH from Lido Finance). Subtracting the (current) 2.5% DAI stability fee on Maker, leads to ~5.5% APR remaining, if ETH price were to be constant. If ETH price appreciates, this could be even higher: e.g. 50% increase over a year's time would lead to an additional 16.67& APR. The initial collateralization ratio should be chosen low enough to accomodate ETH price volatility.
- The deleveraging for withdrawals or collateralization ratio adjustments is done through DYDX Flashloans (or AAVE if DYDX were to not have enough liquidity).
- Thanks to therealmonoloco & poolpitako for maker-dai-delegate, which this strategy builds upon.
-
Install Brownie & Ganache-CLI, if you haven't already.
-
Sign up for Infura and generate an API key. Store it in the
WEB3_INFURA_PROJECT_ID
environment variable.
export WEB3_INFURA_PROJECT_ID=YourProjectID
- Sign up for Etherscan and generate an API key. This is required for fetching source codes of the mainnet contracts we will be interacting with. Store the API key in the
ETHERSCAN_TOKEN
environment variable.
export ETHERSCAN_TOKEN=YourApiToken
- Optional Use .env file
- Make a copy of
.env.example
- Add the values for
ETHERSCAN_TOKEN
andWEB3_INFURA_PROJECT_ID
NOTE: If you set up a global environment variable, that will take precedence
- Make a copy of
- Download the mix.
brownie bake yearn-strategy
To deploy the demo Yearn Strategy in a development environment:
- Open the Brownie console. This automatically launches Ganache on a forked mainnet.
$ brownie console
- Create variables for the Yearn Vault and Want Token addresses. These were obtained from the Yearn Registry. Also, loan the Yearn governance multisig.
>>> vault = Vault.at("0xBFa4D8AA6d8a379aBFe7793399D3DdaCC5bBECBB") # yvDAI (v0.2.2)
>>> token = Token.at("0x6b175474e89094c44da98b954eedeac495271d0f") # DAI
>>> gov = "ychad.eth" # ENS for Yearn Governance Multisig
- Deploy the
Strategy.sol
contract.
>>> strategy = Strategy.deploy(vault, {"from": accounts[0]})
Transaction sent: 0xc8a35b3ecbbed196a344ed6b5c7ee6f50faf9b7eee836044d1c7ffe10093ef45
Gas price: 0.0 gwei Gas limit: 6721975
Flashloan.constructor confirmed - Block: 9995378 Gas used: 796934 (11.86%)
Flashloan deployed at: 0x3194cBDC3dbcd3E11a07892e7bA5c3394048Cc87
- Approve the strategy for the Vault. We must do this because we only approved Strategies can pull funding from the Vault.
# 1000 DAI debt limit, no rate limit, 50 bps strategist fee
>>> vault.addStrategy(strategy, Wei("1000 ether"), 2 ** 256 - 1, 50, {"from": gov})
Transaction sent: 0xa70b90eb9a9899e8f6e709c53a436976315b4279c4b6797d0a293e169f94d5b4
Gas price: 0.0 gwei Gas limit: 6721975
Transaction confirmed - Block: 9995379 Gas used: 21055 (0.31%)
- Now we are ready to put our strategy into action!
>>> harvest_tx = strategy.harvest({"from": accounts[0]}) # perform as many time as desired...
contracts/Strategy.sol
is where you implement your own logic for your strategy. In particular:
- Create a descriptive name for your strategy via
Strategy.name()
. - Invest your want tokens via
Strategy.adjustPosition()
. - Take profits and report losses via
Strategy.prepareReturn()
. - Unwind enough of your position to payback withdrawals via
Strategy.liquidatePosition()
. - Unwind all of your positions via
Strategy.exitPosition()
. - Fill in a way to estimate the total
want
tokens managed by the strategy viaStrategy.estimatedTotalAssets()
. - Migrate all the positions managed by your strategy via
Strategy.prepareMigration()
. - Make a list of all position tokens that should be protected against movements via
Strategy.protectedTokens()
.
To run the tests:
brownie test
The example tests provided in this mix start by deploying and approving your Strategy.sol
contract. This ensures that the loan executes succesfully without any custom logic. Once you have built your own logic, you should edit tests/test_flashloan.py
and remove this initial funding logic.
See the Brownie documentation for more detailed information on testing your project.
Use the --interactive
flag to open a console immediatly after each failing test:
brownie test --interactive
Within the console, transaction data is available in the history
container:
>>> history
[<Transaction '0x50f41e2a3c3f44e5d57ae294a8f872f7b97de0cb79b2a4f43cf9f2b6bac61fb4'>,
<Transaction '0xb05a87885790b579982983e7079d811c1e269b2c678d99ecb0a3a5104a666138'>]
Examine the TransactionReceipt
for the failed test to determine what went wrong. For example, to view a traceback:
>>> tx = history[-1]
>>> tx.traceback()
To view a tree map of how the transaction executed:
>>> tx.call_trace()
See the Brownie documentation for more detailed information on debugging failed transactions.
If you are using Ganache to fork a network, then you may have issues with the blockchain archive state every 30 minutes. This is due to your node provider (i.e. Infura) only allowing free users access to 30 minutes of archive state. To solve this, upgrade to a paid plan, or simply restart your ganache instance and redploy your contracts.
- Yearn Discord channel
- Brownie Gitter channel