This is in continuation of our DeFi series. In this post, we look at yet another decentralized lending and borrowing platform Aave.
πͺ Full DeFi Course: Click the link to access our free full DeFi course thatβll show you the ins and outs of decentralized finance (DeFi).
Aave
Aave launched in 2017 is a DeFi protocol similar to Compound with a lot of upgrades.
Beyond what Compound provides, Aave gives several extra tokens for supply and borrowing. As of now, Compound offered nine different tokens (various ERC- 20 Ethereum- based assets).
Aave provides these nine besides an additional 13 that Compound does not.
Depositors give the market liquidity to generate a passive income, while borrowers can borrow if they have an over-collateralized token or can avail flash loans for under-collateralized (one-block liquidity).
Currently, we can see two major markets on Aave.
- The first is for ERC-20 tokens that are more frequently used, like those of Compound, and their underlying assets, such as ETH, DAI and USDC.
- The latter is only available with Uniswap LP tokens.
For instance, a user receives an LP token signifying market ownership when they deposit collateral into a liquidity pool on the Uniswap platform. To provide additional benefits, the LP tokens can be sold on the Uniswap market of Aave.
As per DeFi pulse, Aave has a TVL (Total Value Locked) of $4.09B as of today.
Aave Versions
Aave has released three versions (v1, v2 and v3) as of now and the Governance token of Aave is βAAVEβ. Version 1 or v1 is the base version launched in 2017 and then there have been upgrades with multiple new features added. Below is a short comparison of when to use v2 or v3.
You should use Aave V2 when:
- You won’t need to borrow many tokens.
- Little profit
- You borrow important tokens like WETH, USDC, etc.
You should use Aave V3 when:
- Many tokens must be borrowed
- High profit margin
- You borrow mid-cap tokens like LINK, etc.
Borrow and Lending in Aave
Borrow
You must deposit any asset to be used as collateral before borrowing.
π‘ The amount you can borrow up to depends on the value you have deposited and the readily available liquidity.
For instance, if there isn’t enough liquidity or if your health factor (minimum threshold of the collateral = 1, below this value, liquidation of your collateral is triggered) prevents it, you can’t borrow an asset.
π‘ The loan is repaid with the same asset that you borrowed.
For instance, if you borrow 1 ETH, you’ll need to pay back 1 ETH plus interest.
In the updated Version 2 of the Aave Protocol, you can also use your collateral to make payments. You can borrow any of the stable coins like USDC, DAI, USDT, etc. if you want to repay the loan based on the price of the USD.
Stable vs Variable Interest Rate
In the short-term, stable rates function as a fixed rate, but they can be rebalanced in the long run in reaction to alterations in the market environment. Depending on supply and demand in Aave, the variable rate can change.
The stable rate is the better choice for forecasting how much interest you will have to pay because, as its name suggests, it will remain fairly stable. The variable rate changes over time and, depending on market conditions, could be the optimal rate.
Through your dashboard, you can switch between the stable and variable rate at any time.
Deposit/Lending
Lenders share the interest payments made by borrowers based on the utilization rate multiplied by the average borrowing rate. The yield for depositors increases as reserve utilization increases.
Lenders are also entitled to a portion of the Flash Loan fees, equal to .09% of the Flash Loan volume.
There is no minimum or maximum deposit amount; you may deposit any amount you choose.
Flash Loans in Aave
Flash Loans are unique business agreements that let you borrow an asset as long as you repay the borrowed money (plus a fee) before the deal expires (also called One Block Borrows). Users are not required to provide collateral for these transactions in order to proceed.
Flash Loans have no counterpart in the real world, so understanding how state is controlled within blocks in blockchains is a prerequisite.
π‘ Flash-loan enables users to access pool liquidity for a single transaction as long as the amount borrowed plus fees are returned or (if permitted) a debt position is opened by the end of the transaction.
For flash loans, Aave V3 provides two choices:
(1) βflashLoanβ: enables borrowers to access the liquidity of several reserves in a single flash loan transaction. In this situation, the borrower also has the choice to open a fixed or variable-rate loan position secured by provided collateral.
π The fee for flashloan is waived for approved flash borrowers.
(2) βflashLoanSimpleβ: enables the borrower to access a single reserve’s liquidity for the transaction. For individuals looking to take advantage of a straightforward flash loan with a single reserve asset, this approach is gas-efficient.
π The fee for flashloanSimple is not waived for the flash borrowers. The Flashloan fee on Aave V3 is 0.05%.
Let’s Code a Simple Flash Loan
Let’s code a simple flash loan in Aave, where we buy and repay the asset in the same transaction without having to provide any collateral. First, we set up the environment for writing the code.
βΆοΈ Note: It is recommended to follow the video along for a better understanding.
$npm install -g truffle # in case truffle not installed $mkdir aave_flashloan $cd aave_flashloan $truffle init $npm install @aave/core-v3 $npm install @openzeppelin/contracts $npm install @openzeppelin/test-helpers
Note: Aave3 is currently available on Polygon, Arbitrum, Avalanche, and other L2 chains. As of now, it is not available on the Ethereum mainnet. Thus, we will fork the Polygon mainnet for our tests.
Set up a new app in Alchemy with the chain as Polygon mainnet and note down the API key.
Create a new file .env
and enter the below info.
$WEB3_ALCHEMY_POLYGON_ID=<API key noted above> $USDC_WHALE=0x075e72a5eDf65F0A5f44699c7654C1a76941Ddc8
π Recommended Tutorial: Solidity Crash Course — Your First Smart Contract
Simple Flash Loan Contract
The contract code (FlashLoanPolygon.sol
) in the contracts
folder.
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "@aave/core-v3/contracts/interfaces/IPool.sol"; import "@aave/core-v3/contracts/flashloan/base/FlashLoanSimpleReceiverBase.sol"; contract AaveFlashloan is FlashLoanSimpleReceiverBase { using SafeMath for uint256; using SafeERC20 for IERC20; event Log(string message, uint256 val); constructor(IPoolAddressesProvider provider) FlashLoanSimpleReceiverBase(provider) {} function aaveFlashloan(address loanToken, uint256 loanAmount) external { IPool(address(POOL)).flashLoanSimple( address(this), loanToken, loanAmount, "0x", 0 ); } function executeOperation( address asset, uint256 amount, uint256 premium, address initiator, bytes memory ) public override returns (bool) { require( amount <= IERC20(asset).balanceOf(address(this)), "Invalid balance for the contract" ); // pay back the loan amount and the premium (flashloan fee) uint256 amountToReturn = amount.add(premium); require( IERC20(asset).balanceOf(address(this)) >= amountToReturn, "Not enough amount to return loan" ); approveToken(asset, address(POOL), amountToReturn); emit Log("borrowed amount", amount); emit Log("flashloan fee", premium); emit Log("amountToReturn", amountToReturn); return true; } }
The contract code contains two important functions.
aaveFlashloan()
which calls the pools functionflashLoanSimple()
. Our test code must call this function to initiate a flash loan.executeOperation()
is a callback function of the pool which pays the loan + interest back to the pool.
Testing Contract
In the test folder, create a JavaScript file config.js
with the following content:
const USDC = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174"; const aavePoolAddressesProvider = "0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb"; const USDC_WHALE = process.env.USDC_WHALE; module.exports = { USDC, USDC_WHALE, aavePoolAddressesProvider, }
In the test folder, create another file testAaveFlashLoanSimple.js
:
const BN = require("bn.js"); const IERC20 = artifacts.require("IERC20"); const AaveFlashLoan = artifacts.require("AaveFlashloan"); const {USDC,aavePoolAddressesProvider,USDC_WHALE} = require("./config"); function sendEther(web3, from, to, amount) { return web3.eth.sendTransaction({ from, to, value: web3.utils.toWei(amount.toString(), "ether"), }); } contract("AaveFlashLoan", (accounts) => { const WHALE = USDC_WHALE const TOKEN_BORROW = USDC const DECIMALS = 6 // USDC uses 6 decimal places and not 18 like other ERC20 // We fund more because we need to pay back along with the fees during Flash loan. // So let us fund extra (2 million round figure to the calculations simple) const FUND_AMOUNT = new BN(10).pow(new BN(DECIMALS)).mul(new BN(500)); 500 USDC const BORROW_AMOUNT = new BN(10).pow(new BN(DECIMALS)).mul(new BN(1000000)); // 1 million USDC let aaveFlashLoanInstance let token beforeEach(async () => { token = await IERC20.at(TOKEN_BORROW) // USDC token aaveFlashLoanInstance = await AaveFlashLoan.new(aavePoolAddressesProvider) // send ether to USDC WHALE contract to cover tx fees await sendEther(web3, accounts[0], WHALE, 1) // send enough token to cover fee const bal = await token.balanceOf(WHALE) assert(bal.gte(FUND_AMOUNT), "balance < FUND") // Send USDC tokens to AaveFlashLoan contract await token.transfer(aaveFlashLoanInstance.address, FUND_AMOUNT, { from: WHALE, }) console.log("balance of USDC in AAveFlashLoan contract:", bal2.toString()) }) it("aave simple flash loan", async () => { const tx = await aaveFlashLoanInstance.aaveFlashloan(token.address, BORROW_AMOUNT) console.log("token address:",token.address) for (const log of tx.logs) { console.log(log.args.message, log.args.val.toString()) } }) });
Again, feel free to watch the video at the beginning of this tutorial to understand the testing process.
Open two terminals.
In terminal 1:
$source .env $npx ganache-cli i --fork https://polygon-mainnet.g.alchemy.com/v2/$WEB3_ALCHEMY_POLYGON_ID \ --unlock $USDC_WHALE \ --networkId 999
This should start a local fork of the Polygon mainnet.
In terminal 2:
$ source .env $ env $(cat .env) npx truffle test --network polygon_main_fork test/testAaveFlashLoanSimple.js
This should run the flash loan test case, and it must pass.
Conclusion
This tutorial discussed Aave, a leading Dapp lending and borrowing provider.
It covered some basic functionalities supported in Aave, such as lending, borrowing, and flash loans.
There are many other features Aave supports and it is not possible to cover it in one post, such as governance, liquidation, and advanced features such as Siloed Borrowing, Credit Delegation, and many more.
The post also examined a simple flash loan contract using Aave API.
You can explore more about borrowing and lending with Aave in this link. It has a full stack Defi Aave dapp with frontend to perform borrowing and lending.
π Recommended Tutorial: Crypto Trading Bot Developer — Income and Opportunity