Aave V3 Protocol Development
Cyfrin Updraft Courses · 1:52:25
Tasuku Nakamura, founder of smartcontract.engineer and an instructor at Cyfrin Updraft, examines Aave V3 contract architecture, interest models and lending operations. The course uses Solidity and Foundry exercises to explore supply, borrowing, repayment and liquidation before building a protocol-integrated application. It assumes Solidity and advanced Foundry experience.
Speakers
Topics
From Cyfrin Updraft Courses, hosted by Cyfrin.
Transcript
Welcome to the course for V3. In this course, I will teach you what Aave V3 is and how it works. You'll also learn about common DeFi terminologies such as collateral, overcollateralized loan, liquidation, flash loan, long leverage, and short selling. There are exercises where you will write Solidity smart contracts that interact with the Aave V3 protocol. Why should you take this course? You should take this course to expand your DeFi knowledge. You'll be able to use the knowledge that you learn in this course in audit contest and bug bounties. You can also try building application and scripts that integrate with Aave V3. There's one final project in this course where you will be writing a Solidity smart contract that will create financial strategies called long
leverage and short selling using Aave V3 protocol. You might also want to take this course if you're thinking about building your own lending market. The prerequisite for this course is basic DeFi terminology. So, before you take this course, make sure that you know what stablecoins such as DAI, USDC are. And another token that you should be familiar with is WETH, wrapped ETH. Another thing that you should know before taking this course is know what a upgradeable proxy contract is. You can still take this course without knowing what a proxy contract is. However, Aave V3 uses proxy contracts. So, when you interact with the Aave V3 protocol, you'll have a easier time understanding what's going on if you know what a proxy contract is and how they work. The
exercises and the project will be done using Foundry. So, be sure to know how to test on main networks and console log to debug your code. Here, I will explain where you can find all of the resources that is used in this course and how to do the exercises. The first step is to get clone this repo. You can do this by clicking on this button and then copying this URL. Inside your terminal, type get clone and then paste the URL. This will clone the GitHub repo. Once the repo is cloned, we'll go into it. CD DeFi Aave V3. The exercises are written in Foundry. It is located under a folder called Foundry. To install the dependencies that are needed to do the exercises, type forge build. Then
there's one more setup for you to do the exercises. The exercises will execute code against the main network. You'll need to prepare a fork URL. There's a file called .env.sample. Inside this, there's an environment variable that you'll need to set. This will be the RPC URL that will be used for the main network for the exercises. I'm going to show you what my fork URL looks like. cat .env and here it is. I got the RPC URL from alchemy.com. If you sign up here, you'll be able to get a free RPC URL which you'll be able to use for the exercises. In this course, the Aave V3 contracts that we'll look at is located under GitHub Aave DAO / Aave V3 origin. In this course, I'll be using diagrams and some Python code to run
simulations. All of these resources are under the folder called notes. To run the Python simulation, you'll need to install a Python notebook called Jupyter. I'll show you the Python simulation in this course, so this is an optional installation. You don't need to install Jupyter to follow most of the course. I'll be showing you how the protocol works by debugging real transactions that were sent to the mainnet. To debug the transaction, I'll be using Tenderly. If you want to follow along, sign up to Tenderly and then go to dashboard. Paste the transaction hash that you want to debug. Here's the transaction where I supplied DAI to the Aave V3 protocol. Okay, and once the page loads, you can scroll down to see all of the contracts and the functions that were called. Furthermore, you'll
also be able to see the parameters that was passed. And if you want to take a look at the code, then you can click on the line to see the actual code that was executed. Tenderly is a helpful tool to do the exercises. By looking at the actual transactions that were sent, you'll have an idea of what parameters to pass and what contracts to call. We'll be using Foundry to do the exercises in Solidity. If you're on Linux, the simplest way to install it is by clicking on this getfoundry.sh link. This will take you to a page showing you the command that you'll need to execute to install Foundry. Simply copy this and then execute it inside your terminal. To do the exercises, navigate to the main page of this GitHub repo for the course. Inside the readme file, look for a section called
exercises. For example, here is one. Exercises for supplying tokens to Aave V3. There are three links. Exercises, starter code, and solution. Exercises will contain the instructions on how to do the exercise and what to do for the exercise. Furthermore, at the bottom, it will give you the command to execute to see if you have done the exercises correctly. The link to the starter code will contain the code where you will write your code to do the exercises. It will also come with some instructions on what code that you'll need to implement.
And finally, if you click on the link solution, you'll be able to see the solution. The Foundry exercises are located under the folder called Foundry. Inside here, there's a readme with some notes on some of the commands that you might need. For example, forge build will build the exercises that you've written. And if you set the Foundry profile setting to solution, it will build the solutions. To execute the test against the code that you have written, follow this template to execute the test. Now, before I show you this, I'm going to explain about this environment variable called fork block number. When you execute a test in fork mode, it will fetch the latest state from the blockchain. However, if you specify the block number, then it will test the state of that block number. So, that the
second time you execute the same test, it will run faster. So, this command over here will get the latest block. To show you this, I'm going to first open my terminal and then I'll set the fork URL. My fork URL is saved under .env file. I'll copy this and then paste it. Next, I'm going to execute this command to get the latest block number. Paste it inside my terminal and then execute it. Let's see what the current block number is. Okay, here it is. Now, when you execute the test, the first time it will fetch the state of this block number. So, it might take a while for the test to execute. However, the second time you run it, it should run faster since it fetched some of the data. So, you can see that the first one took about 10 seconds and the second one took about 2
seconds. So, that is one trick that you can do to execute the test faster. Now, if you want to execute the test against the solutions, all you have to do is set the Foundry profile to solutions. For example, let's execute this command. As expected, the test passes. And finally, switching the profiles between exercises and solutions may cause some problem when you're executing the test. The only solution that I found to go around this problem was to reset the build files. This is done by typing forge clean. Once you do that and you execute the test, in most cases, your problem should go away.
And if you're still having problems, you might want to remove this fork block number and execute the test against the latest state of the blockchain. And finally, if you're curious about the transactions that I sent on the mainnet, inside the readme, there's a section called transactions, which will link to the actual transactions that I sent in this course. You can copy these transaction hashes and then paste it into Tenderly to see what functions and contracts were called. So, in this video, I've explained where to find the resources that I used in this course and how to do the exercises for this course. Aave V3 protocol allows users to lend their tokens and borrow tokens. Users who lend the tokens will earn interest and users who borrow the tokens will have to repay their tokens with
interest. In this video, I'll show you a demonstration of how to supply tokens, borrow tokens, repay, and finally withdraw the token that we supplied. On the left are tokens that you can supply and on the right are tokens that you can borrow. I've already supplied some token and also borrowed some tokens. So, on the top of the screen, you can see that I supplied DAI and borrowed ETH. Let's start by supplying tokens to Aave V3 protocol. The reason why you might want to supply tokens to Aave V3 protocol is to earn interest on the tokens that you supply. And where does this interest come from? Well, it comes from the borrowers. Users who borrow tokens will repay the token that they borrowed plus interest. Part of that interest will be paid to the users who supply the tokens
to Aave V3. Let's supply a token to Aave V3. For this example, I'm going to supply DAI. I'll click on supply. For the amount, I'll put in max amount, 1.63 DAI. Then click on supply DAI. Confirm the transaction on my wallet and I'll wait for the transaction to be confirmed. Once this transaction is processed, let's check back on the top of the screen. On the left, you can see the tokens and the amount of token that I supplied to Aave. Here, I've supplied 5.15 DAI. Now, if I wanted to withdraw this DAI from Aave, then I would click on the button withdraw. Let's click on the maximum amount that we can withdraw.
Notice that I've supplied 5.15 DAI, but the maximum amount that I can withdraw currently is approximately 2.77 DAI. Also notice there's a number called health factor. It says that the health factor will decrease from 2.19 to 1.00. The reason why I cannot withdraw all of my DAI from Aave V3 protocol is because currently I'm borrowing some ETH. When I borrow ETH, this health factor will decrease. When I supply tokens, this health factor will increase. So, going back to withdraw again, my current health factor is 2.19. If my health factor is below 1, then my collateral will be liquidated. Collateral is a
token that we provide to Aave V3 protocol, which will allow us to borrow other tokens. In this example, I provided DAI as collateral and then I borrowed ETH. So, the reason why I cannot withdraw all of my 5.15 DAI is because currently I'm borrowing ETH and I need this health factor to remain above 1.0. If I were able to withdraw all of my DAI, 5.15, then my health factor will be below 1.0, which the protocol will not allow me to do. So, to keep this health factor above 1.0, the maximum amount of token that I can withdraw is approximately 2.77 die. Now, let's withdraw the maximum amount of die
that I can withdraw from Aave B3 protocol. And our transaction went through, and now let's check back on our health factor. Our health factor is 1.01. When this health factor is at or below 1.0, our collateral die will be liquidated. Okay, moving on, let's look at some of the tokens that we can supply. Scrolling down, you can see that there are several tokens that you can supply. We've supplied die, so let's take a look at the details of this token. Starting from the top, we have reserve size equal to What is reserve size?
Reserve size is the amount of tokens that is supplied to Aave. In this case, this reserve refers to the die stable coin. So, the amount of die stable coin that is provided to Aave B3 is 160.34 million dollars worth of die. The available amount of liquidity, which is the available amount of die that we can borrow, is 44.91 million. The remaining amount, 160.37 minus 44.91, is the amount of tokens that is being borrowed currently. The utilization rate is the ratio of amount of tokens that are currently borrowed. We can do a quick math. The amount of die that is supplied is roughly 160 million. Of
that, 40 million are still available. 40 divided by 160 is 1/4, which is approximately 25%. So, there is 25% of the total pool that is available to be lent out. The remaining 75% is already borrowed. 75% is roughly close to 72%. Okay, moving on, let's focus our attention to here. Here, I want to quickly explain the difference between APY and APR. APR stands for annual percentage return, and APY stands for annual percentage yield. Annual percentage return is the annual interest rate without compounding, and annual percentage yield is the annual interest
with compounding. Taking a look at the latest average APR for supply, it is 2.56. So, this means that given that the supply APR remains at 2.56 for 1 year, if you were to supply token today and then wait 1 year, your token that you supplied will increase roughly by 2.56%. That's the calculation done with APR. And if you were to do the same calculation with compound interest, your token will roughly grow by 2.57%. Don't worry if you didn't understand the difference between API and APY. Later in the course, I'll explain them in details. So, moving on, we have collateral usage. This means this token, which is die, can be used as collateral.
Let's look at some of these numbers: max LTV, liquidation threshold, and liquidation penalty. Max LTV, LTV stands for loan to value. The maximum LTV is the maximum amount of loan that you can take out for the value of the collateral that you deposited. Let's say that you deposited 100 die. And the value of 100 die is 100 USD. Since the max LTV is 63%, using die as collateral, we can borrow up to 63 dollars worth of other tokens, for example, ETH. So, that's max LTV. Next, let's move on to liquidation threshold. Liquidation threshold is the percentage at which your collateral can be liquidated. Remember, loan to value
was the ratio of loan, which is debt, over the value of collateral. For liquidation threshold, we take this same LTV. If our current LTV goes beyond 77%, then your collateral can be liquidated. And finally, we have liquidation penalty. Liquidation penalty is the penalty that is paid from your collateral if your collateral is liquidated. For example, let's say that you put in 200 die as collateral, and 100 of that collateral is liquidated. Since the liquidation bonus is 5%, additional 5% of your collateral will be taken and then be paid out to the account who liquidated your collateral.
Basically, this is an incentive for users to liquidate under collateralized debt. Next, we have the borrowing section, which we will come back when I show you an example of borrowing tokens. And finally, we have the interest rate model and utilization rate. Remember, utilization rate means the amount of tokens that are being borrowed out divided by the amount of tokens that are supplied. 72% means that 72% of all of the tokens that were supplied is currently lent out. Let's look at the graph below. This is a graph that describes the borrowing interest rate versus the utilization rate. When the utilization rate increases from 0 to 100, the borrow interest rate will also increase. Basically, this says that the
more token is borrowed, the interest rate will also be higher. Now, you can see over here that there is an angle where the rate of the interest rate changes. This divide over here is called the optimal utilization rate. The protocol targets the utilization rate to be somewhere close to over here where the interest rate remains low. When there are a lot of users, the utilization rate will go above this optimal usage rate, and the interest rate on the borrow will rapidly increase. Okay, so that's interest rate model. Let's go back to the main page. Now, the last feature of supplying tokens to Aave B3 protocol that I want to discuss is called isolation mode.
Scrolling down, and on the left, you see the tokens that you can supply. I have a tag called isolated. See one over here for BAL, and we see one over here for USDE. So, what is isolation mode? What does it mean when a token says it is isolated? Clicking on the information, it says that isolated assets have limited borrowing power, and other assets cannot be used as collateral. So, what does this mean? Let's dig a little bit deeper. According to the Aave documentation, what does isolation mode mean? It says that borrowers supplying an isolated asset as collateral cannot supply other assets as collateral.
Furthermore, borrowers using an isolated collateral can only borrow stable coins that has been configured by Aave governance. Going back to the Aave application, if you were to supply BAL token as collateral, then we won't be able to supply other token as collateral. Furthermore, the token that we can borrow is restricted to some of the stable coins that the Aave protocol has set. Now, let's move on to borrowing tokens from Aave B3. Currently, I borrowed approximately 0.00099 ETH from Aave B3. My current health factor is 1.01. So, I don't know if I can further borrow any tokens from the protocol, but let's give it a try. Okay, so it looks like I cannot borrow any
tokens. So, what I'm going to do is supply some die to increase my health factor. This will increase the health factor from 1.01 to 2.20. Okay, let's now try borrowing some tokens from Aave B3. The current health factor is 2.20. Let's try borrowing more ETH. To borrow ETH, I'll click on borrow. Let's put in the max amount. And you'll notice that the health factor is going to decrease from 2.20 to 1.22. If you were to borrow less, let's change this to 0.001, then you'll notice that the health factor only decreases from 2.20 to 2.00.
In other words, the more you borrow, the lower your health factor becomes. So, let's try borrowing max. I'll click on max. Okay, the transaction went through. So, now I've increased the amount of tokens that I borrowed from Aave B3. You'll notice that the health factor has decreased to 1.22. Let's check the details of our health factor by clicking on this risk details button. Okay, here's the visualization of health factor, liquidation value, and current LTV. Our health factor is 1.22. The more token that we borrow, this will decrease the health factor. If we repay our tokens that we borrow, this will increase the health factor. When the health factor is at or below 1.0, then our collaterals can be liquidated by any
user. Scrolling down, we have the current LTV. The current LTV, the loan to value, calculate the amount of debt that we borrow from Aave B3 in terms of USD, and then divide by the USD value of the collateral. Currently, this is 62.72. When this reaches 77% or above, then our collateral can be liquidated. So, we borrowed ETH. Let's take a look at the details of this token. Scrolling down, I'll click on details. We've already covered the supply info section, so let's look at the borrow info section.
Again, we have the APY and the APR. At the bottom, there is reserve factor at 15%. Reserve factor is a percentage of interest which goes to the collector contract that is controlled by Aave governance. From our perspective, you can think about this as the protocol fee. 15% of the interest that you have to repay will go to the protocol. Okay, and then scrolling down, we have e-mode info. E-mode increases your LTV for a selected category of assets, meaning that when e-mode is enabled, you will have a higher borrowing power over assets of the same e-mode category.
Okay, but what does this mean? Let's check the official documentation. E-mode allows borrowers to extract the highest borrowing power out of their collateral when supplied and borrowed assets are correlated in price. For example, if you were to supply ETH as collateral, and then borrow a derivative of ETH, such as stETH, then we can enable e-mode, which will give us more borrowing power. I'm Going back to the detail page of ETH, if we were to provide ETH as collateral, the max LTV is at 80.50%. However, if we enable E-mode, then this LTV will increase to 93%, which will allow us to borrow more tokens. However, if you were to enable E-mode, we cannot borrow any tokens on the right side of
the screen. There's a specific token that you can borrow. To see the list of tokens that we can borrow, click on this E-mode button. Then let's click on enable E-mode. If you were to select ETH as collateral, for example, WETH, then these are the other tokens that we will be able to borrow using E-mode. For example, we have rETH, cbETH, wstETH, and so on. So, once we enable E-mode, there's a specific collateral that we need to deposit. And given that collateral that we deposit, there's a restriction on the tokens that we can borrow. The collateral and the tokens that we can borrow are listed over here.
And And the reason why you might want to enter E-mode is because it will increase the LTV. It will allow us to borrow more tokens. Okay, and finally, let's repay some of the tokens that we borrowed. To repay, I'll click on repay. Let's try repaying all of the tokens. And then I'll click on repay. Okay, we now repaid the ETH that we borrowed. And this completes the demonstration of how to use the Aave V3 protocol. In this video, I'll explain the difference between APR and APY. APR stands for annual percentage rate. It's the interest rate over a year without compounding. For example, let's say that the daily interest rate is 0.07%, and you borrow $5. To calculate the
interest rate after 1 year, we first need to calculate the debt after 1 year. Compare this with the amount that we borrowed, $5, and then divide by this amount. This will give us the interest rate after 1 year. So, let's first calculate the debt after 1 year. On the day that we borrowed, the debt that we owe is $5. Since the daily interest is 0.07%, this will come into effect after 1 day has elapsed. So, after 1 day, the amount that we owe is $5 plus 0.7% on that $5. Therefore, after 1 day, the debt that we owe is the $5 that we borrowed initially, plus 0.07% on the $5 that we borrowed. 1 day after
this, we do the same thing. The amount that we owe is the previous amount that we owed, and to this, we add the daily interest. The amount that we initially borrowed is $5. The daily interest is 0.07. Multiply these two, and then we add it to our debt. This is the amount of debt that we owe after 2 days has elapsed. We keep doing this until 1 year has elapsed. After 365 days, this is the total amount of debt that we owe. Now, since in each of these terms there's a $5, we can simplify this equation. We will have $5, the amount that we initially borrowed, multiply this by 1 plus the interest after 1 day, and the interest after 2 days, and so on until
365 days has elapsed. So, this is the debt that we owe after 1 year. To calculate the APR, we need to take the difference of debt after 1 year and our initial debt, $5, and then divide by the initial debt. This will give us the percentage on how much the debt has increased. In other words, it will give us the interest rate after 1 year. We first take this amount, which is equal to the initial amount that we borrowed, multiplied by 1 plus the daily interest rate, multiplied by 365 days. And then we minus the initial amount, $5, the initial amount that we borrowed.
And then we divide this by the initial amount that we borrowed. Now, the $5 on top and the $5 over here and this one all cancel out. So, this will be equal to the daily interest rate multiplied by 365 minus 1. Furthermore, the 1 over here and the 1 over here cancel out, and we're left with this term over here. So, the APY is equal to the daily interest multiplied by 365 days, which is equal to 0.2555, which is equal to 25.55%.
From this example, let's come up with a generalized equation. Let's name R to be the periodic interest rate. In our example, this R will be this 0.07% daily interest rate. And then let N be the number of periods in a year. In our example, this was 365 days. Now, we could also set that the period is 1 second. Over here, we could have said that 0.07% per second interest rate. And in that case, this N will be the number of seconds in a year.
Now, to calculate APR, all we had to do was multiply these two numbers, R and N, which you can see over here. We multiply the daily interest rate by the number of days. So, this is the equation for APR. Next, let's move on to APY. APY stands for annual percentage yield. It is the interest rate over a year with compounding. In APR, we took the interest rate over a year without compounding. For APY, we take the interest rate over a year with compounding. Let's look at an example. Let's say that the daily interest rate is 0.07%.
We borrow $5. To calculate the interest rate over a year, we need to compare the difference of the debt when we took out and after 1 year. Then we need to calculate how much the debt has grown. This will give us the interest rate over a year. So, to do that, we first need to calculate the debt after 1 year. The debt on the day that we borrowed is $5. We borrowed $5. The interest rate takes into effect after 1 day has elapsed. So, the amount that we owe is exactly $5. After 1 day has passed, the amount that we owe is the $5, and to this we will need to add the interest rate, 0.07%.
So, $5 that we owe, 5 * 1 plus the interest that we owe, 5 * 0.0007. This is the debt after 1 day. Now, the amount of debt that we owe on the next day is the amount of debt that we owed on the previous day, and to that we apply the daily interest rate. In our example, the amount of debt that we owe on the previous day is this much amount. To this, we apply the daily interest rate of 0.07, so we multiply this by 1 plus 0.0007. We do the same after 3 days has elapsed, 4 days has elapsed, and so on, all the way up until after 360 days has elapsed.
Since we're multiplying 5 by 1 plus 0.0007 365 times, we can simplify this equation to be equal to 5 * 1 plus 0.0007 raised to the power of 365. So, this is the debt that we owe after 1 year. Let's now calculate the APY, the interest rate after 1 year. And to calculate the interest rate after 1 year, we need to compare the amount of debt that we owe initially and the amount of debt that we owe after 1 year.
Divide this by the amount of debt that we initially owed, and this will give us a rate telling us how much the debt has grown. So, the debt after 1 year is this number. Compare this with the debt that we initially owed. Divide this by the initial debt, $5. The $5 on top cancels out with the $5 on the bottom. And this equation will simplify to 1 plus 0.0007 raised to 365 minus 1. So, APY is equal to this equation, which is approximately equal to 0.29099, which is equal to 29.099%.
Now, let's come up with a general equation. We first started out with the periodic interest rate, R. In our example, this R was And then we raise this to the power of N, where N is the number of periods in a year. The number of days in a year is 365, so in our example, this N is 365. Now, if R was a rate that was to be applied every second, then this N will be the number of seconds in a year. And then finally, we minus 1. This is a general equation for APY. So, in summary, APY is the interest rate after 1 year with compounding. And APR is the interest rate over a year without compounding.
In Aave V3 protocol, supply and borrow interest rates dynamically adjust according to market activities. In this video, I'll give you a bird's-eye view of how this supply and borrow interest rates are calculated. In the market, we have supply and demand. Users who want to lend their tokens, and users who want to borrow tokens. This can be quantified as debt and supply. Debt will be the amount of tokens that the users borrowed, plus the interest that they will have to repay. And then the total supply of the tokens will be the current amount of tokens that are inside the Aave V3 protocol, plus any amount that was borrowed, plus the interest that the borrowers will have to repay. We calculate this ratio, and this will be a number between 0 and 1. Inside Aave V3,
this is called a utilization rate. This utilization rate is used to calculate the borrow interest rate. And then from the borrow interest rate, the supply interest rate is calculated. To calculate the supply interest rate, we will first take the borrow interest rate, multiply this by the utilization rate, and then we subtract the protocol fee. Remember that utilization rate is the ratio of debt over the amount of tokens currently in Aave V3 protocol, plus the amount of debt that the users owe. This will be a number between 0 and 1. When the utilization rate is equal to 0, the supply interest rate will also be equal to zero. And when the utilization rate is equal to one, assuming that the
protocol fee rate is equal to zero, then the supply interest rate will be equal to the borrow interest rate. Let's look at example of calculating the supply interest rate. Let's say that the utilization rate is 50%, 0.5. The borrow interest rate is 7% and the protocol fee rate is 2%. Then the supply interest rate is equal to We first take the borrow interest rate, 7%. We multiply this by the utilization rate, 50% and finally we subtract the protocol fees. This is approximately equal to 0.0343 or 3.43%.
This will be the supply interest rate given these parameters. Utilization rate is a number between zero and one that determines the borrowing interest rate. It's basically the ratio of the amount of tokens that are being borrowed divided by the amount of tokens that are available plus the amount of tokens with interest that must be repaid. Let me explicitly show you the equation. Let's say that B is the total debt of a token and S will be the available liquidity of this token. U will represent the utilization rate. The utilization rate will be equal to B divided by S plus B.
B is the total debt including interest that will have to be repaid. We divide this by the available liquidity, the amount of tokens inside of AB3 that are available to be lent out. And then we add this with the total debt. It's a ratio that will tell us how much token in AB3 protocol is being lent out. For example, if all of the tokens were borrowed out, then S will be equal to zero. B will be a positive number, so this expression will be B divided by B which is equal to one. Utilization rate equal to one. On the other hand, let's say that S is a positive number and no one is borrowing this token. Then B will be equal to zero. So zero divided by
some positive number will be equal to zero. Utilization rate will be equal to zero. So in summary, utilization equal to zero means that no one is borrowing the token. On the other hand, utilization equal to one means that all of the token inside a pool is being borrowed. And if the utilization rate is a number somewhere between zero and one, then it means that some of the token is being borrowed and there are some liquidity still available to be borrowed. The utilization rate is a number between zero and one which quantifies the amount of token that is being lent out. The interest rate for borrowing is determined by this utilization rate.
Here's a example graph of how the borrowing interest is determined. On the horizontal axis, we map the utilization rate. Remember, utilization rate is a number between zero and one. So on the horizontal axis, we're only concerned with X equal to zero up to X equal to one. On the vertical axis, you're seeing example of the borrow interest rates. For example, when the utilization rate is equal to zero, the borrowing interest rate starts at 0.05, 5%. And as the utilization rate goes up, you can see that the borrowing interest rate also goes up. Basically, it's saying that the more people want to borrow token, the interest rate on borrow will also increase. Now there's an optimal
utilization rate that the AB3 protocol targets. For this example, we set this optimal utilization rate to 80%. If the utilization rate goes above this optimal utilization rate, then you can see that the interest rate rapidly increases. So there are two interest rates for borrowing. At or below the optimal usage rate, the interest rate gradually increases. Above the optimal utilization rate, the interest rate rapidly increases. When you're looking at the code inside AB3 protocol, you'll come across a term called reserves. So in this video, I'll explain what reserves are. The first place that you might encounter the term reserves is under the contract called pool.sol. This is a contract that serves
as an entry point for users who want to supply and borrow tokens from AB3. This reserves is a state variable and we can start to understand what this reserves is by looking at the state variable. The state variable is stored inside a contract called pool storage. Under here, there's a mapping from addresses to data types.reserve data. The address that you see over here will be the address of the token. For example, this address can be WETH, USDC, DAI and so on. Now let's look at the data that is stored inside reserve data. This is found inside the contract called data types.sol. Inside here, there are two structs, reserve data legacy and reserve data. Here I will quickly explain some
of the data that are stored. The first data is called configuration. Let's come back to this later. Scrolling down, it's also storing an address called A token address. A token is a token that you'll receive when you supply tokens to the AB3 protocol. For example, you supply USDC and in return you get a A token back. We also have variable debt token address. If you borrow tokens from AB3 protocol, this is the token that you'll receive. Interest rate strategy address, this is the address of the contract that will calculate the interest rate. And then we have virtual underlying balance.
This will be the balance of the underlying token that is tracked by AB3 protocol. When you supply tokens to AB3, the way that it tracks the token balances is not by creating the actual token balance that is locked inside the contract. It actually tracks it by this virtual underlying balance. So if you supply token, this will increase and if you withdraw tokens, then this will decrease. From some of the data that is being stored inside the struct reserve data, we can see that it stores information about tokens that are managed by AB3. Informations such as A token, variable debt token and the virtual underlying balance. Let's also look at the configuration. The data type is called reserve configuration map.
Okay and then here it is. It's a struct that stores one data, uint256 and inside this uint256, bunch of parameters are being packed. For example, LTV, liquidity threshold, liquidity bonus and so on. Some of the settings that we need to understand AB3 protocol, I'll explain it later in the course. For now, just remember that reserve data stores some settings for reserve along with some informations such as the A token address, variable debt token address and the virtual underlying balance. And the mapping reserves maps from the underlying token to this struct called reserve data. When you supply tokens from AB3, you will receive a A token.
When you borrow tokens from AB3, you will receive a variable debt token. Both of these tokens are rebasing tokens. In this video, I'll explain what A token, variable debt token and rebase tokens are. Here you're looking at a transaction where I supplied DAI to AB3. In return, I received a A token that corresponds to DAI. We can check the details here. I've supplied DAI to AB3. In return, I received a token that's called A ETH DAI, AETHDAI. This is a token that I received for supplying DAI to AB3.
Here's the contract address for the AETHDAI token. Scrolling down, I'll click on code. All A tokens are proxy contract which means that the tokens can be upgraded. So to query the contract, you'll need to click on the tab read as proxy. And then let's check the balance of the A token that I have. I'll insert my account address here and then click on query. This is the current amount of AETHDAI that I have. Now both the A token and the variable debt token are rebase tokens. Rebase token means that the supply and the balance of the tokens can change without minting, burning or transferring the tokens. Non-rebase token means that the total supply and the balance of the token cannot change
unless there's a mint, burn or transfer. We can see that the A token is a rebase token since this balance is going to change when I click on the query button again, even though I did not send any transaction that would change the balance of my token. So clicking on query, you'll see that the balance of my A token has increased. Since A tokens earn interest, this means that I am earning more of the A token. And then if I click query again, again you'll see that the token balance has increased. You'll see the same behavior with variable debt tokens. Here is an example transaction where I borrowed ETH from Aave. I received some ETH from Aave and I've also received a token called Aave Ethereum variable debt WETH. Again, I'm
going to show you that this variable debt token is a rebase token. Here's the address of the contract. Scrolling down, I'll click on contract. Again, this is a proxy contract, so I'll click on read as proxy to query the contract. And then I'll look for the function called balance of and then paste my account address. Click on query. This is the current amount of debt that I owe to Aave. Similar to the A token, the variable debt token is also rebasing. The amount of debt that I'll have to repay will continuously increase over time. So if I query my balance again, the amount of debt that I'll have to repay increases. Let's click on the balance again. And again, you'll see that the number has slightly increased.
Imagine that we have a debt that compounds every second and for each second, the interest rate may vary. Now imagine that we borrow 100 token from time one to four. And now let's calculate the debt that we owe for borrowing 100 tokens from time one to four. We start out with 100 tokens. From time one to two seconds, the interest rate is 2%. In the next second, the interest rate is 3%. Since the debt compounds, we multiply by 103% to the previous debt that we owe. And finally from time three to four, the interest rate is back to 2% again. The debt compounds, so to the previous debt that we owe, we multiply this by 102%.
This is the amount of debt that we owe, considering that the interest rate changes every second. Let's now generalize this equation. Since the amount of tokens that we borrow can vary, let's replace our 100 with a variable called X. For each second, the interest rates can also vary. Let's replace the actual interest rate that we used in this example with variables. We can also borrow for a longer duration. So, let's extend this equation to include the compounding interest rates that would have applied if we borrowed for a longer duration. We can also start borrowing at a different time. Instead of time equal to one, we could have started at time equal to K.
So, let's replace the index one with K, two with K + 1, three with K + 2, and so on. And this is our final form of equation if you were to borrow X amount of tokens at time equal to K, and then borrow it up until time equal to N. If you were to write this in Solidity code, then we will first get the current debt of the user and the timestamp when this user started borrowing. We also need the current timestamp. And then to calculate the amount of debt that this user will have to repay including interest rates, then we'll need to run a for loop from time equal to K and all the way up to time less than N. For each iteration, we'll need to multiply the current debt by the interest rate at time T. Let's say that the interest rate has 18
decimals, then you'll have to divide these rates by 1E18. Hence, if you borrow for 1 second, this for loop will run once. If you borrow for 10 seconds, it will run 10 times. And if you borrow for 1,000 seconds, the for loop will have to run 1,000 times to calculate the amount of debt that the user owes. The calculation becomes more expensive gas wise as the duration of the debt increases. So, we need a more efficient way to calculate the amount of debt that the user owes given that the interest rate every second may change. Luckily, there's a solution. By rewriting this equation in another way, we can re-implement the code that calculates the amount of debt that the user owes in a more efficient manner. The first step is to define a function that multiplies
all of the interest rates starting from time equal to zero all the way up to now. We'll call this function the rate accumulator function and we'll denote it as capital R of N. And now let's rewrite the equation that expresses the amount of debt that a user owes using this rate accumulator function. We first multiply the equation on the bottom with rates starting at time equal to zero all the way up to time equal to K minus one. And then we divide this by the same rates that we multiplied, rates from time equal to zero to K minus one. Since we're multiplying and dividing by the same numbers, this equation still expresses the amount of debt that the user owes. But now we can rewrite the equation using the rate accumulator
function. The top part multiplies the rates from time equal to zero all the way up to N minus one. This is the same as the rate accumulator up to N minus one. And then the bottom rates are multiplied from time equal to zero all the way up to K minus one. This is the same as evaluating the rate accumulator at K minus one. Using the equation on the right, we can re-implement our code in a more efficient manner. Going back to our example, let's rewrite this debt using the rate accumulator function. The amount of debt including interest that they owe can be expressed as 100 multiplied by the rate accumulator at N minus one divided by the rate accumulator at K minus one. Where K is the time that the user took out this loan and N is the time that the user
repaid the loan. The user took out the loan at K equals to one, so K minus one will be equal to zero. The user repaid the loan at N equals to four, so N minus one will be equal to three. So, this is the amount of debt that the user owes rewritten using the rate accumulator function. Let's rewrite this in code. Going back to the code, we'll first create state variables that store rate accumulators. We'll store the current rate accumulator R of N minus one as a state variable named cumulative rates, which is initialized to 1E18. We assume that this rate still has 18 decimals, hence 1E18 means one. We also need to store the rate accumulator when the user took out the loan. We'll create a mapping from
address from user to uint256, the cumulative rate when the user borrowed. In our equation, this is R of K minus one. Now, let's update our code that calculates the debt of the user. All we have to do is first get the debt that the user borrowed, the initial debt, debts of user. We multiply this by R of N minus one. Let's say that before calculating the debt, the cumulative rate is updated to its current value. So, imagine that there's an efficient way to update the cumulative rates to its current value. Back inside our function calculate debt, we multiply the debt of the user by the current cumulative rates, the current value of the rate accumulator function. And then
we had to divide by R K minus one. This will be stored in the mapping user cumulative rates. When the user takes out the loan, the cumulative rate at that time will be stored in this mapping. So, we divide this by user cumulative rates of user. This is how the user's current debt can be calculated given that we have an efficient way to update the cumulative rates. So, now we can efficiently calculate the amount of debt that this user owes even if the interest rate changes every second. Now, so far we only considered the case where the user took out a fixed amount of loan in a given duration. But what will happen to our equation if the user took out more loans or repaid some of the loans over time. For example, let's say that the
user borrowed an additional 150 token at time equal to four. Now, let's calculate the amount of tokens that this user will owe. To keep this example simple, let's say that the user repaid all of the token at time equal to six. The amount of debt that the user owes at time equal to five is the amount of debt that the user owed in the previous second and to this we apply the compound interest rate. The compound interest rate from time equal to four to five is expressed as R4. So, we multiply the previous debt by 1 + R4. And the same goes for from time five to six. Take the previous debt and to this apply the compound interest, 1 + R5. At time six, the user repay.
Let's now calculate the amount of debt that this user will have to repay. We'll rewrite this equation. Multiply the two terms on the left by 1 + R4 multiplied by 1 + R5. Notice the left term, rate accumulator at time three multiplied by 1 + R4 multiplied by 1 + R5. This is simply equal to the rate accumulator at time five. We also rewrite the term on the right using the rate accumulator function. This user took out an additional loan of 150 tokens at time equal to four. So, the bottom rate accumulator that we need to evaluate is at four minus one, which is equal to three. The loan was repaid at time equal to six. So, the top rate accumulator that we need to evaluate is six minus one, which is equal to five. Now, notice
that both the terms are multiplied by rate accumulator at time five. So, let's factor this out and we get this equation. The rate accumulator on the right, R5, will be the value of the current rate accumulator. R0 will be the rate accumulator when the user took out 100 token as loan. And R3 will be the rate accumulator when the user took out an additional 150 token. All of these values can be efficiently calculated. Now, let's say that instead of borrowing an additional 150 tokens, the user repaid 70 tokens. In this case, all we have to do is change the number on the top from 150 to 70 and then change the plus sign to a minus. And the equation is still correct. Whether the user
increases their debt or decreases their debt, this equation correctly calculates the amount of debt that the user will have to repay. Let's implement this in our code. Let's rewrite this in code. First, assume that there's an efficient function that will update the cumulative rates to its current value. In this example, I'll call this function update cumulative rates. Let's look at the function borrow and repay. If the user were to borrow and take on additional debt, we first need to update the cumulative rates to its current value. This is done by calling the function update cumulative rates. And then we will need to increment the debt of this user by amount divide by the current cumulative rates. Since the cumulative rate has 18 decimals, we'll first multiply the top part by 1E18. And this
is it. The function repay will follow a similar structure. We first need to update the cumulative rates and then from the current debt, we'll have to subtract the amount that we repaid divide by the current cumulative rates. And finally, we also need to update the calculate debt function. Since this mapping debts already contains the user cumulative rates, we no longer need this. All we have to do is divide by 1E18 since the cumulative rates has 18 decimals. And this completes the code. The important parts to remember here is that when the user takes on additional debt, we add the amount of debt that they're taking on divide by the current cumulative rate. When they repay, we deduct the amount divide by the current cumulative rate. And finally, to calculate the amount of current debt
that the user owes, we simply multiply debts of user by the current cumulative rates. We looked at a code example of how to keep track of the debt that the user owes given that the interest rate may change every second. The way we did this was when the user borrowed some amount, we divided by the current cumulative rates. And then when they repaid, we did something similar. We deducted the amount that they repaid divided by the current cumulative rates. Inside the code for Aave V3, something similar happens. When a user borrows token, they will receive a token called variable debt token. When a user supplies token to Aave V3, they'll receive a token. Both of these token inherit from a contract called scaled balance token base. Eventually both of
these token will call the function mint scaled and burn scaled. Let's take a look at the function mint scaled. Inside here we first see that the amount, the actual amount of token that was supplied is divided by what's called index. Here you can think about this index as being the cumulative rates that we saw in the previous example. When you're supplying tokens this index will also be referred to as liquidity index. Once this amount is calculated, then below it mints this amount by calling our internal function called mint. Something similar happens when the token is burnt. Inside the internal function called burn scaled we first calculate amount scaled. This is calculated by taking the actual amount divided by the index again. For
supplying tokens this index will refer to the liquidity index, which is the cumulative interest rates for providing liquidity. And for buying this index will refer to the cumulative interest rates that the user will have to repay. Once this amount scaled is calculated, down below it calls into an internal function called burn burning the amount scaled. The code that you see for Aave protocol is similar to the simplified example that we saw. Take the amount and then divide by the current cumulative rates. Let's take a quick walk through to see how the interest for supplying liquidity is updated. Whether you're adding liquidity to Aave or removing liquidity or borrowing or repaying tokens, the logic for how the interest rates are updated are similar.
So here I'll focus on how the interest rates are updated when liquidity is provided. The function that the user will have to call is called supply under the contract pool.sol. This will call into a library called supply logic calling the function execute supply. The function execute supply will first get the reserve from the storage. Remember reserve stores some information about the token that is being managed by Aave The logic for updating the interest rate is contained under the function called update state and update interest rates and virtual balance. First let's take a look at the function called update state. Here it's calling the function on reserve. This function is declared
inside another library called reserve logic. Inside here it calls an internal function called update indexes. This will update the two indexes, liquidity index and borrow index. Liquidity index is the cumulative interest rates for providing liquidity. It's the multiplication of all of the interest rates for providing liquidity. Similarly borrow index is the multiplication of all of the interest rates on borrowing. Here's the function update index. How the interest accumulate are different between providing liquidity and borrowing tokens. For providing liquidity the interest accumulates linearly over time. And for borrowing the interest compounds every second.
Here's the code for how the interest accumulates for providing liquidity. First it calculates the amount of interest that accumulated since the last time this contract was updated by calling the function calculate linear interest. After this cumulative liquidity interest is calculated, it is multiplied to the current liquidity index. Remember that liquidity index represents the cumulative interest rates. It's the multiplication of all of the interest rates since this contract was deployed. This is how the next liquidity index is calculated. You'll see a similar thing happening for a borrow index. The next variable borrow index is calculated by taking the current variable borrow index and then multiplying by the cumulative variable borrow interest. This cumulative
variable borrow interest is calculated by multiplying the interest rate every second since the last time this contract was updated. In other words it's a compound interest. So this is the function update indexes. Going back to the function update state we just covered the function update indexes, which updates the liquidity index and the variable borrow index. So now let's go back to the supply logic. The next part that I want to cover is called update interest rates and virtual balance. So we need to go back to the reserve logic library again. Here's the function update interest rates and virtual balance. This function will calculate the next interest rates given the current amount of tokens that are
being supplied and the current amount of tokens that are being borrowed. This logic is under the function called calculate interest rates and it calls an interface called I reserve interest rates. There's a default contract called a default reserve interest rate strategy V2, which calculates this interest rate. Let's look at this contract. Okay, here's the function calculate interest rates. Inside here it first calculates the utilization rate, borrow usage ratio and supply usage ratio. And from this usage ratio it calculates the borrow interest rate. The logic for this is contained over here. Remember a few videos back we looked at the interest rate model. This graph represents the borrow interest rate depending on the utilization between zero and one. The
code inside here implements that logic. If the utilization rate is greater than the optimal utilization rate, then to the current variable borrow rate it adds an additional rate. And then once the variable borrow rate is calculated, we can also calculate the liquidity rate, which is take the variable borrow rate, multiply by the supply usage ratio and then subtract the protocol fee. And this completes the code walk through for the function calculate interest rates. Now let's go back to the reserve logic contract. Once the interest rate is calculated it updates it and then at the end it updates the virtual underlying balance. If tokens were supplied then the virtual underlying balance will increase and if the tokens were withdrawn, virtual underlying balance
will decrease. After the liquidity and the borrowing indexes are updated and the interest rates are also updated, it finally calls the function mint on the A token address. The A token is a token that is minted when you supply tokens to Aave. This token inherits from another contract called scaled balance token base. We've already seen this contract. When the function mint is called it eventually calls a function called mint scaled. And inside here we see that the amount is divided by the current liquidity index to calculate amount scaled and this is the amount that is being minted. And that completes the code walk through for the function supply. In summary what you'll see when you look at the code for withdrawal, borrow or repay is that it first updates
the state, updates the indexes for liquidity and borrow. Next it will calculate the interest rates for borrowing and providing liquidity. And then it will call the function mint or burn on the scaled balance token base. The way that the Aave contracts are organized is the following. The user will interact with the pool contract. The pool contract is actually a upgradeable proxy, which means that there's a contract that actually stores the state variable and the logic to be executed is stored in another contract. Some of the functions that user can call on the pool contract are supply to supply their token as liquidity, borrow and repay tokens, withdraw to withdraw their liquidity, liquidation call to
liquidate a collateral for a bad debt and then flash loan simple. The logic for supplying, withdrawing, borrowing and repaying tokens are separated into libraries. For example, when the user supplies liquidity it will execute code inside supply logic. When the user borrows it will execute code inside borrow logic. In both cases it will also update the state of the reserves. Therefore it will also execute some code logic inside reserve logic. Now these are code to be executed but the actual data, the actual state variable will be stored in the pool contract.
Furthermore, the code logic for reserve configuration and user configuration is stored in another library. There's also the I reserve interest rate strategy that will calculate the interest rates. And then we will have Aave Oracle which will get the asset prices. For each underlying token that is managed by Aave there will be a A token and a variable debt token. A tokens are minted when liquidity providers provide their liquidity into Aave and variable debt tokens are minted when users borrow these token. When a liquidity provider provides token to the Aave protocol, for example let's say they provide USDC. The USDC will eventually be locked inside the A token
that corresponds to USDC. For DAI and WETH there will also be another A token and variable debt token. Each of the tokens here will have a separate A token and variable debt token where inside the A token it will hold the underlying token. The minting and burning of A token and variable debt tokens are managed by these libraries. So this is how the contracts in Aave are organized. Users interact with the pool contract. The pool contract executes some logic inside the library contracts. The actual tokens that are being supplied will be stored in A token, the debt will be tracked by variable debt token and each token that is managed by Aave will have a separate A token and variable debt token. Let's
look at the actual transaction of supplying tokens to Aave. Here you're looking at a transaction debugger inside Tenderly. Scrolling down you can see all of the functions and the contracts that was called when I supplied DAI to Aave. To supply tokens to Aave you'll need to call the pool contract. The pool contract is a proxy contract which you can see over here. And then on the right you can see that I've called a function supply with these parameters. This is the address of DAI. This is the amount of DAI that I provided. Further going to the right, there's a parameter called on behalf of. This is an address where I can specify who should receive the A token for supplying my DAI. Going back to the code we can see this. Here's the parameter called on behalf of. It
passes this parameter to supply logic {dot} execute supply. Inside the function execute supply, I'll highlight the params struct which contains the parameter on behalf of. Scrolling down, it passes this on behalf of parameter to the function mint on the contract A token. Going to the A token, the function mint will pass this on behalf of parameter to mint scaled which is a function that is inherited from scaled balance token base. And finally, inside the function mint scaled, on behalf of is the receiver of the A token. Calls the internal function mint for the amount amount scaled, and this amount scaled is allocated to the address on behalf of. So, this on behalf
of is the address that's going to receive the A token. Okay, moving on. The pool contract is a proxy contract. The actual code that will be executed is over here, pool instance. Again, it will call the same function supply passing in the same parameters. The function supply will call into the function supply logic {dot} execute supply, which we saw earlier. And then, it first calls supply logic cache. Since the state variable reserve is a state variable, it's caching this state variable into memory to save some gas. Next, it calls the function update state. Remember, inside update state, it updates the indexes for liquidity and for borrowing, which are indexes that is used to calculate the
interest that accrue for providing liquidity and the interest that accrues to debts. Next, it calls a function called validate supply. And then, it calls a function update interest rates and virtual balance. Inside here, the interest rate for borrowing and providing liquidity is updated along with the virtual balance. The virtual balance is the internal balance of the token that is tracked by Aave V3. When you provide liquidity, this virtual balance will increase. And when you withdraw tokens, this virtual balance will decrease. Next, it calls safe transfer from on the DAI token. Since in this transaction, I'm supplying DAI as liquidity, it transfers DAI from me into the pool contract. Let's look at the receiver of the DAI. From my account,
where is the DAI being sent to? So, this is my account and the DAI is being sent over to this address. I've copied the address of the receiver of the DAI token inside Etherscan. This address turns out to be the A ETH DAI token contract. So, the DAI is sent from my account into A ETH DAI token contract. And then, next it calls a proxy to mint tokens. A token is a proxy contract. So, here it's minting the A ETH DAI token to me. And then, it does some validation and emit events. So, this was a quick code walk-through of the function supply. In Aave V3, interest on debt compounds every second. The interest for supplying token is a combination of linear and compounding interest. Now, to calculate
the debt for any user, we introduced the function called the rate accumulator function. The interest rate may vary every second and the interval where this interest rate is applied to doesn't matter. Using this rate accumulator function, we can correctly calculate the interest on debt. But, how about the interest for providing liquidity? Since the interest for providing liquidity is a combination of linear rates and compounding rates. In this video, I'll explain how the interest for supplying token is calculated and also explain that we can still use this rate accumulator function with a slight modification.
As a review, let's start by calculating the debt. And for simplicity, we'll say that the rate is equal to 1% from time equal to zero to time equal to three. At time equal to three, the rate updates to 2%. If a user borrows 100 token from time equal to one up to five, then the debt that they owe will be the amount of tokens that they borrowed multiplied by the interest for each second. We can express this using the rate accumulator function as 100 multiplied by R4 divided by R0. Now, when you supply a token, the interest applies a little bit differently. Unlike the debt, the interest does not compound every second.
The interest will grow linearly every second until there's an update on the interest rates. In this example, the interest rate updates at time equal to three. So, if a user supplied 100 tokens at time equal to one, the interest rate will increase linearly from time equal to one to three. So, this is 1 + R1, the interest that linearly increased from time equal to one to two, plus R2, the interest rate that grew from time equal to two to time equal to three. At time equal to three, the interest rate updates. And this is where the compounding for interest applies. To the previous amount, we multiply the new interest. From time equal to three to five, the interest will grow linearly.
At time equal to five, let's say that we withdraw the tokens. Then, the total amount that we can withdraw including interest will be the previous amount multiplied by the interest rate that grew linearly from time equal to three to five. Let's compare this with the debt. For the debt, the interest compounded However, when you supply tokens, the interest rate increased linearly until the rates were updated. In this example, the rates were updated at time equal to three. Hence, at time equal to three, we multiply the part of the interest that grew linearly. And at time equal to five, when we withdraw this token, we do the same. The part of the interest that grew linearly from time equal to three to five is 1 + R3 + R4. Looking at the equation for the interest on debt and
the interest on supply, they look slightly different. So, you might be asking, can we still use the rate accumulator function to calculate the interest on supply? And the answer is, you can. We simply need to modify the part of the interest that grows linearly. For example, let's re-label R1 + R2 as S1 and R3 + R4 as S2. Now, you can see that the equation for debt and for supply looks similar. For the debt, we have 1 + R1. And for the supply, we have 1 + S1. The next terms are 1 + R2 for the debt and 1 + S2 for supply. The final step is to redefine the rate accumulator function for supply. Instead of multiplying all of the rates per second, we multiply the sum of the
linear interest. We'll re-label this as S of n, and this is equal to 1 + S0 multiplied by 1 + S1 multiplied by 1 + S2 and so on. Each S of I here will represent the accumulation of the linear interest between updates. And finally, we can rewrite the amount of tokens that we will receive including interest using the rate accumulator function. This is equal to 100 multiplied by S of 2 divided by S of 0. And now, the algorithm that was used to calculate the debt for every user can also be used to calculate the liquidity plus interest for all liquidity providers. Here is an example transaction where I borrowed DAI from Aave V3. Let's look at some of the contracts and the functions that are
called when the function borrow is executed. I'm inside the Tenderly transaction debugger and I pasted the transaction hash inside here. Scrolling down, you can see all of the contracts and the functions that were called along with the parameters that were passed. So, this is really helpful to understand how the contract works. The function borrow first calls a proxy contract. The pool contract is a proxy contract. Hence, you're seeing the name of the proxy contract instead of the pool contract. On it, it calls the function borrow passing in the parameters the asset that you want to borrow. In this case, this is DAI. The amount of DAI that I want to borrow and other settings. The interest rate model is set to two. Where two means that the
interest rate model is variable debt. Before the current version, there was another interest rate model for the stable debt. However, in the current version, there is only variable debt. So, variable debt interest rate model will be equal to two. And then, scrolling to the right, there's another parameter called on behalf of. This parameter allows us to borrow debt on behalf of another user. For example, let's say that Alice approves Bob to take on debt on her behalf. Then, for this parameter, if Bob was to call this function, he will set this parameter on behalf of to the address of Alice. Since Alice has approved Bob to take on debt on her behalf, he'll be able to take out loan and the debt will be allocated to
Alice. Let me show you this in code. Inside the function borrow for the contract pool, here we have a parameter called on behalf of, which is passed to the function execute borrow on the library contract borrow logic. Inside the library contract borrow logic and inside the function execute borrow, let's highlight the params struct and then look for the parameter called on behalf of. Scrolling down, okay, here it is. When we borrow tokens from Aave, it will mint a I variable debt token. It calls the function mint and then passes in several parameters. User, this user will be message sender, the account that called into the function borrow. On behalf of is the parameter that we're
interested in and there are other parameters. Let's take a look at the contract variable debt token. Okay, here it is. The function mint. Inside it, if the user is not equal to on behalf of, then decrease borrow allowance. This function decrease allowance is declared inside another contract called debt token base. What it does is it would decrease the allowance from delegator to delegatee. If Alice had allowed Bob to take debt on her behalf, then the delegator will be Alice and delegatee will be Bob. Alice approves Bob to take on debt, which is specified by the amount. If the user is not equal to on behalf of, if the caller is not equal to
on behalf of, then decrease the borrow allowance. And then, it will call the function mint scaled. The function mint scaled is declared inside the contract scaled balance token base. In our example, Alice approved Bob to take on debt on her behalf. So, this parameter on behalf of will be Alice. The internal function mint is called on on behalf of. This is the address that's going to be receiving the debt token. In our example, this on behalf of will be Alice. Alice takes on the debt, however, Bob is able to borrow the tokens. In Aave, this feature is called credit delegation. It allows users to give credit to other users so that they can borrow tokens using your credit. Going
back to the transaction debugger, let's look at the rest of the functions that are being called. Since the pool contract is a proxy contract, it will call the function borrow on the implementation contract pool instance, passing in the same parameters. And then moving on, it eventually calls into the library borrow logic and calls the function execute borrow. Inside the function, it first caches the state variable reserve to save gas. Updates the state. We already seen when we did a call walk through for the function supply that the function update state will update the liquidity and the borrow index. And then later on, you'll see that it updates the interest rates and the virtual balances. In between these
calls, it will mint the variable debt and transfer the token out to the caller who wants to borrow that token. The variable debt is minted over here. The variable debt token is a proxy contract, so here you're seeing the name of that proxy contract. Once the debt token is minted to on behalf of, it would transfer the tokens to message sender. We can see this by scrolling down, then scrolling to the right, and then over here it calls transfer underlying two. Again, this is a proxy contract. Let's check this in code. Is this proxy contract the variable debt token or is it the A token? Back inside the library borrow logic, we minted variable debt token. And then scrolling down, it
updates the interest rates and virtual balance. And then scrolling down further, we see that it calls the function transfer underlying two on the A token. So, now we know that the A token is a token that holds on to the underlying tokens. This token is transferred to user, where user is message sender. When the function borrow logic.executeBorrow is called, this user is specified as message sender. So, back inside the borrow logic, the transfer underlying two transfers the underlying token to message sender. And that completes a brief call walk through for the function borrow. Interest on debt compounds every second. The amount of interest that has compounded since the
last time the borrow index was updated is given by this equation, 1 + X raised to the N, where X is the interest rate and N is the time that has elapsed since the last time the borrow index was updated. For example, if the rate was 1%, then X will be 0.01. And if 10 seconds has elapsed since the borrow index was updated, then N will be equal to 10. And if 100 seconds has elapsed, then this N will be equal to 100. The calculation for compounding interest becomes more expensive as this N gets larger. To solve this problem, that calculating compound interest becomes more expensive as N gets larger, Aave B3 uses another mathematical equation that
will approximate this compounding interest. It uses binomial expansion to approximate the compounding interest 1 + X raised to the power of N. We expand the summation. Next, we replace the Y with a one. Since we're approximating 1 + X raised to the power of N, we don't need all of the terms. Adding the first four terms and omitting the rest of the terms is a good enough approximation. And this is the equation that is used inside the Aave B3 protocol to approximate the compounding interest for a duration of N seconds. How good of an approximation is this?
Well, we can run a Python simulation to see how good the approximation is. I have my Jupyter Lab open. Inside here, I've written a function that will calculate the binomial expansion for the first four terms using Python. This function is called binomial approx, which takes in two inputs, R and N. R will be the rate and N will be the duration. Now, since Solidity does not support decimal numbers, a common way to handle this is to have 10 raised to some power equal to one. In this example, I'll say that 10 raised to the power of 27 is equal to one. Once I have this function that will approximate 1 + X raised to the N, next I run the simulation. For N, I set it to a day, 24 hours multiplied by 3,600 seconds. And
then we'll run the loop for 30 days. For the interest, I set it to 10%. Inside the for loop, it's going to calculate two numbers. The first number Y will be the exact amount of 1 + X raised to the power of N. And the variable Z will be the calculation of the binomial expansion. It appends these two results into a list, and then we graph the results. Here you're looking at a result of running the simulation for 30 days. So, let's compare how good of an approximation the binomial expansion is. Shown in blue is the exact amount if we were to compound 10% every second for 30 days. And shown in orange is the approximation. You can see that for a short amount of time, the approximation is really close to the actual number,
but as time goes on, the difference gets larger. At the end of the 30 day, the difference is approximately 7 times 10 raised to the 27. Since one is represented as 10 raised to the 27, this will be a difference in 700%. So, in 30 days, the approximation is off by 700%. However, if you were to run this simulation for a shorter duration, let's say 10 days, and then look at the results, the two graphs are close to each other and the difference being small after 10 days. The difference is 5 multiplied by 10 raised to the 25. 10 raised to the 27 is 100%. 10 raised to the 26 is 10%, so 10 raised to the 25 is 1%. So, this is a 5%
difference here. And then if you were to only do it for a day, then the difference is really small number. It's less than 1%. So, in summary, we saw that the binomial expansion is a good approximation to 1 + X raised to the N given that we run the simulation only for a day and the rate is 10%. When it comes to borrowing tokens on Aave or when you're looking at the code that implements the logic for borrowing, you might come across a term called reserve factor. So, in this video, I'll explain what reserve factor is. Reserve factor is the percentage of borrowing interest that will be kept by the protocol. When a user borrows and then repays the token, they'll have to repay with interest. Part of that
interest will go to the protocol. The percentage that will go to the protocol is determined by the reserve factor. Here, the reserve factor is 15%. This means that the 15% of the interest that was paid will be kept by the protocol. We can see this in code. The contract that is responsible for calculating the interest rates for borrowing and for supplying token is the default reserve interest rate strategy B2 contract. Inside here, there's a function called calculate interest rates, which will calculate the two interest rates, borrowing and supplying. If we scroll all the way down, you can see that the supply interest rate is calculated by taking the current borrow interest rate and then multiply by the utilization
rate and subtract the percentage that will be kept by the protocol. So, that is reserve factor, a percentage of interest that will be kept by the protocol. Let's look at example of max LTV. As a review, LTV stands for loan to value. And max LTV will be the maximum borrowing power of a specific collateral. Let's look at example. Let's say that the current price of ETH is 3,000 USD. And the max LTV for ETH is set at 93%. If you were to deposit one ETH as collateral, then what is the maximum amount of other tokens in terms of USD that we can borrow? This is what max LTV will tell us. To calculate max LTV, all we have to do is multiply the amount of
collateral that we have by the current price of the collateral and finally multiply by the LTV. Here in our example, we deposit one ETH as collateral and the price of ETH is currently 3,000 USD with LTV 93%. So, let's multiply all of these numbers to calculate max LTV. This is we need to calculate 0.93 multiplied by one ETH and multiplied by the price of one ETH. This is equal to 0.93 multiplied by 3,000, which turns out to be 2,790. Given that our current max LTV is currently 2,790, we're able to borrow tokens up to this USD value. For example, given that USDC is exactly equal to one USD, we will be
able to borrow 2,790 USDC. Liquidation threshold is a threshold at which borrow position is considered under collateralized. It's a number that is to be compared with the user's LTV, loan to value. The user's LTV is a ratio that is calculated by taking the debt that the user took on in terms of USD, divide this by the USD terms of the collateral that they deposited. This will give you a ratio. This ratio will be a non-negative number. So, for example, let's say that the user's LTV is a number somewhere between zero and one. The liquidation threshold will also be a number between zero and one. And here, it's important that this liquidation ratio is strictly less than
one. Since the LTV is calculated by dividing the debt over the collateral in terms of USD and this protocol strictly requires that loans are over collateralized, the protocol needs to make sure that the USD value of the debt is always less than the USD value of the collateral. Therefore, dividing those two numbers, the ratio must always be strictly less than one. So, the liquidation threshold must also be strictly less than one. The protocol wants to trigger a liquidation before the debt becomes under collateralized.
And then you have the maximum LTV that is specific for this user. So, these are the three numbers that you should remember about liquidation threshold. We have the user's LTV, which is less than or equal to the max LTV that is specific to this user. And then we have the liquidation threshold, which is greater than max LTV, but also less than one. The health factor is the single most important number that you need to pay attention to when you borrow tokens from Aave. Health factor less than one means that your collateral can be liquidated. So, it's important to keep your health factor above one. Here I will explain how the health factor is calculated. To calculate the health factor, we first need to calculate the average liquidation threshold. It's basically
the weighted sum of all of the liquidation thresholds where you deposited a collateral. To calculate this, let's denote c r of u to be the USD value of the collateral locked in reserve r by user u. We'll denote b r of u to be the debt in USD from reserve r by user u. For example, let's say that Alice deposited one ETH as collateral when the price of ETH is 3,000 USD. Then c of ETH for Alice will return 3,000. As another example, if Bob deposited 1,000 USDC as collateral, then this c r of u will be c of USDC for Bob will return 1,000 USD.
Let's move on to the example of b r of u. Let's say that Alice borrowed 1,000 USDC. Then this r will refer to USDC, this u will be Alice, and this value for USDC for Alice will return 1,000. She borrowed 1,000 USDC. Given that one USDC is exactly equal to one USD. All of the reserve have a specific liquidation threshold that is unique to that reserve. For example, ETH might be liquidation threshold at 77% and USDC might have a liquidation threshold at 80%. We'll denote the liquidation threshold that is specific to reserve r as l of r. Given these notations, we're now finally ready to define what the
average liquidation threshold for user u is. Let's denote this as l of u. The average liquidation threshold for user u is calculated by taking the weighted sum of the collaterals that this user deposited. For each collateral, we multiply that by the liquidation threshold of that collateral. And then we divide by the total USD value of the collateral that this user locked. This is how the average liquidation threshold for user u is calculated. This average liquidation threshold will be used in the next step to calculate the health factor. We'll denote h of u to be the health factor of user u. The health factor is calculated by taking the average liquidation threshold of this user u. Multiply this by the total USD
value of the collateral that this user deposited. And then divide by the total USD value of the debt that this user took on. This is how the health factor is calculated. If this health factor is less than one, this user's collateral can be liquidated. Now, let's try to understand how the number that is calculated from this equation will behave as the price of the collateral goes up and down and as the price of the debt goes up and down. Remember that when a user borrows, their health factor must be above one. For simplicity, assume that this liquidation threshold is one or 0.5. They're easy numbers to use. And now let's consider this part of the equation. Let's say that Alice deposited ETH as collateral. That's the
only collateral that she deposited and then borrowed USDC. So, we're only concerned with two tokens, ETH on top and USDC on bottom. Let's say that the price of ETH is 3,000 USD and Alice deposited one ETH. Let's also say that the price of USDC is $1 and Alice took out a loan of 1,000 USDC. So, now you can see that on top this will be 3,000 since she deposited one ETH when one ETH is exactly equal to 3,000 USD. She took out a loan worth $1,000. 3,000 divided by 1,000 is three. So, currently her health factor will be equal to three.
Now, let's consider the case if the price of ETH goes down. Let's say it goes down to one ETH equal to 500 USD. So, now on top you have 500 USD and on the bottom the debt is still 1,000 USD. This is 500 divided by 1,000, which is equal to 0.5. Her health factor is now below one. It is equal to 0.5. And for simplicity here, I assumed that the liquidation threshold was equal to one. You can see from this example that when the price of the collateral goes down, the health factor will also go down.
When the price of the collateral goes up, the health factor will also go up. And likewise, when the price of the token that you borrowed goes up, the health factor will go down. And when the price of the token that you borrowed goes down, then the health factor will go up. When you want to repay the tokens that you borrow, you need to call the function repay on the contract pool.sol. The amount to repay is specified by this parameter called amount. If you wanted to repay all of your debt, then you cannot simply specify the current amount of debt that you owe. Since the variable debt token is a rebase token, the amount of debt is continuously increasing. The amount of debt that you need to repay when you send a transaction will be slightly lower than the actual amount of token that you'll need to repay when the
transaction is executed. So, let's see how we can specify this amount so that we can pay all of our debt. The function repay executes another function called execute repay on the library contract borrow.sol. Inside the function execute repay, I'm going to highlight the struct called params. This is the parameter that was passed from the pool contract. So, going back, we're concerned with our parameter called params.amount. Scrolling down, we see it mentioned over here. And then it sets a variable called payback amount to params.amount.
What is this payback amount? The payback amount is initially set to variable debt, where the variable debt is the variable debt token balance of on behalf of. On behalf of will be the account that you're paying the debt for. So, first get the variable debt. This is the current amount of debt that this user owes to Aave. And then this variable debt is set to the amount to be paid, payback amount. Okay, and now we can understand this part of the code. If params.amount is less than payback amount, the total amount that can be paid at this moment, then the actual amount to be paid is only a partial amount of the total debt. Set the payback amount to the amount that was
specified. So, now I think you can see the problem here. Let's say that when we executed the function repay, our debt was 100 tokens. So, we send a transaction to repay for 100 tokens. Inside the borrow logic, when this function is executed, let's say that our debt our current debt is 101 token. Since the variable debt is a rebase token, the balance of the tokens are always increasing. Debt is always increasing. Payback amount 101 token. The amount that we specified 100. Our total debt that we need to repay at this moment is 101 token. The amount that we specified is 100. Even though we wanted to pay all of our debt, there's a fraction of debt that is remaining. Back
inside the pool contract, if you wanted to pay all of our debt, then for this amount we need to specify amount that will be greater than the payback amount, the balance of variable debt when this function is executed. For example, we can set this amount to the maximum uint256. In this case, we're saying that we're going to pay all of our debt. And the payback amount, the balance of the variable debt, will certainly be less than the maximum uint256. So, if you wanted to repay all of your debt, that is how you do it. You set this params.amount to a number that is greater than the current balance of variable debt. And one way to do this is to set this amount to the maximum uint256. Recall that to repay all of our debt, this amount had to be greater than
the current debt when this function is executed. One way to do this was to set this amount to the maximum of uint256. The reason why we had to do this is because the variable debt token is a rebase token. The amount of debt that we owe is always increasing. The amount of debt that we see when we send a transaction will be slightly less than the actual amount that we'll have to pay when this function is executed. We fall into the same problem for the function withdraw. The function withdraw is called when you want to withdraw the token that you supplied to Aave. This token can either be a collateral that you deposited or a token that you deposited into Aave simply to earn the interest for providing liquidity. Let's say that you wanted to withdraw all of
your token that you supplied to Aave V3. To make this a little bit easier to understand, let's put in real numbers. Let's say that the amount that you want to withdraw is 100 tokens. The function withdraw is going to execute a function called execute withdraw on the supply logic contract. Inside the function execute withdraw, we're going to look for a parameter called amount on the params struct. Scrolling down, okay, here it is. Amount to withdraw is params.amount. If params.amount is equal to the maximum of uint256, then set the actual amount to withdraw to user balance, where this user balance is the scaled balance of message sender multiplied by the next liquidity index.
This next liquidity index is the current liquidity index, the liquidity index that is up-to-date. Multiply this by the scale balance of message sender to get the actual amount of token that this user can receive. This includes the amount of token that they supplied plus any interest that they earn for providing their token as liquidity. This is the maximum amount of token that they can withdraw. If params.amount is specified through the maximum amount, we limit this amount to the balance of their tokens. Amount to withdraw is set to the user's balance. So, now you can see the same problem that we saw when we looked at the function repay. If when we call the function withdraw, our token
balance was 100, and then we set this amount to 100, and let's say that the user balance, since it's always accruing interest, is currently equal to one hundred one token, then the amount that we're going to withdraw is 100 token, and there will be one token left over inside this contract. If you wanted to withdraw all of our token, we need to make sure to specify that the amount to withdraw is the maximum of uint256. Otherwise, you're leaving some tokens inside the Aave V2 protocol, and considering the gas cost to withdraw those small amount of tokens, it might not be worth it to claim them.
Collaterals that back up a under collateralized loan can be liquidated. Liquidation means that the collateral is given to whoever pays the debt. The amount of collateral to be liquidated is determined by what's called a close factor. The close factor is the maximum percentage of debt that can be paid during liquidation. In the current implementation of the Aave V2 protocol, there are two cases for the maximum amount of debt that can be repaid. The default is 100% of the debt. All of the debt can be paid. And then there's another condition where it will only allow up to 50% of the user's total debt to be repaid. For the rest of the video, I'll explain what this other condition is, and what it means for 50% of user's
total debt can be repaid. The first condition is that the collateral to liquidate and the debt to repay both must be greater than a constant called minBaseMaxCloseFactorThreshold. This is currently set to 2,000 USD. You can think about this as the USD value collateral to liquidate and the debt to repay both must be greater than 2,000 USD. The next condition is that the health factor must be greater than 0.95. Recall that for collaterals to be liquidated, health factor must be less than one. Here, it's saying that the health factor must be less than one, and also must be greater than 0.95. The last condition is that the debt to repay must be greater than user's total debt
multiplied by a constant called default liquidation close factor. Currently, this is set to 50%. So, in other words, the debt to repay must be greater than 50% of the user's total debt. So, these are the three conditions that need to be satisfied for the max debt to repay to be at 50% of user's total debt. Next, I'm going to explain what 50% of user's total debt looks like. We'll represent the user's total debt as a red rectangle shown here. 50% of the user's total debt, so we'll split this rectangle in half. Imagine that the composition of this user's total debt is the following: user's debt in token A is above 50%, and the remaining debt are composed of other
tokens. For example, let's put some real numbers in. Let's say that the user's debt in total is 10,000 USD, and we'll set user's debt in token A, shown over here, as 6,000 USD, slightly above 50% of 10,000 USD. Now, remember that over here, one of the other condition was that the debt to repay must be greater than 2,000 USD. In this example, this 6,000 USD is greater than 2,000 USD. In this case, the maximum amount of debt in token A that can be repaid is 50% of the user's total debt, which will be 5,000 USD. Debt in token A is 6,000 USD.
However, since this satisfies this condition over here, the maximum amount of debt that can be repaid is 5,000 USD worth of token A. Now, you might be wondering, what if the user's debt in token A is 51% instead of 60%? So, after liquidating 5,000 USD worth of token A, let's say that there is 1% left over here. Furthermore, let's say that this user's collateral can still be liquidated. But now, since the debt to be repaid is so small, liquidators won't have the incentive to repay this debt since the gas fee to execute a liquidation might be higher than the amount of collateral that they will receive. To prevent small amounts of debt to be remaining after liquidation,
the protocol checks that the debt remaining after liquidation is big enough so that in case there's another liquidation, the debt is big enough to motivate the liquidators to repay the debt, receive the collateral, and that value of the collateral is large enough to cover the gas fees. The amount of collateral to liquidate is based on a simple equation. So, in this video, I'll explain about the equation, liquidation bonus, and protocol fee for liquidation. The equation that calculates the amount of collateral to liquidate is based on this equation. The amount of debt to cover multiplied by the USD value of the token that was borrowed is equal to the amount of collateral to liquidate multiplied by the USD value of the collateral. Inside the code of Aave V2,
you'll see this part of the equation being divided by the collateral price to calculate the amount of collateral to liquidate. Remember this fact, and you'll have a easier time understanding how the amount of collateral to liquidate is calculated inside the code. Next, I'm going to explain about the liquidation bonus and the protocol fee that is taken for liquidation. Imagine that the total amount of collateral to liquidate is represented as this brown rectangle. The total amount of collateral to liquidate will include the liquidation bonus and the protocol fee. To get to this total amount of collateral to liquidate, we first calculate the collateral to cover debt.
This is based on this equation above. Once the collateral to cover debt is covered, we multiply this by some percentage to calculate liquidation bonus. For example, if the collateral to cover debt was one ETH, and the liquidation bonus was 5%, then this total amount will represent 1.05 ETH. And finally, from this liquidation bonus, a protocol fee is subtracted. The liquidation bonus will go to the liquidator, the account that called the liquidation. The protocol fee will be kept by the protocol. Now, imagine the case where the collateral to cover debt plus the liquidation bonus exceeds the amount of collateral that the user has.
For example, let's say that the user only has one ETH as collateral, and then the collateral to cover debt is exactly equal to one ETH. Let's also say that the liquidation bonus is again 5%. So, here in total, there is 1.05 ETH. However, the user only has one ETH as collateral. In this case, the amount of collateral to cover debt will be reduced so that it can still pay liquidation bonus and liquidate all of user's collateral. Here's my current position. I've deposited 5.06 DAI as collateral, and then borrowed 0.0017724 ETH. Currently, my health factor is at 0.89. Remember that if the health factor is less than one, then my collateral can
be liquidated. However, here I'm not worried about my collateral getting liquidated for two reasons. The first reason is that my collateral is only worth $5.06. The other reason is that my collateral probably will not be liquidated. So, you might be asking, the health factor is less than one, how come my collateral is not liquidated? The reason probably is is that the gas fee to liquidate this collateral is more than the collateral that they will get. My collateral is worth $5.06. However, the transaction to liquidate this collateral is probably more expensive than the collateral that they will receive. There's no incentive for liquidators to liquidate this collateral. Hence, you can see that I still have my collateral, and my health
factor is way below one. This is one aspect of over collateralized lending markets that you should be aware of. When your collateral is small, even if your health factor is less than one, your collateral probably will not be liquidated. And the reason is the transaction fee to liquidate this collateral is probably more expensive than the collateral that they will receive. The Aave V2 protocol has a feature called flash loan. A flash loan enables a caller to borrow tokens without depositing collateral, with the restriction that the borrowed tokens is repaid in the same transaction where you borrow the tokens. Inside the pool contract, there's two ways to get a flash loan. You can call the function flash loan to get loans on multiple tokens, or you can call the function
flash loan simple to borrow a single token. In this video, I'll explain how the function flash loan simple works. So, to borrow a single token using flash loan, you will call the function flash loan simple. The main function that is executed is called flash loan logic.executeFlashLoanSimple. This function is located inside the library called flash loan logic. Inside it, it will first calculate the amount of tokens that you will need to repay. The amount of tokens that you need to repay is the amount that you borrowed plus some fee on the amount that you borrowed. Next, it will send the tokens to the receiver address that you specified. After the tokens are sent, it will call function called execute operation on the receiver. The receiver
address here must be a contract that implements the function called execute operation. At this point, the contract has the amount of tokens that it requested to borrow. Inside this function, execute operation, you write your custom code to do whatever you want with the tokens that you borrow. For example, after flash loaning a token, you might do arbitrage. After this function is done executing, you must repay the tokens that you borrow plus the fee on the token that you borrow. So, after the function execute operation, the code inside here will withdraw the tokens that you borrow plus the fee that you owe to the protocol.
This is done inside the function handle flash loan repayment. Inside this function, you can see that it transfers the token from the receiver address to the A token address for the amount that was requested plus the fee. Therefore, if you want to use a flash loan, you must write a contract that will call the function flash loan simple. This contract must implement a function called execute operation. And at the end of this function, this contract must approve the pool contract to withdraw the amount that was requested plus the fee on the amount that was requested.
Once this function execute operation is done executing, Aave V3 protocol will withdraw the amount of the tokens plus the fee from the receiver contract. Using Aave V3 protocol, we can execute two financial strategies, long leverage and short selling. Long leverage is a financial strategy that you will execute when you want to bet that the price of an asset will go up. Now, you can bet that the price of an asset will go up simply by buying the asset, holding on to it, and when the price goes up, you will sell that asset. If you want to bet aggressively and amplify the potential profit that you would make if the price goes up, then you will use a long leverage. To execute a long leverage, you first borrow cash and then buy the asset that you're betting that the price
will go up. If the price goes up, you will sell this asset, repay the cash that you borrowed. Let's look at an example. Since this is a bet that the price of asset will go up, there are two cases to consider, when the price goes up and when the price goes down. We'll start with the case of when the price goes up. When the price goes up, the price move in the direction of your bet. You made the correct bet, hence this will be a profit. So, let's say that we create a long leverage position when the price of ETH is 2,000 USD and we close the position when the price of ETH reaches 4,000 USD. For this example, we'll say that we start with $2,000 We use this $2,000 cash to buy one ETH.
The next step is to borrow cash. Let's say that we'll use the Aave V3 protocol to borrow stablecoin, for example, USDC. And to borrow stablecoin, you'll first need to deposit a collateral. In this example, we'll use this one ETH as collateral to borrow some stablecoin. For simplicity, I'll just refer to the stablecoin as USD. Since in Aave V3, the USD value of the tokens that we borrow must be less than the USD value of the collateral that we deposited, let's first calculate the maximum USD value that we can borrow. Currently, one ETH is 2,000 USD. Let's say that the LTV setting for ETH as collateral is set to 90%, 0.9. Then the maximum amount of tokens that we can borrow in terms of
USD is given by this LTV multiplied by the collateral amount multiplied by the price of the collateral. This is equal to 0.9 * 1 ETH as collateral multiplied by the price of ETH, which is equal to 1,800 USD. So, let's say that we borrow 1,800 USD, the maximum amount of USD value that we can borrow. In practice, you shouldn't borrow up to the maximum limit since your collateral might get liquidated if the price of ETH goes down. However, to keep the math simple, we'll say that we'll borrow the maximum amount that we can borrow, 1,800 USD.
Once you borrow some cash, the next step is to buy the asset. So, let's calculate the amount of ETH that we can buy given 1,800 USD. If you wanted to buy one ETH, we would need 2,000 USD. Currently, we have 1,800 USD. So, we cannot buy one ETH. We can only buy a fraction of a ETH, and this is equal to 0.9 ETH. Using 1,800 USD, we buy 0.9 ETH. And in this example, the price of ETH goes up from 2,000 to 4,000 USD. Now, it's the time to close our leverage position and realize our profit. So, now let's sell all of our ETH, one ETH plus 0.9 ETH, to calculate the USD value of our position. We have
1.9 ETH in our hand. The current price of one ETH is 4,000 USD. If you were to sell 1.9 ETH, we will get back 7,600 USD. Finally, let's calculate the profit for opening and closing a long leveraged position. Our profit will be the difference of the final amount of cash that we have minus the initial amount of cash that we have minus the amount that we borrowed, which we will have to repay. The final amount of cash is 7,600 USD. And assuming that there's no fee for borrowing, we pay the 1,800 that we borrowed. And finally, we subtract the amount of cash that we initially had.
This is equal to 3,800. If we simply bought one ETH when one ETH was at 2,000 USD and then sold this one ETH at 4,000 USD, the profit that we will make is 2,000 USD. However, by taking a long leveraged position, we amplified our profit from 2,000 USD to 3,800 USD. So, this is the case of when the price goes up. When the price goes up, we make a profit. What happens in the case when the price goes down? When the price goes down, we will make a loss, and this loss will be amplified compared to simply buying the token and then selling it after the price goes down. For example, let's say that we buy one ETH when the price of ETH is 2,000
USD and then we'll close this long leveraged position when the price of ETH is 1,000 USD. Again, we'll start with $2,000 in cash. We open a long leveraged position. We start out with 2,000 USD and then buy one ETH. Deposit this one ETH as collateral to borrow USD from Aave V3 protocol. In this example, we can borrow up to 1,800 USD. So, we borrow the maximum amount that we can borrow and then buy ETH when the price of ETH is 2,000 USD. We can buy up to 0.9 ETH. Let's say that the price of ETH didn't go up. The price of ETH went down to 1,000 USD. So, now we want to close this position before our loss gets any bigger. We sell all of the ETH that we have. We have 1.9 ETH, one ETH over here
plus the 0.9 ETH over here. The current price of ETH is 1,000 USD. So, we get back 1,900 USD in return. Finally, let's calculate the loss after closing this position. 1,900 is the final amount of cash. We repay the 1,800 that we borrowed. And finally, we subtract the initial amount of cash that we had. This turns out to be minus 1,900 USD. Let's compare this with the loss that we would have made if we simply bought the token at 2,000 USD and then sold it at 1,000 USD. In this case, the loss will be 1,000 USD. However, by taking a leveraged position, our loss is amplified. Our loss is minus 1,900 USD.
So, in summary, to open a long leveraged position, we will first borrow cash. In our example, using Aave V3 to borrow this cash, we first needed to deposit a collateral. Once you borrow cash, you buy the asset that you think that the price will go up. When the price goes up, you will sell this asset and then repay the cash that you borrowed. We saw in the two examples that long leverage can both amplify the profit and the loss. The other financial strategy that you can execute with the Aave V3 protocol is called short selling. Short selling is a financial strategy that you can execute when you want to bet that the price of an asset will go down. For example, if you think that the price of ETH will go down, then you can short ETH to potentially make a profit. If the
price of ETH actually goes down, then you'll make a profit. To short an asset, you first borrow the asset and then immediately sell the asset. Later, when the price of the asset goes down, you will buy it and then repay the asset that you borrowed. Since you're selling the asset at a high price and then buying it back at a lower price, the difference will be the profit. Let's look at an example. Now, since this is a directional bet on the price of an asset, you will make profit if the price of the asset goes down. And if the price of the asset goes up, then you will make a loss. Let's begin by looking at the case when the price of the asset goes down. In this case, you will make a profit. Let's say that we create a position to short an asset when the
price of one ETH is 2,000 USD and then we close our position when the price of ETH has gone down to 1,000 USD. In this example, we'll say that we start out with $2,000 in cash. On Aave, we use this $2,000 as collateral to borrow ETH. So, let's calculate the amount of ETH that we can borrow if you were to use $2,000 as collateral when the price of one ETH is at 2,000 USD. Let's first calculate the maximum amount that we can borrow in terms of USD and then we'll convert that into the amount of ETH that we can borrow. Let's say that the LTV setting inside the Aave V3 protocol for USDC is set to 90%, 0.9. The max borrow in terms of USD is given by LTV multiplied by the collateral amount
multiplied by the collateral price. This is 0.9 multiplied by 2,000 USD that we put in as collateral, and here we'll assume that the price of one USDC is equal to $1. So, this is equal to 1,800 USD. Our max borrow in terms of USD is 1,800 USD. Let's now convert this amount into the amount of ETH that we can borrow. Currently, the price of one ETH is 2,000 USD. What is the maximum amount of ETH that we can borrow? The maximum amount that we can borrow in terms of USD is 1,800 USD. The price of one ETH is 2,000 USD. So, the maximum amount of ETH that we can borrow is 0.9 ETH. Using 2,000 USD C as collateral, we borrow 0.9
ETH. Here, we're betting that the price of ETH is to go down. So, we immediately sell this ETH. The current price of ETH is 2,000 USD. So, if we sell 0.9 of them, we'll get back 1,800 USD. We wait a while and let's say that the price of ETH has gone down from 2,000 to 1,000 USD. Let's now buy back this ETH. We borrowed 0.9 ETH. So, let's buy back 0.9 ETH. Now here for simplicity, we're assuming that the fee on borrowing is equal to zero. In reality, if you borrowed 0.9 ETH, then you'll have to pay the amount that you borrow plus some interest. Once we have this 0.9 ETH, we'll repay this. We borrowed 0.9 ETH, so we repay the 0.9 ETH. Now let's calculate the profit that we made. When
we sold the ETH that we borrowed, we had 1,800 dollars in cash. When we bought back the 0.9 ETH that we borrowed, one ETH was equal to 1,000 USD. So, buying 0.9 ETH takes only 900 USD. We were able to repay the 0.9 ETH that only spending 900 USD. The leftover 900 USD will be our profit. We looked at a case where we created our short position and the price went up. When the price goes down, we'll make a loss. So, let's calculate the amount of loss that we'll make. In this example, again we'll start with one ETH equal to 2,000 USD. Let's say that the price of ETH when we close this position is one ETH equal to 4,000 USD. Again, we'll say that we start with
2,000 dollars in cash. The strategy that we'll execute will be the same. We have 2,000 USD in cash. We use this as collateral to borrow 0.9 ETH and then we immediately sell this 0.9 ETH. When we sell this, one ETH is 2,000 USD and then we sell 0.9 of them. So, we get back 1,800 USD. Later on, we close our short position. We borrowed 0.9 ETH, so we need to repay 0.9 ETH. So, we will buy 0.9 ETH and then repay the 0.9 ETH that we borrowed. Since the price of ETH did not go down, it went up, we'll make a loss. Let's calculate the amount of loss that we made. When we sold the ETH, we got back 1,800 USD. We need to buy back this 0.9 ETH when one ETH is equal to
4,000 USD. 0.9 * 4,000 will be 3,600. So, to buy back 0.9 ETH, we'll need to pay 3,600. Taking the difference, our loss is minus 1,800 USD. Now there's actually two topics that I don't teach in this course, max leverage and flash leverage. When you create your long or short position, you can actually repeat the process over and over again to amplify your long leverage or your short selling position. The maximum amount of leverage that you can create using over-collateralized loans is described by this equation. There's also a technique called flash leverage, which will use flash loans to create the same leveraged position. Both of these topics
are explained in the course Rocket Pool ETH integration. Currently under section three called Aave flash leverage. So, if you're interested in how the equation for the max leverage is derived or how to use flash loan from Aave to create a leveraged position or the math that describes the amount of flash loan that you'll need to take to create this leveraged position, then check out the Rocket Pool ETH integration course under section three Aave flash leverage.