This is a third project that I've done as part of my learning of smart contract development using Solidity and Foundry. This is a DeFi application for users to deposit collateral in the form of wETH and wBTC tokens, and then mint decentralized stablecoin DSC. The DSC is pegged to a value of $1 USD and the peg is supported by the 200% overcollaterilization in the system. The system is designed to incentivize liquidations of the user's collateral by external parties, if user's health factor is below a threshold. The liquidators incentives are extra collateral that the system will give to the liquidator, so that they are profitable.
- Run
git clone https://github.com/accurec/CyfrinUpdraftCourseDeFiProtocol.git
- Run
make installto install required dependencies. - Run
make buildto build the project. - Add
.envfile with the following variables:SEPOLIA_RPC_URL- could take this from Alchemy;ETHERSCAN_API_KEY- needed for automatic verification, can get it from Etherscan account. Make sure you also provide local account key usingcast wallet importcommand. Then, inenvfile you can supply the key name underLOCAL_ACCOUNTvariable. Also need to addLOCAL_RPC_URL, andSEPOLIA_ACCOUNT_ADDRESSfor deployemtns to Sepolia, along with theSEPOLIA_ACCOUNTvalue similar to what we would import forLOCAL_ACCOUNT. - Run
make deploy-localto deploy to localanvilnetwork (don't forget to start it). - After deploying to local there will be output of deployed contracts in terminal log like this:
Deployed wETH token: 0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9
Deployed wBTC token: 0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9
Deployed wETH price feed: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
Deployed wBTC price feed: 0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0
Deployed DSC token: 0x5FC8d32690cc91D4c39d9d3abcBD16989F875707
Deployed DSCEngine contract: 0x0165878A594ca255338adfa4d48449f69242Eb8F
- After the contracts have been deployed, we can add more variables to
.envfile:LOCAL_WETH_ADDRESS- the wETH token deployed address.LOCAL_USER_ACCOUNT- this would normally be a local user address provided by anvil, such as0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266. It would be an account that we stored the key for in theLOCAL_ACCOUNTvariable.LOCAL_WETH_USER_AMOUNT- this is an amount of wETH that we would want to mint for local user to then deposit as collateral.LOCAL_DSC_ENGINE_ADDRESS- the DSCEngine deployed address.LOCAL_MINT_DSC_AMOUNT- the amount of DSC we would want to mint for the user after they deposit the collateral.LOCAL_DSC_ADDRESS- the DSC stablecoin address.LOCAL_WETH_PRICE_FEED_ADDRESS- this is the address of a wETH price feed.
- We can then interact with these contracts to get some initial data, to make sure that they are correctly setup. For example:
make get-local-weth-latest-price, then get the second parameter value from the output and convert it todecvalue like this:cast --to-base VALUE dec. The response should be200000000000. - We can then start using the protocol by calling
makecommands in order:make mint-weth-for-local-user- will mint some wETH for local user to use as collateral.make local-user-approve-weth-spend- will approve spending wETH for DSCEngine contract.make local-user-deposit-weth-collateral-and-mint-dsc- will deposit wETH as collateral and mint DSC (assumint DSC amount to mint was not too big, otherwise the transaction will fail).make get-dsc-balance-for-local-user- check DSC balance for local user.make get-local-user-health-factor- get health factor for local user.
NOTE: I have not used/deployed this on Sepolia testnet, since I do not have enough test tokens there at the moment.
- One of the protocol's weak points is that if
wETHand/orwBTCprices plummet, then the system will not be able to incentivize liquidations and DSC stablecoin backing will be rendered insolvant. - ChainLink network can become stale/blow up. I'm using the
OracleLiblibrary to make sure that if the price feeds are stale, then the protocol stops execution and liquidations/minting of DSC are reverted.
As part of lesson I've learned a bunch of things:
- Using Openzeppelin
ERC20Burnable,Ownablecontracts to create DSC stablecoin contract. - Using library to wrap ChainLink oracle get price functionality and revert, if the feed is stale.
- Fuzz testing. Invariants and handlers.
- Re-entrancy vulnerability concept and how we can protect against it.
- Better understanding of how to do proper math in Solidity.
- Concepts of how to use collateral, mint stablecoins, and support health factor so that stablecoin stays backed by the collateral. Concept of liquidations and incentives.
- Concepts behind
abi.encodePacked, function call encoding including parameters. How to verify the call in the web3 wallets, such as Metamask.
- Simple Security Toolkit
- Ethereum Unit Converter
- Re-Entrancy Vulnerability Overview
- Foundry Fuzz Testing
- Fix tests so that they are passing on Sepolia testnet.
- Add more scripts for interactions.
- Add integrations tests.
- Fix
invariant_gettersShouldNotRevertinvariant so that all getters can be fuzz tested. Most likely need to add the logic to handler. - Deploy and test on Sepolia testnet. Add
Makefilecommands to deploy to Sepolia.
