Cyfrin Updraft: Uniswap V3 Full Course

Cyfrin Updraft Courses · 6:24:21

Tasuku Nakamura, a smart contract engineer and educator, teaches the mathematics and contract structure of Uniswap V3. The course develops concentrated-liquidity intuition and then examines swaps, factories, position management, fees, flash loans and TWAP oracles through code walkthroughs and exercises. It assumes Solidity, advanced Foundry and Uniswap V2 knowledge.

Speakers

Topics

From Cyfrin Updraft Courses, hosted by Cyfrin.

Transcript

Welcome to the course for UNISOP V3. This course is for solidity developers who have experience working with Foundry. To fully understand this course, you should also have a basic understanding of a constant product AMM such as Unisoft V2. What will you learn in this course? You'll learn the algorithms of UNISB3. Some of the topics that we'll cover are math for liquidity, algorithm for swaps, and the algorithm to calculate the fees for liquidity providers. I will also explain the math and the code for time weighted average pricing tap. And finally, there will be several exercises in foundry. In this course, we won't cover the advanced math library used in unisoft v3. We'll work a little bit with the periphery contracts position manager and the router

contract. However, we will not go into the details of how they work. Why should you take the course? Many of the core math used in unis swap v4 to calculate liquidity and to calculate the swap amount is basically copied over from unis swap v3. So by taking this course you'll have a foundational understanding of some parts of unisop. Another reason to take this course is that you might have ideas for a new amm. U3 is a influential contract. So I'm sure that when you're doing audit contest and bug bounties knowing the core mechanics of unis swap b3 will help. This course has some exercises in Foundry. So here I'm going to explain how to set up Foundry to do the exercises and then where to look for the exercises and the

solutions. So the first step is to navigate to the GitHub repo advanced D5 2024 and then get clone this repo. You can do that by clicking on this button called code and then copying this git URL and then inside your terminal type get clone followed by this URL. So once you clone this repo, head over to the readme and then scroll down and you're looking for a link called Uniswap B3. Okay, here it is under topics, Uniswap B3. Click on this and this will take you to another page. Inside here, it links to all of the resources that you'll need for this course. In particular here, I want to show you what the exercises will look like. Scrolling all the way down.

Okay, here it is. Exercise one, single pull exact input. Let's click on this to see what the exercise looks like. Okay, here it is. Here is the exercise. Inside this contract, the instructions are laid out to how to do the exercises. Once you fill out code inside here, you'll execute the foundry test to check your answer. Now, if you're feeling stuck, you can check the solutions. Notice how the folder is structured. Let's click on this folder called B3. There are two folders here, exercises and solutions. Exercises will contain incomplete solidity files where you will fill out the code to complete the tasks.

Solutions will contain the contracts with the answers filled in. And finally, I'll show you where to look for instructions on how to set up Foundry for this course. Let's go back to advanced D5 2024. Okay. And then under readme, go all the way down to a link called exercises and solutions under table of contents. Click on this and then this will take you to a section called exercises and solution. Here you'll find all of the instructions that you need to set up the test for Foundry. Basically, what you need to do is forge build to install dependency and to initialize Foundry project. And then afterwards to execute the test, you'll need to set up the fork URL. This will be the RPC URL to the main network. And

here are some example test commands that you can execute to either execute the exercise or to execute the solution. The full version of this course is available on Siphon Updraft. Follow the course on Siphon Updraft for better tracking quizzes, prove your knowledge, and join a community of over 50,000 web 3 engineers ready to help you out and answer your questions. Imagine that on DUSDC pool in UNISAB B2, we have 100 tokens each. At this point, the price of one die is equal to one USDC. Let's say that we swap one D for one USDC. We will have 101 D and roughly 99 USDC. And at this point, the price of one die is roughly 0.98 USDC. But if you want to have a DUDC pool so that after swapping

one token for the other, the price remains between 0.99 and 1.01, 01 then we would need far more tokens inside this pool to be able to swap one die for some amount of USDC so that the price remains above 0.99 or to swap one USDC for some amount of die so that the price remains below 1.01 01 we will need 200 tokens each. Drawing this out on the constant product curve X * Y = L² we will have 200 D and 200 USDC which would produce this curve in purple. And let's say that the price 0.99 corresponds to this point on the curve and the price 1.01 corresponds to this point on the

curve. When the amount of die in this pool is 200 and the amount of USDC is also 200 then on this curve we can swap one token for the other and then after the swap the price will remain inside 0.99 and 1.01 01 for the price to remain in these two price ranges we roughly need only one token but to produce this curve we need 200 tokens in other words we need 200 die and also 200 USDC so that after swapping one token for the other the price remains inside 0.99 and 1.01 01. But if we zoom in over here, we can see that starting from the current price, let's say is over here,

to move this price to 0.99, the amount of USDC that goes out is this part. So we only need this much amount of USDC to support the price change from the current price to 0.99. And likewise, for the price to increase from 1 to 1.01, 01 the amount of D that we'll need is this much. So if you have this much amount of D and this much amount of USDC then we can create a constant product AMM so that when we swap one token for the other it will still remain inside the price ranges of 0.99 and 1.01 and the rest of the token the tokens that are over here and the tokens that are over

here are no longer needed. And this is the core idea of unis swap B3. This is called concentrated liquidity. Concentrated liquidity means liquidity bounded within some price range. Going back to our previous example, let's say that we have 200 USDC and 200 D. What unis swap B3 does is using these real amounts of tokens 200 USDC and 200 D. And given the price ranges 0.99 and 1.01, 01 it can construct this larger constant product curve so that all of this 200 USDC and 200 die will be utilized within the price ranges of 0.99 and 1.01. For example, again let's say that

the current price is equal to one. We can swap out all of the 200 die so that the price will increase to 1.01 01 or we can again start from the current price equal to one and swap out all of the USDC so that after the swap the price will be 0.99 on yin swap B2 the maximum amount of tokens that we can swap so that the price remains inside 0.99 and 1.01 01 was one token. However, by concentrating our liquidity inside the price ranges in unis swap B3, we are able to create a pool that can swap 200 tokens. If we were to construct the same green curve in unis swap B2, then we will roughly need about 40, and 100

tokens each. However, in unis swap B3, by concentrating our liquidity, we only need 200 D and 200 USDC. This 200 D and 200 USDC that is actually needed in this price range is called the real reserves. These are the actual amount of tokens that we need in this price range to create this green curve. This 40,100 token of USDC and 40,100 of D is called a virtual reserves. This is the hypothetical amount of tokens that are needed to create this green curve. Let's make a comparison of how much more efficient this unis swab B3 curve is compared to the unis swab B2 curve. If we were to create this green curve on

unis swab B2 then we would need 40,100 tokens. In unis swab B3 we can accomplish this only by having 200 tokens. Dividing 40,100 by 200 this is roughly equal to 200. So in our example by using unis swap B3 we can amplify our liquidity by roughly 200 times. In this video I'll list out some differences between unis swap b2 and unis swap b3. Inside the smart contract unis swap b2 it tracks the reserves of token x and token y. And from this we can calculate the liquidity and the price. However in unis swap b3 things are the opposite.

The smart contract of unis swap B3 tracks liquidity and price. Using this liquidity and price, we can calculate the reserves of token X and token Y between some price ranges P A and PB. The next difference between Uniswap B2 and B3 is passive liquidity management and active liquidity management. As a liquidity provider and unis swap B2, all you have to do is deposit some tokens. Over time, your liquidity will collect swap fees. This liquidity that the liquidity providers deposited is represented as a ERC20 token. However, in Uniswap B3, liquidity must be managed actively and the token that you get for providing liquidity is a ERC 721. When

you add liquidity to Uniswap B3, you'll have to specify a price range. When the current price is within that price range, then your liquidity position will collect swap fees. when the current price goes outside of the price range that you set, then your liquidity will no longer collect swap fees. So, in order to collect swap fees, you'll have to reposition your liquidity to the current price range. So, as a liquidity provider, you'll need to actively engage with the UNISB pool to constantly collect swap fees. The liquidity that the users provide and the amount of swap fees that's been collected by that liquidity depends on the price range when the liquidity was provided and how long the liquidity was provided. So this

can no longer be represented as a ERC20 and this is why it is represented as a ERC 721. Some other difference between unisoft B2 and B3 is the swap fees. On B2 there is only one swap fee 0.3%. However, on B3 currently there are four swap fees 0.01, 0.05, 0.3 and 1%. More fees can be added by the unis swap governance. Another difference between unis swap b2 and b3 is how the t-op is stored. The time weighted average price in unis swap b2 the time weighted average price is stored as a arithmetic mean. However, in unis swap b3 it is

stored as a geometric mean. Next, let's look at some pros and cons of Uniswap B3. Let's start with the pros. Concentrated liquidity in Uniswap B3 allows liquidity providers to utilize all of their tokens. So, in UNIS swap B3, we have a higher capital efficiencies for LPS. We can also add liquidity using one token. In UNIS swap B2, when you add liquidity, you need to deposit both tokens. However, in UNIS swap B3, by specifying a price range that is outside of the current price, we can only add one token. Using this feature, we can easily create a range limit order. For example, let's say that the current price of ETH is 1,500 USDC and you're willing to sell your ETH for

1,600 USDC and above. So, what you can do is add liquidity, let's say, to the price range of 1,600 USDC and 1,700 USDC. And if the current price of ETH goes above 1,700 USDC, then all of your liquidity is now in USDC and you were able to sell all of your ETH above 1,600 USDC. So that's range limit order. Next, let's look at some cons of unis swap v3. One of them is active liquidity management. If you want to continuously collect swappies on unis swap v3, then you'll have to reposition your liquidity every time the current price goes outside of your price range. Another con of unis swap B3 is that liquidity is

represented as ERC 721s nonf fungeible tokens. Liquidity can no longer be transferred easily like in unis swap v2. So for a smart contract developer you'll need to put in more effort to integrate unis swap b3 into your smart contracts. So these are some pros and cons of a unis swap b3 and the difference between unis swap b2 and b3. Here we have a constant product curve X * Y = L² the curve that is used in unis swap v2 for such pool it is desirable to have a higher liquidity on the graph if we increase the liquidity you'll see that the constant product curve displayed in purple shifts over to the top right furthermore you can see that the curve

becomes more flat why it is desirable for AMMs to have higher liquidity is that higher liquidity means less price impact on an AMM large liquidity, we can swap a lot of tokens before the price changes. However, in a AMM with low liquidity, then even if we were to swap a little amount of token, the price will change a lot. For example, if we had a unis swap B to a die USDC pool and let's say that the liquidity is really low, then for putting in one die, you might only get 0.9 USDC. This is not a good deal for a swap. So, higher liquidity means less price impact. And this will also mean that more traders will be swapping on this AMM. Now let's say that

we have a constant product AMM and the amount of token X is equal to 100 and the amount of token Y is also equal to 100. And this dot over here labeled as P represents the current price. Now let's say that we only want to provide liquidity to some price ranges P of A and P of B. For example, if this was a die USDC pool, we can say that the price range we want to provide liquidity is between 0.99 and 1.01. And if we were to swap tokens on this AMM curve so that the price after the swap remains inside this price range, then the amount of tokens that we can swap will be about this much for token X and about this much for token Y.

This is a really small amount. But what if we wanted to utilize all of this 100 token X and all of this 100 token Y and we only want to provide liquidity between these price ranges? This is possible in unis swap B3. Unis swap B3 will allow us to concentrate our liquidity between the price ranges P of A and P of B. So that all of this original token X will be used between the current price P and the upper price P of B. And all of token Y will be used between the price ranges P and the lower price P of A. If we were to create the same curve on unis swell b2, then we would roughly need 254 token x and 254 token y making these price ranges P of A and P of B smaller, we get a higher

liquidity and higher liquidity means less price impact. On the opposite direction, if we increase the price range, then liquidity is decreased. And as we increase the price range further, the curve of the concentrated liquidity converges into the curve of unis swap B2. What this means is that if we were to provide liquidity to the price range 0 to infinity, then we get the same curve as unis swap B2. As we decrease the price range, the liquidity will be concentrated into a smaller price range and we will have a curve with higher liquidity. For example, let's imagine that this curve represents D and USDC pool and we only want to support the

price ranges between 0.99 and 1.01. So to do this, I'm going to set the price range between 0.99 and 1.01. And let's see where the concentrated liquidity curve is on the graph. So I'm going to zoom out all the way. And you can see over here this is our original unis swap B2 curve and this is the curve of the concentrated liquidity when the liquidity is concentrated between the price ranges 0.99 and 1.01. If we were to create the same curve on unis swap B2 then we will roughly need about 20,51 token X and 20,51 token Y. However, in unis swap v3,

we can construct the same curve by concentrating our liquidity between the price ranges of 0.99 and 1.01. And the only amount of tokens that we use to create this liquidity curve is 100 token x and 100 token y. In unis swap v2, if you know the amount of tokens inside the contract, then you can calculate the spot price. However, in UNISAB B3, it is the opposite. The smart contracts keep track of the price and liquidity.

Knowing the price, liquidity, and the price ranges, we can calculate the amount of tokens that must be locked in those price ranges. The way that the price is stored inside Uniswap B3 is by this formula inside the smart contract of Uniswap B3. It keeps track of the current tick. And to get the price, you would take 1.001 raised to the tick. This tick can both be a negative number and a positive number. When the tick is equal to zero, the price is equal to one. When this tick is negative, then the price will be less than one. And when the tick is positive, then the price will be greater than one. So to show you this, as I slide this tick over to the negative number, you see over here that the price is less than one. And as I move this

further and further to the negative numbers, you see that the price approaches zero. If I go the other way, as I increase the tick, the price increases. And if I increase further, the price goes above one. And if I increase it further, you can see that the price skyrockets to infinity. So this is how unis swap b3 keeps track of the spot price. It uses a formula price is equal to 1.001 raised to some tick. This formula is a exponential function that ranges from 0 to infinity. As the tick slides to negative infinity, the price approaches zero. And as the tick slides over to positive infinity, the

price also skyrockets to infinity. In the previous video, we saw how unisoft B3 calculates the price. It uses this formula. The price is equal to 1.001 raised to some tick. In this video, let's see where this price will be on the constant product curve as we increase the tick and as we decrease the tick. So as a review on unis swap v2 we can calculate the spot price given the amount of tokens. In unis swap v3 given the price and the liquidity we can calculate what the amount of tokens should be. And using this fact that given the liquidity and the price we know exactly where the amount of tokens should be on this curve. We can plot

this price as we change the ticks around. So for example, if I increase the tick, we can see that the price increases. And if I decrease the tick, we can also see that the price decreases. Let's imagine that we are a liquidity provider to our unis swap B3 pool. For simplicity, we'll say that we are the only liquidity provider to this pool. When we add liquidity to our unis swap B3 pool, we are creating a position. Position means liquidity concentrated in a price range. And to add liquidity, we'll need to know several things. The current price that is stored inside the unis swap B3 pool contract, the price ranges to add liquidity and the amount of tokens to

add. There are several conditions to the amount of tokens that we can add depending on the current price and the price ranges. But here we won't get into the detail of that. What I want to explain in this video is how to visualize this liquidity between the price ranges P of A and P of B. And to visualize this position, we'll plot prices against liquidity. On the horizontal axis, we'll plot the prices. The price in units of B3 is given by 1.00001 raised to some tick. So here, instead of using prices, I'll use ticks.

And here on the horizontal axis, we have T of A which corresponds the tick of the lower price P of A. And we have T of B which corresponds the tick of the upper price P of B. And here's the current tick that corresponds to the current price. As the price increases, so does the tick and it shifts over to the right. As the price decreases, the tick shifts over to the left. So on this horizontal axis, if we move over to the right, it's moving over to positive infinity. And if we shift over to the left, it's moving towards negative infinity. On the vertical axis, we'll plot liquidity. When liquidity is high, the height of this purple rectangle is

also high. And as we decrease the liquidity, the height of this purple rectangle decreases. Right now, the current tick T is below the lower tick T of A. As the price increases, the tick moves over to the right. And now this current tick is in between our position between the price ranges T of A and T of B. As the price increases, the current tick moves over to the right. And when the current price crosses over the upper price of B, this tick goes outside of our liquidity position. Furthermore, we can call this purple rectangle with red for token X and blue for token Y. First, notice that when the current price is above the

upper price range PB, this liquidity position will all be in token Y. the amount of token Y in between this price range is 214 and the amount of token X is zero. So on this graph we can say that when the current tick is above the upper tick T of B then all of this liquidity will be in token Y and when the current price is below the lower price range P of A. On this graph over here, we can see that the position between P of A and P of B consists only of token X and the amount of token Y in this position is zero. So on this graph over here, we can represent this as all of this liquidity being only in token X.

As the price increases, the amount of token Y in this liquidity position increases and the amount of token X decreases. And if we go the other way around, as the price decreases, the amount of token X in this position increases and the amount of token Y decreases. In the previous video, we learned how to visualize a single position on the liquidity price graph. On the horizontal axis, we map the price or the tip and on the vertical axis, we map the liquidity. On the left, you see some constant product curve of the concentrated liquidity for several positions. And for different positions, I've highlighted them in different colors. For example, take a look at this constant product curve with a low

liquidity. The liquidity is only provided within these price ranges. So, the part that is highlighted in purple represents the price range where this liquidity is positioned. The same goes for this light blue position, this orange position, and this lime green position. Let's start by reviewing what a single position would look like on the liquidity price graph. So we're focusing on this single position. This position provides a liquidity between these two price ranges P of A2 and P of B2. And on the liquidity price graph, you can see that the position is displayed over here in orange. As I increase the price, you can see that the current tick moves over

to the right. And when the current tick overlaps the lower price range, this liquidity becomes active. And when this liquidity becomes active, I've highlighted this active liquidity in bright purple. As we move the price along this position further, currently this orange position is active. And as the price increases, the current price goes outside of this position and there is no active liquidity anymore. So that's a review of a constant product curve when a liquidity is active for a single position. Let's now consider the case when there are multiple positions.

What does the curve of the active liquidity look like? And what does a liquidity price graph look like when we have multiple positions? So to begin with, I'm going to first show you where the positions are on this liquidity price graph. Here we have the position for the concentrated liquidity curve in purple over here. Next, we have the one in bright blue. We've already seen the one in orange. And here's the one in lime green. Showing all of them together, it looks like this. The liquidity for these individual positions are all overlapped. To show them correctly on the liquidity price graph, we need to stack them up. And here's what we get when we stack all the liquidity up. So we can see over here that on top of the purple position, we

stack up the green position. And over here, all three positions overlap. The purple, the blue, and the green. Let's see what happens to the constant product curve of the active liquidity as we increase the price. As we increase the price, this tick will swing from left to right. So as we increase the liquidity, you can see that the first position, the one in pink becomes active. So the active liquidity will only be this position. The curve of the active liquidity matches the curve of the concentrated liquidity for this purple position. And as we increase the price, next we see that there are two positions that are active now. And by active I mean that the current price is within

some price range that is set by a position. And here we have two positions that are in range of the current price. We have the position in purple that's active and we also have the green position that is active. The total liquidity that can be utilized at this current price is a sum of the liquidity of the purple position and the green position. and the resulting constant powerup curve is displayed in bright purple. Notice that this bright purple curve is greater than both the curve for the purple position and the curve for the green position. Okay. As we swing the price further, next there are three active positions purple, bright blue and lime green. We sum up the liquidity for

these three active positions and the resulting liquidity is displayed in this bright purple curve. And again, this constant product curve is greater than any of the individual constant product curve. The one for green, the one for bright blue, and the one for purple. Also note that for this narrow price range where three positions are active, tokens from this green position, the tokens from this blue position, and the tokens from this purple position are all utilized for a swap. And as we increase the tick further, now the purple position becomes inactive since the current price is above the upper price range of this purple position and the total active liquidity has decreased.

And as the price increases, the tick swings over to the right. Now this green position has become inactive. As the price increases further, the only active position is this blue position. And as the price increases further, there are no longer any position that is active. So we looked at how each individual position stack up on this liquidity price graph. Another way to look at this is to just look at the shape of the total liquidity. And to the right of the current tick, all of the liquidity will be in token X and to the left of the current tick, all of the liquidity will be in token Y. So I'm going to remove the highlight for these individual positions.

Now you can see that to the right of the current tick, liquidity is all in token Y. As the price decreases and the current tick shifts over to the left, you can see that to the right of the current tick, liquidity is in token X and to the left of the current tick, liquidity is in token Y. As the price decreases, the tick moves over to the left. More of the liquidity is converted to token X. And when the current tick is below the price range of all of the positions, all of this liquidity will now be in token X. Let's look at a real world example of what the liquidity price graph looks like. And if you want to follow along, you can go to app.unisoft.org and then click on

explore. For this example, I picked up W USDT. And the reason why I picked W USDT is because WE is token zero and USDT is token one. In the previous video when we looked at the liquidity price graph to the left of the current price liquidity is all in token Y and to the right of the current price liquidity is all in token X. Here we'll say that token zero is token X and token one is token Y. So in this example token X will be W and token Y will be USDT. And what you see over here on the bottom is a liquidity price graph of USDT and W. As we swing the cursor from left to right, you'll see that this price will increase. So,

as I move the price to the right, right now the price of one W is 3,146 USDT. And as I swing it over to the right, the price of one W in terms of USDT increases. Another thing to notice is that this weird shape of the liquidity price graph. This graph represents the liquidity at each price. And at each price, liquidity is calculated by stacking up all of the position that overlaps with the price. Another thing to note is that at the current price, so if I zoom in, you can see that at the current price, liquidity is partially in USDT and partially in to the left of the current price, all of the liquidity is in USDT. Again, remember that in this pool, USDT is

token Y or token one. And to the right of the current price, liquidity is all in W. And again, in this poll, we w is token zero or token X. So in summary, what we see here is that as we move the cursor from left to right, the price increases. And to the left of the current price, all of the liquidity is in token Y, in this case USDT. And to the right of the current price, liquidity is all in token X. In this case, this is WE. There are several important contracts that you need to know to interact with unis swap v3. And these contracts are split into several repositories. We have B3 periphery, B3 core, swap router contracts, and

universal router. Inside the repository B3 periphery, the most important contract that you'll need to remember is called nonfungeible position manager. This is a contract that will manage your position when you add and remove liquidity and to collect fees. The two important contracts inside the B3 core repository are uniswap B3 factory contract. This will deploy the unis swap B3 pull contract and this unis swap B3 pull contract is a contract that holds on to two tokens adds removes liquidity and it's also the contract that you'll be able to call swaps on. Now, similar to unis swap B2, this full contract is a low-level contract and to interact with it, you need another contract. Similar to unis swap B2 where we have the unis

swap b2 pair contract and the unis swap b2 router contract. Also in unis swap b3 we have the unis swap b3 pull contract and some other router contract. The main router contract that we'll be looking at is called swap router 02. This contract is inside the repository swap router contracts. Now this swap router 02 contract has been upgraded to another contract inside the repository universal router. This universal router contract is a more comprehensive contract that will allow you to swap between unis swap B2 B3 and some NFDs. But in this course we won't touch on this universal router contract. Instead we will look at swap router 02. Okay let's take a look at how the different contracts connect to each

other and what are some important functions that we'll need to remember. We will start from unis swap b3 factory contract. This contract is used to deploy the unisoft v3 pull contract. To deploy a contract the user will call the function called create pull and inside the unisoft b3 factory contract it will deploy the unisoft v3 pull contract. Inside the unis b3 pull contract the important functions that we need to remember are mint, burn, collect, swap and flash. Mint and burn are used to add and remove liquidity. When the function burn is called inside the unisoft v3 p contract, it doesn't actually send the tokens back. All it does is it removes a position to collect swap fees. And to

also actually remove the tokens, you need to call the function called collect. There's also a low-level function called swap. And if you wanted to get a flash loan, you can also call the function flash. Most of these functions are low-level. And when these functions are called, it will call back into message sender. So this usually means that to call these function the caller must also be a smart contract. For example, the function mint to add liquidity to unisaw B3 pull contract will have a call back function that will call back into message sender. Again, this means that the caller of the function mint must be a smart contract.

The easiest way to add liquidity to a unis pool contract is to use the contract called nonfgeible position manager. This contract will call the function mint on unisoft B3 pull contract and unisoft B3 pull contract will call back into this nonfgeible position manager. By using this contract, the liquidity that we add to unisaw B3 pull contract will be represented as a ERC 721. To remove a position from UNISBK pool contract, the nonfgeible position manager will also call the function burn. And to collect fees, the non-f fungeible position manager will also call the function collect on UNISB pool contract. The liquidity provider can call the functions mint, increase

liquidity, decrease liquidity, collect, and burn on the contract nonf fungeible position manager. Mint is called when a user wants to add liquidity to a position for the first time. If this user wanted to increase liquidity to the same position, then they would call the function increase liquidity. If they wanted to decrease the liquidity to this same position, then they would call the function decrease liquidity. Now, similar to the function burn inside unisol B3 pull contract that doesn't actually send the tokens back. It just removes the position. The function decrease liquidity behaves in a similar manner. When this function is called, it doesn't actually send the tokens back.

All it does is it decreases the liquidity from the position. To actually remove the tokens and to also collect swap fees, we must call the function collect. And lastly, to burn this NFD, the user will call the function burn. Okay, so there are two other low-level important functions inside B3 pull contract. Let's start with flash. Flash is used to get a flash loan from Unisaw B3 contract. Since the amount that is borrowed must be paid in the same transaction, this flash must also be a smart contract. This contract is not part of Uniswar B3 protocol. This is a contract that the developer writes and then deploys. And to get a flash node, this smart contract will have to call

the function flash on unis pull contract. Okay. The last low-level function is swap. This is used to swap tokens. Remember that in unis swap b2 when the low-level function swap is called on unis swap b2 pair contract before the swap is done executing you'll have to manually send the tokens into the pair contract. The function swap inside unis swap b3 p contract executes in a similar way. When this loadable function swap is called it will call back into message sender and inside the call back we'll have to send the tokens to the unisar bk contract. So the only way that this low-level function swap can be called on unisoft B2 pull

contract is by another smart contract. There are several router contracts that can call into unisoft B2 pull contract. The router contract that we'll take a look at is called swap router02. And this router contract will call the low-level function swap on unis pull contract. For a user to execute a swap on the swap router 02 contract, they can call the functions exact input single, exact output single, exact input, and exact output. Exact input single will swap with a single pool and it would try to swap all of the tokens that the user sent. Exact output single will also swap with a single pool contract. This function is called by the user when the

user wants some exact amount of token out. For example, let's say that we have diep pool and the user wants exactly one W and the maximum amount of D that they're willing to spend is 3,000 D. Then they will call the function exact output single and tell swap router 02 contract that they want exactly one with and they're willing to spend 3,000 die. The functions exact input and exact output work in a similar manner to the functions exact input single and exact output single. The difference is that they swap between multiple pools. For example, if you wanted to trade from ref to die and then from die to MKR, that's a multihop swap. So it will involve multiple unis swap B3 pool contracts. So

in this case, the user will call either exact input or exact output. How do you get the spot price directly from unis swabb3? For example, how would you get the price of beef in terms of USDC from a unis b3 contract? To get the spark price, you'll need to look at the contract called unis swap b3 pool. This contract has a strug called start zero and it is stored as a state variable. Inside the strug there are two datas that we need to get to calculate the spot price. The two datas that we can use to calculate the spot price are the square root price x96 and the tick.

Knowing either one of them, we'll be able to calculate the spot price. We'll take a look at an example later. Here I want to briefly explain why this strct is called slot zero. The strct is called slot zero because all of this data goes into the zero slot in the storage. As a quick review in EBM when you declare a state variable these state variables are stored in different slots. Each slot can store up to 32 bytes. And the strct is called slot zero because all of this data fits inside 32 bytes. And all of this data is stored in the zero slot of the storage. And we can see over here that the first state variable that is declared inside this smart contract is

called slot zero. So in this state variable all of this data is stored. So that is why it is called slot zero. The main reason why all this data is stored in slot zero is to save gas. Okay. With that said, let's now take a look at a real world example of square root price x96 and tick. We'll look at the unisaw B3 pull contract for W USDT. So I'll scroll down and I'm inside ether scan. I'll click on read contracts and then scrolling down. I'm looking for a function called slot zero. So there it is. Click on this then hit on query and you see over here that the tick is minus 195,31 and the square root price x96 is

this big number. In the following videos, I'll explain the math for how to use this tick and square root price x96 to calculate the price. In this video, I'll explain the math equation for how to calculate the price given that we know the tick. We'll say that x represents token zero and y represents token one. P will be the price of x in terms of y. A simple example is think about x as being ref and y as being USDC. In this case, P will be the price of F in terms of USDC. In USB B2, to get the stock price of token X in terms of token Y, what we had to do was get the amount of token one that is stored in the unis swap B2 pair contract and then divide by the amount of token zero that

is stored in the unis swap pair contract. However, in unis swap B3, we can no longer do this. And this is because in unis swap b3, it no longer keeps track of the amount of tokens that is locked inside the contract. Instead, it keeps track of the current price. And from the current price, if we know the liquidity and the price ranges, then we can calculate the amount of tokens that must be locked in those price range. But this is still a useful equation knowing that the price P is equal to the ratio of token Y to token X, especially when we're dealing with decimal conversions.

For example, let's say that X is and Y is USDC. USDC has six decimals and W has 18 decimals. So when we take the ratio we're left with 10^ the 6 / 10 18 which is 10 -12. And if you wanted to normalize this ratio to let's say 10 18 then we'll have to multiply by 10 12 to cancel out with the 10us2 and then multiply by 10 18. I'll explain more about decimal conversions when we actually write some code. Moving on, in unis B3 the price is defined to be 1.00001 raised to the tick. So if you know the number for what this tick is,

then we take 1.00001 raised to the tick to calculate the current price. Let's go over some example of calculating the price given that we know the tick. For this example, I'll use the tick that I got from W USDT pool. So in this contract, WE is token zero or token X and USDT is token one or token Y. So to get the price, I'll label this P. You'll do 1.00001 raised to the tick. Let's print this out and see what this number is. Print P. And here it is. Notice that this number is equal to 3.53 and so on multipus 9. We're getting the price of

we in terms of USDT and currently the price of beef is around 3,500 USD. So why isn't this number around 3,500? Instead, it's a really small number. The reason why we're seeing a small number here is because we haven't done the decimal conversion. As a review, we said P is equal to the ratio Y / X and this is the price of token X in terms of token Y. In our case, we said that token X is W and token Y is USDT. W has 18 decimals. So one W is represented as 1 E18 or 10 raised to the 18 and 1 USDT has six decimals. So this is represented

as 1 E6 or 10 raised to the 6. And now when we look at the ratio of P = Y / X, this will be the ratio of USDT / USDT has six decimals. So the numerator will also have six decimals for the ratio of P. And the denominator is W. So it will have 18 decimals. This whole ratio will have a decimal of 1 E minus 12. And that is why we're seeing a small number here because we're multiplying the price of we in terms of USDT by this number 1 minus 12. If we remove these decimals from the price P, then we'll get a number that is closer to the market

price. So from P, P is multiplied by 1 E6 and then divided by 118. So to cancel out with the first one E6, we'll divide by 1 E6. And then to cancel out with the next 1 E18, we'll multiply by 118 and then print it out. And we get that the price of one W in terms of USDT is around 3,531. Let's look at another example of calculating the price from the tape. And this time we'll use the pool USDC with.

So in this pool, USDC will be token zero or token X and W will be token one or token Y. In the last example, the pool was W for token zero and USDT for token one. In this example, it's USDC is token zero and W is token 1. And remember that the ratio P is equal to Y / X and this is price of token X in terms of token Y. In this example, if we replace the X with USDC and Y with W, we get that P will represent the price of USDC in terms of W. For example, this P might be some number like 1 USDC equal to 0.001 W. That number is a little bit

hard to comprehend since when we think about the price of W, we think about it in the opposite terms. The price of W in terms of some stable coin like USDC or USDT. So to get the price of we in terms of USDC, we'll need to flip this P. 1 / P will be equal to the ratio X / Y. And this will be equal to the price of W in terms of USDC. Okay, with that said, let's try to calculate the price of W in terms of USDC given that we know what the tick is. Here's the tick that I fetched from the pool USDC with from this address. And the price P again will be equal to 1.001 0001 raised to the tick and let's print this out. Print P. And we get a really

large number. The current price of ETH in terms of USD is around 3,00 to 3,500. So this number is way off. And as I mentioned earlier, to get the price of we in terms of USDC, we'll need to do 1 / P. So let's do that. Print 1 / P and then print it out. And we now get a small number roughly 3.53 * 10 to the -9. The reason why this number is really small is because we haven't done the decimal conversion yet. So let's work through this out. One with has 18 decimals 1 E18 and one USDC has six decimals 1 E6.

We said that 1 / p is the price of we in terms of USDC and the ratio is given by x divided by y. In this pool, token 0 or token x is USDC and token 1 or token y is 1 / p = x / y is the ratio of USDC /. And this is equal to 1 6 /8. And this is equal to 1 - 12. To remove this decimal, what we need to do is take 1 / p. And then we cancel out this 1 6 by dividing by 1 6. Then we'll cancel out this 1 18 by multiplying by

118. Multiply 118. Okay, let's print this out. Print and then execute the code. and we get that the price of we in terms of the USDC is roughly around 3537. Remember that weird variable inside slot zero called square root price X96. In this video, I'll explain what this is and how to use this to calculate the price. The square root price X96 is defined to be the square root of price P. This is obvious from the name. Then it multiplies by some factor called x96 inside the code of unis swab b3.

This is called q96. And q96 is simply equal to 2 raised to the 96 power. To calculate price p given that we know what square root price x96 is. We first take this square root price x96. And this square root price p is multiplied by a factor of q96. So we'll first divide this square root price X96 by Q96. After we divide this, we're left with square root price P. So to get back the price, we square this and we get back P. And this is how we will calculate the price P given that we know square root price X96. Let's look at another example of

calculating the spot price in Uniform B3. This time we will calculate the spot price given the square root price X96. And for this example, I'll use the square root price X96 that I got from the web USDT pool. Remember that this square root price X96 is the square root of price multiplied by some factor. And inside the code of unisaw B3, this is called Q96. So let's define Q96 in our Python code. Q 96 is equal to 2 to the 96. To get the price we'll say P is equal to We'll first divide this square<unk> P X96 by Q96. SQRT P * X96 / Q96. This will give us the square root

of price. And to get the price we square this. Okay, let's print out P. Print P. And again we get a small number 3.37 * 10us 9. We're getting a small number because we have not canceled out the decimals for and USDT. So let's go back to the equation again. Price P is the ratio of token Y over token X. In this pool USDT we is token X and USDT is token Y. So Y is USDT and X is W. Okay.

How about the decimals? USDT has six decimals 1 E6 and WE has 18 decimals 1 E18. So at the moment this price will be the price of we in terms of USDT and we also have these decimals and that is why we're seeing a small number over here. And to cancel out this decimals, we need to first divide by 186 since here the price is multiplied by 186. And then we need to multiply by 118 to cancel out the division by 118. Okay. And let's print out the price again. And this time we get that the price is equal to 3,378. One ref is roughly 3,378 USD.

Another useful math equation to keep in the back of your head is the conversion between square root price x96 and tick. So as a review, the price p is defined to be 1.001 raised to the tick. And we also saw that given the square root price x96. We can calculate the price by using this equation square root price x96 / 296 and then squaring this. Now I want to explain given that we know the square root price X96 how do we calculate the tick and this math is used inside smart contracted unison B3 during a swap to calculate the current tick given the square root price X96 so to calculate the tick given that we know the square root price x96 we will first take the

log of both sides so I'll copy this equation and then paste it here taking a log on both side of the equation on the left side this tick comes out and on the right side this two will come out. Next I'll divide both side of the equation by log of 1 01. Dividing this side of the equation by log of 1.001 this will simply be one. And dividing the right side of the equation by log of 1.001 we will have this. And now we have equation for the tick. You don't have to remember this equation, but if you need to find the tape and given that you know the square root price X96, you can use this equation to calculate the tick. For our final example of playing

around with the spot price of Unisaw B3 using Python code, we'll calculate the tick given that we know the square root price X96. And for this example, we'll be using the USDC web pool. First, I'll define the constant Q96. Q96 is equal to 2 to the 96. Next, I'm going to copy paste the square root price X96 and the tick that I got from this contract address. Okay, here they are. So, what we'll do next is we'll calculate the tick from this square root price X96. And we'll double check that the tick that we calculated matches this tick. This is the actual tick that is stored in the contract over here. So take let's name this t is equal to 2 *

math.log and inside this log we need to do square<unk> px 96 divided by q96 and then outside of this math.log we need to divide this by math do log 1001. Okay, so that's the tick that we calculated given that we know square root price x96. Let's print this out and compare with the actual tick that's over here. So, print key. And the tick that we calculated is 195,4002. The actual tick is also 195,4002. Here's an exercise to get the spot price for my unis swap B3 pool

contract. The pool contract is USDC W. And in this exercise, I want you to get the price of F in terms of USDC and then return the price with 18 decimals. One thing that might be useful for you for this exercise is to use the library full math mole did. What this function allows you to do is multiply two units 256 and then divide by another unit 256 without any overflow. This is a useful function when you multiply square root price x96 with root price x96. Okay, let's go over the solution.

First, let's review what price we need to return. Do we need to return the price Y / X or do we need to return the price X / Y? So, if we have P, this is the ratio of token Y / token X. And in our case, token X is USDC and token Y is W. So this ratio will be W divided by USDC. Remember that this ratio represents the price of token X in terms of token Y. In our case, this X is USDC and this Y is worth. So once we calculate the price based on the data that is stored in

start zero, we'll get a price of USDC in terms of W. But what we actually want to return here is the price of we in terms of USDC. So again to do this we'll need to flip this ratio. What we need to calculate is 1 / P. This will be X / Y. And this will be the ratio of USDC over. And when we calculate this 1 over p, we'll get the price of left in terms of USDC. So what we need to find is 1 / p. Before we do that, let's also calculate how many decimals this 1 / p has. If we look at p, p has y will be w. We w has 18 decimals. So this will be 1 18. And

then on the bottom we have USDC. USDC has six decimals. 1 e6. This is 1 12 decimals. For 1 / p we need to flip the decimals. So 1 over p has on the numerator we'll have 1 e6 and on the denominator we'll have 1 18 and this will be -2 decimals. So far we know that we need to calculate 1 / p to get the price of f in terms of we also know that 1 / p has 1 minus 12 decimals. Next let's think about how we will get this price p from slot zero.

Inside slot zero, there's a data called square root price x96. And we'll need to use this to calculate the price peak. Let's start by reviewing what square root price x96 represents. Square root price x96. And we said that this will represent the square root of price P. And this is multiplied by a constant called Q96. And this Q96 is simply 2 to the 96. To get this price that represents P, we need to take the square of square root price X96. So this will be square<unk> price X96 * square<unk> price X96. And this will be equal to two

of these one over here and then multiply by the same thing again. And when we do this, we'll get the square root of P * the square root of P which is simply equal to P. This is the price that we wanted to get. And then let's multiply by two of Q96 times Q96. Again, each of these Q96 has 96 bits. And here we have two of these. So this will be 2 * 96 bits. And this is equal to 192 bits. Let's do a little bit of math to see how big the price can be before this number overflows. Just by Q96* Q96 we use up 192 bits. Un 256 has 256 bits minus 192

bits and this is equal to 64 bits. So this means that we have 64 bits to represent this price pe. Now imagine that we want to return 18 decimals. So out of the 64 bits that we have 2 to the 64 we're going to use 1 18 decimals to represent the decimal part of the price. And if you punch in the numbers into a calculator we get that this is approximately equal to 18. And what this means is that if we were to return the price with 18 decimals then the maximum price that we can return is roughly 18.

For example, currently the price of beef is above 3,000. And this means that when we do this calculation, we won't be able to return the price of beef. So when we do this calculation to get this P out before we do this, we need to somehow make this part of the multiplication smaller. One way we can do this is by saying square<unk> price X96 / Q96*<unk> price X96 / Q96. And this will give us square root price P * square root price P. So this will be equal to P. The problem with this approach is that because we're dividing by Q96, if this square root price X96 represents a really small

number, then this will round down to zero and the price will be inaccurate. Okay, to solve these two problems, one is the problem that if he did this, then the price might overflow and if he took this approach, then the price might be incorrect. To solve two of these problems, we're going to use the library full math dom to calculate the price purely without any overflow. So we'll say price is equal to full math dot mold divided. The square root price x96 is stored inside zero.0 square<unk> price x96. And we'll multiply it by itself.0 0 dot square<unk> price

x96. And then notice here that when we multiply square<unk> price x96 by itself, we get two of these Q96. We'll remove one of them by dividing by Q96. So right now this price represents the P that we discussed over here. What we actually need to return is 1 over P. So that would be the next step. Currently the price is equal to square<unk> of P * Q96 * square<unk> of P * Q96. So that's this part and then we divide this by Q96. And again by using this small div

function we can multiply 2 un 256 and then divide by another 256 without any overflows. Okay. So this will be equal to we have a square root price P over here and a square root price P over here. So this will be P and then we have 2 Q96 as a numerator and 1 Q96 as a denominator. So we're left with 1 Q96. So this is what this variable price represents. The ratio of token Y / X and multiply by Q96. What we need to return is 1 over price. This be equal to 1 * q 96. Now when we do this 1 / price, notice that

we're doing 1 / a large number. So in solidity, this is going to return zero because divisions round down. So what we need to do is multiply this 1 / price by a large number so that it doesn't round down to zero when we divide by p * q96. So I'll type price is equal to 1 / price. 1 / price will represent this number over here. First I'll cancel out this q96 by multiplying the top by q96. And then remember that when we said over here that 1 / p has decimals 1 e -2. So cancel out this 1 e - 12

decimals. I'll multiply the top by 1 e2. And lastly for this exercise we want to return the price with 18 decimals. So we'll multiply this by 118 1. Okay. And that completes the exercise. Let's execute the test. Inside my terminal I'll first set up a environment variable for the forth URL. And then to execute the test for this exercise, I'll type forge test d-forge url fork url. And the path to the test is match path test unis swap b3 exercises unis swap b3 spot price test.

soul and then we'll print out the console logs by typing dashb. Okay. And a test pass. The price that was logged is 3.28 * 10^ the 21. We said that we wanted to return this price with 18 decimals. 21 - 18 is 3. So the stop price given by the USDC ref pool on B3 is currently roughly 3,284 USDC per one. In yin swap B3, there are several equations that we need to derive to answer questions like the amount of token X and amount of token Y between a price range and other questions like the amount of token X or

Y that we'll get for a swap. The first two equations that will be helpful to know when we're doing math with unis equations is rewriting the amount of token X and the amount of token Y in terms of the liquidity L and the price P. To begin with, we have the constant product equation X * Y = L². The spot price P in a constant product curve is given by the amount of token Y divided by the amount of token X. In UNISAB B2, it is easy to know the amount of token Y and the amount of token X in the contract. From these, we can easily figure out what the spot price is.

However, in UNISAB B3, this is no longer true because there may be multiple positions in different price ranges. We cannot just simply take the amount of token Y and the amount of token X in the contract to figure out what the spot price is. Instead, in UNISAB B3, it keeps track of the current price and the current liquidity. And from these, we can figure out what the amount of token Y and what the amount of token X should be in a price range. To find the amount of token X given the liquidity and the stock price P, first I'm going to copy these two equation and paste it here.

And we can write x in terms of l and p if we do l² / p. So I'll take l² and then divide this by p. And this will be equal to l² is x * y and p is y / x. The y on the top and the y on the bottom cancel out and the x comes to the top. So we will have x². So I get l 2 / p is equal to x². I'll take the square root of both side of the equation. On the right we have square<unk> of x². So this is simply equal to x. And if I take the square

root of the left side of the equation, the top will be a L and the bottom will be a square root of P. So we get if you know the current liquidity L and the price P then we can calculate the amount of token X. L / greater P is equal to X. Next we'll do something similar to get an equation for Y in terms of L and P. So I'll copy this equation and then paste it here. If we take L^2 * P, then we'll get X * Y * Y / X. The x over here cancels out with the x over here and we're left with y^2. So we have l^2 * b is equal to y^2. Again, we'll take the

square root of both sides. On the right side, square<unk> of y^2 is simply equal to y. And on the left side, square<unk> of l 2 * p is equal to well, the l is going to come out and we can remove this power two. and we're left with L * the square root of P. So given that we know the liquidity and the price, we can calculate the amount of token Y and this is equal to L * the square root of P. We need one more equation to answer important questions like the amount of token X and the amount of token Y that we need between the price ranges P of A and P of B to provide this much amount of liquidity. Or we might ask the question we have this much amount of

token X and we want to provide liquidity between P of A and P of B. So what is the amount of token Y that we need to provide? To answer questions like these, we need the equation for the curve of the real reserves. So let's say that we have the curve of the virtual reserve in green. This is simply the constant product curve of the concentrated liquidity. The curve of the real reserve shown in orange is derived simply by taking the curve of the virtual reserve shifting it over to the left and to the bottom. We shift this green curve over to the left until the price P of B intersects with the Y-axis. And then we move the green curve down until the price P of A intersects with the X-axis.

And this represents the curve of the real reserves. The curve of the real reserve is described by this equation. In this video, I'll explain how to derive this equation. As a starting point, let's say that we have a constant product curve X * Y = L². In a concentrated liquidity between the price ranges P of A and P of B, the amount of token X and the amount of token Y splits into two parts. For the amount of token X, we have the real amount of token and some virtual amount of token. And likewise for the amount of token Y, it splits into two parts. The real amount of token Y and the virtual amount of token Y. We can express this as a mathematical equation. The amount of token X that is needed to create this

X * Y= L² splits into two parts. The real amount plus the virtual amount. And likewise, the amount of token Y splits into two parts. The amount of token Y that is needed to satisfy this equation X * Y = L² splits into two parts. The real amount of token Y plus the virtual amount of token Y. And now we can rewrite X * Y. X is equal to the real amount X sub R plus the virtual amount X sub B. And likewise Y is equal to the real amount Y of R + Y of B. And since X * Y = L², this part must also be equal to L square. To find the curve of the real reserves, we need to find what this

value XB and YB is equal to. And to find the values X of B and Y of B, we'll use these two equations. Rewriting X in terms of the liquidity L and the price P and rewriting Y in terms of the liquidity L and the price P. Let's start by solving for X of B. Now to simplify our problem, we take this equation and set X subar equal to zero. So we'll consider the case when x subar the real amount of token x is equal to zero. On the graph we will have the curve of the virtual reserve and the real amount of token x is equal to zero.

If the real amount of token x is greater than zero then we will have some amount of x over here. Since it is equal to zero the real amount of token x will be over here. And in this case we still need to satisfy the constant product equation x * y= l². So the amount of token y such that the point x y will be on this green curve is over here. So y must be over here. This vertical line in green is the virtual amount of token y and this vertical blue line is the real amount of token y. Okay. So when the real amount of token x is equal to zero on the curve of the virtual reserve the point xy must be over here. From here there are two approaches that we can

take to solve for X of B. The first one that I'll show you is the geometric approach and next I'll show you the algebraic approach. So when the real amount of token X is equal to zero, the point XY will be over here. When XY is over here, the amount of token X will be this much amount which is equal to X sub B. And the month of token y must be equal to this vertical blue line plus this vertical green line which is equal to y r + yb. Okay, notice that x is equal to xb. And now we already know what xb must be equal to. Going back up, we can use this equation to figure out what x sub is. So going back down, x is

equal to x sub. And using the equation above, we rewrite this X in terms of the liquidity and the price. The liquidity is L and the price at this point is P of B. So X subB will be equal to L / the roo<unk> of P of B. Another approach we can take is by solving this equation when X sub is equal to zero. The equation for the constant product curve XR + XB * Y R + YB. Since xubr is equal to zero, this equation simplifies to x sub b * y r + yb and this must be equal to l². Okay, so we can solve for x of b by taking this equation and then

dividing by y r + yb. So x of b is equal to l² / y r + yb. Okay. And then going back up, we can use this equation to rewrite Y R + YB in terms of liquidity and price. The liquidity is the same L. How about the price? The price when Y is equal to Y R + YB will be P of B. So this price will be P of B. Okay. So we can now rewrite the bottom part of this equation. Replace this with L * the square root of P of B. Now notice that we have a L square on top and we have a L on the bottom. These two cancel out and we're left with X sub B

is equal to L / the square root of P of B. Okay, so these were two approaches that we can take to figure out what X of B is. Next, we'll do something similar to figure out what Y of B is. Okay, to find Y of B, we'll go back to this equation. We'll consider the case when the real amount of token Y Y bar is equal to zero. So going back when the real amount of token y bar is equal to zero. So this will bring y bar over here and when y is over here the total amount of token x this will be x of r + x of b must be over here. So that the point xy will be on this curve of the virtual reserve. When we add the real amount of

token x with the virtual amount of token x and we also add real amount of token y which is zero with the virtual amount of token y. The point xy must be over here on this green curve. And to find out what y of b is equal to, again we'll take two approaches. Geometric approach and algebraic approach. At this point, this x is equal to some real amount of token x with the virtual amount of token x. X subr plus x sub b. The amount of token y is also the same. However, since the real amount of token y is equal to zero, this will simplify to y = to y of b. Now, using this equation again, we can rewrite y in terms of l and

p. So, when y is equal to y of b, what is the price? The price is p of a. So, at this point, y is equal to y is all in virtual amount. So this will be y of b and this is equal to rewriting in terms of liquidity l and the price this is equal to l * the square root of p of a. Another approach that we can take is the algebraic approach. So starting from this equation I'll paste it here. Starting with this equation we know that y bar is equal to zero. So we can simplify this equation. y bar is equal to zero. So we can remove this and we get x sub r + x

sub b * y of b is equal to l². Okay. So we're solving for y of b and to do this we'll divide both side of the equation by x sub + x sub. So we get y of b is equal to l² / xr + x sub. Again we'll use this equation to rewrite x in terms of liquidity and price. So at this point we have X is equal to some real amount of token X plus the virtual amount of token X and the price at this point is P of A. So we can replace the bottom part of this equation with L / the square roo<unk> of P of A and this

is equal to the L square on the top cancels out with the L on the bottom and the square root of P of A comes to the top and we get that Y of B is equal to L * the square root of P of A. So those are two ways to find Y of B. Okay, now that we figured out what x sub and y sub of b is, the last step is to figure out how do we get this orange curve, now that we know how to get this equation for the green curve. To draw out the curve of the real reserve shown in orange, what we have to do is move the curve of the virtual reserve shown green to the left and bottom. What we're doing here is we're moving this green curve over to the left so that when x subar is equal to zero,

this will match the xaxis equal to zero. And by shifting this green curve to the bottom, we're making it so that when the real amount of token y bar is equal to zero, it will match on the y-axis the point where y equals zero. To show you this, let me try dragging this green curve. So we'll shift this green curve to the left so that when xr is equal to zero, this will match the point x equals to zero. Okay. Next, I'm going to move this curve to the bottom so that when y bar is equal to zero, this will match the point y = to zero. And you can sort of see that the two curves overlap. The curve of the virtual reserve and the

curve of the real reserve overlap. And this is how the curve of the real reserve is derived. We take the curve of the virtual reserve and slide it over to the left. The amount that we'll need to slide is x of b. And then next we slide it down. The amount that we'll need to slide down is y of b. When we do this, we'll get the curve of the real reserves. Remember these equation where we can calculate the value of x and y given that we know what liquidity L and price P are. We'll use these two equations to answer two questions. The two questions that we'll answer in this video are given the liquidity L and the price B, what is the amount of token X between P and P of B? On the graph, we

have the current price P and the upper price P of B. What is the amount of token X that we need so that the current price can go all the way up to P of B? And the other question is what is the amount of token Y between price P and P of A. from the current price P to the lower price range P of A. What is the amount of token Y that we need so that the price can move from the current price P all the way down to the lower price P of A? Well, we can easily find answers to these two questions by using these two equations. So, let's start with the first question. What is the amount of token X between the price P and P of B? In other words, what we're asking here is what is this length of

this red line? And to answer this question, all we have to do is figure out what the x component when the price is at p. So what is the x value over here? And what is the value of the x component when the price is at p of b? So the x will be over here. Taking these two difference, we'll get the length of this red line, which will be the value of x. Let's start by figuring out what the x component is for the current price p. So we have the current price P here and the X component will be over here. Well using this equation that we can rewrite X in terms of liquidity and the price. The X over here will be equal to L / the square root of current price P.

We're simply using this equation over here to rewrite X. And then we'll do the same when the price is at P of E. When the price is at P of B, the X component will be over here. And again using this equation the x value over here will be l / the square root of p of b. When we apply this equation in the case of the price p of b here we'll need to replace this p with the price p of b. So that is why we have l / the root of p of b. So now that we know what the x values are for when the price is at p and when the price is at p of b, we can now figure out what this distance of the red line is. So x is equal to x will be this

length and we can get this length by taking the difference of these two points. At the current price p x is equal to l / the roo<unk> of p. When the price is at p of b, the x component is equal to l / the roo<unk> of p of b. Taking the difference between these two points will give us the length of this red line which is equal to x. So the amount of X between P and P of B is given by this equation. And now we can do something similar to answer the question what is the amount of Y between P and P of A. The value of this Y is the length of this blue line. And we can get the length of this blue line by figuring out what the Y component is for the

current price P and what the Y component is for price P of A at the current price P. So to figure out what the y component is, all we have to do is apply this equation. So y will be equal to l * the square root of p. And then we do the same to figure out what the y component is for price p of a. To figure out the y component when the price is at p of a, we would do l * the square root of p. P over here is p of a. So this will be equal to the y component when the price is at p of a is equal to l * the roo<unk> of p of a. Now we can figure out what the value of y is. The y will be the distance of this blue line which

is the difference between the two points l * the<unk> of p minus l * the<unk> of p of a. y is equal to l * the roo<unk> of p of a. This would correspond to the y component at the price pus * p of a. This is the y component at the price p of a. Taking the difference, we get the length of this blue line. And this answers our second question. What is the amount of y between the current price P and P of A? The answer is given by this equation. So far these two equations use P, P of A and P of B. But sometimes it's difficult to remember what P, P of A and P of B are. For example, when we use these equations, do

I have to remember that P of B is always greater than P of A. So to make these two equations easier to remember, let's generalize these two equations. So I'll copy this and then paste it here. Next, I'll replace the terms P, P of A, and P of B with terms that indicate whether the price is higher or lower. So let's start with this equation for the term P and P of B. In this case, which is the lower price. This will be the current price. So I'll rename this P with P lower to indicate that this is the lower price. And in this case between P and P of B, P of B is the higher price. So I'll rename P of B to P of upper to indicate that P upper is a price that is

greater than or equal to P lower. Okay. And we'll do the same for this equation between P and P of A. If you look at this graph, which is the higher price and which is the lower price? Well, in this case, P is greater than or equal to P of A. So I'll rename this P to P upper. And then between P and P of A, the lower price is P of A. So I'll rename P A to P lower. So all we did was we took these two equations and then we labelled the terms P, P of A and P of B with terms that indicate whether the price is high or low by renaming them as P lower and P upper. And now we have two

equations that tell us the amount of token X and amount of token Y between two price ranges P lower and P upper. So now using these two equation we can answer questions like what is the amount of token X between the price ranges P of A and P of B. Before we ask the question what is the amount of token X between the current price P and the upper price P of B. But now using this equation we can ask a more generalized question. What is the amount of token X between two price ranges P of A and P of B? The answer is given by the length of this red line and this length can be calculated by applying this equation. So for P lower you put P of A and for P upper you put P of B. And likewise using this equation we can ask the question

what is the amount of token Y between the price ranges P of A and P of B. The answer is the length of this blue line which is given by this equation. Another question that you might have is given the current price P and the current liquidity L, what is the maximum amount on token X that you can put in before this current price goes below P of A? And again, we can answer this question by using this equation. For P upper, you put the current price and for P lower, you put P of A. And likewise you can ask the question given the current price P what is the maximum amount of token Y that you can put in before this current price exceeds P of B and again we can answer this question by using this

equation for P upper we will put P of B and for P lower we will put the current price the function that actually executes the swap inside unisoft B3 is inside the contract called unisoft B3 pool and the function is called swap before we do a full walkthrough of this function. I'm going to first give you an outline of how this algorithm for the swap works. Let's start with the important inputs to the function swap. There are other inputs, but we'll focus on these three inputs. 041 tells the direction of the trade. If we're putting in token 0 and then getting out token 1, then 041 will be true. Otherwise, we're doing a swap putting in token 1 and then getting out token zero. In this case,

041 will be equal to false. and then amount specified. This amount can either be positive or negative number and this tells either how much token the user wants to put in or how much token the user wants to get out out of the swap. And then the square root price limit. The swap algorithm will continue to execute until this amount specified reaches zero or the current price reaches the square root price limit. From these inputs, the algorithm first calculates the type of the swap. The two type of swaps are exact input and exact output. Exact input means that the caller specify the amount of tokens that they're going to put in. Exact output means that the caller specify the amount of tokens that they want out out of the

swap. And the way it is computed is by looking at amount specified. If amount specified is greater than or equal to zero, this means that the caller is willing to put in this much amount of token into the contract. So it will be a positive number. And this would tell unis swap b3 that this trade is a exact input. For exact output, user is specifying that they want to get some amount specified amount of tokens out of the pool. The token is leaving the pool. So amount specified will be a negative number. Next algorithm runs a while loop to calculate amount in and amount out.

We'll come back to the details of how this loop calculates the amount in and amount out later. After this loop is done executing, the algorithm knows what the next liquidity is. the next square root price, the next tick, amount zero, and amount one. Here we have plus and minus. Plus means that token is coming in and minus means that token is going out. And at this point, it also knows what the swap fee is. From these values, the state variables for liquidity, square root price, tick, and fee growth are updated. Fee growth is a state variable that is used to check the amount of swap fees that were collected from this plus minus amount zero and amount one. If this amount is a negative, then tokens are sent out. The swap call back is executed on message

sender. So this means that message sender must be a smart contract. And at this point, message sender must send a token in to the unisoft B3 pull contract. After the swap call back is done executing, the unisoft B3 pull contract will check the balance per token in. Okay, so this is an outline of how the swap algorithm works. Now let's dig a little bit deeper and look at what the loop does to calculate amount in and amount out. The loop will continue to execute while the amount specified remaining is not equal to zero and the current square root price is not equal to the square root price limit. So going back to the inputs here we have amount specified and this amount specified is used to set a local variable called

amount specified remaining inside the loop. It's either going to add some amount or deduct some amount until this amount remaining is equal to zero. And the other input that we saw was the square root price limit. The current price, the current square root price will be kept in a local variable. And while this square root price is not equal to the square root price limit, the while loop will continue to execute. Inside the while loop, it's going to first get the next tick. The way it gets the next tick will be explained in another video. From the next tick, the square root of the price of the next tick is calculated. We'll call this square root P next. After the next square root price next is calculated, the algorithm calculates the amount in,

amount out, and the fee between the two prices, the current square root price P and square root price next. And once that is calculated, the current square root price P is updated. Once you know what amount in and amount out are, next we need to update this amount specified remaining. And the way it is updated is different whether the trade is at exact input or at exact output. If this swap is at exact input, then amount specified is greater than or equal to zero. This is because the caller is specifying the amount of tokens that will come into the pool.

From this amount specified remaining which is greater than or equal to zero, we deduct the amount of tokens that must come in between the price ranges square root price P and square root P. Next, if the swap is an exact input, this amount calculated is interpreted to be the amount of token that will go out. Remember that for the amount of tokens that's going out, it is represented as a negative number. So from amount calculated we minus amount out the amount of token that's going to go out from the two price changes the current square root price P and square root P next. Okay. So let's take a look at what if the swap is a exact output. If the swap is an exact output then amount

specified will be less than zero. The user is requesting to take some tokens out. Token is leaving so amount specified is less than zero. Again this while loop is going to continue running until this amount specified remaining is not equal to zero. So to amount out specify remaining we add the amount of token that is going out and this amount out is calculated over here. We'll come back to how amount in amount out fee and the next square root price P is calculated. So moving on for exact output next it calculates amount calculated. In this case, amount calculated means the amount of tokens that must come in. Since token is coming into the pool, this amount calculated

will be a positive number. Once all of these are calculated, it's going to update the local variables inside the while loop to prepare for the next iteration of the while loop. It's going to update the local variables liquidity, square root price P, tick, and fe. Once this loop is done executing, it's going to return to here. return to this end of the loop. And among other things, the two variables that it's going to return is amount specified remaining and amount calculated. From these two variables, it will calculate the amount of token zero to come in and go out and amount of token one to come in and go out. Okay, so this is an outline of what the while loop does to calculate amount in and

amount out. Next, let's take a look at how amount in, amount out, fee, and the next square root price P is calculated between the price ranges, the current square root price P and square root P next. To calculate the amount of token in and out, and the fees between the price ranges, the current price P and the next price square root P next. These are the inputs that we will need to pass. The two price ranges, the current liquidity and amount specified remaining. Again here remember that amount specifying remaining can mean two things. If this number is greater than or equal to zero then this means the amount of tokens that's coming in and if it's less than zero then it's amount of tokens that's going out. From these we

need to calculate amount in amount out and fee. So let's take a look at how it does this. The function that is getting called to compute the amount in and amount of token out is called compute swap step. First it needs to determine the type of swap. Is it a exact input or is it a exact output? If it is an exact input, then it needs to calculate the maximum amount of token that can come in between the current price P and the next price P target. Here for the input, we passed in square root P next. But inside this function called compute salt step, this square price P next is called square root P target. So we calculate the maximum amount of tokens that come in between the current price square root

price P and square root P target. Next once we calculate the maximum amount of token in we can calculate the actual amount of token that will come in and then it will calculate the next square root price. Okay. So these are the two calculations that are executed for exact input. For exact output, it's going to calculate the maximum amount of tokens that can go out between the price ranges square root P and square root P target. Based on the maximum amount of token out, next it's going to calculate square root P next. So at this step, we know what the next square root price is. And from this, the algorithm calculates the amount in and amount out. From the amount in that is calculated, next it's going to calculate the fees. And once

that is done, the result of the calculation is returned to this step. So at this step, we will know what the next square root price P is, amount in, amount out, and the swap fees. For the last part of this video, I'm going to explain a little bit more about this step over here. And to explain the algorithm over here, for this example, we'll say that this swap is a 041. Token zero is coming in and token one is going out. Let's say that some amount of token is coming in and some amount of token out is going out and the current price will be the square root of P. The target will be square root of P target by putting in some amount of token X and then getting out some amount of token Y.

This will decrease the price. It will shift the price from over here from the right to the left. Okay. So over here I said max amount in and max amount out. What do this look like visually when we represent it on this bar graph? Let's start with max amount. Max amount is the maximum amount of token that can come in before the current price square root P reaches square root P target. Visualize that as the tokens come in, this will push the current price from right to left and the liquidity will be more in token X and less in token Y. And this max amount in is the maximum amount of token that can

come in for the current price to reach the price target square root P target. Max amount out is something similar. Max amount out is the maximum amount of tokens that can go out until the current price square root P reaches the target price square root P target. Okay, so that's max amount in and max amount out. Next, I'm going to explain a little bit more about square root P. Next square root P next is the next square root price either for putting in some amount of token in or taking out some amount of token out. For this example, I'll explain what square root P next is when some amount of token in is coming in. So let's say that we started

our liquidity in this position and then some amount of token in came in. The current square root price before this amount of token came in was over here. And after it came in, after this much amount of token X came in, the next square root price, let's say, is over here. And this is what the code refers to as square root P next. And that completes the explanation for the algorithm for the swap. Imagine that there are multiple liquidity positions. For example, here's one. Here's another one. Here's another one. And here's another one. When we stack up all of these individual liquidity position, we get a graph that looks like this. Let's say that the current price is over here represented as a vertical dotted line.

To the left of the current price, liquidity is all in token Y. To the right of the current price, liquidity is all in token X. During a swap, this current price will move either to the left or to the right. If token X is coming in and token Y is going out, then the price will shift over to the left. And if token Y is coming in and token X is going out, then the price will move over to the right. As the price goes back and forth, we can see that the liquidity changes. For example, currently the liquidity is at 14. And let's say that there's a swap and it swings the price over to a lower liquidity and now the liquidity is at four. And as another example, let's say that the price swings over to the right.

As the price swings over to the right, we can see that the liquidity changes. Liquidity is now at 13. Liquidity is now at 8, 5, and then zero. As the price changes, how does unis swap B3 keep track of the active liquidity? Active liquidity is represented as the height of this rectangle. And the height of this rectangle is calculated by stacking up all of the liquidity at that price. For example, when the current liquidity is at 14, this is the sum of two liquidity positions. And we can see this by toggling off and on the positions. Then I'm going to turn on and turn off the other position. And you can see that at this price there are two positions that are active. Hence, we get

a rectangle that is higher than both of them. The height of the resulting rectangle is calculated by adding up all of the heights of the individual rectangles that are currently active at the price. Okay. But how does unis swap B3 keep track of the current active liquidity which is the sum of all of the liquidities that are currently active? To understand how unis swap B3 keeps track of the current active liquidity we need to understand what's called liquidity net. Liquidity net basically means that when the price changes eventually it will cross over a tick and when it does it will either plus or minus some number to the current liquidity and this number is called liquidity net. Let's start with a simple example. Let's say that we have a single

position and we have a current liquidity equal to L which is represented by the height of this rectangle. We have the current tick over here at T and we have two ticks T lower and T upper which define a price range for the position. So for this example, we only have one position and it has a liquidity between the price ranges T lower and T upper. When a position is created at the lower tick, it will assign a positive liquidity net and to the upper tick it will assign a negative liquidity net. If two positions either overlap or intersects at these boundaries, tick lower and tick upper, then liquidity net is calculated by summing up all of these individual liquidity net. The other

thing that we need to understand how the current liquidity is checked is the direction of the price. If the price increases, we associate this with a positive number + one. If the price decreases, then we associate this with a minus one. With these two numbers, the direction of the price change and these liquidity nets at the boundaries of tick lower and tick upper. We can now keep track of the current liquidity. Let's say that this current tick associated with the current price moves all the way over to the left. When this current tick crosses over tick lower, we need to update the active liquidity. Let's call this next liquidity. And the next liquidity will be equal to the current liquidity L. To this, we add some

number. And this number that we need to add is a multiplication of two numbers. The direction of P and then we multiply this by plus or minus the liquidity net. For example, in this case, let's start with the direction of the price. The price decreased from over here to over here. So the direction of price will be a minus one. Then we need to multiply this by a plus or minus delta L liquidity net. In this case at the lower take we have the plus delta L that is stored. So to the direction of P let's say this is minus1 2 -1 2 -1 we multiply this number -1 + delta L. In this example, we only have one position. So let's say

that this liquidity net is equal to the liquidity of the position which is L. So -1 * L and the current liquidity is also equal to L. So what do we get? We will get in this case L + -1 * L which is equal to zero. Let's look at another simple example going the other way. Let's say that the current price is somewhere over here and the current liquidity is L. Let's also say that there was a swap and it increased the price. So now the tick crossed over tick upper. When this tick crossed over tick upper, we need to apply this algorithm.

So current liquidity is L. The direction of the change of the price is a positive. So we will do + one. And then the liquidity net stored at this tick upper is a minus delta L. In this example, again there's only one position. So the liquidity net is equal to the liquidity of this single position which is equal to L and we have a minus. So I'll copy this put it here single position. So liquidity net is equal to the liquidity of the position and we keep the minus that we have over here.

Okay so let's do the math. This is equal to L + 1 * - L or this simplifies to L minus L which is equal to zero. In summary, the way the current liquidity is updated is when the current tick crosses over one of these tick lower or tick upper, it will apply this algorithm. And this algorithm is to take the current liquidity, we multiply by the direction of the price change. If the price increases then we multiply by + one and if the price decreases we multiply by minus one. We multiply this direction of the price by liquidity net which is stored at tick lower and tick

upper. Let's look at example of how the current liquidity is updated using liquidity net. The vertical dotted line in black will represent the initial tick before the price changes. We'll label this as tick zero. The purple dotted line will represent the location of the tick after the price changes. And the difference in tick between the initial ticks and the tick after the price changes we'll represent it as tick delta. For example, if the price increases then the ticks will also increase and tick delta is represented as a positive number. Likewise, if the price decreases from the initial tick, then tick delta is represented as a negative number. Now, let's say that there are multiple positions. To get the liquidity at each tick, we will stack up

all of the liquidity positions that overlap. And we will get a graph that looks like this. To the left of the current tick, liquidity is all in token Y, so we'll color this blue. And to the right of the current tick, liquidity will all be in token X, so we'll color this red. I'll highlight the liquidity at each price as a pink line. Then also display a label. Currently, liquidity is equal to 13. So as a tick moves you can also see that the current liquidity also changes. Currently the liquidity is equal to three and now it is equal to zero and now it is equal to 5. Remember in the last video we said that to get the liquidity net every time we create a position to the tick lower we will associate a positive number. For example

if we're creating this position with liquidity equal to four then to the lower tick we associate plus four. And take a note over here that we have two overlapping positions. One for 10 liquidity and one for three liquidity. And to the upper tick, we associate a negative of the same number. Again, looking at this example, we're creating a position with liquidity equal to 4. So to the upper tick, we associate a minus of that liquidity minus 4. And likewise, we can sort of see a position over here.

We have a positive 10 on the lower tick and we have a minus 10 on the upper tick. And to calculate the liquidity net, all we have to do is add up all of these pluses and minus at each tick. For example, let's start with a simple case. Here we have a single position. So the liquidity net will be +4. A more interesting example is where the positions overlap. Here two positions overlap. One with 10 liquidity and one with three liquidity. We add up all of these numbers. So the liquidity net will be + 13. Then we do the exact same thing for the upper ticks. Let's start with the simple example again. Again here we have a single position with liquidity equal to 4. At the upper tick when we

add up all of these purple numbers we get a liquidity net of minus4. A more interesting example is when we take a look at over here. Notice that for the lower tick we have a +3 but at the same liquidity height when this liquidity deactivates we have a minus 10 over here and this is because when we add up all of these purple numbers we have a minus 10 over here and this is the only number. So liquidity net at this tick is minus 10 with these liquidity nets the numbers that are in pink. Let's go through an example of how the current liquidity shown here will change. Let's start with a simple example of using a single position. So I'm going to move the initial price over to here. And then

I'm also going to move the current price to match the initial price. The current active liquidity is equal to four. This matches the liquidity of this position. Let's increase the price and see how this current liquidity will change. So as we increase the price, it's going to cross over this tick. And when it does, the current liquidity is now equal to zero. This is because the way we calculate this liquidity is by taking this liquidity net. This is a minus4. And then the direction of the price. The direction of the price change was positive. So this will be + one. The liquidity before was four. To this we add a minus4. So we will get zero. And if we go the other way for example let's

say that we start from here again. Then when we go the other way the price is decreasing. So the direction of the price is a minus one. 2 minus one. We'll need to multiply by this +4 and then add it to this current liquidity. So it will be equal to zero. Okay, let's take a look at another example. So I'm going to move the initial tick to over here and then also the initial price to match the initial tick. So I'll give you two more examples. Let's start with a easier one. when the price decreases. When the price decreases, the direction of the price is negative -1. And you can see over here that tick delta is also negative. And as the price crosses over this tick, the current liquidity is equal to 13. The

direction of the price is a minus1. Liquidity net is + 13. The next liquidity will be current liquidity plus the direction of the price minus one time liquidity net 13. 13 + -1 * 13 is equal to zero. As we decrease the price, you can see that the liquidity updated to zero. Okay, so let me give you one more example. Again, we start at this price and let's say that the price increases. So the price increases, the current liquidity is 13. The direction of the price is a positive number. So we'll need to multiply +1 by liquidity net which is equal to minus 10. To this current liquidity 13 we add + 1 * - 10.

So this will be 13 - 10. So the active liquidity when the current tick crosses over this tick must be equal to 3. Let's see the current tick crosses over this tick and now the liquidity is equal to three. Then when the current tick crosses over this tick you'll need to apply a minus three. to the current liquidity and the liquidity is now zero. So this was an example of how liquidity nets that are stored at the ticks keep track of the current liquidity. Every time the current tick crosses over one of these ticks, it will either add or minus some liquidity net to update the current liquidity. Given some liquidity L and the price ranges P lower and P upper. If you wanted to answer the question, what is the amount of token X

between these price ranges P lower and P upper? Or if you have another question like what is the amount of token Y between these price ranges then we saw in the earlier videos that this equation answers our question that the amount of X between the price ranges is given by this equation and the amount of Y in the price range is given by this equation. Now using these two equations we can also ask a different question. The questions that we can answer using these two equations are if we were to add or remove this much token X, then what is the resulting price? And likewise, if we were to add or remove this much amount of token Y, then what is the resulting price? The questions that we'll answer in this video are what is the price

after adding or removing delta X amount of token X and what is the price after adding or removing delta Y of Y. Let's start with the first question. What is the price after adding or removing delta x? This question is actually two questions. What is the price after adding delta x and what is the price after removing delta x? Let's start with the first one of what is the price after adding delta x. Let's consider the case when we add delta x from price upper. On the graph, it will look like this. Here we have the constant product curve and starting from the price upper, we will add this much amount of token x. So the price must decrease. The price will decrease from the starting price, price

upper to the lower price, price lower. So to answer our question, what is the price after adding delta x? We'll use this equation. I'll copy this equation and then paste it here. And I'll replace this x with a delta x. Okay, using this equation, the question that we need to answer here is what is the price after adding delta x? We started out with P upper and after adding delta X the price will be at P lower. So using this equation what we need to find is P lower in terms of delta X liquidity L and P upper. We can derive this answer by simple algebra. So I'll copy this past here. We want to rearrange this equation

so that P lower will be on one side of the equation and everything else will be on the other side of the equation. So first I'll bring this over here and then instead of a minus this will be a plus and then I'll bring the plus sign over here. Next I want a common denominator of square root of p upper. So what I'll do is I'll multiply this delta x by square root of p upper. So our equation will look like this. Next I'm going to simplify the left side of the equation. As the numerator we will have L + delta X time square roo<unk> of P upper and the denominator will be the square root of P upper. Notice that square root of P lower this is the thing that we want to find is on the bottom. So I'll bring

this to the top by multiplying everything by P lower and then I'll bring this over to the bottom. Then I'll bring the L over here. And then over here we'll have a one. So I did was flip the numerators and the denominators. Now the square root of P upper will come to the top and our equation will look like this. To get square root of P lower, all we have to do is multiply everything by L. And finally we get that the square root of P lower is equal to L * of P upper / L + delta X time of P upper. Our original question was what is the price after adding delta X. However, for our final answer, we'll keep it as this.

We'll keep our answer in the form of square root of P lower. And this is because when you look inside the code for units of B3, a lot of the math is done using the square root of price. So we'll keep our equation like this in the form of square root of price. And when you look at the code inside UNISAB pool contract, you'll see this form of equation being used inside the function first law. Okay. So we answered the first part of the question. Let's also do the same for when we remove delta x. What would be the equation when we remove delta x starting from price lower? What is the equation for price upper? So we go back up over here. Let's say that we start from price lower and we remove delta x amount of

token x. The final price after removing delta x amount of token x must be over here. And what is the equation for this price upper? Again, we can solve this equation by starting from this equation and with some simple algebra. All we have to do is solve for P upper. So, what we're doing here is the price will increase from P lower to P upper. And using this equation, we want to solve for a square root of P upper. So, the first thing that I'll do is bring this over to the right and bring this over to the left. Next, on the right side of the equation, I want delta x to have a denominator of roo<unk> of p lower. So, I'll multiply delta x by p / p lower.

And now we have a common denominator of roo<unk> of p lower. Next, I'm going to flip the numerator in the denominator. On the left side, square root of p upper will come to the top and l will come to the bottom. And I'll do the same on the right side of the equation. bring the square root of P lower to the top and bring this equation to the bottom. The last thing that I'll do is multiply both side of the equation by L. On the left side, this will remove the L. And on the right side, we'll have a L on the numerator. And now we have a equation for square root of P upper. When we remove delta X starting from P lower. So we have two equations. one describing the price lower after adding liquidity

and one describing the price upper after removing liquidity. Comparing these two equations, they look almost identical except for over here we have a plus delta x and minus delta x over here. So we can generalize these two equations into a single equation. So if you were to add delta x to this delta x, we add a plus sign. If we were to remove delta x to this delta x, we will have a minus sign. Next, this left side of the equation square root of p describes the price after. So let's re label this as price after. And on the right side of the equation, this price describes the price before adding or removing liquidity. So let's re label

this as price before. And now we have a generalized equation of what the price is either after adding or removing liquidity. If we were adding liquidity, this will be plus delvex. And if we were removing liquidity, it will be minus delvex. Okay, we'll do something similar to answer the question. What is the price after adding or removing delta y? Let's start with the first part of the question. What is the price after adding delta y? So take a look at this graph over here. We'll start from price lower, p lower, and we're going to add delta y, amount of token y. the resulting price.

Let's call this P upper. And what is the equation for P upper? Well, scrolling back up again, we'll be using this equation to answer our question. And instead of having a Y over here, we'll replace this with delta Y. Okay? So, we're going to be adding delta Y. So, this will bring the price from P lower to P upper. The price will increase from P lower to P upper. And using this equation what we want to find is we want to find P upper. So starting from here we can find P upper simply by bringing this L * square root of P lower to this side of the equation. This minus will become a plus. To get the square

root of P upper, all I have to do is divide both side of the equation by L. Dividing the first term by L, I get deltaY / L. And dividing the second term by L, the L on the top cancels out with the L on the bottom. And we're left with square root of P upper is equal to this equation. Next, let's do the same for if you were to remove delta Y starting from P upper. If you were to remove delta Y starting from P upper, so we start from here and then we remove this much amount of token Y. The resulting price will be P lower. And what is the equation for P lower? Again, starting from this equation, we can answer this question.

We have a P lower here. So, we need to just rearrange the equation to have P lower on one side of the equation and everything else on the other side of the equation. I'll bring this over here to the left and then delta Y to the other side. And then I'll divide both side of the equation, dividing the first and dividing the second term. dividing the first the L's will cancel out and we're left with square root of P upper minus delta Y / L. So we have two equations now the price lower after adding delta Y and the price upper after removing delta Y. The first equation I'm going to rearrange it also remove this cell and notice that we have two equations that

look almost identical. We can generalize these two equations now. So if you were to add delta y then the resulting price after is given by this equation. And if you were to remove delta y then we will have a minus over here next to delta y. The resulting price we'll call this price after. And the price before we add or remove delta y. We'll call this price before. Now we get the equation that the square root of price after is equal to the square root of price before plus minus delta y / l plus when we're adding delta y and minus when we're removing delta y. The function compute swap step

inside the library contract swap math computes the amount of token in token out and the fees given the price ranges and the liquidity. This function is called inside the function swap of the unis swap B3 pool contract and it returns the next square root price x96 amount in amount out and fees. The way the fee is calculated inside this function can be a little bit confusing. So in this video we'll go over the math of how the swap fee is calculated. The swap fee is calculated from the amount of token that comes in. In this video we'll say that token in is token x and token out is token y. We'll say that f is equal to the swap fee percentage.

This f will be a number between zero and one. Capital a will be equal to the amount in before swap fee. Swap fee is charged on amount of tokens that come in. So we can say that fee the actual amount of fee is equal to a * f. A is the amount in before swap fee and f is the swap fee percentage. This a n that you see over here will represent the amount in after the swap fee. Since a is the amount in before the swap fee and we already have an expression for the fee, we can rewrite a n which is the amount in after the swap fee to be equal to a minus the fee. And this amount in must be less than or equal to the maximum amount in the maximum amount in in this case is the amount of token x that can

come into this liquidity until the current price reaches the lower price via. You can imagine that as more token X comes in and more token Y leaves this liquidity, then the price will shift over to the left and the amount of token X inside this liquidity will increase. And at this point where the current price P is equal to P of A, this liquidity is all in token X and the maximum amount of token in is the maximum amount of token X that can come in until this current price reaches the lower price P of A and A out represents the amount out. This A out must be less than or equal to the maximum amount of token out. In this case, the maximum amount of token out is the amount of

token Y that can leave this liquidity until the current price reaches the lower price range P. So imagine that as the current price shifts over to the left, the amount of token Y in this pool will decrease until the current price reaches the lower price P of A. So the maximum amount of token Y that can leave this pool is this amount, the amount of token Y between the price ranges P and P of A. With these variables defined, let's now derive the equation for the feed. Now there are two cases to consider. Exact out and exact in. Exact out means that the caller specify the amount of tokens to leave the pool and unis swap B3 will calculate the amount

of token in that must come in. Exact in means that the caller specify the amount of tokens to come in and unis swap B3 will calculate the amount of token that will go out. So let's start with exact out. For exact output, we first need to calculate the maximum amount of token that can come out between the price ranges, the current price P and the lower price P of A. So, scrolling back up in this example, the maximum amount of token that can come out between the current price and the lower price P is the amount of token Y over here. So, this will be the maximum amount of token out. We first need to calculate what this maximum amount of token out is between the price ranges P and P of A.

Once we calculate this maximum amount of token out between the price ranges P to P of A, next we can calculate the actual amount of token that can come out from the price ranges P to P of A. Once we calculate the amount of token that will come out from this liquidity, we can next calculate the amount of token in that must come in. And once we calculate amount in, we can calculate the fees. To calculate the fees, we'll use these equations. At this point, we know what a end is. So, using this equation, we'll work our way backwards to calculate what the fee is. So, a n is equal to a n is equal to the amount in after the swap

fee, which is equal to a minus fee. A is the amount in before the swap fee and the fee is the actual swap fee. We can replace this v since we know that v is simply equal to a * f. This is equal to a minus a * f. We can simplify this to a * 1 - f. Now we can figure out what a is given that we know what a n is. All I have to do is divide both sides of the equation by 1 - f. And I get that this amount in before the swap fee must be equal to a in the amount that comes into this liquidity divided by 1 minus f. And once we figured out what a is, we can

also figure out what fee is. So going back up, we said that fee, the fee is equal to a * f. We figured out what a * f is. So we can now figure out what the fee is in terms of a n. So this is equal to a is equal to this equation. So we can replace this a over here with this expression. And then to get the v we times this by f. So this is the equation for the v. The swap fee is equal to a n / 1 - f * f. And we can actually see the formula inside the function compute swap step. Scrolling

all the way down, we see how the fee is calculated. Fee amount is equal to amount in * fee / 1 minus the fee. Next, I'll explain how the fee is calculated for exact in. For exact in, it turns out that there are two cases to consider. When a n is equal to the max amount in and when a n is less than maximum n. We'll start with case when a in is equal to max amount in. For the case when token in is token x and token out is token y, the current price will decrease. So the first step is to find the maximum amount in between the price ranges P to the lower price PA. Scrolling back up, this

max amount in will be the amount of token X that can come in between the current price P to the lower price P of A. As token X comes in and token Y leaves this liquidity, this rectangle in blue will fill up with rectangle in red. And when the current price reaches the lower price P, all of this rectangle will be in red. And at this point, the liquidity is all in token X. The amount of token X that can come in to fill out this blue rectangle is max amount in. Once we calculate what maximum amount of token that can come in is, we can actually calculate the amount in. And once we calculate the amount of token that will come in, we can also calculate the amount of token that will go out.

From the amount of token in that we calculated, we can also calculate the fee. So let's start with the case of when amount in is equal to max amount in for a n equal to max amount in. This is the case where token X will come in to this liquidity and it will swap all of this token Y for token X. So at the end we will have the current price equal to the lower price P of A and all this liquidity is now in token X. The way that the fee is calculated in this case follows the same equation that we derived over here. In this case we know what a N is.

So we don't have to figure out what this capital A is. We can take a shortcut and just say that the fee is equal to a n / 1 - f * f inside the function compute swap step. You can see that the way the fee is calculated is the same equation that we derived. FE is equal to amount * v / 1 - v. So this is the fee for exacting when amount is equal to max amount. The other case that we need to consider is when amount is less than max amount in. When a n is less than max amount, we will have the case where some amount of token x comes in and some amount of token y leaves this liquidity.

As a result, the current price will shift over to the left. However, it does not reach the lower price via. To the right of the current price, we will have the previous amount of token x plus the amount that came in. And to the left of the current price, we will have some amount of token Y left. In this case, the way unis swap B3 calculates the fee is to take whatever amount that is remaining minus a n. A n is the amount that was calculated to come into this liquidity and a is the amount in before the swap fee. And this is equal to a. A n is equal to a minus v. So we can replace this a n with a minus v. And this equation simplifies to being fee is

equal to fee. So what's going on here is that a is the amount of token in before the swap fee is deducted and a in is the actual amount of token that will come in which includes the swap fee. If you take the difference, we get the fee back. Going back to the function compute swap step and looking at the place where the fee is calculated, you can see the code over here. The way it calculates the fee is take amount remaining and minus amount in. This amount in that you see over here is the a that we saw in the math equation. So that was the explanation of how the swap fees are calculated. If you look at the code, it's a little bit confusing. However, if you do the math, it turns out that in

all cases, swap fee is a percentage of amount of tokens that come in. In this video, I'll do a code walk through for the function swap inside the contract unis swap b3 pull. This contract is inside the repo B3 core. The contract name is unis swap b3 pole. And the function that I want to explain in this video is called swap. This is a lowle function inside unis swap b3 to swap a token for another token. For the inputs to this function, it's going to take in the recipient. This will be the receiver of token out 041. If this is set to true, then it will mean that token zero will come in and token one will go out.

If this parameter 041 is set to false, then it will mean that token one will come in and token zero will go out. Amount specified will determine whether the swap is a exact input or exact output. Notice here that this parameter amount specified is a int 256. So it can be both negative and positive number. When this number is a positive number, then this means that this swap is a exact input. The user specifies the amount of token to come in and unis swap BT will calculate the amount of token to go out. On the other hand, if amount specified is less than zero, then this means that the user specified the amount of tokens that they want to pull out out of this pool. And in this case, unis swap B3 will calculate the amount of

token that must come in. Then we have the square root price limit x96. This is the price limit that the caller is willing to accept. Notice here that this variable name ends with x96. And you'll see this a lot inside the code for unis swap b3. So what is x96? Well, to simply put x96, all it means is that that's some kind of variable and then it's multiplying it by 2 to the 96. The last input data encodes the data to be passed over to the unis b3 swap callback. So if you go all the way down at the end of the swap, it transfers the tokens out and then it calls a function called unis swap B3 swap call back message sender and inside

the call back it's going to pass in the amount of token zero and amount of token one which will be reading from this pool and the amount of token that must come into the pool and the last parameter is the data. So this data is the data that was encoded inside the function input for the function swap. Okay, so these are the inputs of the function slot. Moving on, it first checks that this input amount specified is not equal to zero and then it loads slot zero. So remember that inside slot zero, so I'll go all the way up to find the struct called slot zero. Okay, here it is.

Here's slot zero. And inside the EVM storage of slot zero, all of this data is stored. And the main reason that it is stored in slot zero is to save gas. Inside the strct, we can see that it stores the current tick, the current square price x96 and other stuff. These parameters that are used for the price oracle. Okay, so let's go back down. So once in those slot zero to memory again to save gas, it checks that this function is not re-entered. So this is a re-entry cart. Okay. And then it checks the square root price limit that was passed as input. Next, it updates the re-entrance log and then it loads some state variables into memory. Again, this

is used to say guess. Okay. And then it creates a variable called exact input. Remember that the input if amount specified is greater than zero, this means that some token is coming into this full contract. So this will be an exact input. If amount specified is less than zero then this means that the caller is requesting to pull out some token from this pull contract. So in this case this swap will be a exact output. Okay, moving on. If those more variables including state variables into memory inside a strate will be used inside the while loop to execute swaps. Inside the while loop it will execute swaps in the

current liquidity. Remember that in unis 3 different users can put liquidity into different price ranges. These liquidities will be stacked up to create a bar graph. And inside this while loop we're only swapping in the bar that represents the current active liquidity. We'll come back to this while loop later. Let's move on. And inside this while loop it will calculate the final amount of token that must come in and the final amount of token that will go out. It will also update the current tech and the current square root price x96 that is stored in memory. If these values are not the same as the initial values, then it will update the state variables that track the square root price x96 and the current tick. So this is what the code over here is doing.

Okay. So moving on. Next, I will update the current liquidity if it has changed. Then I will update state variables called fee growth global 0x128 and fee growth global 1x128. These are state variable that track the amount of swap fees that was collected. Using these state variables, liquidity providers will be able to collect fees. I'll explain in another video how these state variables track fees for liquidity providers. Okay, so moving on. Next, it determines the amount of token zero and the amount of token one that must come in and go out. Now, the conditional statement here is a little bit confusing. So, I want to explain what's going on here. We can see that it

compares whether 041 is equal to exact input and if it is, it will execute the first condition otherwise it will execute the other condition to determine the amount of token zero and amount of token one. If you list out all four possible cases for 041 in exact input and also list out what amount zero and amount one must be then we'll understand what's going on over here. So let's start with the case when 041 is true and exact input is also true. When 041 is true then it means that token zero is coming in and token one is going down.

Exact input means that amount specified is greater than zero. And this amount specified remaining is the amount specified that is remaining after executing this while loop which calculates the exact amount of token that must come in for exact input. If amount specified meaning is greater than zero then it means this pool could not take in all of the token that the user specified. So the actual amount that will come in is the amount that user specified minus remaining. For the first case, we have 041 equal to true and exact input. So the token that is coming in is token zero and the amount that must come in is the amount specified by the user minus remaining. And inside the

while loop, it's also going to calculate a variable called stake amount calculated for exact input. This is the amount of token that will go out for a 041 token that is going out is amount one. So to this variable amount one we set state amount calculated. The other case where 041 is equal to exact input is when both of them are false. So when both of them are false let's start with 041. 041 equal to false means that token one will come in and token zero will go out. And since exact input is false then this means that this swap is a exact output. So token one will come in and token zero will go out. Then the caller specify the amount of token that they

wish to pull out from this pool. Amount zero will be equal to the amount specified the user. This is the amount that the user requested to take out from this pool minus amount specified remaining. The amount of token that must come in is stored inside calculated state amount calculated. In this case, this is a one for zero swap. So token one will come in and the amount of token one that must come in is calculated. In these two cases, the amount of token zero and amount of token one are calculated in the first expression.

Okay. So let's now consider the case when 041 is not equal to exact input. There are two cases when 041 is false and exact input is true and when 041 is true and exact input is false. Let's start with the first case. When 041 is false, this means that token one will come in and token zero will go out. exact input equal to true. So amount specified will be a number greater than zero. And this is the amount of token that the user specified to put inside this pool. The token that's coming in will be token one. So here we see that amount one is equal to the amount specified by the user minus remaining.

The token that's going out is token zero and this is stored in state.ount calculated. And for the last case 041 equals to true and exact input equals to false. Token zero will come in and token one will go out and the user specify the amount of token to go out. Token one will go out. So amount one must be equal to the amount specified by the user minus the remaining for exact output. User specifies the amount of tokens to go out and unwrap B3 calculates the amount of tokens to come in. Since this last case is a GL41 token that's going to come in is token zero and this amount is calculated by unisol B3. So in the last two cases amount zero and amount

one is calculated by this expression. Okay. So moving on for the last part of the swap function it's going to transfer the token out and then call the call back on message sender. The callback is called a unis swab swap call back and inside here message sender must send the tokens that is requested and then afterwards this contract is going to check that the correct amount of token came in for 041 token one will go out. So the pool will transfer token one and token zero must come in. So it's going to call the call back on message sender and then afterwards it's going to check the balance of token zero. If this swap is not a 041, then it is a 1 140. Token

out will be token zero. So it's going to first transfer token zero and then it's going to call the call back. Then afterwards, this pull contract is going to check the balance of token one. Okay, for the last part of this video, let's dig a little bit deeper inside the while loop. The while loop will continue to execute while the amount specified remaining is not equal to zero and the current square root price x96 is not equal to the square root price limit x96 set by the user. Inside this while loop, it's going to first get the next tick. Let's take a look at this function called next initialize tick within one word. Inside the library called tick bitmap, there is a function called next initialize tick within one word. And

what this function is going to return is either the next initialized or uninitialized tick up to 256 ticks away from the current tick. Once it gets the next tick, it will make sure that this next tick is within minimum and max tick. Okay. And then moving on from this tick next, it will calculate the next square root price. And with this next square root price, it will calculate the amount of tokens to come in, amount of tokens to go out, and the fee for the swap. And it will also calculate the current square root price X96. If the swap is an exact input then from amount specified remaining it will deduct the amount of token to come in plus the fees. If it is an exact output then to amount specified remaining it will add

amount out. In both cases this amount specified remaining will approach zero. For exact input it would approach from the positive number and decrease to zero. For exact output, it will start from a negative number and then an increase to zero. Okay. And moving on. Next, it calculates the protocol fee if it is enabled and then it will update the state variable fee growth global x128 which is loaded into memory. Again, this is the variable that enables liquidity providers to collect fees on swaps. Okay. And then moving on, if the current square root price x96 has reached the next square root price x96.

So this next square root price x96 represents the square root price x96 that we got for the next tick. If the current price if the current square root price x96 is equal to this next one and if the tick is initialized then it will store some variable for the price oracle and then what's more interesting is this part it will get a variable called liquidity net and then update the current liquidity by this liquidity net.

Remember that liquidity net is used to keep track of the current active liquidity. This code over here is how it's done. And then at the end of the loop, it will update the tick. Okay, so that completes the code explanation inside the while loop. And that also completes the code explanation for the function swap. The swap router 02 contracts has four functions that we can call to swap tokens. The functions are called exact input single, exact input, exact output single, and exact output. We'll examine how each of these functions work. But before we do that, I'm going to first explain one of the internal parameters that is used when any of these function is called. When a function exact input single or exact

input is called, a internal function called exact input internal is called. And when the function exact output single or exact output is called, a internal function called exact output internal is called. Inside the function exact input internal, you can see over here that there is a parameter called path. This parameter path encodes the two tokens and the fee which identify the pool to swap one on inside the function exact output internal. We can also see the parameter path and again this parameter name path encodes the tokens and the fee which identify the pool to swap on. The data type of the parameter named path is bytes and the way that the tokens and the fees are encoded is the following. We start with some token and then next we encode the

fee and then followed by a token. These three parameters will identify a pool. If you wanted to do a swap between two pools, then we follow this by a fee and token. And these three parameters will identify the next pool. For example, let's say that we wanted to swap from D to USDC on a pool with fee 0.01%. And then afterwards, we want to swap USDC for W on the USDC pool with 0.3% fee. In this case, the path will be encoded as the address of D 100 and then the address of USDC followed by 3,00 and then the address of W. These two numbers 100 and 3,000 are scaled up by 10 to the

6. So if you divide 100 by 10 6, you'll get 0.01%. If you divide 3,000 by 10 6, then you'll get 0.3%. So this is how the path is encoded. It encodes the tokens to swap and the pools to use for the swaps. Next, let's take a look at how the function exact input single inside the contract swap router 02 works. We have a user that's going to call the contract swap router 02. And the swap router 02 will call into unis swap b2 pull contract. Inside swap router 02, there is an internal function called exact input internal. And inside this function, the path will be encoded as token in fe and then token out. The user will first call the function exact input

single. This function is called when you want to swap a token with a single pool. If you wanted to swap with multiple pools, then you will call another function called exact input, which we will take a look at later. The swap router 02 will call into the function called swap on unis swap B3 pool contract. The unis swap b3 pool will transfer the token out to the user. And then next it will call a call back called unis swap b3 swap call back on the swap router 02 contract. Inside the call back the swap router 02 will call transfer from for token in transfer from the user to unis swap b2 p contract.

Notice here that token now is transferred to the user before the user has to pay the token in. This is the same pattern that we saw in unis swap b2. Next I want to dig a little bit deeper and explain what functions are called and how they are called. First the user calls a function exact input single on swap router 02. This function will execute a internal function called exact input internal. The function exact input internal will call the function swap on unis swap b3 pool. Among other things the function swap will execute two things. Transfer token out to the recipient. In this case the recipient is the user and then afterwards it will execute the call back unis swap b3 swap call back. The call back is executed on

the contract. swap router 02. Inside the callback of swap router 02, it would transfer the token in from the user to the unis swap b3 p contract. Let's say that we have a unis swap b3 with token A and B. We have another one with token B and C and we have another one with token C and D. If you wanted to swap token A for D, then we will need to swap A for B and then for B for C and then for C for D. to execute a swap that involves multiple pools. We can call a function called exact input on the swap router 02 contract. So let's say that we wanted to swap token A for B, B for C, and then finally from C to D. First, the user will call the function exact input on the swap router 02 contract. The swap

router 02 contract will run a loop to execute swaps on multiple pools. For each pool, it will call the function swap, receive some tokens, and then send some tokens out. In our example, it will first call the swap on unis b3 pool having the tokens A and B. Unisoft B3 pool contract for token A and B will send token B to the swap router 02 contract. This token B that is sent to this router contract will be used in the next swap to send the token B over to the Unisoft B3 pool with token B and C. And after the token is sent over to the swap router 02 contract, it will call the call back function unis swap b3 swap call back. Inside the call back, the swap router 02 contract will send token

A from the user over to the first pool pool with token A and B. And that completes the first swap of putting token A and then receiving token B. We still have two more swaps to execute. The swap router Z2 contract will call the function swap on the next pool having the tokens B and C. This second pool will send token C over to the swap router Z2 contract and then again it will call the call back function called unis swap B3 swap call back. Remember that token that was sent over to the swap router 02 contract in step three. Now this token is transferred over to the pool with token BC. This completes the second swap of swapping token B for token C. And then we have one more swap to get token D. So at the moment the

swap router 02 contract has token C. It calls the function swap on unis swap b3 pull with tokens C and D. And again the unis swap b3 pull contract will send the token out before receiving any token in. Since this is the last swap instead of sending the token over to the swap router 02 contract the unis swap b3 pull contract will send the token directly over to the user and then it will call the call back unis swap b3 swap call back. Inside the callback, token C is sent from swap router 02 over to the last pool unis pool with token CD. This is an example of how tokens are swapped between multiple pools when the function exact input is called on swap router Z2.

Next, I'm going to explain what functions are called and what parameters are passed when the function exact input is executed. When the function exact input is called, we need to pass in the path. For our example, we're swapping from token A, B, C, and then D. So the path will be encoded as token A followed by the fee that will identify the pool having token A and B followed by token B and then followed by fee that will identify the pool for token B and C and then finally followed by the fee that identifies the pool for token C and D.

The payer will be transferring the token in. In this case, this will be the user. Next, it will execute a while loop to call swaps on the individual pools. Starting with pool AB. Inside this while loop, it's going to call the internal function called exact input internal. Here, the recipient, the address that is going to be receiving the token out is set to the router contract. This is because once it receives the intermediate token, it's going to send it over to the next pool. The function swap is called on pool A B. Token B is transferred over to recipient. Here the recipient will be the router contract.

This token B that is received by the router contract will be used in the next iteration to send this token B over to the next BC. Once the token is sent, next it's going to call unis swap B3 swap call back. This function is inside the router contract. Inside the router contract, it would transfer token A from the payer. In this case, the payer is the user. So, it's going to transfer token A from the user to pool AB. We're still inside the loop and to prepare for the next loop, the code will set the payer to the router contract and the parameter path is set to token B, C, and D. Here, token A is removed from the path since we are done with that swap. The first three parameters, token B, V, and token C will

identify the pool to swap on. And then we move on to the next iteration of the for loop. Call the internal function exact input internal again. And again the recipient the address that will receive token C is set to the router contract. The router contract will receive token C and then send it over to the last pool CD. So just like in the first iteration it will call the function swap on pool BC. Token in is token B and token out is token C. The unisolob contract will transfer token C to recipient. Here since recipient is set to the router contract, this token C is sent over to the router contract.

Then afterwards, it's going to call unis swap B3 swap call back on the router contract. Inside the call back, the router will transfer token B from payer. In this case, the payer is the router to pool BC. Remember back in this step, token B was transferred over to the router contract. So at this step, we still have token B in the router contract. And this is why the router contract can transfer token B over to pool BC. To set up for the next iteration of the for loop, again the payer is set to the router contract. The last swap will be from token C to token D. Here the payer means that the router contract will transfer token C over to the pool C, D. And the parameter path is updated

to C, FE, and D. From the previous parameter, we remove token B and FE. And these last three parameters will identify the last pull to execute the swap one. And then for the last iteration, it will call the function exact input internal. Notice that in the previous two iterations, recipient was set to the router contract. For the last iteration, the recipient is set to the user. Here it means that token D will be sent to user. It will call the function swap on pool CD. The unisell pool contract will transfer token D to recipient. recipient is set to user. So token D will be sent over to the user and then the unis swap B3 swap call back

is executed on the router contract. The router contract will transfer token C from payer. Here payer is set to the router contract. So token C will be transferred over from the router contract over to pool CD. And that completes the call trace when the function exact input is called. If you wanted to get some specific amount of token from a swap and the swap only involves one pool, then you will call the function exact output single. Inside the swap router 02 contract, when the internal function exact output internal is called, the path will be encoded as following. Token out, V and then token in. These two parameter will identify the pool to swap on. Here notice that

for exact input single, the path was encoded as token in V and then token out. For exact output single, this is the opposite. We start with token out followed by fee, then end with token in. The user will first call exact output single on swap router 02. Swap router 02 will call the function swap on unis swap pull contract. From unis swap b3 pull, token out will be transfer to the user. Next, unis swap pull contract will call unis swap b3 swap call back on swap router 02. Inside this call back token in will be transferred from user over to the pool contract. Let's take a look at the call trace when the function exact output single is called. So when the user calls the

function exact output single on the swap router 02 contract, this function will first call internal function called exact output internal. The internal function will call the function swap on the unisop pool. Inside the function swap, it will execute many codes, but two of them will be to transfer token out and then to call the call back unis swap B3 swap call back on the swap router 02 contract. Inside this call back, token in will be transferred from the user over to the pool. If a user wants a specific amount of token out from a swap and the swap involves swapping between multiple pools, then they will call the function exact output. For example, let's say that this user wants 100 of token D. To get 100 token D, they first need to figure out

how much token C they need. And to figure out how much token C that they need for the swap, they will first need to figure out how much token B that they will need. And again, to figure out how much token B that they will need, they first need to calculate the amount of token A that they'll need to put in. So to execute the swap where the user puts in token A and it will be swap for token B. This token B will be swap for token C and finally this token C will be swap for token D. The order of the swaps will be reversed. We first execute a swap from C to D and then we execute a swap from B to C and then finally we execute a swap from A to B. So first the user will initiate the swap by calling exact

output. Again the swaps will happen in the reverse order that is shown here. So the first swap will happen with the pool having token C and D. the unis swap b3 pull with token C and D will first transfer token D to the user and then it will call the unis swap B3 swap call back on the swap router 02 contract. At this point token D has left the unis swap B3 pool contract and the swap router 02 contract owes token C to this pool to pay for this token C that the swap router 02 owes to this unis swap B3 pool contract. It will call a swap on the unsub with tokens BC. transfer the token C over to this unis swap B3 pool contract. So the swap router 02 will call the function swap on unis swab bull

with tokens BC. Token C will be sent over to unis swab BP pool with tokens C. And this completes the swap from token C to token D. However, for the pool with tokens B and C, token C has left. So the swap router 02 now has to pay this pool with token B. After token C is transferred, this pool will call the unis swap B3 swap call back on the swap router 02. Now remember again that currently the swap router 02 owes token B to unis swap B3 pool with token BC. To pay this pool with token B, the swap router 02 will call swap on UNIS BT pool with token AB. This will transfer token B from unis BT pool with token AB to the

pool with BC. And this completes the swap from token B to C in this pool. But now we still have token A that we need to pay to this pool. This pool will call the unis swap B3 swap call back on the swap router 02 contract. Inside the call back token A will be transferred over from the user to unis swap B3 pool contract. And this completes the last swap. Put in token A and transfer token B out. Next let's examine the call trace when the function exact output is called. When the function exact output is called, it will make a recursive call into the internal function exact output internal, the path is encoded in the reverse order of the swap. If you wanted to swap from token A to B and then from B to C and then from C to D, the path

will be encoded as token D and then FE and then token C. These three parameter will specify the pull to swap token C to D. Then we're followed by FE then the address of token B. These three parameters specify the pool to swap from token B to C. And finally the last three parameter the address of token B fee and the address of token A specify the pull to swap from token A to token B. The function exact output will call internal function called exact output internal. One of the parameters that is passed into this function is the recipient. For the first call, the recipient is set to the user. This recipient will be the receiver of token out. And inside this function, it will call the swap function

on the pull contract. The pull contract that we first call is the pull for token C and D. Token C will come in and token D will come out. Inside the swap function, it will transfer token D to the recipient. Here the recipient is the user. So token D will be transferred over to the user. The amount of token that will be transferred here is the amount that the user specified. And then it will call the unis swap d3 swap call back on the swap router contract. Inside the callback, it updates this path parameter. We did a swap from token C to D. So we update it by removing token D.

The new path will encode that we'll need to swap from token B to C and then from A to B. And then it will call the function exact output internal again. Notice here that we call the exact output internal over here. And before this is done executing inside it, we call the function exact output internal again. In other words, it's making a recursive call into the function exact output internal. Notice that for the first call to exact output internal, the recipient was the user. This user received token D. This time the recipient is set to the pool with token CD. And then we will call the function swap on the pool BC. Token B is coming in and token C is going out. The recipient here, this will be pool CD

will receive token C. Inside the swap function, token C will be transferred over to the recipient. And again, this recipient is the pool CD and then it's going to call the unis swap b3 swap call back. Notice that the last time the unis swap b3 swap call back was called it updated the path and then call the internal function exact output internal. And again the code will execute in a similar manner. At this point the swap from token B to C is completed. So we update the path to our final pool from token A to B. And then we call the internal function exact output internal again. This time the recipient will be pool BC. Exact output internal will call the function swap on pool with token AB.

Token A will come in and token B will go out. The recipient will receive token B. In this case, the recipient is pull with token B and C. And this over here will complete the swap from token B to C. Next, it will call the unis swap B2 swap call back again. And to finish this recursive call, the call back will transfer token A from user to pool AB. Token B left from this pool and it expects token A to come in. And this transfer of token A from the user to the pool AB will terminate this recursive calls. And this is example of what the call trace will look like for exact output. In this video, I'll do a code walk through for the contract swap router 02. The contract swap router02 is

used to swap tokens for unis swap b3 pools. This contract is located under the repo called swap router contracts. The contract swap router02 inherits two contracts B2 swap router and B3 swap router. To swap with unis swap B3, we'll look at the contract B3 swap router. So here it is over here. And inside it we have several functions. The functions that we'll take a look at are exact input single, exact input, exact output single, and exact output. Let's start with exact input single. The function exact input single is used to swap a specific amount of token in for some amount of token out. The amount of token that the user desires to put inside the

pool is specified by the user. The amount that comes out will be calculated by unis swap B3 pool. And this function is called exact input single because it will only swap with a single pool. To swap with multiple pools, you'll need to call the function exact input which we will take a look at later. The function first checks whether to swap the token using the balance of the token in inside this contract or to pull the token in from the caller. For simplicity, we'll say that token in will come from the caller. So has already paid we assume is set to false. Okay. And then it's going to call an internal function called exact input internal. Let's take a look at what this function does. The function exact input internal is called both by

the functions exact input single and exact input. Remember that in one of the previous video we said that this path encodes the tokens and the fees which will identify the pool. And the order in which the tokens are encoded will tell which is token in and which is token out. For example, let's say that the path is encoded as a v and token b. Then in this case, token name will be a and token b will be token out. If we had it the other way, let's say that we encode first token b fe and then token a. Then token b will be token in and token out will be token. Now this function exact input internal will also be called by the function exact input. The function that you would call if you wanted to

swap with multiple pools. For example, let's say that we wanted to swap from D to USDC on the D USDC pool with 0.1% fee and then from USDC to web in the pool with 0.3% fee. Then the path must be encoded like this. Token in will be die and then token out will be USDC. In the next swap, USDC will be token in and ref will be token out. Next, it checks whether this swap is a 041 by comparing the address of token in and token out. Okay. And moving on, it calls the function swap on the unis swap B3 pool which is computed by taking in token in token out and the fee. When this function swap is called inside unisoft

B3 pool contract, it's going to call this function and we said in a previous video that at the end it's going to transfer the tokens and then it's going to call the call back called unisaw B3 swap call back. This call back is executed back inside the B3 swap router. So if you go all the way up here, it is the function. It's called unis b3 soft callback and inside here this is a example of exact input. So it will execute this part of the code pay token in from the payer. The payer will be the caller of the function exact input single to message sender. This function was called by the unis swab bt. So message sender will be the unis swab bt.

pay from the caller to the unisoft B3 pool for amount to pay. Okay. And that will complete the execution to the function unisoft B3 call back. And then this swap function will return to here. And that ends the call to exact input internal. Moving on, let's take a look at the function exact input. The function exact input is similar to exact input single. The caller will specify the amount of tokens that they want to put inside UNISAB B3 and UNISAB B3 will calculate the amount of tokens that will go out. The difference between exact input and exact input single is that exact input single will only call swap with a single pool. On the other hand, exact input will execute swaps with

multiple pools. For example, if you wanted to swap from USDC to W, then you will call the function exact input single. However, if you wanted to swap from die to USDC and then from USDC to web, then you would need to call the function exact input. Again, the first part of this code would check whether to swap with tokens that is inside this contract or not. And for simplicity, we assume that token name will come from the caller to this function. So, we assume that has already paid is set to false. In this case, the payer will be set to message sender. Next, we have a while loop. In each iteration of the while loop, it will call the function exact input internal and then execute this part of the code. If there are

multiple pools left, this parameter is queried by calling the function has multiple pool on the input path. If it has multiple pools, then it will set the payer to this contract and then from the current path, it will remove the first token that is encoded into path. As an example, imagine that path is encoded as token A, V, token B, V, C, V, and D. On the first iteration, it will remove token A and V. On the next iteration, it would remove token B and V. And on the last iteration, this path no longer has multiple pools. So, we'll be executing this part of the code. It will set

amount out and then break from the while loop. So, this is how the while loop works inside the function. exact input. On each iteration, it will call the function exact input internal to swap tokens with a single pool of unis pull contract. And then after the swap, it will remove a token and a fee from the path. When the path no longer has multiple pools, the while loop will exit and we move on to this part of the code, which ends the execution for the function exact input. Next I want to go a little bit deeper into how exact input internal is called inside this while loop. So in the first iteration notice that payer is set to message sender and the recipient of the first token is set

to address this. So when there are multiple pools to swap the initial payer will be message sender and the recipient of token out will be this router contract. In the last iteration, this boolean has multiple pool will be false. So the recipient of the last token will be the recipient set inside the parameter and the payer well inside the while loop payer is set to this contract. So for the last iteration of this while loop, token in will come from the router contract and token out will be sent to this pram.

And that completes the code walk through for the functions exact input and exact input single. Moving on, let's do a code walk through for the function exact output single. The function exact output single is called when a user wants specific amount of token from a single unis b3 pull contract. The unis b3 pull contract will calculate the amount of token that must come in and then pull that amount of token in. This function will call internal function called exact output internal. the function exact output internal from the input called path it would decode the token out token in and the feed. I'm going to show you how the path is encoded when the function exact output single is called.

So let's go back and you can see over here that the path is encoded as token out v and token in. This is the reverse order of how path is encoded compared to exact input single. In exact input single path will be encoded as token in b and then token out. However, for exact output single, the path is encoded as token out first fee and then token in. So going back to the internal function exact output internal, it will get the token out, token in and the fees and then calculate 041 by comparing token in and token out. Next, it will call the function swap on unis swap bull contract. Again the unis swap v3 pull contract will execute the function swap

and at the end of the swap it will call a call back called unis swap v3 swap call back. This call back is again executed inside a swap router contract and inside here since this call is a exact output this part of the code will execute and also for exact output single we don't have multiple pools so this part of the code will execute. What it does is ask the payer which will be the caller of the function exact output single to pay to the unisoft B3 pool for amount to pay. Okay, that's exact output single. Next, let's take a look at the function exact output. The function exact output is the most difficult function to understand in this contract.

The reason why it's difficult to understand is because exact output will make recursive calls to exact output internal. This function is similar to exact output single. User specifies the amount of token that they want to take out out of unis swap b3 and unis swap b3 will tell the user how much token that must come in. The difference between exact output single and exact output is exact output single will only call swap with a single pull. Exact output will swap with multiple pools. For example, if you wanted one ref from USDC ref pool, then you will call exact output single. On the other hand, let's say that you wanted one ref and you only had D. One way to get ref from D is to first

swap D for USDC and then USDC to W. In this case, the user will call the function exact output. And continuing with our example of swapping from D to USDC and then from USDC to web. For exact output, the order of the swaps will be in the reverse order. First, it will swap from USDC to WE. This W will be sent over to the caller. Now this USDC web pull still needs USDC to come in to complete the swap. So this swap router contract will next execute a swap between D USDC pull. Send the USDC over to the USDC pool and then pull the die from the caller. So you can see that it first swapped with USDC reflect pull. So let's take a look at

the function exact output internal. Inside the function exact output internal the parameter path is encoded as token out fee and then token in. For example, if we're swapping from die to USDC and then from USDC to ref the path will be encoded as ref. This is a pool fee USDC 100 and then die. This part of the code will get the first full. In our example, this will be ref and USDC. Token out will be ref and token in will be USDC. thing and moving on it's going to call the function swap on the unis swap b3 pool the unis swap b3 pool will call back into a call back unis swap b3 swap call back from here this will be a

swap with exact output so this part of the code will execute and for our example it also has multiple pool so this part of the code will execute now notice that to get to this part of the code the function exact output internal was called which called a function swap on b3 three and the function swap call back into this function new subb swap call back and from here we're calling back into this internal function called exact output internal the function exact output internal calls back into the function exact output internal when there are multiple pools it is making a recursive call this part of the code is what makes the function exact output difficult to understand so assuming that

there are multiple pools let's see what happens over here. First it will remove the first token from the path. For example, if the path was left, USBC and die, it will remove the first token. So it will remove the token ref and v. This new path will be passed to the function exact output internal. Okay, imagine that when this part of the code is executed, there are two pools to swap with. When this part of the code is executed, it will remove one pull. So we're only left with one pull. It's going to call exact output internal again. Going back to exact output internal. Notice that this parameter recipient is now set to the pool that called into the unis b swap callback. So

if you go back up, you can see over here that this function exact output internal is called with message sender for the second parameter. The second parameter is recipient. message sender to the callback unis swap swap call back is the pool itself. The recipient for the next swap is set to the previous pool contract. Okay. And it's going to call the function swap again. And if we started out with 3000 USDC 100 and die in this iteration the path will be USDC 100 and die. And it's going to call the function swap on the pool USDC die. And again this function swap will call back into the call back unis swap call back.

This is still exact output. So this part of the code will execute. However, at this point let's say that the path is USDC 100 and type. It no longer has multiple pull. So this part of the code will execute. And in this case it will transfer token in from the payer. The payer here will be the caller to the function exact output to message sender. So to the first pool in our example, this will be the USDC dipole for amount to pay. And this part of the code will end the execution to the recursive calls to the function exact output internal.

And this completes the code walk through for the function exact output and the function exact output single. There are four exercises to swap with the unis swabb3 swap router 02 contract. I'll first explain the setup. So the setup is we have ref WBTC and the router contract. This will be the swap router 02 contract. If you need to look at the interface, you can locate to source interfaces unis swap b3 and then click on swap router. This is the interface that you'll need to use to call the functions to swap with unis swap v3. The four exercises will be to call the function exact input single, exact input, exact output single, and exact

output. Let's start with the first exercise, which is to call the function exact input single. So going back to the test file, the setup is that this contract will be allocated with 1,00 die. You'll be swapping this D with W and also with WBTC. And this test contract has approved the router contract to spend D that is locked inside this contract. Okay. So the first exercise is to swap 1,000 D that is locked in this contract for W on D pool with 0.3% fee. Now if you want to swap die for W in a pool with a different swap fee, feel free to do so. For your convenience, I've included a constant called pool fee which is set to 3,000.

This is the pool fee for 0.3% fee. Okay. So the first exercise, I want you to call the function exact input single to swap 1,00 die for ref. To call the function exact input single, you'll need to look at the I swap router interface. And if you look at the function exact input single, you'll need to pass in a parameter called exact input single params which is over here. Token in token out and fee will determine the pool to swap on. Token in will be die and token out will be ref. For the recipient, set it to this test contract.

Amount in will be 1,000 die. And for amount out minimum here, we'll keep it simple and you can set it to zero or one. And likewise for a square root price limit x96 we'll keep it simple so you can just set it to zero. Okay, so that's the first exercise. Let's go over the solution for the first exercise. The first exercise is to call exact input single on swap router 02 contract. Over here I'll call router exact input single. Then we'll need to pass in the parameter navigating to the eye swap router interface. This is the str parameter that we need to prepare. So copy this and then I'll paste it here inside this test file. The str exact

input single parameter is not defined. It is actually imported as I swap router. So over here I'll need to type I swap router dot exact input single. Token in will be token out will be left fee. This will be the pool fee that will determine the pool. We're swapping on DF pool with 0.3% fee and the fee is defined over here. So I'll type pool fee. Recipient will be the address that will receive token. Now in this case this will be ref. This test checks that ref is sent to this contract. So recipient will be the address. This amount in we're going to send 1,000 die.

So this will be 1,00 times 118 die has 18 decimals amount minimum let's just say 1 and square root price limit x 96 we'll set it to zero that completes exercise one let's try executing this test we'll execute this test against the mainet fork so I'll first set up the fork URL and then we'll execute the test by typing forge test d-forork URL fork URL from the environment variable match path test unis swap b3 exercises and the name of the contract that we're executing is called unis swap b3 swap tests and I also want to display the console log so I'll type dash

bbb okay and our test pass for putting in 1,00 die we currently get about 0.332 w for the second exercise I want you to call the function exact input on the swap router 02 contract in For this exercise, you'll be swapping 1,00 die for W and then from W to WBTC. This should be done in a single call to the swap router contract by calling the function exact input. The final token that comes out which is WBTC should be sent to this contract. Let's take a look at the interface for swap router 02 again. So inside swap router02, you'll need to call the function exact input and you'll need to prepare a struck which will be the

input. The struck name is called exact input params. You'll need to encode the path which will encode the path from die to W and then from W to WBTZ. The recipient will be set to this test contract and amount in will be 1,000 D and for amount out minimum we'll keep it simple again and you can set it to one or zero. And note that for this exercise WBTC has eight decimals. To execute the function exact input on swap router 02 contract, we first need to encode the path. For this exercise, we're going to swap from die to web and then from left to WBTC. So path will be equal to abiencode packed. We'll need to encode

die followed by the pool here. I'll type unit 2400 and then token out will be ref. This will be the first swap. The second swap will start from ref. So ref will now be token in. The pull fee is again 24 3000 and then token out will be WBTC. Next we need to call the function exact input on the router contract. Router dot exact input. Okay going to the interface. We'll need to prepare this parameter. The strct exact input is not declared inside this contract. So it must be imported from I swap router dot exact input params. The path be the path

that we prepared above. Recipient will be this contract. Amount in will be 1,00 die 1,00* 1 E18. Amount out minimum. Let's just set it to one. And this completes the code to execute the function exact input on swap router 02 contract. Let's try executing the test inside my terminal. I'll first set the environment variable for 4QL and then we'll execute the test by typing forge test for QRL matchpath test unis swap B3 exercises unisoft B3 swap tests and our test executed successfully. We put in 1,00 WBTC has eight decimals. So we got back around

0.016 WBTC. For exercise three, I want you to call the function exact output single on the swap router 02 contract. And in this exercise, I want you to call the function exact output single to swap a maximum of 1,000 die to obtain exactly 0.1 W. And the W that comes out from the swap should be sent to this test contract. The function that we'll need to call is exact output single. Let's take a look at the interface for exact output single. Exact output single will be this function and again you'll need to prepare this parameter to pass to this function. Token in token out and fee will determine the pool to swap on.

Recipient will be this test contract. Amount out will be 0.1. Amount in maximum will be 1,000 D. Here we're saying that we're willing to spend a maximum of 1,000 D and we want exactly 0.1. And for square root price limit x96 again we'll keep it simple and set it to zero. Okay. So that is exercise three. Call the function exact output single. Let's go over the solutions for how to call exact output single on the swap router 02 contract. First I'll type router exact output single. And let's check back the interface to see what parameter we need

to prepare to call the function exact output single. Okay, here is the function exact output single and we'll need to prepare this parameter. We'll need to import this truck called exact output single prams. This is from I swap router dot exact output single prams. Token in we're swapping D for W. So this will be D. Token out will be W. fee will be 3,000 or we can use the constant that is defined in this contract pool fee recipient will be this contract amount out in this exercise we want to get out 0.1 W has 18 decimals so 0.1 will be 0.1

* 118 amount and maximum we're willing to spend up to 1,000 D 1,000 * 118 square price limit x96 set it to zero. Okay, let's try executing the test. Set the fork urio as an environment variable and then execute the test forge test for urio match path. The path for this test is test unis b3 exercises unisoft b3 swap.est.so. Okay. And our test passed. To get 0.1 web, we had to spend about 300. For the last exercise, I want you to call the function exact output on

swap router 02. In this exercise, I want you to swap maximum of 1,00 die to obtain exactly 0.01 WBTC. Swap die to W and then from W to WBTC. Send the W back to this test contract. Now note again that WBTC has eight decimals. Okay, let's take a look at the function declaration exact output inside the interface for swap router 02. The function exact output is going to take in a single parameter which is this strct. So you'll need to prepare this strct to call the function exact output.

The first parameter path will encode the tokens to swap and the pools to call. Remember that for exact output path must be encoded in the reverse order of the tokens. In this exercise, you'll be swapping from D to W and then from W to WBTC. So the path must be encoded as WBTC W and then finally D. The recipient will be this test contract. Amount out will be 0.01 WBTC and amount in maximum will be 1,000 D. Okay, so that is the last exercise. Call the function exact output on swap router 02. Let's go over the solution for the last exercise to swap with unis. In this exercise, we'll need

to swap from D to W and then from W to WBTC. And we also want exactly 0.01 WBTC. And we're willing to spend a maximum of 1,000 D. So we first need to prepare the parameter. This will be Avi.incode pack. Remember that for exact output, we need to list out the tokens and the fees in the reverse order. Here we're swapping from D to W and then from W to WBTC. This order needs to be in the reverse order. So we start out with WBTC. The fee for WBTC web will be 30,000. So UN 2400 then followed by W. Next we need to encode the pull from D to W with P V

30,000. So again you 24 3000 and then D. Next, we'll call the function exact output on the swap router 02 contract. Router exact output. Let's check the interface and see what parameter we need to prepare. This is a strct that we need to prepare. Again, we'll need to prefix this with I swap router dot exact output pars. The path is the parameter that we prepared above. Recipient will be this contract. amount out for this exercise we want exactly 0.01 WBTC and WBTC has eight decimals so this will be 0.01 01 *

18 amount in maximum. The maximum amount of D that we're willing to spend in this swap is 1,00 die. 1,00 * 118. Okay, this completes the code for calling the function exact output on swap router 02. Let's try executing this test. Set the forl environment variable and then execute the test forge test for URL. The path is unisab exercises unisab swap.est.solo. Okay. And our test pass to receive 0.01 WBTC. We have to spend roughly 65. Unis swap B3 uses create 2 to deploy the pool contract unis swap B3 pool.

Because it uses create 2, the address of the pull contracts can be determined before they are deployed. But the way the factory contract deploys the pull contracts is not straightforward. So in this video, I'll explain how the unis swab B3 factory contract deploys the pull contracts. We'll first begin with a review of create 2. How does create 2 compute the contract address? To compute the address, we'll need to take the catch 256. The first input will be 0x FF. The next input will be the address of the deployer, the address that deploys the contract. Next will be a random 32 bytes called salt. This will be specified by the deployer. And the last input will be the catch 256 of the contract's creation by code. When you

compile and deploy a contract, there are two bite codes that are produced. When you deploy a contract, it first sends the creation by code. The creation by code will be executed, do some setups, and deploy the runtime by code. Loosely speaking, creation by code is the bite code of the contract and the constructor. And then the next input for this kak 256 will be the constructor inputs. After taking the kak 256 of these inputs, you would take the last 20 bytes. And this will produce the address determined by create 2. Now notice that since we're taking the kak 256, there are several inputs that will change the address of the contract. The things that would change the address are the address of the deployer, salt specified by the

deployer, and this inner kak 256. Assuming that we're deploying the same contract, the creation by code will always be the same and constructor inputs might be different. So assuming that the deployer and the contract that we're deploying are the same, there are two parts that would change the address of the contract. The two parts that can change the address of a contract are the salt and the constructor inputs. And why do we need this salt? Well, imagine the case that we want to deploy the same contract at a different address with the same constructor inputs. For example, you might want to deploy multiple ERC20 contracts with the same constructor inputs. In this case, you'll need to change the salt to get a different

address. Okay, so this is a review of create 2. Let's now look at how unis swap B3 factory contract uses create 2 to deploy the pull contract. Here's how the address of a unis swab B3 pull contract is calculated using create 2. We take the last 20 bytes of catch 256 of the following inputs. 0x FF deployer. Here the deployer will be the address of the factory contract. The salt will be the catch 256 of token zero token one and feed. And for the last input remember that we take the catch act 256 of the creation bite code and the constructor inputs here. The creation bite code will be that of the unisaw b3 pull contract and notice that there is no constructor inputs. This is how the

address of unisaw pull contract is calculated. As I mentioned earlier about salt, since this contract has no constructor input, we need to specify a unique salt so that we can deploy unisoft B3 pull contract at different addresses. And now you may have several questions. For example, why is the salt set to the catchup to 56 of token z token 1 and v? And furthermore, why is there no constructor inputs when we initialize this unis swap b3 pull contract? How do we initialize the unis swab b3 pull contracts without passing any constructor inputs? To understand how the address of unis b3 pull contract is calculated in that manner, we first need to understand the goals that we

need to achieve when unisaw pull contract is deployed. The first goal is that the pole address must be determined by the following inputs. Token zero, token one and fee. If you know token zero, token one and fee, then we can calculate the address of the pool contract. And it doesn't matter whether the pull contract is already deployed or not yet deployed. The second goal that must be achieved when the pull contract is deployed is the initialization parameters of the contract. Inside the pull contract, we'll need to initialize token zero, token one fee, the address of the factory contract and tick spacing. Tick spacing means that every time there's a swap and the price changes, then the tick will jump by this amount of tick spacing instead of increasing or decreasing by one. For

example, if the tick spacing is 10, then the tick will increase or decrease by multiples of 10. Remember what I said earlier that given that the address of the deployer and the contract to be deployed are the same, then the only two inputs that we can play around with to change the address of the pull contract is assault and the constructor inputs. But the first goal that says that the pole address is determined by these parameters tells us that token zero token one and v must be equal to either the salt or the constructor inputs. In other words, when we look at the inputs for the salt and the inputs for the constructor inputs, they must be equal to token zero, token one and fee. For example, you can take the catch 256 of token zero as salt and for the

constructor inputs, you'll need to put in token one and fee. Another example is you can take the ketak 256 of token zero token one and v as salt and have no constructor inputs. This first goal restricts that the inputs the salt and the constructor inputs must be equal to token zero token one and fe. With this in mind, let's take a look at the second goal. We have token zero, token one and fe that needs to be initialized. Furthermore, we have more inputs that needs to be initialized. Factory address and tick spacing. And from our first restriction, this tells us that the factory address and the thick spacing cannot be part of the constructor input.

If they were, then this would change how the create to address of the pull contract is computed, which in turn means that the pole address cannot be calculated just by these three inputs. So we have a problem here. We want to be able to calculate the pole address by three inputs and we need to initialize these parameters, but not all of these parameters can be passed as constructor inputs. So how does unis swap b3 achieve these two goals? The solution is to set the salt as ketchup 256 at token zero token one and fee and have no constructor inputs. This will achieve our first goal. To achieve the second goal, unis swap b3 factory contract temporarily stores the initialization inputs inside the factory contract. And

when the unis swap pull contract is deployed, it will read this data from the factory contract. Let's see how this is actually executed. To deploy a Uniswap B3 pool contract, the user will first call a function called create pool on the Uniswap B3 factory contract. Next, the factory contract will store the following initialization parameters. Factory token zero, token one, V and tick spacing as a state variable into the factory contract and then it will deploy the unisoft B3 pull contract using create 2. Here these initialization parameters are not passed inside the constructor of unisaw B3 pull contract. It will get these initialization parameters by reading the state variables that are stored inside unisaw B3 factory contract. And this is

how unisoft B3 pull contract is deployed using create 2. Finally let's also take a look at the call trace. First the user will call the function create pool with the inputs token zero token one and feed. The factory contract will call internal function called deploy passing in the address of the factory token zero token one fee and tick spacing. This input tick spacing will be a setting that is stored inside the unisoft B3 factory contract. And this internal function will first store the initialization parameters factory token0 token 1 v and text spacing. Next it will deploy the unisoft bull contract using create. Here the salt is set to the catch 256 of token zero, token one and feed. And also

notice that there are no constructor inputs. And this also means that the address of all unisaw B3 pull contracts can be determined by these three inputs. Inside the constructor of unisaw B3 pull contract, it will get the initialization parameters from message sender. Here message sender will be the factory contract. And again this initialization parameter was stored over here. And once the unisoft BK pro contract is deployed, we return back to the internal function deploy and it would delete the initialization parameters. This is the call trace for the function create pool.

There are two exercises for unis B3 factory contract. For the setup, it deploys two ERC20 contracts which will be used in exercise 2. In exercise one, I want you to get the address of the USDC pool with 0.1% fee. To get the address of this pool, you'll need to call the function get pool from the interface I unisaw B2 factory contract. Let's go over the solution for exercise one. Get the address of the pool for the USDC with 0.1% fee. So to get the address of the pool, we'll need to call factory get pool. And checking back on the interface for I unis swap B3 factory. To call the function get pool,

we'll need to pass in three parameters. address of token A, token B and V. Here it doesn't matter if you pass in D and USDC or USDC and D. In either case, you'll get the same pull address. So to the function get pull, we'll pass in the inputs D USDC and how do we pass in the fee for 0.1% fee? When the pool fee is calculated, the denominator is 10^ the 6 1 E6 and 0.1% will be 100 / E6. You can verify this using your calculator. So, moving on for the pool fee, we'll pass in 100. Before we execute exercise one on the main network, I'll first delete

exercise 2 for now. Inside my terminal, I'll set an environment variable named for URL. And then we'll execute the test forge test for URL set to the for URL from the environment variable. And the path to the test is test unisoft B3 exercises unisoft b3 factory.est.sole. Okay. And our test passed. The second exercise is to deploy a new unisoft B2 p contract using the tokens token A and token B which I deployed inside the setup. And the pool fee will be 0.1%. To deploy a pool inside Unis B3 factory inside the interface by Unis B3 factory you'll need to call the function called

create pool passing in the inputs token A token B and fe this function will return the address of the pool that was deployed. Call the function create pool on the factory contract and assign the address of the pool that was deployed to this variable. Let's go over the solution for exercise two. To deploy a pool, we'll need to call factory dot create pool. And the three inputs that we need to pass are token A, token B, and fee. For token A, we'll pass in address of token A, address of token B.

And for the fee, we'll need to pass in 0.1, which is 100. Okay, that completes this exercise. Let's try executing exercise two. Inside the terminal, I'll execute the same test command again. Forge test for URL with the for URL of environment variable match path. The path of the test is test unisoft B3 exercises unawar factory.est.sol. Okay. And our test passed again. When adding or removing liquidity from a unisoft B3 pool, you might have several questions. For example, you might be wondering how to calculate the amount of token X and the amount of token Y to add liquidity given a price range. Or if you're removing liquidity, you might wonder the amount

of token X and the amount of token Y that you will receive for removing liquidity. All of these questions can be answered by three equations. But to get there, we first need to derive an equation for liquidity given the amount of token X, amount of token Y, and the price ranges and the current price are known. So in this video we will derive the equations for how to find liquidity given the amount of token X amount of token Y the current price P and the two price ranges P lower and P upper. Recall that in one of the previous videos we derived the equation for the amount of token X and the amount of token Y between price ranges P lower and P upper. We will be using these two equations to derive the equation for liquidity.

Let's say that we have some price range PA and PB and imagine the case where the current price P is less than or equal to the lower price P of A. In this case, liquidity will all be in token X. And this is because for the current price P to swing from P of A to P of B, this much amount of token X must exit the pool. So in this case, what is the equation for liquidity? Well, to derive this equation, we'll be using these equations. I'll copy this equation and then paste it here. And we'll replace P lower and P upper with P A and PB. P lower will be PA and P upper will be PB.

From this equation, we can now derive equation for the liquidity. So to begin with, I'll copy this equation. And I'll first simplify the right side of the equation. We have a L here and a L here. So we can factor this out and put a one here. And also put a one here. And these will be in parenthesis. Next, I'm going to flip this equation around. So, I'll bring the x over here. Now, we can see that if you divide the left side of the equation by these terms, then we'll get an equation for L. And this is the equation for liquidity L given that we know the amount of token X and the price ranges PA and PB. Now, inside the code of unisoft B3, you'll see this equation in another form. What you'll see is this

equation on the right. The way to get to this equation starting from this equation is to do some algebra on the denominator. So this is how liquidity is calculated when the current price B is less than or equal to the lower price B of A. Next, we'll derive the equation for liquidity when the current price P is above the upper price P of B. Again, let's say that we have two price ranges. The lower price P of A and the upper price V of B. And imagine the case where the current price P is above this upper price P of B. In this case, the liquidity between P of A and P of B will all be in token Y. And this is because for the current price P to swing from P of B all the way down to P of A,

this much amount of token Y must exit the pool. Now to derive the equation for the liquidity L, again we'll apply this equation here. P upper will be PB and P lower will be PA. Now to get the equation for the liquidity L, I'll first paste this equation again. And the first thing that I'll do is factor out liquidity L. We'll have a parenthesis here. Remove this L. It comes out out of the parenthesis. And then we'll have another parenthesis. Next, I'm going to flip this equation so that the Y will come over here. And this L * these terms will come to the left. And now to get the equation for liquidity L, all I have

to do is divide these terms and we get that when the current price P is greater than or equal to the upper price P of B, then liquidity is equal to Y / P of B minus square root of P of A. The last case we will consider is what happens when the current price P is between the price ranges P of A and P of B. Then what is the equation for liquidity? Well, to answer this question, all you have to do is apply the equations that we have derived so far. Now, the liquidity between the price ranges P to P of B will all be in token X and the liquidity between P to P of A will all be in token Y. And these two liquidity are not necessarily equal.

So, we'll label them separately. We'll call L of X to be equal to the liquidity from current price P to the upper price P of B. And then for the liquidity from the current price P to P of A, we'll call this L of Y. Let's first derive the equation for the liquidity between the current price B P to P of B. Scrolling back up, all we have to do is apply this equation and we have one small thing that we need to change. In the last case, we consider the case for the lower price P of A. So in the equation, we'll have P of A over here. In this example, our lower price will be the current price P. So what we have to do is replace this P of A with the current

price P. And this is the equation for liquidity between the price ranges P to P of B. We'll do something similar to derive the equation for L of Y. So I'll scroll back up and then copy this equation. And note here that for this equation, we considered when the current price P is greater than or equal to the upper price P of B. And you can see this P of B over here. In our case, in this case, the upper price will be the current price P. So we'll replace this P of B with the current price B. And these two equations tell us the liquidity between the current price P to P of B and the liquidity from P of A to B. Now that we know how to calculate liquidity

given that we know the amount of token X, the amount of token Y, current price, and the price ranges P of A and P of B, we can now answer the question, what is the amount of token X and the amount of token Y that must be added when we're adding liquidity? And likewise, what is the amount of token X and the amount of token Y that will be removed when we remove liquidity? These two questions can be answered. Now, we'll first define two variables. L0 will be liquidity before and L1 will be liquidity after. For example, L0 can be liquidity before adding liquidity and L1 is liquidity after adding liquidity. Or it can be L0 is liquidity before removing liquidity and L1 is after removing liquidity. And we'll define delta L to be equal to L1

minus L0. We're just taking the difference of the liquidity. And in this video, we'll answer the question, how much delta x and how much delta y to add or remove if liquidity changes by delta l between the price ranges P of A and P of B. Let's start with the case where the current price P is less than or equal to the lower price P of A. And in this video, we'll consider the case what happens to liquidity when we add liquidity. The math for liquidity delta when we remove liquidity is exactly the same. So let's say that we have liquidity L0 between the price ranges P of A and P of B. And let's say that in this price range we add some delta X and the liquidity increases from L0 to L1.

In this case what is the equation for liquidity delta? Remember again liquidity delta we defined it as L1 minus L0. We derived in the previous video that liquidity is equal to x / 1 / the<unk> of p of a minus 1 / the roo<unk> of p of b. For l1, we can apply the same equation except the amount of token x will be different. In this case, the amount of token x will be the amount of token x that was before adding liquidity plus the amount that was added delta x.

And we're now ready to answer the question, what is delta? By definition, it is equal to l1us l. When we subtract L1 from L0 on the numerator, we're left with delta X and the denominator is the same. So we get this equation. This is the equation for delta L when the current price P is less than or equal to the lower price P of A. And what does this equation tell us? How is it useful to us? Well, let's say that you're adding liquidity to a price range that is above the current price P. In this case, the current price P will be less than or equal to the lower price that you set P. When we apply this equation, we can tell the change in liquidity and we can also tell the amount of token

next that we need if we were to change the liquidity by this much amount. So for example, let's say that we know the amount of token X to put in between the price ranges P of A and P of B and the current price P is less than or equal to P of A. Then using this equation, we can tell the change in liquidity. Another application is if you knew the change in liquidity, then we can figure out the amount of token X that we need to put in. Next, we'll derive the equation for delta L liquidity delta when the current price P is above or equal to the upper price P of B. To begin with, let's say that we started with liquidity L0. To this, we add some amount of delta Y and the liquidity increases from L0 to L1.

Okay, let's now calculate delta L. Let's start with L0. We apply the equation that we derived in the previous video and we do the same for L1. For L1, the amount of token Y has changed. Since we added liquidity, we added this much amount of token Y. So the amount of token Y that we put up here as a numerator is the previous amount of token Y plus the amount that we added just now delta Y. Now that we know L1 and L0, we can now calculate delta L. Again, by definition, this is equal to L1 minus L0. And notice that the denominator for L0 and L1 are the same.

The only difference is is the numerator. When we subtract the numerator of L1 from the numerator of L0, we are left with delta L. So the equation becomes delta L is equal to delta Y / the roo<unk> of P of B minus the square root of P of A. Again, the same question. What does this equation tell us and how is it useful? Well, it tells us the amount of token Y that we need and the change in liquidity. If we were to add liquidity below the current price D, for example, let's say that we have some amount of token Y and we want to add liquidity between the price ranges P B and P of A and the current price D is greater than or equal to the upper price P B. So we know the amount of token Y that we need to put in. We plug in all

the numbers and we get the change in liquidity. Another way to use this equation is if you wanted to change the liquidity by delta L, then this equation tells us that we need this much amount of token Y. For the last case, we'll consider when the current price P is between the lower price P of A and the upper price P of B. In this case, between the price ranges P of A and P of B, we have some amount of token X and some amount of token Y. Let's say that we added delta X amount of token X and delta Y amount of token Y and the liquidity increased to L1. In this case, what is the equation for delta L? To answer this question, we first need to follow a rule that says that liquidity between the price ranges P to P of B

must be equal to the liquidity between P to P of A. This is a special rule that only applies when the current price P is in between the lower price P of A and the upper price P of B. So, let me say it again. The liquidity from the current price P to P of B must be equal to the liquidity from P of A to P. With this in mind, let's calculate L0 and L1. L0 is equal to in the previous video we derived that L0 is equal to this expression. Now this liquidity is the liquidity from the current price P to P of B and this must be equal to the liquidity from P of A to P. The liquidity from P of A to P is given by this equation. So this is the equation

that L0 satisfies. And for L1, we'll have similar equations. Here's the liquidity between the price P to P of B. And note that since we added delta X on the numerator, we have the previous X plus delta X. And this must be equal to the liquidity from P of A to P. And again, note that on the numerator, we have delta Y because we added some amount of token Y. So these two equations must be satisfied for L1. Let's now calculate delta L. By definition, delta L is equal to L1US L0.

For L1US L0, if you look at this side of the equation, if you do L1 - L0, we see that the denominators are the same. And for the numerator, we'll have X + delta X - X. So evaluating this side of the equation we get that delta L is equal to delta X / 1 / the<unk> of current price P P minus 1 over the<unk> of P of B. And likewise we'll do the same for these two equations. L1 will be this and L0 will be this. When we subtract it on the numerator, we're left with delta Y. And the denominator is the same over here and over here. So we'll have the same

denominator after subtracting. And this is equal to delta y / the roo<unk> of p minus roo<unk> of p of a. Okay. But what do these equation tell us? And again, how do we use these equations? Well, it tells us that if we were to add liquidity by delta l, then this is the amount of token x that we need to put in. And this is the amount of token y that we need to put in. Another application is let's say that we know the amount of token x that we want to add liquidity between the current price p and the upper price p of b. Then we'll have a question. What is the amount of token Y that we'll need to put in between the price P and P of A? Using this equation, you'll be able to solve for delta Y and answer that question.

When a liquidity provider adds liquidity to a unis swap B3 pool, they'll specify a price range. The lower tick and the upper tick that defines this price range cannot be any arbitrary tick. It has to be a multiple of tick spacing. And this tick spacing is different for each pool. For example, here I have a tick space of 10 and the vertical dotted line represents the ticks that are multiple of this tick space. If you were to add liquidity to this pool for the lower tick and the upper tick that defines the price range, they have to be a multiple of the tick space. So for example, I can set the lower tick to minus 20 and the upper tick to minus 10. Both of these are multiples of the tick space 10. So they are valid price range to add

liquidity. However, in this pool, you won't be able to add liquidity for the price ranges tick equal to minus20 and tick equal to minus5. This is because minus15 is not a multiple of the tick space 10. As I mentioned earlier, different pools have different tick spacing. For example, the USDC die pool with 0.01% swap fee has a tick space of one. On the other hand, the die pool with 0.3% swap fee has a tick space of 60. The reason why different pools have different tick spacing is to pick between the concentration of liquidity and the consumption of gas. Lower tick space means liquidity can be concentrated higher at the cost of using

more gas during a swap. On the other hand, higher tick spacing means that liquidity can be concentrated less and also during a swap less gas will be consumed. For example, if we had a tick spacing of let's say four, since the smallest price range that we can add liquidity to get smaller for putting in the same amount of tokens, we will have higher concentration of liquidity. Now during the swap inside the code of unis b3 pull contract, it will execute a while loop and inside this while loop, it will execute a smaller swap between these tick spaces. So for example, we have a current price over here and as the swap is executing on the first iteration, it will execute a swap in between these two pink lines and then in

the next iteration it will swap in between these two pink lines. In the next iteration of the while loop, it will execute a swap in the next multiple of tick spacing. So in this case to swap from here to all the way to here we have to iterate through once twice and three times to move the tick from tick equals to zero to tick equals to minus 10. So this is how pools with lower tick can consume more gas during a swap. On the other hand, let's consider what happens when the tick spacing is a larger number. For example, let's set the tick spacing equal to 10 and we'll start with the current tick equal to zero again and we'll swing it over to minus 10. So again, let's say that there was a swap

and this would decrease the tick from tick equal to zero to tick equal to minus 10. As the tick moves over to minus 10, we now enter the first iteration of the while loop inside the code of unis pull contract. And then as the tick decreases further, we hit tick equals to minus 10. And at this point we only iterate it once. In the case of tick spacing equal to four, we iterate it three times. In the case tick spacing equals to 10, we only iterate it once. The tick jump the multiple tick spacing only once in this case. So this is what it means that pools with higher tick spacing may consume less gas during a swap. Now pools with higher tick spacing also comes with a cost of lower

concentration of liquidity. And this is because the minimum price range that we can add liquidity is larger compared to a pool with lower tick spacing. When we look at a pool with tick spacing let's say equal to five then the minimum price range that we can add liquidity is this much. However, for tick spacing equal to 10 the minimum price range that we can add liquidity is larger. Larger price range means that we can concentrate our liquidity less. So in summary, when you add liquidity, the price range that you specify has to be a multiple of the tick spacing, which is different for each pool. Pools with lower tick space can concentrate liquidity higher, but during a swap it may use up more gas. Pools

with higher tick spacing can concentrate liquidity less, but during a swap it may use up less gas. Pools with low tick spacing are suitable for token pairs where the price has low volatility. For example, USDC die pair pools of high tech spacing are suitable for token pairs where the price has high volatility. For example, die ref pair. To add liquidity to a unis swap b3 pool, the function meant inside a contract called unisoft B3 pool which is inside a repo B3 core must be called. Now this function is a low-level function and if you're adding liquidity as a user, you be interacting with another smart contract. The standard contract

interactive is called nonfgeable position manager which is inside the repo B3 periphery. This nonf fungeible position manager will call into the unis swell bull contract. In this video, I'll briefly explain what's going on inside the function mint. The function mint is both used to add liquidity for the first time and also to increase liquidity. The parameters to pass are recipient. This will become the owner of the position and the parameters that specify the position tick lower, tick upper and amount. This will be the amount of liquidity to add to the position that is defined by tick lower and tick upper.

And this arbitrary data will be passed as a call back to message sender. You can see this data over here. We'll come back to this later. So going back up, these are the parameters and for the output, it will return the amount of token zero and amount of token one that was needed to add this much amount of liquidity. Inside the function, it first calls an internal function called modify position. The parameter to this functions are the owner which will be the recipient that is specified by the input. the two ticks tick lower and tick upper and here we have a parameter called liquidity delta which is defined by the amount from the input. This liquidity delta tells the internal function modify position to modify this

position specified by these three inputs by this much amount of liquidity. Notice that this amount can both be a positive number and a negative number. Okay, let's take a look at this internal function called modify position. The function modify position will take in a strruct parameter called modify position params that we saw earlier. And then for the output, it's going to return the position that was either created or updated and the amount of tokens that must come into the pool or the amount of tokens that must leave the pool depending on liquidity delta. If liquidity delta is positive, this means that we're trying to increase the liquidity of this pool. So amount zero and amount one will be positive. If we're trying to decrease the liquidity from this pool, then amount zero and

amount one will represent the amount of tokens that is leaving the pool. So these numbers will be negative. Okay. So first it checks ticks make sure that tick lower and tick upper are valid ticks and then it will get slot zero to save some gas and then it will call internal function called update position. Let's take a look at this function update position. Scrolling down here's the internal function called update position. The first four parameters are obvious. Owner will be the recipient, the two ticks that define the position and liquidity delta to update the position by and then the tick will be the current tick. This current tick will be stored in slot zero. And this function is going to return the position. First, it gets the position

which is defined by the owner tick lower and tick upper. Next, it will load two state variables into a local variable. These state variables are fee growth global 0x1 to8 and fee growth global 1x1 to8. These two state variables are used to track fees for liquidity providers. Scrolling down, we have a if condition if liquidity delta is not equal to zero. First, it will store some price information for the time weighted average pricing price oracle and then it will call the function update on tick. Let's take a look at what this function does. This function is inside the library called tick. And scrolling down the function that I'm looking for is called update. When this function update

is called first, it's going to load the data that is stored inside the storage mapping. From the tick, it will load a strct called tick.info which stores these information. And then it will compute the next liquidity in this tick by taking the liquidity before and then adding liquidity delta. If the liquidity that is stored at this tick was equal to zero then here it will initialize a tick. If the current tick is less than the tick to store the info for then it will initialize some parameters and then set the flag called initialize to true and then it will update the liquidity. And the last part of this function is to update liquidity net. Remember that

liquidity net is a number that is used to update the current liquidity when there is a swap. And this is done either by storing a positive or a negative number at the tick. When the current tick crosses over this tick, it will add this liquidity net to the current liquidity to get the new liquidity. Okay, so this is the function tick.update. Let's go back to the function B3 pool. So it will call the function update on the lower tick and also on the upper tick. And then next if the ticks for lower tick and the upper tick if either of them were flipped here flipped means either liquidity before was equal to zero and liquidity after is greater than zero or liquidity before was greater than zero and liquidity

after is equal to zero. In this case it will store the tick in a mapping called tick bit map. This is a data structure that is used during a swap to efficiently find the next tick. Next it will calculate the fee growth inside tick lower and tick upper. And this fee growth inside is used to calculate the fee that is owed to this position. So let's take a look at the function position.update which for the inputs it will pass in liquidity delta and fee growth inside 0x128 and 1x128. The function position.update will be inside the library called position and the function called update. The first part of the code will update the liquidity by

liquidity delta. Next, it will calculate the amount of tokens owed to this position. And here, this tokens owed zero and tokens owed one is the amount of fee that was collected for this position. The way it calculates this is to take the latest fee growth inside and then minus it by the previous fee growth inside, multiply this by liquidity and then divide it by 2 to the 1 128. And this is how fee is calculated. This is done both for token zero and for token one. We'll come back to how this actually calculates the fee for this position in another video. So moving on, it will update the liquidity and it will also update fee growth inside. And lastly, if there was any fees that were

collected, then it will update this by incrementing it by the amount of fee that was collected. Okay, so going back to unisoft B2 pull contract. The last part of this code is to remove the ticks if liquidity was removed and the liquidity at this tick is equal to zero. So that's the function update position. This function was called by the function modify position. So we'll go back to here. The function modify position calls the function update position. So moving on the next part of the code inside this if condition if params that liquidity delta is not equal to zero calculates the amount of token zero and the amount of token one that is needed to change the liquidity by liquidity delta. If the

current tick is less than tick lower then liquidity is all in token zero. So the amount that we'll need to calculate will just be in token zero. So here we calculate amount of token zero that is needed. Otherwise if the current tick is less than tick upper. So in this case we have the current tick in between the two ticks tick lower and tick upper. And in this case we'll need to calculate both token zero and token one to change liquidity by liquidity delta. And you can see this over here inside here. Since we're modifying the current liquidity we'll also need to update the current liquidity which is done over here. Otherwise the current tick is above tick upper. In this case liquidity

will all be in token one. So here we calculate the amount of token one that is needed to change liquidity by liquidity delta. And that completes the function modify position. Basically what it does is updates the position that is defined by the owner and the two ticks tick lower and tick upper and then it calculates the amount of token zero and amount of token one that must either come into the pool or leave the pool. So that completes the function modify position, let's now go back to the function mint. Inside the function mint, after calling the function modify position, it's going to use two of the outputs that was returned, amount zero and amount one. Notice that here they are both in int 256 to represent either tokens coming in for positive and

negative for tokens going out. Since we're adding liquidity here, we assume that this amount zero int and amount 1 in are both positive number. So here we'll cast it into units 256 and with these amount amount zero and amount one it will call a call back called unisoft b3 mint call back on message sender and inside here message sender must send an amount zero of token zero and amount one of token one into this contract and after this callback is executed this code checks that the balance increased by amount zero and amount one and that completes the code walk through for the function mint To add liquidity, the function mint is called inside the contract you saw with

the pupil. To remove liquidity, you'll need to call the function burn. This function burn is a low-level function. And if you are a regular user, then you won't be calling this function directly. Instead, you will probably call the contract nonfungeible position manager, which will call into the function burn. For the inputs, it takes in three inputs. the two ticks that define a position tick lower and tick upper and the amount of liquidity to remove. For the output, it's going to return the amount of liquidity that was removed, amount zero and amount one. Now, this function removes liquidity, but surprisingly, it does not transfer the tokens amount zero and amount one. To actually transfer the tokens, we'll need to call another function called collect,

which we'll do a code walk through later. So, the function burn is used to remove liquidity. Inside the function, it first calls a function called modify position. And for the parameters for the owner, it's going to pass in message sender and the two ticks, tick lower and tick upper. For liquidity delta, notice that it's passing in a negative amount. Since we're removing liquidity, liquidity delta will be negative. We already discussed how the function modify position works when we looked at the code for the function m. So, we'll omit the explanation here. What's important to notice here is that the position here is defined by message sender and the two ticks. So this means that only the owner will be able to

remove liquidity from their position. Since the only position that they can remove liquidity from is the position that they own. This function modify position returns three outputs. the position and the amount of token zero and amount of token one that must exit this pool when the liquidity in this position is updated by liquidity delta. This amount zero and amount one will be negative. So here we cast it into a positive number and if either of these is positive then we update the position by incrementing tokens old zero and tokens owed one. And again, notice that just by calling the function burn, it does not transfer any tokens out. To actually transfer the tokens, we'll need

to call a function called collect. The function collect is used both to collect fees on swaps and to actually transfer out the tokens from removing liquidity. To remove liquidity, we first need to call the function burn to decrease the liquidity for a position. And to actually transfer the tokens out, you'll need to call the function collect. For the inputs, it's going to take in the recipient. This will be the address to send the tokens to the tick lower and tick upper that defines a position and the amount of tokens to transfer out. If these amounts are greater than the actual amount that is owed to this position, then the maximum amount that will be transferred out is the amount owed to this position. Inside the function, it's going to first get the position that is defined by message

sender and the two ticks, tick lower and tick upper. and then it calculates the actual amount of tokens that can be transferred out. If this amount requested is less than the amount of tokens that are owed, then the amount that will be transferred out is the amount that is requested. In other words, the amount of tokens that will go out is the minimum between the tokens that are owed and the amount requested. If there is any amount of tokens that can be transferred out, then the position will be updated. Tokens owed will be decreased and the amount of tokens will be transferred out. You can see this over here for token zero and for token one. And that ends the code walkthrough for the function collect.

The most common way to manage liquidity for a unisaw B3 pole is to interact with a smart contract called nonfgeible position manager. There are four functions that you can call on this contract. The functions are mint, increase liquidity, decrease liquidity, and collect. In this video, I'll show you an overview of how a contract's non-f fungeible position manager and the contract unisoft B3 pool interacts when a user calls the function mint. Let's say that a user wants to create a new position in a unisoft B3 pool. To do this using the contract nonfgeible position manager, the user will call the function mint specifying the price range that they want to add liquidity to and the amount of tokens that they want to add. Next, the non-f fungeible position manager will call the function mint on

unis swap b3 pool. The pool contract will calculate the amount of tokens that the user must send and then call call back called unisoft b3 mint callback. And inside the callback tokens token zero and token one are transferred from the user over to the contract unisoft b3. Let's look at the code for the function inside the contract non-f fungeible position manager. This contract is inside the repo called B3 periphery. The contract nonf fungeible position manager is a ERC721. So when we call the function mint, it will mint a NFT. And this NFT represents our position. The function mint takes in a single input, a stroke called mint params. This mint params is

specified inside the interface by nonfgeible position manager. Here's the data that is passed as inputs. Token zero, token one and fee which determine the pool. The price changes to add liquidity. Tick lower and tick upper. The two amount of tokens we wish to add. The minimum amount of tokens that must be added. The recipient of the NFT and deadline. The last time stamp the function to call mint is valid. Okay. So these are the parameters that are passed to the function mint. Going back to the function first, it checks the deadline and for the output it's going to return token ID. This will be the ID of the NFT that was minted. Liquidity will be the actual amount of liquidity that was added and amount zero and amount one.

The amount of tokens that was transferred over from message sender to increase liquidity by this much amount. Okay, let's take a look at the function body. First, it calls a function called add liquidity. This function inherits from another contract and this contract is under base and the name of the contract is called liquidity management. Inside here there's a function called add liquidity. First it creates a strct called pull key. This pull key is not that important but it might be useful to remember that this pool key stores three data token zero token one and feed. And remember that from these parameters.

From these three parameters we can identify the pool from this pool key. It will calculate the address of the pool and then get the current square root price x96 from the pool and then calculates the liquidity. The amount of liquidity that will increase if we were to add these much amount of tokens into the price ranges square root ratio ax96 and square root ratio bx96. These two square root ratio are calculated above by taking the tick lower and tick upper. Okay. Once the liquidity is calculated, next it calls the function mint on the contract unis swap b3 pull. Now the pull contract will call back into a call back called unis swap b3 mint call back and

it specifies the amount of tokens that are needed to increase the liquidity by this much amount. Okay, so going back to the callback, it would transfer the tokens from the payer over to message sender. Since the unis swap b3 pull contract call this function unis swap b2 make callback here message sender will be the unisoft b2 pull contract for token zero it would transfer from the payer over to the pull contract for the amount amount z which is specified over here and the next line does something similar except for token one transfer token one from the payer over to the pull contract for the amount amount one owed once the call back is done executing the function Add liquidity is

also done executing and we go back to the function mint. So we call the function add liquidity and after adding liquidity at this point we transferred over the token from message sender over to the pull contract. Next it will call internal function called mint. This function will mint the NFT and the owner of this NFT will be the recipient which is set by the input parameters. Next I will calculate the position key which is specified by the address of this contract and the two ticks tick lower and tick upper. This position key is used to get the position data that is stored in the contract saw B3 pool and from this gets the latest fee growth inside zero last X1 128 and 1x18. These

are data that is used to calculate the amount of fees that this position can collect. Next, it caches the pull key and what it does is it stores this data over here as a state variable and then assigns a pool ID to this data. This data stores the address of token zero, token one and fee. Next, it stores the data called positions for the token ID setting the pool ID, the two takes, the amount of liquidity that was added and the latest fee growth inside zero last x128 and 1x128. And that ends the execution for the function mint. Once a position is created by calling the function mint on the non-f fungeible position manager, let's say that this

user decides to increase liquidity to this position. The function that he'll have to call is called increase liquidity on the contract nonfgeible position manager. So to increase liquidity to an existing position which is managed by this nonfgeible position manager contract, the user will first call the function increase liquidity. The non-f fungeible position manager will call the function mint on unis swap b3 pool. Uniswap b3 pool will calculate the amount of tokens that are needed and then call call back called unisoft b3 mint call back. Inside this callback, token zero and token one that I needed to increase liquidity is transferred over from the user to the unisaw3 pull contract. The function increase liquidity inside the contract nonfgeible

position manager is used to increase the liquidity for a position. This position must be a position that was created by calling the function mint on the nonf fungeible position manager. For the input, the input is defined inside the interface I nonf fungeible position manager. And here's the inputs that must be passed. Token ID will be the ID of the NFD that was minted. The next two inputs are the amount of tokens that the user wish to add. And the two inputs after that are the minimum amount of tokens that must be added and the deadline. If the time stamp when the function increase liquidity is executed is more than this deadline then the function call will revert. Let's go back to the function increase liquidity inside the contract nonf fungeible

position manager. When the function increase liquidity is executed it will first check that dine has not expired. And for the outputs it's going to return the amount of liquidity that was added and the amount of tokens that was transferred into the pool contract. Inside the function, it first gets the position which is identified by the token ID. This is the NFD token ID. Next, it gets the pool key and remember that this pull key stores three data address of token zero, token one and fee and it calls the function add liquidity. Add liquidity will call the function mint on unisoft B2 pull contract and then it will transfer the tokens from message sender over to the pull contract. In return, it returns the amount of liquidity that was added and

the amount of token zero and token one that was transferred over from the caller to the pull contract. Next, it calculates the position key which is computed by taking the address of this contract and the two ticks and then it gets the position that is managed by this nonfgeible position manager by calling the function pool. And this is done to fetch the latest fee growth inside zero last x18 and 1 x1 to8. Again, these two variables are used to calculate the amount of fees that was collected by this position. To calculate the fees, we take the latest fee growth inside zero last x1 to8 and then minus it from the previous one which is stored inside position fee growth inside zero

last x18. We take this difference multiply by the previous liquidity and then divided by 2 to the 1 to8. And this will calculate the amount of fee that was collected by this position. We'll discuss how the math for this works in a later video. Okay, moving on. It does the same for token one. Calculate the amount of fees that was collected by this position. Next, it updates the fee growth inside zero last x18 and fee growth inside one last x128 to the latest values and then increment the liquidity. That completes the code walk through for the function increase liquidity. Once a user has a position which is created by the nonf fungeible position manager. Let's say that this user decides to decrease liquidity. Then this user will call the function

decrease liquidity. So first the user will call the function decrease liquidity on nonfgeible position manager. Next the non-f fungeible position manager will call the function burn on unis swap B3 pool. Now if you remember from the code walk through for the function burn inside unisoft B3 when the function burn is called it decreases the liquidity but it doesn't actually transfer the tokens. And this is the same over here. When the user calls the function decrease liquidity, it calls the function burn on RBT pool contract, but no token is transferred over to the user. To actually transfer the tokens, the user will have to call another function called collect. The function decrease liquidity will decrease the liquidity for a position, but it doesn't actually transfer the tokens. For the

input, it's going to take in a single strct called decrease liquidity params which is defined inside the interface I nonf fungeible position manager. Inside the strere here are the parameters that we'll need to pass. Token ID will be the ID of the NFD that was minted which represents a position. Liquidity will be the amount of liquidity to decrease by and amount zero min and amount one minimum amount of tokens that will be deducted when we decrease the liquidity by this much amount. and dead bind is the last time stamp that the call to this function is valid. Let's go back to the function decrease liquidity inside the contract nonvulnerable position manager. There are two modifiers for this function. Check deadline which will make sure that the deadline is not

expired and it also has a modifier called is authorized for token which checks the authorization of message. for token ID and then it's going to return two outputs amount zero and amount one which is the amount of tokens that were deducted for decreasing liquidity. First it checks that liquidity from the input is greater than zero and then gets the position identified by the token ID. Next, it checks that the liquidity of this position is greater than or equal to the liquidity that was passed from the input. And then it gets the pool key, gets the unis swap B3 pool contract from the pool key and then calls the function burn on unisoft B3 pool.

Calling the function burn on unisoft B3 pool does not transfer any tokens. It just decreases the liquidity and then also tells us how much token we can deduct. Next we get the latest fee growth inside zero last x1 through8 and one last x1 through8 which is stored inside p.positions for the position key. The position key is computed by the address of this contract and the two ticks tick lower and tick upper. Next it updates the position that is stored in this contract. It adds the amount of tokens that were deducted for decreasing liquidity and then it also adds the amount of fee that was collected for this position. And it does the same for token one. The fees for the position is

calculated by taking the difference of the latest fee growth inside and the fee growth inside that was stored in the position. So after it calculates the amount of fee that can be claimed, it updates this fee growth inside zero last x128 and one last x128 to the latest V growth inside which was fetched over here. And finally it updates the liquidity for this position by decreasing this liquidity by the amount that was specified by the input. Okay. And that completes the code lock through for the function decrease liquidity. The function collect inside the contract nonfgeible position manager can be called in two situations. The first situation is to just collect the swap

fees for providing liquidity. The other situation is to remove liquidity. To remove liquidity, the user will first call the function decrease liquidity on the non-f fungeible position manager. And to actually transfer the tokens out, the user will next call the function collect. So in either case, to collect fee or to remove tokens after decreasing liquidity, the user will call the function collect on the non-f fungeible position manager. Next, the non-f fungeible position manager calls two functions on unis pool. First, it calls the function burn. When this function is called, it will calculate and update the amount of fees that can be collected by the contract nonf fungeible position manager. And then next it will call the function collect on unisoft B3 pro. This

will transfer the tokens from unisoft B3 pole contract over to the user. To collect soft keys or to remove tokens after decreasing liquidity, you'll need to call the function collect takes in a single input. a strct called collect params. This collect params is defined inside the interface I nonfudgeible position manager. For the inputs, it's going to take in token ID. This will be the ID of the NFD recipient. This will be the address that will be receiving the tokens. Then amount 0 max and amount one max. The maximum amount of tokens to transfer. First, this function checks that the input amount 0 max is greater than zero or amount one max is greater than zero. and then it sets the address for the recipient. If the recipient is

not set, then it sets the recipient to this contract. Otherwise, it uses the recipient that is specified by the input. Next, it gets the position that is stored inside this contract. Gets the pool key and then gets the unis swap v3 pull contract caches the variable tokens zero and tokens one which is stored inside position. tokens zero and tokens one. If this position has any liquidity then it will call the function burn on unisoft B3 pull contract and this is done to update the fe growth inside zero last x1 through8 and p growth inside one last x1 to8 that is stored inside the pull contract. So once it calls the function burn, these values will be the

latest value. Using this, it calculates the amount of fee that was collected for this position and then adds it to the variable tokens zero and tokens owed one. Since the fees that can be claimed are now up to date, the code will update fee growth inside zero last X128 and fee growth inside one last X128 to their latest values. Moving on, next it calculates the amount of tokens that can be transferred out. If the amount that was specified by the input is greater than the actual amount of tokens that are owed, then the amount of token to transfer is the amount of tokens that is owed. Otherwise, the amount that was specified by the input will be transferred over. In other words, the amount to be transferred is the minimum of the input amount zero max and the

amount of tokens that are owed. This is done for both token zero and for token one. And then to actually transfer the tokens, it will call a function collect on the contract saw V3 pool. After the tokens are transferred, it will update the position that is stored in this contract. The tokens that are owed are stored inside the variable tokens owed zero and tokens owed one. When the function collect was called, amount zero collect and amount one collect was transferred out. So the current amount of tokens that are old are the difference tokens old zero minus amount zero collected and tokens old one minus amount one collected. The new value is stored inside position tokens old zero and tokens old one. And that ends the code

walkthrough for the function collect. There are four exercises for managing liquidity with unis swap b3. The contract for the exercises are located from their foundry test unis swabb3 exercises and the name of the contract is called unis swabb3 to liquidity. tests let's take a look at the setup. Scrolling down in this exercise you'll be managing liquidity with the web die pool with a 0.2% soft fee. So web die and the nonf fungeible position manager are all initialized. Next there are some constants that may be helpful to complete the exercises. minimum tick maximum tick and the pool fee for the diagramraph pool with 0.3% sw which is equal to 3,000 and inside this pool the tick spacing is equal to 60 inside the

function setup this contract is given 300 die and three ref and this contract approves the non-f fungeible position manager to spend auto bre and die next contract has some helper functions that are used for the test mint to mint liquidity and the function to get the position based on the token ID the First exercise is to mint a new position by adding liquidity to the die pool with 0.3% swap fee. You are free to choose the price range and note that when you pick a price range both the lower tick and the upper tick of the price range must be divisible by the tick spacing of the pool. Again, this contract is given 3,000 die and three ref amount of tokens to create a new position. Recall that

when you mint a new position using the non-f fungeible position manager, the nonfgeible position manager mints a NFD. Set this recipient of the NFD to this contract. Write your code here to mint a new position using the nonfgeible position manager. So that's exercise one. Let's go over the solution for the first exercise. The first thing that we'll need to do is call the function mint on the contract nonfgeible position manager. So over here I have the interface for nonfungeible position manager. And here's the function mint that we need to call. So I'll copy this str because this is a strct that we'll need to pass in to call the function mint. And then back inside our exercise, I'll paste the str. So the contract that we need to

call is called nonfungeible position manager. This contract inside this exercise is initialized as manager. Then call the function mint. And then we'll need to pass in the str nonfungeible position manager dot mint params. And then we'll need to pass in these parameters. For token zero, we'll pass in die. And for token one, we'll pass in left. The pool fee for this die pool will be 0.3%. So inside here, we'll put 3,000. Tick lower and tick upper. This is the price range that we're going to put liquidity into. And for this exercise, it doesn't matter what we put in here as long as tick lower and tick upper are multiple of tick spacing of this pool. So scrolling back up, the

tick spacing for this pool will be 60. And for this exercise, I'll use max tick and min tick and then round it to a multiple of tick spacing. I'll say int to four tick lower is equal to min tick divided by tick spacing and then multiply by tick spacing. Tick spacing. When we divide min by tick spacing, then split division cuts off the remaining decimal parts. So we'll get a number that is a multiple of tick spacing. And then we multiply this number by the tick spacing. Again we do the same for tick upper. int 24 tick upper is equal to max tick / tick spacing times tick spacing and then pass it as a parameter here.

Take lower and take upper amount zero desired. Amount zero is die. And for this exercise we are given 3,000 die. So for here I'll just put 1,000 D 1,000 * 1 E18 and token one will be ref. We are given three refs. So here I'll put one ref which is 1. Then amount zero minimum the minimum amount of token zero that must be added as liquidity. For simplicity I'll put zero and then amount one min. Again for simplicity I'll put a zero. And the recipient of this NFD that represents this position. For this exercise, we'll have to set it to this contract. So this say address this and deadline will be block timestamp. Okay,

let's try executing exercise one. Inside my terminal, I'll set the fork URL as an environment variable. And to execute the test, I'll type forge test dash fork url forg url matchpath test unis swap v3 exercises unis swap b3 liquidity test. And furthermore inside this contract we have several exercises. I only want to execute this test called test mint. So I'll pass in an extra parameter called d- match test and then the name of the test test mint. Okay. And our test passed. The second exercise is to increase liquidity

for a position. The position is already minted by calling a helper function called mint and it assigns a variable called token ID. Given this token ID, what you'll need to do is increase liquidity for this token ID. Again, initially this contract is given 3,000 D and 3 UF. Some of these tokens were used to mint the position by calling the function mint. To get the amount of tokens that are left inside this contract, you can call balance of on ERC20. So using any amount of tokens that is less than or equal to the remaining amount of tokens inside this contract. I want you to increase the liquidity for this position. And to increase liquidity, you'll need to call the function increase liquidity on the nonf fungeible position manager. If you

need to take a look at how to call this function, you can do this by going to foundry source interfaces unis swap B3 and click on I nonfgeible position manager and then scroll down to find the function called increase liquidity. This function takes in a single str parameter and these are the parameters that you need to pass in. The next exercise is to increase liquidity to a position that already exists and this position is represented as an NFD which has the token ID given over here. To increase liquidity to existing position, we'll need to call the function increase liquidity on the nonf fungeible position manager. So here I'll say manager dot increase liquidity and then we'll need

to pass in a str. The str will be declared inside the interface I nonf fungeible position manager and here's a str increase liquidity friends I'll copy this and then I'll paste it inside here this str I nonvible position manager that increase liquidity then for the token ID I'll pass in the token ID that is given amount zero desired here we can say for example die dot balance of address this saying that whatever Whatever amount of dye that is inside this contract, try to put it in as liquidity. But for simplicity, I'll just put in a number. Let's say 500 D. 500 * 1. And amount one desired, I'll just try

to put in let's say one8. Amount zero minimum. Again, we'll keep it simple. Put a zero. And for amount one minimum, again, put a zero. Deadline block time stamp. Okay, that completes exercise two. Let's try executing this test. Note that the name of this test is called test increase liquidity. Inside the terminal, I'll execute the same test command as in the previous exercise and then change the last parameter for match test. We're going to execute the test called test increase liquidity. And then we also display the console log. So say dashb and our test passed. For increasing liquidity, we put in approximately

499. And for the same amount we put in 0.12 E. The next exercise is to decrease the liquidity for a position. The position is minted by calling a helper function called mint and it assigns a token ID. Given this token ID, the exercise here is to decrease liquidity. The amount of liquidity to decrease is up to you. The amount of liquidity in this current position is fetched by calling the function get position and it is stored in the strct position. This will be the maximum amount of liquidity that you'll be able to decrease. Any amount equal to or less than that is okay for this exercise. To decrease liquidity, you'll need to call the function decrease liquidity on nonfgeible position manager. And if you

need a refresher on how to call this function, you can navigate to the I nonf fungeible position manager interface and then take a look at the function decrease liquidity. These are the params that you'll need to pass. The third exercise is to decrease liquidity. As a setup, we are given a position where the token ID is initialized as a variable called token ID. One requirement for this exercise is that the amount of liquidity to decrease cannot exceed the position's liquidity. And this position's liquidity is stored inside the truck called position. To decrease liquidity, we'll need to call the function decrease liquidity on nonfgeible position manager. Manager dot decrease liquidity. And then we'll need to pass in a parameter. The parameter is

defined inside the I nonf fungeible position manager interface. And here's the strct that we'll need to fill out. I'll copy this and then paste it here. This will be I nonfgeible position manager decrease liquidity. For token ID, we'll pass in token ID. And for liquidity is stored inside a strct called position. And this position strct is defined up at the top over here. The way this data is fetched is by calling the function get positions and it gets all the information by calling positions on nonfungeible position manager. Once it fetches all of these data, it just

stores it into a str. And one of the data that is stored is the liquidity of the position. So for this exercise, let's try decreasing all of the liquidity. P 0 liquidity amount zero main minimum amount of token zero that must be decreased let's set it to zero for simplicity and for minimum amount of token one that must be decreased again let's set it to zero and that line will be block timestamp okay that completes exercise three let's try executing this note that the name of this test is called test decrease liquidity inside my terminal I'll execute the same command again and the test execute will be test decrease increase

liquidity. Okay. And our test passed. So when we decreased all the liquidity, we withdrew 999.999 and so on amount of D and approximately 0.258 E. The last exercise is to remove all liquidity from a position. Recall that to actually transfer the tokens out, you'll first need to call the function decrease liquidity and then call the function collect. Both of these functions are inside the nonfgeible position manager. And if you need to look at the parameters, you can look at them here. Here's the parameter for the function collect. In this exercise, a position is minted with the token ID assigned to a variable called token ID.

The liquidity for this position is stored inside a strct called position. To remove liquidity and transfer the tokens out, you'll need to call the function decrease liquidity on the non-f fungeible position manager and then call the function collect on the position manager. Again, the last exercise for liquidity is to remove all liquidity. To do this, we'll need to decrease the liquidity and then call a function collect to actually transfer the tokens. We wrote the code to decrease liquidity in the last exercise. So, let's go copy that and then paste it into here inside the test test decrease liquidity. I'll copy this part of the code which calls decrease liquidity on nonfungeible position manager and then I'll paste it here. We won't need the output.

No, just call decrease liquidity and the amount of liquidity to decrease will be all of the liquidity for this position identified by the token ID. Next, we'll need to call the function collect to actually transfer the tokens. So over here call manager.colct and let's see what strrus we need to pass in here to call this function. Again inside interface for I nonf fungeible position manager I'll scroll down and then copy the strct called collect pars back inside our exercise I'll paste this str and then prefix this strct with I nonpudgeable position manager token ID will be token ID recipient will be this contract so this will be address this for amount

zero max we will pass in the maximum of 1 to8 so I'll type height in 128 domax and the same for amount max type in128x. This will tell the nonfgeible position manager to transfer all of the tokens that are owed to this position. And this includes the amount of tokens that are collected from the swap fees and the amount of tokens that are owed for providing liquidity. And that completes exercise for let's try executing this exercise. Note that this exercise is called test collect. Inside my terminal, I'll execute the same command again. And for the last parameter match test, we only want to execute the function test collect. So we'll pass in test collect, then execute

the command. Okay. And our test passed. When liquidity is added in unis swap b3, the two ticks, the lower tick and the upper tick that define this liquidity position is stored in a mapping called tick bitmap. During a swap, the next tick where liquidity exists is found by calling a function called next initialize tick within one word. In this video and in the next video, I'll explain how this function works to find the next tick. So again, tick bit map is a mapping that stores the ticks that define a liquidity position. It's a mapping from int 16 to uint 256. To store a tick into this tick bit map, the tick is first broken down into two parts. The first 16 bits starting from the left and going right is stored as

int 16 and the next eight bits is stored as 8. For example, let's say that the tick is minus 200,697. Here's the binary representation. And since here we're dealing with int 24, this sequence of zeros and ones is 24 bits. In other words, there are 24 ones and zeros. The first 16 bits starting from the left and going right is converted into int 16. Inside the code, this is called word position. In this example, when we evaluate this 16 bits as int 16, this turns out to be minus 784. The last 8 bit is converted into 8. And inside the code of unis swab v3, this is called bit position. In this example, when we

evaluate this 8 bits as 8. This turns out to be seven. Let's look at an example of how this tick is stored into the tick bit map. We first break this tick into two parts. The first 16 bit is evaluated as int 16 and the last 8 bit is evaluated as unintent 8. In this example, the first 16 bits turns out to be minus 784. We use this number as a key to the tick bit map. And let's say that the un 256 value that we get back looks something like this. Instead of thinking about this un 256 as a single number, it's helpful to think about this as a sequence of zeros and ones having the length 256. And for this example, let's say at the seventh index, we have a zero here. Also notice that the bit

position, the last eight bits, is also equal to seven. What we're going to do next is change this zero at the seventh index to a one. To do this, we create a mask 256 bits of zeros except there's a one at the seventh index. Do an exclusive or with the current value of the tick bit map at the key minus 784. And this will turn the zero at the seventh index to a one leaving everything else unchanged. This is how our tick is stored into a tick bit map. And if we wanted to remove this tick from the tick bit map, let's say that there's a one over here. Now when we do a exclusive or with a one and a one here, we will get a zero. This is how a tick will be removed from a tick bitmap.

To get a tick from a tick bit map, we will get the 16 bits that represents the key for the tick bit map. and then append eight bits to this 16 bits. For example, let's say that we have a tick bit map and we're accessing the key minus 784. This will be the first 16 bits of the tick. The tick bit map will give us a un 256 value. And again, instead of thinking this 256 as a number, we think about it as a sequence of 256 bits. For this example, let's say that we wanted to convert this one at the seventh index into a tick. We rewrite this seven as 8 bits and then append this eight bits to the 16 bits that came before. 16 bits from the key of the tick bit map and 8 bits from unit

256. And this is how a tick is recovered from a tick bit map. Now that we understand how a tick is stored inside the mapping called tick bitmap. Next, let's take a look at the function called next initialize tick within one word that will find the next tick during a swa. We'll start with a review of how a tick is broken down into two parts. Let's say that we have an int 24 tick equal to -200,697. Here's the same number in binary. The first 16 bit is called a word position inside a code of unis swap b3. And this 16 bits is converted into int 16. In this example, when we evaluate this 16 bits as int 16, this turns out to be minus 784. The remaining eight bits is called bit position and it

is evaluated as unit 8. In this example, this turns out to be equal to 7. To find the next tick less than or equal to the current tick, we'll need to search right on the tick bit map. The key for the tick bit map is int 16. For this example, let's say that we access the key minus 784. Again, this key is referred to as the word position inside the code of unisol B3. From this key, we get a value of 256. For this example, I'll be using index 7. And we'll say that it is somewhere around here. And we also say that at index 7, the value that is stored is zero. We're looking for the next tick to be less than or equal to the current tick. Let's say that the current tick is at index 7. If you search for one to the left of index 7,

then we're searching for a tick that is greater than or equal to the current tick. So, what we need to do here is search for a one to the right of index 7. To look for a one that is to the right of index 7, we first create a mask. This mask will have a one at index 7 and everything to the right of it is also equal to one. From this UN 256 value that is stored inside a tick bitmap. We want to get all ones to the right of index 7. And to do this, we'll apply this mask. We'll use a bitwise n with this value. This will give us a UN 256 value where to the left of index 7 all of the numbers are equal to zero.

This is because when we do a and with 0 and zero it will be equal to zero. When we do a bitwise and with 0 and one it is also equal to zero. At index 7 and to the right of index 7 everything is a one. So when we do a bitwise and with one and zero we get a zero. If we do a bitwise and with one and one we get a one. In other words, this operation of creating a mask and then doing a bit wise end will give us all ones to the right of index 7. From this value, what we want to find is the leftmost one. And to do this, what we can do is find the most significant bit of this mask value.

In this example, let's say that everything is a zero over here and our first one is over here. When we find the most significant bit from this mask value, the index in this example will be equal to one. This is the index where the first one occurs starting from the left and then searching right. Okay. So now that we know the next bit position, the next step is to calculate the next tick. To find the next tick, we start off with the current tick and to this we minus the bit position. This will clear out the last eight bits, turn them into all zeros. And then next we add the next bit position. So as an example, let's say that this is our current tick. From this we minus the bit position. So all

of these one will turn into zeros. And then we add the next bit position. So remember that the next bit position is the index of the most significant bit of the masked value. In this example, it is equal to one. In binary, this is equal to 0 0 0 0 0 0 0 0 and then one and this binary turns out to be. We start out with the current tick equal to -2,697. In this example, the bit position is equal to 7. So we minus this 7 and then the next bit position is equal to 1. So we add + one and we get that the next tick is equal to - 200,73. The way to find the next tick that is greater than the current tick is similar to the last example. Instead of

searching right on the tick bitmap, in this case, we'll have to search left on the tick bitmap. Again, we'll start with the tick bitmap keys, which is int 16. And we'll say that the key that we're accessing is minus 784. This will have a UN 256 value. And again, for this example, let's say at the seventh index, we have a zero. From this UN 256 value, we need to look for a one either to the left of index 7 or to the right of index 7. But which direction should we search for a one? So let's think about this. If you were to search for a one to the right of index 7, then we are looking for a tick that is less than or equal to the current tick. So to find the next tick that is greater than the current tick, we'll need to look for a one to

the left of index 7. And to do this, we'll first create a mask. This mask will have a one at index 7. And to the left of index 7, everything will be one. To the right of index 7, everything will be zero. We apply a bit wise and with this mask and the value that is stored in the tick bitm map. The resulting value will have all zeros to the right of index 7. And this is because to the right of index 7 everything is zero. When we do a bitwise and with zeros we get a zero back. At index 7 and to the left of index 7 everything is a one. So when we do a bit wise and with a one with either a zero or one we get the value back. If it is a one and a one

then we get a one. If it is a one and zero, we get a zero. What we achieved here is that we got all ones at and to the left of index 7. Once we found all ones at index 7 and to the left of index 7, this gives us the ticks that are greater than or equal to the current tick. From all of these ticks that are greater than or equal to the current tick, we need to find the smallest one that is greater than the current tick. And the way we'll do this is by finding the rightmost one. Everything to the right of index 7 is all equal to zero. So if there's any ones in this value, it will be at index 7 or to the left of index 7. So we'll search for the rightmost one to the left of index 7. In

other words, what we're doing here is finding the index of the least significant bit. In this example, let's say that everything over here is a zero and the least significant bit is over here. The first zero is index 255. The next one is 254. So this one will be 253. So in this example, the least significant bit will be equal to index 253. Now that we found the next bit position, let's now calculate the next tick. To find the next tick, we start out with the current tick minus the bit position of the current tick and then add the next bit position. To make sure that the next tick is greater than the current tick, we add a one. Let's see what's going on here using binary. Here

we have our example tick. From this we minus the current bit position and this will turn all of these ones into zeros. Next we add the next bit position. The next bit position is equal to 253. When we rewrite this as 8 bits this turns out to be 1 1 1 1 01. And then lastly we add this + one. We started out with the current tick equal to - 200,697 minus the current bit position which is equal to 7. add the next bit position which is equal to 253 and then plus one to make sure that the next tick is greater than the current tick and this is equal to minus 200,450 starting from this video I'll

explain how fee for liquidity providers are calculated in unisoft B3 to begin with let's start with a simple example let's say that the liquidity in a unisoft B3 pool looks something like this and from this let's also say that Alice has S liquidity between these price ranges the active liquidity We'll label it as L0 and Bob swaps DY amount of token Y for DX amount of token X. This will move the current tech over to the right. And let's say that the active liquidity changed from L0 to L1. Fe is collected on token in. In this case, this is token Y. We'll label F0 as the amount of fee that was collected on liquidity L0 and F1 is the fee that was collected on liquidity L1. From this

simple example, let's calculate the fees that Alice can collect for providing liquidity. We'll label the total fees earned by Alice as F. And this is equal to well fee F0 was collected on liquidity L0. Alice will earn a percentage of this F0 and how much percent can she collect? To answer this question, imagine a simple case. Let's say that Alice provided all of L0. then the percentage of fee that she can earn from this liquidity will be 100% or f0. However, in this case she provided S amount of liquidity out of L0. So the percentage will be the total amount of liquidity will be L0 and the amount that she provided is S and S divided by L0

will give the percentage fee of F0 that Alice can collect. Now this is only one fee that she collected for liquidity L0. But there's also another fee F1. So we'll need to add this. F1 is the total amount of fee that was collected in liquidity L1. The total amount of liquidity in L1 is of course L1. From this the amount of liquidity that she provided is S and S divided by L1 will be a percentage. The percentage of F1 that Alice can collect. So in this example, Alice provided S amount of liquidity in a liquidity pool that looks like this. And in a single swap, the active liquidity swap from L0 to L1 collecting fees F0 and F1. In this case, the amount of fee that Alice collected

in this swap is given by this equation. Let's now consider a case where Alice has s amount of liquidity over some time and during that time there are multiple swaps and also the liquidity might change over time. However, the amount of liquidity that Alice provided S will remain constant. We assume that Alice's liquidity S is a constant. She provides some liquidity S over some time and this S remains a constant. She does not further add or remove liquidity. We'll label F of I to be the fee on token Y collected at liquidity LI and we'll say that this I ranges from zero to some number N. Again, we'll say that F is the total fees of token Y earned by Alice.

Now the equation is exactly the same for token X. So for these examples that I'll show you, I'll use token Y. Let's say that the first fee that was collected is F0. Then from the previous equation, then we know that the amount of fee that Alice can collect is the percentage S / the liquidity L0. And the same goes for the next fee that was collected. Let's call this F1. Alice can collect the percentage S / L1. And we repeat this pattern until some number n. We can write this equation in a concise way by saying sum from i= 0 to n s * f of i / l. In this equation, s is a constant. So we can pull this out. This is an important equation to remember since

unisoft b3 uses a state variable called v growth which is based off of this equation. Let's see an example of this equation. Let's say that at time t1 the liquidity pool looks like this. And again Alice has provided s amount of liquidity. Let's say that there was a swap of token Y for token X. The active liquidity changed from L0 over to the right L1 and the swap collected F0 amount of token Y from liquidity L0 and F1 amount of token Y from liquidity L1. Let's say that some time has passed since T=0. Let's call this T = 1. And notice that the shape of the liquidity has also changed. However, the amount of liquidity that Alice has provided remains the same. Let's say that there

was a swap from token X to token Y. The active liquidity started at L2 and it swung over to L5. Remember that in unis swap B3 fees are collected on token N. So when there was a swap for token X to token Y, there's no fee collected on token Y. So F_sub_2, F3, F4, F5 are all equal to zero. Once again, let's say that some time has passed. Let's call this T equals 2. And again, the shape of liquidity has changed. Let's say that there was a swap from token Y to token X. The active liquidity changed from L6 to L8. Along the way, it collected fee F6, F7, and F8. With this in mind, let's now calculate the amount of fee that Alice collected. Again, we'll label this

as F. The percentage of fee that she collected from F0 will be S / L0. The percentage of fee that she collected on F1 is S / L1. We can also say that the percentage fee that Alice collected for f_sub_2 is s / l2. But here we know that f_sub_2, f_sub_3, f_sub_4, and f_sub_5 are all equal to zero. We continue this until time t = 2. The last fee that was collected was f8. The percentage of f8 that can receive is s / liquidity l8. Previously, we looked at how to calculate fee for a liquidity position.

And I also mentioned that this part of the equation is called fee growth and it is a state variable inside the code of unisab that tracks fee for each position. In this video, I'll dig a little bit deeper and explain more about fee growth. We'll begin by explicitly defining what fee growth is. So imagine the case that swap collects fee of fi of token y and liquidity l by for i ranging from zero to some number n. We'll define fee growth fo to be equal to add up all the liquidity that was collected at a liquidity and then divide by the liquidity. For example, let's say that a fee of f0 was collected and at that time the liquidity was l. Then we would do f0 / l0. We add up all of this from i= to0

to i = to n. We can also write this in a concise way. Starting from i equals to zero go all the way up to n and for each i add the terms f of i / l i. Recall from the previous video that when we multiply this number by the liquidity of a position then we can calculate the fee that was collected by that liquidity position. Okay. So this is fee growth. Next let me give you an example of how we can visualize fee growth. I use token y for this example. The way I think about fee growth is that on the horizontal axis I think about the ticks and I map the fee growth on the vertical axis. Let's say that there was a swap of token Y to token X and a collected fee on token Y. And this is because token Y

is token N and in unis swap 3 fee is collected on token N. So when there's a swap of token Y to token X, two things will happen on this graph. Fe growth will increase and the current T will move right. the current tech will move right because there's a swap. More token Y is coming in and more token X is going out and the fee growth will increase because we're collecting fee on token Y. We can visualize this as a diagonal line that increases as the tick moves from left to right. The tick moves from left to right because there's a swap and the fee growth increases because here we're collecting fee on token Y. We do this simultaneously and we get a diagonal line. Okay, what happens when there's a swap from token X to token Y? Here we're

just mapping out the fee growth of token Y. When there's a swap from token X to token Y, again, fee is collected on token in. In this case, token in is token X. So, there's no fee collected on token Y since it is token out. How do we map this on the graph on the left? Well, since there's no fee that is collected, the fee growth will remain the same. However, since there is a swap from token X to token Y, the current tick will move left. On the graph, it will look like a straight line that moves from right to left. It moves from right to left because there is a swap that moved the tick from right to left. And this line is a flat line since there's no fee growth. This pattern repeats every time there's a swap. The tip of this zigzag will

represent the current fee growth and the current tick. And this is how I think about V growth. Now for this example, I used fee growth on token Y. For token X, it is similar but a little bit different. The difference is when there's a swap of token X to token Y, then the fee growth on token X will increase. On the graph on the left, it will look something like this. The tick will move from right to left. And since the fee growth increases on token X, we'll have a diagonal line that increases as it moves towards left. And similar to what we said about fee growth from token Y, when there's a swap from token X to token Y, no fee is collected on token Y. In the case for fee grow from token X, something similar will happen. If there's a swap from token Y

to token X, since token Y is the token that is coming in, fee is collected on token Y and no fee is collected on token X. So there will be no fee growth. However, the tick will move from left to right. What it will look like on the graph is this flat orange line. As the tick moves from left to right, there's no increase on the fee growth of token X. So, it will be a flat line. In the previous video, I provided you with a simple example of how multiplying liquidity by the fee growth will calculate the amount of fee that this liquidity position can collect. However, things are not so simple when we need to also consider that the fee growth will go out of the price ranges. For example, here let's say that there's a liquidity position between the ticks minus 3 and +

3. This position is highlighted in white lines and as you can see sometimes the fee growth will go out of bounds and other times fee growth are within this liquidity position. So in this case how do we calculate the fee that is collected by this liquidity position. The basic idea to calculate the fee growth in this case is to calculate the fee growth that is within this liquidity position and then multiply by the liquidity. So in this video I'll give you a basic idea of how to calculate the fee growth inside a liquid D position. Again let's start with a simple example of how to calculate the fee growth inside. Imagine a case where there are two ticks I lower and I upper which represents a liquidity position. And

imagine the simplest case for how to calculate the fee growth between these two ticks. Imagine that the fee growth will always be inside the two ticks I lower and I upper. And let's ask the question, what is the fee growth inside tick I lower and tick I upper? In this case, the answer is simple. All of the fee growth is inside these two ticks. So the fee growth inside in this case is equal to the fee growth. The height of this fee growth or you can think about it as the length of this orange line is equal to the fee growth inside. For the next example, imagine the case where we have a liquidity position again from tick I lower and tick I upper and the fee growth crosses I lower and then

eventually crosses I upper. In this case, what is the fee growth inside these two ticks? This is highlighted as a green rectangle between these two ticks. And we want to calculate the fee growth inside. The fee growth inside in this case is the height of this green rectangle. And we can calculate this by starting off from feed growth and then minusing whatever height of the fee growth that is above tick I upper and the height of FE growth that is below tick I lower. Let's label the height of the fee growth that is below tick eye lower as FB short for fee growth below.

And then in the same manner let's name the fee growth above tick I upper as FA short for fee growth above. Again, to calculate the fee growth inside, what we're interested is the length of this orange line or the height of this green rectangle. And to calculate this, we start off with the current fee growth FG. And then from this, we minus this height of this red rectangle, which we labeled it as FB. And finally, we minus the height of this red rectangle called FA. And this will give us the height of this green rectangle, which is equal to the length of this orange line. This is the equation for fee growth inside.

Okay. But what if we had a more complex case? For example, here you can see that the fee growth goes below tick eye lower and then later it enters this liquidity position again. And then the same over here it exits the liquidity position and then later comes back inside the liquidity position. In this case, how do we calculate the fee growth inside? To calculate the fee growth inside, we'll need to sum up all of the height of these green rectangles. This is the part of the fee growth that is inside the two ticks. To calculate the fee growth inside, we take the current fee growth and from here we minus the fee growth below and feed growth above. And this will give us the sum of the heights of the green rectangles, which is also equal to the length of this orange line.

And again, FE growth inside is equal to the current V growth minus the height of this V growth below. And then from here, minus the length of this V growth above. And now we can generalize this idea to come up with an equation for fee growth inside. Let's define a function called f of b of i to be equal to the fee growth below tick i. And we also define a function f of a that takes in a tick as input. And this is defined to be the fee growth above tick i. We also define a function f of rar which will take in two inputs tick lower and tick upper. In the white paper of uni b3 this is also called f of r stands for range. What this function is trying to say is the V

growth within the range of tick eye lower and tick I upper. And we'll define this function to be the V growth inside tick I lower and tick I upper. Now we already know how to calculate this function from the example above. This is equal to the current fee growth minus the F growth below tick I lower minus the fee growth above tick I upper. So this is a general equation of how to calculate the fee growth inside two ticks tick I lower and tick I upper. Once we can come up with a explicit formula for fee growth below tick I high and fee growth above tick I then we'll be able to calculate the fee growth inside the two ticks I lower and I upper. And once we can do that we multiply by the liquidity to calculate

the amount of fees that can be collected by a liquidity position. Even if the fee growth sometimes go out of bounds of tick high lower and I upper. This video is an animated example of fee growth inside. So let's say that we have some liquidity position between two ticks. Tick equal to minus5 and tick equal to 5. The vertical purple line will represent the current tick. Now let's run the animation to see what V growth inside will look like for this liquidity position. Okay. So let's say that there was a swap and it swung the current tick over to the left and at some point the current tick crossed below the lower tick. The fee growth inside is highlighted in green and the fee growth below is highlighted in red. Rim's

current tick crossed over the lower tick of the liquidity position. The fee growth inside stopped increasing and the fee growth below started increasing. Next, let's say that there was another swap that brought the current tick from being below the lower tick and into this liquidity position into the price ranges of the two ticks. Since this example shows the fee growth of token X, when token Y is coming in, the fee growth does not increase. However, since this is a swap from token Y to token X, the tick will move from left to right. Again, let's say that there was another swap from token X to token Y.

And in this case, we can see that the fee growth increased. After the swap, the current tick still remains inside this liquidity position. Hence, the fee growth inside also increases. And we can see this that the highlighted green rectangle increased over here. Okay. And after that, let's say that there was a swap that brought the current tick above the upper tick. And now the current tick is above the upper tick. So as long as the current tick is above the upper tick, the fee growth inside will remain the same and fee growth above will increase.

And you'll see that this red rectangle which represents fee growth above increase. Now the current tick is inside the liquidity position again. And so you see that the fee growth increase again on the next swap. The current tick remained inside this liquidity position for part of the swap. You can see here that the fee growth inside increased until here until the current tick went below the lower tick. Then from there fee growth below started to increase. Next there was another swap from token Y to token X. No fee is collected on token X. So this fee growth

remains flat. At this point the current tick is outside of the liquidity position. And on the next swap, the current tick moved inside the liquidity position. So during the swap, part of the fee growth was above the upper tick and then the remaining fee growth was inside the liquidity position. I'll play this animation again. I hope this gave you a better intuition for how to visualize V growth inside.

Inside the code of unisaw v3, there's a state variable called v growth outside. And this state variable is used to calculate both v growth above and v growth below. I'll explain how this works in the next two videos. In this video, I'll explain how v growth outside is initialized and how it is updated. Let's first start by defining some variables. We'll say f of g is the current fee growth. And we also define the fee growth outside at tick i to be fi to be equal to the fee growth outside at tick i. Next, let's take a look at the algorithm how this fee growth outside is initialized and how it is updated. The state variable fee growth outside is initialized as following. F oi will be equal to the current fee

growth. If the tick is less than or equal to the current tick otherwise if this current tick is less than the tick that is associated with the fe growth outside then it is initialized to zero. It's not so obvious why f growth outside is initialized in this manner. But over the next two videos when we look at the example of how f growth outside is used to calculate feed growth above and feed growth below this will become more obvious. And the way the fee growth outside is updated is the following. When the current fee growth fo crosses tick i, then the fee growth outside at tick i is updated by taking the current fee growth and then taking the minus of the current v growth outside and then adding it to the current fee growth.

Okay. So this is how fgraph outside is initialized and how it is updated. In the next two videos, we'll see how this algorithm correctly calculates the f growth above and fth below. Now that we know what feed growth inside is, how it is initialized and how it is updated. Let's now examine how this is used to calculate fee growth below. We will start by defining some variables. Again, f of g will be the fee growth of token y at current time. We also define something similar. f of g of k will be the fee growth of token y at time tk where this time variable tk has the following property. If we have TK and TK + 1 then TK + 1 will be greater than TK and so on. So what we will have is TK is

less than TK + 1. TK + 1 is less than TK +2 and so on. And finally we'll define F of E to be equal to the V growth of token Y below tick I hereby created a giant table and each row will represent a time interval. For example, the first row will represent the time interval from T0 to less than T1. The next row will represent the time interval from t1 to less than t2. And the next one will represent the time interval from t2 and less than t3 and so on. For the first column, we'll fill out what f of b should be equal to at each of these time intervals. And then on the next column, we'll fill out what f growth inside should be according to this algorithm.

And lastly, what we're going to do is we'll rewrite f of b fe f growth below in terms of fe growth outside. Okay, so let's begin. For this example, let's say that over time the fee growth moves something like this. And here we have tick i and in highlighted in red will be the fee growth below. When we sum up all of the heights of these red rectangles, we'll get fee growth below. So let's begin by filling out what feed growth bill should be for each time interval. Let's start with the first one. For time between t0 and less than t1, let's say that at time t0, fee growth was over here. This is labeled as f of g of zero.

And at time t1, it went below the tick. In between these two time, between time t0 and t1, what should be the fee growth below? Well, if you look at the diagram, we can see that the FE growth below should be the height of this red rectangle at the bottom. And the height of this red rectangle is equal to the height of this FE growth at f of g0. So f growth bel at this time interval will be f of g0. How about for time between t1 and t2? Well, at time t1, the tick crossed over tick i. And then at time t2, the tick went above this tick i. In between time t1 and t2 fee growth was

over here. So what should be the fee growth below in this case? The fee growth below should be the previous fee growth below which will be f of g0 plus the height of this red rectangle. Again so this will be f of g0. f of g0 is the height of this red rectangle at the bottom. And then to this we add the height of this red rectangle over here. Between time t1 and t2 the current fee growth will be somewhere over here. So the height will be the current fee growth minus the fee growth when it went below this tick. This will be at f of g1. So the height of this red rectangle will be fg minus f of g1. Between time t2 and t3 the fee growth will be over

here. So what is fee growth below? Well, in this case, the fe growth below will be the height of this red rectangle plus the height of this red rectangle at the bottom. The height of the red rectangle at the bottom is f of g0. The height of this red rectangle will be f of g2 minus f of g1. How about at time between t3 and t4. Again, we're going to follow the same pattern that we saw over here. To the previous fee growth below, we're going to add some new height of this red rectangle. The previous heights that represents FE growth below will be f of G2 minus F of G1 plus F of G0. I simply copy and pasted the FE growth below from the previous time interval. And to this, we'll need to add some new height.

Between time t3 and t4, the current fee growth will be somewhere over here. And at time t3, the fee growth went below this thick I. So if we take the difference of current V growth minus F of G3 then we get the height of this red rectangle. So this will be f of G minus F of G3. Okay. And how about for time interval between T4 and T5. At time T4 the current T crossed over this T. So the F growth is no longer below tick I as long as the FE growth is above this tick I fee growth below will not increase. At this point the time between T4 and T5. What is free growth below?

Again to calculate this fe growth below, what we need to do is add the height of this red rectangle over here between time t4 and t3. And then to this we add the previous figure growth below. Here's the previous figure growth below. This is the height of this red rectangle and the height of this red rectangle. And to this we need to add the height of this red rectangle. And the height of this red rectangle will be f of g4 minus f of g3. Okay. How about between time t5 and t6 in this time interval eg growth will be over here on the left side of pick i.

So what we need to do here is add to the previous fee growth below. We need to add the height of this red rectangle. The previous fee growth below we can just copy it from here and then paste it here. This will represent the height of this red rectangle plus the height of this red rectangle and the height of this red rectangle. To this we'll need to add the height of this red rectangle. And this is expressed by the current fee growth minus f of g5. And finally, how about for time interval between t6 and t7? At time t6, the current tick crossed above tick i. So to calculate the fee growth below, we need to add the height of this red rectangle and height of the other fur below. Here's the previous fee growth below. And to this, we add the

height of this red rectangle, which will be f of g6 minus f of g5. Next using the same example let's see how fee outside tick I is updated. Let's begin by considering the time for t0 to t1. So if you go back over here between time t0 and t1 v growth will be above tick i. So how do we initialize v outside fo abi? Well, scrolling up, we see here that f oi is initialized as f of g if current take IFC is greater than or equal to tick i. So this applies to our case back over here. We initialize fi to be fg0

between the time interval t0 and t1. V growth is above tick i. The current tick is also above tick i. So we initialize f o by to be fg0. How about for time between t1 and t2? Well at time t1 notice that f growth crossed over this tick. And how do we update fob by when the current tick crosses over this tick? Let's go back to this algorithm. When fogg crosses tick, we update foy to be equal to the fe growth at the time that it crossed over tick.

And then to this we do minus fo by. Okay. So going back here at time t1 the fe growth was equal to fg of1. This is the time when the f growth crossed below tick i. And to this we need to do minus f o by. The previous foy is equal to f of g0. So we get that the new f by is equal to f of g1 minus f of g0. Okay. How about for time between t2 and t3. Going back over here again, notice that at time t2, the fe growth crossed over ti. So again, we'll need to apply this algorithm on how to update fo by the current v growth at time t2 when it crossed over the tick is f of g2. To

this we need to minus the previous fi. The previous fi is f of g1 minus f of g0. We flip all the signs. So a plus will become minus and a minus will become plus and we get minus fg1 plus fg0. At time t3 the current tick again crossed over tick i. So we'll need to apply the algorithm again. The current fee growth at time t3 when it crossed over the tick i is fg3. To this we need to add the previous terms where all of these terms the signs are flipped. Plus becomes a minus and minus becomes a plus. So the first term will be minus fg2. The next term will be plus fg1 and the last term will be minus fg0. At time

t4 again the current fee growth crossed over tick. So we apply the algorithm again. The current fee growth at time t4 is f of g4. To this we add the previous fo by and flipping all of the signs and we get minus fg3 plus fg2 minus fg1 plus fg0. We repeat this pattern for the last two terms. At time t5, the current fee growth is fg. And then to this we add the previous fo by flipping the signs and we get this. And at time t6 the current fee growth is fg6. And then to this we add the previous fo by flipping the signs. Okay. Now that we filled out f by next let's see how this fi relates to f growth

below. What you can immediately notice is that f of b is equal to fg0. How about FY? It's also equal to FG0. So in this case, FOB when we rewrite it in terms of FY is equal to F O Y. And the same goes for all of the odd rows. In the third row, we see that FOB is equal to FG2 minus FG1 plus FG0. And this is also equal to F O on the third row. The same goes for the fifth row and the seventh row. Okay. How about the even rows? How can we rewrite FB in terms of F O? Let's compare the second row. F of B is equal to FG minus FG1 plus FG0. How about FOY? FO Y is equal to FG1 minus

FG0. For FB we have three terms and for FO by we have two terms. For FOB we have a FOG and then we have minus FG1 and then we have a plus FG0. For FO by we don't have a FG but we do have FG1. We also have a FG1 over here. And we also have a fg0 zero which we have over here. Also notice that these two terms have the opposite signs. Here we have a minus for fg1. Here we have a plus. So to rewrite f of b in terms of f o i, let's first start by putting in the missing term which is fg. And then to add the last two terms, remember that the last two terms have the opposite signs. So we do minus f o. The same is true for the fourth row. We have a fg over here. And

all of these terms have the opposite signs from all of these terms. And the same is true for the sixth row. F of B will be equal to FG minus F O. Notice that we have a nice pattern here. F of B is equal to F O Y or it is equal to FG minus F O. So let's generalize this into our equation. We'll define ILC to be equal to the current tick. And then we'll come up with the formula for FOB in terms of FO by first. Notice that for time interval between t0 and t1 and t2 and t3 t4 and t5 and t6 and t7 we had the term f of b is equal to f o. And for these time intervals let's see where the

current tick is for time between t0 and t1 the current tick was above tick i for time interval between t2 and t3 again the current tick was above tick i. And the same goes for the time interval between T4 and T5 and the time interval between T6 and T7. The current tick was above tick I. So going back to this equation, we can generalize this. When the current tick I of C was greater than or equal to tick I, V growth below F of B is equal to F O. And in the other cases we can see that the current tick was below tick I. So this will be the time between T1 and T2, T3 and T4 and T5 and T6. Okay. So going back over here we

can say that when the current tick I of C was less than tick I V growth below is equal to F of G minus FO A by. And now we have an equation for what V growth below is in terms of FO A by and the current F growth FG. In the next video we'll derive the equation for F growth above in the same manner that we did over here. In the previous video, we came up with a formula for feed growth below based on fee growth outside. In this video, we'll do the same for fee growth above. We'll derive the equation for fee growth above based on fee growth outside. So, let's start with definitions. We'll say that f of g is equal to the fee growth of token y at current time. And we also define something similar called f of g k. This

will be the fee growth of token y at time tk. And again, this notation for time has a restriction. t of k is less than tk + 1 and t of k + 1 is less than t of k + 2 and so on. In other words, time is always moving forward. And then we'll define f of a to be the fe growth of token y above tick i. In this video, we'll look at an example of how to calculate fee growth above. And then we'll relate it to f growth outside. And again for the algorithm for fee growth outside, we'll follow this algorithm. We'll say fi to be equal to the fee growth outside at tick i. To initialize this fe outside, we'll say that f growth outside is equal to f of g if current tick i c is greater than or equal to the

tick that is associated with this f growth. Otherwise, when we initialize fe growth outside and the current tick is less than this tick i, then we initialize it to zero. And again to update it, when the fe growth crosses this tick, we update this v growth outside by the following algorithm. FO of I is equal to the current V growth minus the current FO of I. Okay, so with that said, let's now look at an example of V growth above. Let's say that we have some tick eye and over time the fee growth went left and right. Sometimes this fee growth was above this tick eye and other time it was below it. And what we're going to do is calculate the fee growth above F of A. Visually, this fe growth

above is a sum of the height of these red rectangles. On the right, what we're going to do is calculate what fe growth above should be for each time interval. And once we calculate the column for feed growth above, next we'll calculate fee growth outside. And this will be based off of this algorithm over here. And lastly, using the fee growth outside, we'll recalculate fee growth above. Okay, so let's start with the first time interval. the time interval between t0 and t1. So let's see where f growth is for time interval between t0 and t1. At time t0, let's say that the fee growth was over here. And at time t1, the fee growth was over here. In between the time between t0 and t1, fee

growth will be somewhere over here. And in this case, what is the fee growth above? Well, to calculate this, what we have to do is sum up all of the heights of the red rectangle that is below FG1. In this case, we don't have any red rectangles below FG1. So, in this case, we start out with FE growth above equal to zero. Okay. How about for time between T1 and T2? For time between T1 and T2, the FE growth will be over here. At time t1, feed growth started over here. And at time t2, this fee growth crossed over this tick. And what is f growth above? Well, between time t1 and less than t2, the fee growth will be somewhere over here. The height of this

red rectangle in this case will be the current fee growth minus the time that it crossed above tick eye which will be at fg1. So the height of this red rectangle for the time interval between t1 and less than t2 is expressed by fg the current fee growth minus fg1. At time t2, the current free growth crossed over tai. For time between t2 and t3, we know that the height of the red rectangle is given by this height of the red rectangle. So the fee growth above in this case will be fg2 minus fg1. The time interval between t3 and t4 the fe growth was somewhere over here. So v grow above will be the height of the

previous v growth above which will be the height of this red rectangle plus the height of the red rectangle over here. The height of this red rectangle is given by fg2 minus fg1. And the height of the red rectangle when the feed growth is over here is given by fg minus fg3. fg3 is the base of this red rectangle. And fg over time will travel from starting from here and then keep going up. So the height is given by FG minus FG3. For the time interval between T4 and T5, we know that the F growth above is the height of this red rectangle plus the height of this red rectangle. So F growth above is given by FG4 minus FG3. That's the height of this red rectangle. And FG2 minus FG1 that is

the height of this rectangle. For the time interval between T5 and T6, the current FE growth will be over here. And FE growth above will be the height of this red rectangle. Wherever this fee growth might be between time t5 and t6 plus the previous fee growth above. Again the previous fee growth above is given by these terms which I copied and pasted from the row above. And then the height of this red rectangle will be fg minus fg5. And for this last example let's look at the time interval between t6 and less than t7. And in this case the fea will be the sum of this red rectangle plus this red rectangle and this red rectangle. Okay. Now that we filled out fe growth above, next let's fill out feed growth outside. To begin

with, let's review how unis swabb3 initializes this fe growth outside. Going above fe growth outside is initialized as the current fee growth if the current tick i of c is greater than or equal to the tick i associated with the fee growth outside. Otherwise, it is initialized as zero. Okay. So how about in our case when we initialize feed growth outside where is the current tick IFC and where's the tick associated with this feed growth outside. So going here let's say that we initialize the fee growth outside over here. Current tick will be over here and the tick that is associated with this feed growth outside is over here. In this case we have the current tick less than this tick i. So we will initialize this fee growth

outside to be equal to zero. At time t1 we see that the fee growth crosses tick i. For fe growth outside at time t1, we'll need to apply this update row. The new fee growth outside is equal to the fee growth when it crossed over tick. And then to this we need to add minus the current fee growth outside. The fee growth when it crossed over tick is fg1. And then from this we need to minus the previous fee growth outside. The previous one is equal to zero. So minus Z and this is still equal to FG1. Okay, let's move on. At time t2, the current tick again crossed over tick. So we need to apply the update rule again. The fee growth when it crossed over tick is

given by FG2. And the previous fee growth outside is given by FG1. So we do a minus FG1. Next at time t3 again the current tick crossed over tick. So we need to update this fee growth outside again. The fee growth when it crossed over to Kai is given by FG3. The previous fee growth outside is given by FG2 minus FG1. And from this we need to flip all of the signs. So we get minus FG2 plus FG1. The next time the current tick crosses over tick I is at time T4. Vthrow at this time is FG4. To this we add the minus of the previous V growth outside. And the pattern repeats for time t= to 5 and time t= to 6. Okay.

Okay, now that we filled out f growth outside, let's now see how f growth above relates to feed growth outside. Can we come up with an equation for f growth above based on f growth outside? Similar to what we saw in the previous video when we related f growth below with free growth outside. Here we'll see a similar pattern for rows 1 3 5 and 7. Feed growth above and feed growth outside are exactly the same. Here we have a zero. Here we have a zero. On row three, we have FG2 minus FG1. And over here, we also have FG2 minus FG1 and so on. Okay. So, how about even rows? How can we get the equation for F growth above based on F growth outside? Let's start with the second

row. On the second row, notice that for F growth above, we have FG minus FG1. And for FE growth outside, we only have FG1. Here, we don't have the term FG that is present over here. However, we do have the terms FG1 that is over here and over here. However, the signs are flipped. So to rewrite FE growth above in terms of FE growth outside, let's start by putting in the missing term which is FG. Okay, so we have FG and then next we have the same terms FG1. However, we have a minus here and over here we have a plus. We can easily fix this by putting in a minus F O. So what we're doing here is putting a minus over here. So now f of a is equal to this

term. We do the same for the fourth row. We have a fg. We don't have a fg. For f of a we have the terms fg3, fg2 and fg1. And for f o by we also have the same terms. Again you'll notice that the signs are flipped. So to get f growth above in terms of f growth outside, we start with the missing term f of g and then we'll need to add v growth outside and flip the signs. You can check for yourself that row six is the same. So now we have a nice pattern for how to calculate V growth above. Let's generalize this into an equation. We'll rewrite F growth above in terms of V growth outside and the current V growth FG. We'll define if C to be equal to the current tick. And F

growth above F of A is equal to remember that when we started out we started out with V growth above below tick I. And we can double check this. If you go back over here, fth above started below tick. And at each time the f growth crossed over this tick I. So going back over here, we know that for over here current tick was less than tick i. For the next one, we know that the current tick was above tick i. And for the next one, we know that the current tick was less than tick i. And again for the next one, we know that the current tick was above tick i. and so on. So let's now generalize this. When the current tick I of C was

greater than or equal to tick I f growth above is given by FG minus F O. On the other hand when the current tick was less than this T I V growth above was given by F O. What we did here was we just summarized these equations. What we accomplished so far is we found out a formula for FE growth below and also for free growth above. In the next video, we'll use this fee growth above, feed growth below, and feed growth inside to calculate the amount of fees that can be collected from a liquidity position. In the beginning of the video, we defined a function called f of bar that takes in two inputs, tick eye lower and tick eye upper. And we defined this to be equal to the fee growth inside tick eye lower and tick eye upper. We also said that

this is equal to the current fee growth minus the fee growth below of tick eye lower minus the fee growth above of tick eye upper. And now we know what all of these are. The current fee growth is a state variable that is stored inside the contract of unisb3. And we also know how to calculate fee growth below for any tick and fee growth above for any tick as well. So now we know how to calculate fee growth inside between two ticks tick eye lower and tick I upper. Now while the fee growth is a state variable that was initialized when the smart contract was deployed, a liquidity position can be created and removed at any time. So to calculate the fee growth inside for a position we need to calculate the fee growth inside when this position is created and also when the fee is

collected taking the difference of these two fee growth will give us the correct fee growth inside for this liquidity position. So let's say that we created a position at time t0 then let's say that we claim the fee at time t1. At time t0 we need to calculate the fee growth inside and then at time t1 when we actually claim the fees we'll need to recalculate the fee growth inside again. Taking the difference this will give us the correct fee growth inside for a position. Now why do we need to take the fee growth inside when a position is created and also when we claim fees. One way to understand this is let's say that we only take the fee growth inside when we claim the fee. So this will be f1.

Loosely speaking, this would mean that we're taking the fee growth inside of tick eye lower and tick I upper ever since the contract was deployed. But the time that the liquidity position was created was probably after the contract was deployed. So what we need to do here is sort of like taking a snapshot of the fee growth inside when the liquidity position is created and then recalculating the fee growth inside to claim the fees. The difference of f_sub_1 and f_sub_0 will give us the fee growth inside between the times t0 and t1. Okay, so now that we know how to calculate a fee growth inside for a position between time t0 and t1, we're now ready to calculate the fee for this liquidity position. To calculate a fee for a liquidity position, let's say that s is a liquidity for a position between

tick i lower and tick i upper. And we'll say that this s remains a constant over time. In this case, the fee that can be collected for this liquidity position is given by the following equation. the liquidity S times the difference of the fee growth inside F_sub_1 minus F_sub_0 and again F0 we denote this as the fee growth inside when this liquidity was created and F_sub_1 will be the fee growth inside when the fee is actually claimed taking the difference and then multiplying by the liquidity S this will give us the fee that can be collected for this liquidity position in this video we'll look at the code that are relevant for calculating the fee growth for a liquidity position the first part that we'll look that is under a contract

called tick.so and this contract is under the repo v3 core contracts library and the contract is called tick.so inside this tick. contract there's a function called update and scrolling down you can see it over here this part of the code contains the logic for how fee growth outside is initialized and you can see over here that if the tick that is associated with this fee growth outside is less than or equal to the current tick then this fee growth outside is initialized to be the current fee growth and the fee growth is tracked both for token zero and for token one remember a few videos back we said that the fee growth outside is initialized as the current fee growth when the current

tick is greater than or equal to the tick that is associated with this fee growth. And this part of the code is how the fee growth is initialized. Next, let's take a look at what happens when the current tick crosses over the tick and how the fee growth outside is updated. Scrolling down, there's a function called cross. This function will be called when the current tick crosses over a tick. And when it does, the fee growth outside that is associated with this tick is updated by the following. The new fee growth outside is equal to the current fee growth minus the current fee growth outside. And this is true for both token zero and for token one. We're still in the same contract. Next, let's take a look at a function that will calculate the fee growth inside. So I'll scroll up

and I am looking for a function called get fee growth inside. Remember the math equation that calculates the fee growth inside and this is how the code is implemented. The first part of the code calculates the fee growth below. If the current tick is greater than or equal to the lower tick then the fee growth below is set to be the fee growth outside associated with this lower tick. Otherwise it is equal to the current fee growth minus the fee growth outside. And similarly the fee growth above is calculated as following. If the current tick is less than the upper tick, then the fee growth above is equal to the fee growth outside associated with the upper tick. Otherwise, it is equal to the current fee growth minus the feed growth

outside. And once feed growth above and feed growth below are calculated. To calculate the fee growth inside, we do take the current fee growth and then minus the fee growth below and the fee growth above. This is how fee growth inside is calculated. To see how a fee that can be collected for a liquidity position is calculated, we need to look at another contract. The contract is called position.sole and it is located under the folder libraries. The function that we need to look at is called update. And inside here we can see how the fee is calculated. For example, for token zero, we take the current fee growth inside and then minus it with the previous fee growth inside that is associated with this liquidity position.

And then we multiply by the liquidity to calculate the amount of token zero that is owed as fee. And the same goes for token one. And that is how a fee is calculated for each liquidity position in unis. Unisaw B3 allows you to borrow tokens as long as the tokens plus some fee are paid in the same transaction. This is called a flash none. And to get a flash not in unisaw B3, you'll need to call a function called flash on the contract unisoft B3 pool. It's going to take four parameters. Recipient, amount zero, amount one, and data. Recipient is the address that unisaw B3 will send the tokens to and amount zero and amount one or amount of tokens to send. and data is a arbitrary bytes data that is sent to

the unisoft B3 flash callback contract. Inside this function, it first calculates the fee. Then next, it gets the balance of token zero and token one before the tokens are sent out. After that, token zero and token one are sent to the recipient for the amounts amount zero and amount one. And then next, it calls a contract called I unisaw B3 call back on message sender. When it calls the function called unis b3 flash callback for the parameters it's going to pass in the fees fe 0 and f1. Fe0 is the fee on token zero and fe is the fee on token one and then the arbitrary data that was passed as input to this function. Notice that it calls a function unb call back on message

sender. So this means that message sender must be a contract and this contract must call into the function fresh and then after the function.b2 B2 flash call back is executed on message sender. It gets the balance of token zero and token one after this function is done executing. So when we get a flash none, we'll need to write our custom logic inside this function. And then after this function is done executing, it's going to check that the balance of token zero and token one after is greater than or equal to the balance before plus the fees. Next, it calculates the fee to be given to the protocol and the fee that is given to the liquidity provider. And you can see over here that the fee growth global for

token zero and token one are updated. And that completes the quick call blocker for the function flash. Here's our exercise to get a flash loan from unis b3. Inside this contract, there are several tasks. So let's take a look at them. The first task is inside the function called flash. This function will be called to initiate a flash zone from a unisoft B3 pool. And the first task is to AI encode a strct called flash call back data. If we scroll up, you can see what this strct is. Inside this truck, we have three parameters.

Amount zero. This will be the amount of token zero to borrow. Amount one, the amount of token one to borrow. And the caller. The caller will be the caller of flesh. So inside the function flesh, this will be message. Once you ABI encode this strct called flash call back data, the next task is to call the function flash on unisaw B3 pool. The unisaw B3 pool and token zero and token one are all initialized inside the constructor. And if you need to know what parameters to pass to call the function flash, you can navigate to where the interface I unis b3 pool is defined. Scrolling up, this is where it's defined under source interfaces unisop by unisawb pool. If you go here,

you'll know what parameters to pass to call the function flash. When the function flash is called on the unis swap b3 pool, the unis swap b3 pool will call a call back called unis swap b3 flash call back. And inside here, the pool will pass three parameters v 0, v1, and the data that will be passed from the caller. So back in task two once you AI encode the flash callback data pass this data into the function flash and you'll be able to get the same data over here for task three check that message that sender is actually the pool contract and then next decode this data into flash call back data this flash call back data again encodes these three data and using these transfer the fees

that was requested fee 0 and fee one from the caller in this case this will be the account that called into the function flash. Once the fee is paid by this caller, repay the unis swap bt pool for the amount borrowed and the fee. Now, if you wanted to add more custom logic, for example, maybe after getting a flash swap, you might want to do an arbitrage, then you would write your custom logic in between either task four and five or five and six. Next, let's take a look at the test. The test is inside unisawb exercises unisawb.test.sole. And here's the setup.

The pool that we're going to be testing on is the unis swap B3 die ref pool with 0.3% fee. And this contract, this test contract is given a million die. And it approved the unisoft B3 pool contract to spend an infinite amount of D. Inside the test, it will initiate a flash by calling the function flash on the unisoft B3 flash contract that you wrote. and then for simplicity it will just log the fees that the unisoft B3 pole requested. Okay, so that is the exercise for unisaw B3 flash. Let's go over the solutions. The first task is to AI encode the flash call back data. So let's say bytes memory data is equal to AI encode. We'll encode the

strructall back data and then we'll fill out the data that we need for this strct. So the data that we need are amount zero, amount one and caller. Amount zero, this will come from the input amount zero and the same for amount one. Amount one will come from the input and the caller will be message sender. The caller of the function flash is message sender. Okay, so that's task one. Let's move on to task two. Call i unis btpool. How do we call this function?

Well, let's navigate to this interface I unisoft BP pool and find out how to call this function flash. Inside the interface I unisoft BB pool, let's find where the function flash is defined. Okay, here it is. For the parameters, it's easy to remember. Recipient amount zero amount one and data. Going back to our contract, the pool contract is already initialized. So I'll say pool/ recipient who who is going to receive the tokens that we want to borrow. In this example, this will be this contract. So this will be address this amount zero. We'll just simply pass the amount zero that's specified over here. Amount zero. And then same for

amount one. And then lastly data. This is the data that we prepared in task one. Okay. So that completes task two. Let's move on. Task three check message sender is pool. We can do this by saying require message sender is equal to address of the pool. Only the unisoft v2 pull contract will be able to call this unisoft v2 flash call back. And for the error message I'll just say not authorized. The next task is to decode the data from the input into the strct flash call back data. So I'll say flash call back data memory. I'll name this decoded is equal to ABI do decode the data and we're going to decode this data

into the strct flash callback data. The next task is to transfer fees from flash callback data caller. This will be the fee that will be repaid to the pool contract and the fees are specified by the pool P 0 and P1. So say if e0 is greater than zero then transfer token zero token0 dot transfer from from the decoded data decoded caller and then let's transfer this to this contract address this for the amount v 0 and we'll do the same for fee one. If V1 is greater than zero for token one, transfer from the colleic.aller to this

contract for the amount V1. Okay, the last task is to repay the pool for amount borrow plus V. For token zero, we know that we borrowed some amount if this decoded amount zero is greater than zero. So say if decoded dot amount zero is greater than zero then token0 transfer to the pool contract address pool for the amount the amount that we borrow decoded at amount zero plus the fee that we need to repay fee zero. And let's do the same for token one. If decoded dot amount one is greater than zero, then transfer token one for the amount amount one plus fee

one. And that completes task number six. And again, this was a simple example of flash swap. And if you wanted to add some custom logic like doing a arbitrage after getting a flash swap, then you would write your custom logic in between task four and five or five and six. Okay, let's execute the test. Inside my terminal, I'll first set the environment variable for for URL. Next, we'll execute the test by typing forge test and then for URIL and then the path to the test match path test unis swap b3 exercises unis swap b3/ test.soul and then we'll print out the console logs

dashb. Okay. And our test passed. In unis swap b2 the time weighted average price also called t-wap is taken by summing up the prices for each second and then dividing it by the duration. Basically it is taking the arithmetic mean of the prices. However in unisaw b3 the time weighted average price is calculated by the geometric mean. Basically you multiply the prices for each second and let's say that there are n prices. Next you take the nth root of all of these numbers that you just multiplied. This is the geometric mean. To be more precise, let's say that there are numbers a1, a2, a3, all the way up to a n. There are n numbers. And now to calculate the geometric mean of all of these numbers, what you would do is

multiply all of these numbers from a1, a2, a3 all the way up to a n. And since there are n terms, you would take the nth root of this multiplication. This is the geometric mean of the numbers a1, a2 all the way up to a n. To calculate the tap and union slot B3, we will take the geometric mean of the prices that are taken for each second. For example, let's say that we have the prices P of T1 + 1, P of T1 + 2, P of T1 + 3 all the way up to P of T2. Price for each second in the time interval from T1 + 1 to T2.

Then to calculate the TWOP, let's call this P average. And to calculate this, we first multiply all of these prices and then we'll need to take the nth root of this multiplication. Okay. But how many terms are there between the time intervals from t1 + 1 to t2? Let's consider the case when there are only two prices t1 + 1 and the price at t1 + 2. In this case, there are two prices. So there are two terms. As another example, how many terms in between t1 + 1 to t1 + 3? Well, we can just count them 1 2 and 3. We can also come up with a math equation that will tell us how many terms are in between from the time

intervals t1 + 1 to t2. We start out with the last term t2. And then from this, we minus the first term. This will be t1 + 1. And then we also need to include this term. So we'll need to add a plus one. This is the amount of prices that are in between the time intervals t1 + 1 to t2. And this is equal to t2 minus t1. And to quickly see that this equation is correct, let's say again that there are only two prices t1 + 1 and t1 + 2. When we apply this equation using only two terms, do we get the correct number of terms? So let's say that t2 is equal to t1 + 2. And for t1 + 1, we'll keep it the same. So let's say t1 + 2 minus t1 + 1. The difference will

be 1 + 1 and that will be 2. So the number of terms between t1 + 1 and t1 + 2 will be two terms. Let's see another example. Let's say that we want to count the number of terms between t1 + 1 and t1 + 3. If we replace t2 with t1 + 3 and then do this math, what do we get? We have a + three and then we have a minus one, so that's two. and then plus one. So that's three. So three terms. Okay. So it looks like this equation correctly describes the amount of terms in between the time duration t1 + 1 and t2. And now we need to take the n fruit where n is equal to the number of terms that we multiplied. Here we calculated the

amount of terms here are t2 minus t1. And this is how the t-wap is calculated in unisaw v3. Now, of course, inside a smart contract to calculate the time weighted average price, you wouldn't want to multiply all those prices. It would take too much gas. So, Unis swap B3 uses a clever trick so that we can still calculate the time weighted average price without multiplying all the prices for each second. This is done by storing a state variable called a tick cumulative. This tick cumulative is a cumulator of all of the prices ever since the contract was deployed. But before I explain what tick cumulative is, let's first review what price and ticks are. So as a review, let's go over price and tick. Let's say that P is a

price. And just like in unis swap B2, you can think about this price as the ratio of token Y over token X. In other words, the price of token X in terms of token Y. And we'll label T as the tick. The relationship between the price and the tick is given by the following equation. Price is equal to 1.00001. 0001 raised to the tick. Next, I'll explain what price accumulator is. Let's first define t of i to be equal to the tick at time i. Then the price accumulator, we'll label this as a of t, is equal to the sum from i=0 to i= t of the tick at time i. So, what we're doing here is summing up all of the ticks ever since the contract was deployed for each

second. Okay, so with this price accumulator, how would we calculate the time weighted average price in Unisaw B3? What is the relationship between this equation and the price accumulator? We'll first start with this equation of the time weighted average price between the time intervals t1 + 1 to t2 and then we'll work our way down to rewriting this equation in terms of the price accumulator. So first I'll rewrite this the inner prices using the ticks. So the price at time t1 + 1 can be rewritten as 1.001 raised to the tick at time t1 + 1.

And the same goes for time at t1 + 2 t1 + 3 and all the way up to time t2. Next I'll rewrite this n fruit using exponents and a fraction. Also, if you remember your math from high school, you know that if you have the same base and it is multiplied by different exponents, then we can take the same base and then just add up the exponents. So, we have 1.001 raised to the sum of the ticks T of T1 + 1 T of T1 + 2 all the way up to T of T2. Next, I'll rewrite this sum using the summation notation. So the summation will go from I = to T1 + 1 all the way up to T2. Now notice that we have something that looks like the price

accumulator. Going back up, we said that this is the price accumulator. So I'll paste this here. And let's compare this term to this term. For the price accumulator, it starts from I equals to zero. However, in this expression, we have that I starts from T1 + 1. Is there a way where we can rewrite this in terms of the price accumulator? Well, what we can do is we first need the price accumulator to go up to time t2. So let's rewrite this as a of t2. We take the price accumulator all the way up to time t2.

So this will be equal to just go up to time t2. Okay. Let's now compare this term with this term. On the right I have extra terms that starts from i= to0 all the way up to i = to t1. So if we minus all of the terms from i =0 to i = to t1 then we will get all the terms that are inside this summation. So what we need to do is take the price accumulator all the way up to t1 and then minus it from the price accumulator a t2. This will cancel out all of the terms that start from i= to0 to i = to t1. So this is equal to a t2 minus a t1 is equal to this term over here. The price

accumulator a t2 goes all the way up to time t2. But also has some terms from i = to0 to i= to t1 that are not present in here. So if we minus all the terms from i= to0 to i= to t1 then this part of the equation is equal to this summation. Okay. So now we can rewrite this as we'll just replace this summation with the price accumulator a t2 minus a t1. And this top part a2 minus a t1 divided by the time interval t2us t1 is called a time weighted average tick. What we showed is that we can rewrite the time weighted average price of this form using the price

accumulator and then rewrite it as this equation. This is the equation that is used to calculate the time weighted average price in unis swab b3. In unis swab b3 if you know the average price of token x then you can easily calculate the average price of token y. You will simply take the reciprocal of the average price of token x. However, this equation does not apply in unis 2. Let's call P of X the spot price of token X in terms of token Y. And if you want to think about in real tokens instead of token X and token Y. A easy way to remember is having token X equal to E and token Y equal to some stable coin like USDC. And we'll label P of Y to be the spot price of token Y in terms of token X. And for the spot price both in

unisoft B2 and in UNISOB B3, this is true. If you know the spot price of token X, then we can calculate the spot price of token Y to be equal to 1 over the spot price of token X. However, when we take the time weighted average price of token X and token Y, this is not true in Uniswap B2. So, let's label P of X of average to be equal to the TWOP of token X. And P of Y of average is the TWOP of token Y. In unis swap b2 the time weighted average price of token y p of y of average is not equal to 1 over the time weighted average price of token x.

However, in unis swap b3 this is true. If we know the time weighted average price of one token then if we just do one over that then we get the time weighted average price of the other token. Let's go through an example of calculating the time weighted average price of both tokens both in unis swap b2 and in unis swap b3. We'll start with unis swap B2 and see that just because we know the time weighted average price of one token doesn't mean that if we take the one over that we'll get the time weighted average price of the other token. Let's calculate the time weighted average price using a simple example.

Let's say that at time zero the price of token X was equal to 3,000 and that from time 1 all the way up to time 3, the price was at 1,000. To calculate the time with the average price of token next in unisoft B2, all we have to do is take the price at each second, add them all up, and then divide by the duration. From time 0 to 1, we have 3,000. From time 1 to 2, we have 1,000. And then from time 2 to 3, we have 1,000 again. So on the top, we have 3,000 + 1,000 + 1,000. And the whole duration is 3 seconds. So we divide the sum of the prices by 3 and we get 5,000 divided by 3. Okay, how about the time weighted

average price of token Y. Now given that the spot price of token X was 3,000 from time 0 to 1 and then 1,000 from time 1 to 3, the spot price of token Y can be calculated by taking one over this price. And this is we're using this equation over here. The spot price of token Y at each second is calculated by just taking one over the price of token X. So the first one will be 1 over 3,000. The next two will be 1 over 1,000. The whole duration is 3 seconds. Simplify this and we get 7 over 9,000. And now let's compare the time weighted average price of token X with the time weighted average price of token Y. Let's start with the time weighted

average price of token Y. So we calculated this to be equal to 7 over 9,000. And now we want to compare this with this equation. We want to double check that just because we know the time weighted average price of token Y doesn't mean that we also know the time weighted average price of token X. So going back over here, what is 1 over the time weighted average price of token X? Well, this is equal to we just flip the denominator and the numerator and the 5,000 goes to the bottom and the three goes to the top. We get 3 over 5,000.

And as you can see, these two are not equal. So we just shown that in unis swap b2 just because we know the time weighted average price of one token doesn't mean that we can simply calculate the time weighted average price of the other token by taking one over that time weighted average price. So this is an example in unis swap b2 how about in unis swap b3. So we said earlier that if you know the time weighted average price of one token then we can easily calculate the time weighted average price of the other token. So let's go through a simple example using the same price over the same duration. To calculate the time weighted average price in unisoft B3, we first need to calculate the time weighted average tick. So let's call T of X of average to be equal to the average tick of the price of token X.

And let's name T of Y of average to be equal to the average tick of the price of token Y. Once we figure out the average ticks to calculate the average price, we would take 1.001 raised to these average ticks. Okay, let's start by calculating the average tick of token X. From the previous example, we had the price equal to 3,000 for the first second and 1,000 for the next two seconds. To calculate the tick given the price, we would need to take the log of 1.001 for each of the prices and the duration is 3. This turns out to be roughly equal to 72,743. Okay. Next, let's calculate time weighted average tick for token Y. Given that the spot price of token X was

3,000, 1,000, and 1,000, the spot price of token Y will be taking the one over the spot price of token X. So, this will be 1 over 3,000, 1 over 1,000, and 1 over 1,000 again. And to convert the spot price into tick, we will again need to take the log of 1.001. And again, the duration is three. Now, although these two equation don't look similar, here's the interesting part. this 1 over 3,00 we can convert it to minus log of 1.001 to 3000 and the same for the next two terms. Now notice that the first term for the time weighted average tick of token X is equal to the time weighted average tick of token Y except we have a minus here and the same goes for the

last two terms. Since the time weighted average take of token X, we calculated this to be roughly 72,743. The time weighted average take of token Y, the terms are the same except we have a minus sign. So this is roughly equal to minus 72,743. Okay, let's now calculate the time weighted average price in Uniswap B3. Let's start with the time weighted average price of token Y. This is given by the equation of 1.001 0001 raised the time weighted average tick of token Y and we calculated this time weighted average tick of token Y to be roughly equal to -72,743. So this price is roughly equal to

1.1 raised to the minus 72,743 and this is equal to 1 / 1.1 raised to the 72,743. But now notice this part. This is roughly equal to 1.001 raised to the time weighted average tick of token X that you can see over here. And let's compare the last two terms. 1001 raised to the time weighted average tick of token X is exactly equal to the time weighted average price of token X in UNISAB B3. So what we've shown here is that in unis 3 if we know the time weighted average price of one token then we can easily calculate the time weighted average price of the other

token by taking one over that. We seen an example in saw B3. Next let's actually go to the math to see why that the time weighted average price of one token is equal to one over the time weighted average price of the other token. We'll name ti to be equal to the tick at time i. And let's say that P of X sub I is the price of token X at time I and this is equal to 1.001 to the T of I. To calculate the spot price of token Y at time I, we would take 1 over the spot price of token X at time I. And from this equation, we can derive a useful equation that we'll use later. The right part of this equation is equal to 1 / 1.001 raised to the tab. Okay, but this

is equal to 1.001 raised to the minus t of i. Okay, so we'll come back to this equation later. Let's say that we wanted to calculate the time weighted average tick of token x over some time interval where the duration is equal to n. Then the equation is given by this formula. Add all of the ticks from time t1 + 1 all the way up to t1 + n. And since there are n terms, divide this by n. Okay. And to calculate the time weighted average tick of token Y, we'll need to do something similar except what will be the tick for token Y at time I. Well, we can take a look at this equation to figure out what the tick is for token Y.

At time I, the tick is given by minus T of I. So the average tick over the same duration N will be equal to the summation from I= to T1 + 1 to T1 + N. And then we sum up all of minus T. And then there are n terms so we divide by n. The difference between the time weighted average tick of token x and the time weighted average tick of token y is that here we have a minus and here we don't have a minus. We can now calculate the time weighted average price of token y. This is given by 1.001 raised to the time weighted average tick of token white. And from this equation over here we said that these two are only different by a

negative sign. So rewriting T of Y of average, we can just simply put minus TX of average. And this is equal to 1 / the time weighted average price of token X. And this is the mathematical explanation of why the time weighted average price of one token is equal to 1 over the time weighted average price of the other token. How would the time weighted average price in Uniswab B2 and in UNISAW B3 react when the price changes suddenly? To find this answer, I wrote a simple Python script. And in this Python script, it calculates the time weighted average price both in unisaw B2 and then in unis swaw B3. And then it will graph the spot price, the time weighted

average price in unisaw B2 and in unisaw B3 over time. So for the first simulation, I have the price where at each second it's equal to 1,000 and at some time the price drops to one and then it remains one for the rest of the time. This is the spot price. The next part of the code calculates the cumulative price in unisaw B2 and the cumulative tick in unisaw B3. And then the code after that calculates the time weighted average price for unisaw B2 and in UNISAB B3. And lastly, it plots the graph of the spot price and the time weighted average price in UNISOB B2 and in UNISOB B3. The spot price is shown in blue and we can see that the price is at 1,000 and all of a sudden it drops to

one. The time weighted average price in Unisaw B3 is shown in green and you can see that it sort of follows the spot price and when the price drops it sort of curves and then converges to the spot price. Now take a look at the time weighted average price in unis swar B2. It follows the spot price and then when the price drops it slowly converges to the spot price of one. To summarize what's happening here, when the spot price suddenly drops, the time weighted average price calculated in unis swab B3 converges to the spot price quicker than the time weighted average price calculated in unisaw B2. Okay, so this is a situation when the price suddenly drops. Let's take a look at another

situation. Let's see how the time weighted average prices react when the price suddenly spikes up. So the price is at one for some few seconds and then all of a sudden let's say that the price spikes to 1,000 and then it remains at 1,000 for the rest of the time. And then let's run the simulation again. Scroll down and let's see what the graph looks like. So let's start with the spot price. The spot price is at 1 and all of a sudden it jumps up to 1,000. How about the time weighted average price in unis swap B3? This is shown in green. The time weighted average price in unis swap B3 initially doesn't react to the jump in price. It remains close to the previous spot price which is equal to

one and then all of a sudden it catches up to the new spot price. However, the time weighted average price calculated in unis swab B2 immediately reacts to the price change going up and at each second this time weighted average price calculated in unis swab B2 is always greater than or equal to the time weighted average price calculated by unisaw B3. To summarize, when the spot price spikes up, the time weighted average price calculated in unisaw B2 reacts quicker than the time weighted average price calculated in uni B3. In the previous video, I explained how Unispaw B3 stores the data that accumulates the ticks for each second.

In this video, I'll explain where this cumulative tick is actually stored and how it is updated. So, we'll take a look at three contracts. The Oracle unisoft B3 and the Oracle library. The first contract Oracle.soul is inside the repo B3 core libraries Oracle. And inside here, we'll first take a look at a strct called observation. This is a strct that stores some tick cumulative at some time block time stamp. Whenever the liquidity inside a unis b3 pull contract changes or whenever the price changes this observation strct is stored inside the unisaw b3 pull contract. Inside the truck there are two other data seconds per liquidity cumulative x18 and initialized but we won't cover this in

this video. We'll mainly focus on tick cumulative how it is updated and how we can actually use this to calculate the t-op. A new observation struck is saved whenever the liquidity changes or the price changes and this is done by calling a function called write. Let's go to the unisoft B3 pool and actually see where this function called write is called. First we can see here that it calls observations.right. This is called inside the function modify position. Again, whenever the liquidity changes, this modify position is called and inside it, it stores the observation.

The other place where observations.right is called is inside the function swap. So whenever there's a swap in the current tick changes, observations.right is called. The next function that I'll explain is called observe inside the unis swap bull contract. This is a function that you'll call to get the tick cumulatives. For the input, you'll pass in an array of seconds. Seconds go from now. For example, zero will mean 0 seconds ago from the current time. So this will be the current time. And if this array element contains a one, this means that 1 second ago from the current time. This seconds ago is directly passed to another function, a internal function called observations.observe. And this internal function is fed with more inputs. The

current time stamp, the current tick, and the current liquidity. Let's take a look at this function. Observations.observe. This function is located inside the Oracle library and here it is the function observe. What this function will do is for each second ago it will calculate the tick cumulative at that time and this is done by calling the function called observe single. Let's take a look at this function. Okay, here's the function observe single. When the seconds ago that is passed from the input is equal to zero. Then this means that it's trying to get the current to cumulative. And there are two cases. If the block timestamp for the latest observation is not equal to the current time, then it calls another internal

function called transform that will transform the last observation accounting for the current time and the last time this observation was updated. The simple case is when this block timestamp for the last observation is equal to the current time. In this case, it would just simply return the take cumulative and another data that is stored inside the observation called seconds per liquidity cumulative x128. Let's slide track and take a look at the function called transform. Remember that tick cumulative is the summation of the tick for each second. However, there's no guarantee that an observation was made for each second. So to calculate the tick cumulative for each second, what we need to do is take the last tick cumulative and then multiply this by the

duration of how long this current tick was at the current tick. And this is done by taking the difference between the current time stamp and the last time an observation was made. This is called a delta. And we multiply this delta by the current tick. And this over here says that the current tick was at the current tick for this time interval called delta. and then we add this to the previous tick cumulative. This is how the tick cumulative up to the current block timestamp is approximated. Going back to the function observe single, we just cover the function transform and we also cover this part.

If the input for seconds ago is not equal to zero, then we move on to this part of the code. The target time stamp will be the current time minus seconds ago. And from this target time stamp it calls an internal function called get surrounding observations. Without looking at the details of how this function works, we can see that it returns two observation. Observation before or at this time and another observation at or after this time. Next, it compares the two observation that was returned with the target time. If one of the observation that was returned matches the time stamp, then it returns the tick cumulative for that time stamp.

If the target time stamp matches before at observation, then it returns the tick cumulative per before at. If the target time stamp matches the at or after time stamp, then it returns that tick cumulative. If neither of the two conditions are true, then we move on to this else block. Inside here, we know that the target time stamp is in between the two observations before, at and at, or after. What this code inside here will do is draw a line between the two observations of before at tick cumulative and after or at tick cumulative. And then over here it does a linear approximation of the tick cumulative between the two tick cumulatives at before at and after or

at. If the target time is closer to the observation at at or after, then this linear approximation will be close to the tick cumulative at at or after. On the other hand, if the target time stamp is closer to the observation at before or at, then this code will return a tick cumulative that is closer to before or at. Okay, so that's the function observe single. So we covered the library called Oracle.so. This is a library that handles writing observations and fetching observations. But to actually implement a tap, I want to show you another contract called Oracle Library.

Looking at this code will give you some hints on how to write a T-w price oracle. This contract is located under BT periphery libraries and the name of the contract is called Oracle library. Okay, there are two functions that I want to explain. The first function is called consult. One of the things that this function will do is return the average tick over some time duration. And this is called arithmetic mean tick. For the input, it's going to take in the pool and a number called seconds. seconds ago. Seconds ago from the current time and using this input seconds ago, it's going to initialize a array of unit 32 where the first element will be the seconds ago and the next element will be zero 0 seconds ago from

now. Next, it will call the function observe on the pull contract. Remember that this observe function returns the tick cumulatives for the seconds ago that were requested. And once we had the two tick cumulatives, one for the current time and one for the seconds ago, remember from the math video, we now know how to calculate the average tick over that time duration. And we can see this code over here. The tick cumulative delta is calculated by taking the difference of the two tick cumulatives. The tick cumulative stored at index one. This will be the tick cumulative from 0 seconds ago. And the other one is tick cumulatives at index zero. And this will be the tick cumulative from seconds ago. And to calculate the average tick inside this

code, it is called the arithmetic mean tick. You take this tick cumulative delta and then divide it by the seconds ago. Now once we have this arithmetic mean tick. We need to call another function to calculate the time weighted average price of a token. And this is done by calling a function called get quote at tick. The function get quote at tick will calculate the amount of token out given a tick and amount of token in. Here think about this base amount as amount of token in base token will be token in and quote token will be token out. Given these three inputs it will calculate the amount of token out. Later we'll use this function in the exercises and for the tick we'll pass in the time

weighted average tick. From this tick they will calculate the square root ratio x96 and then there are two cases to calculate the amount of token out. Basically they do the same thing except that for better precision the code is split into two parts and this depends whether this square root ratio x96 is going to overflow or not. We'll look at the case for when this square root ratio x96 does not overflow. In this case, we first multiply the square root ratio x96 by itself to get ratio x1 92. Remember that this x96 means that this square root ratio is multiplied by a factor of 2 to the 96. We have two of these. So the resulting number will have 2 to the

192 and this will give us the ratio. In other words, first we have square root of p. This is multiplied by 2 to the 96. And we have two of these. And the result of multiplying<unk> of p * 2 96 by<unk> of p * 2 96 is we have a square root of p *<unk> of p. So over here we'll get the p which represents the price. And then we also have 26 * 2 to the 96. So this will result in 2 to the 96. So this is what this part of the code is doing.

The resulting number is the price P multiplied by 2 to the 1 196. Next, this ratio X192 is either multiplied by the amount of token that's coming in or 1 over that ratio is multiplied by the amount of token that is coming in. And the way to understand it is remember that P we said that is equal to the ratio of token Y over token X. And also note that in unisoft B3 tokens are ordered. So we will have token X is less than token Y. This is done by comparing the addresses of the tokens. If this base token is less than quote token, this means that this base amount refers to token X. So we multiply P by some amount of token X. Let's call this

lowerase X. And we will get the amount of token Y. For example, let's say that token Y is USDC and token X is W. And let's also say that P is equal to 3,000 USDC per 1 ETH. And let's also say that amount of token next X is equal to 1. So when we do P * X, this is saying 3,00 USDC over 1 E* 1. If we were to put in 1 E, what is the equivalent amount in USDC? And this would give us 3,000 USDC.

Okay, moving on. If base token is greater than quote token, then we know that this base token refers to token Y. Since token X is always less than token Y. In this case, to calculate the amount of token X that will come out, what we'll need to do is 1 / P * the amount of token Y. And this is equal to P is equal to the ratio of Y / X. So 1 / P will be the ratio X / Y. And to this we multiply some amount of token Y and this will give us the amount of token X.

Again for example let's use this example. Token Y is USDC. Token X is W. And the current price P is 3,000 USDC per one E. So what we need to do is do 1 / P. So this will be 1 E over 3,000 USDC. Since Y is USDC, let's say per Y, we do 6,000 USDC. 6,000 USDC. And what do we get? If we do this math, we get that this is equal to 2 E. And what this tells us is that when the price of one E is 3,000 USDC and we put in 6,000 USDC, we'll get back two E. Now, note that instead of just multiplying and dividing

these numbers, it's calling another library called mold div. What this function can do is multiply two un 256 and then divide by another un 256 without overflowing the first multiplication. In the first case, we multiply ratio x192 which is equal to the ratio p * 2 to the 1 196. Multiply this by the amount of token that's coming in and then afterwards it still has this extra 2 to the 96. So we'll need to divide by 2 to the 196 to remove this. And this is done by bit shifting one by 192. This is equivalent to 2 to the 196. And likewise in the other case we need to multiply by 1 / p by the

amount of token that's coming in. We have the amount of token that's coming in and we also have this base 2 to the 192 multiplied by the base amount and then divide by the ratio P which has a 2 to the 196. And this 2 to the 196 will be cancelled out with this 2 to the 196. And that completes the code walk through for the function get quote epic. In this exercise, you will create a T-w using unis swap b3. The pull contract and token zero and token one are all initialized inside the constructor. And in this exercise later, you'll need to call this function get quote at tick to calculate the amount of token out based on the amount of token in. And the exercise is over here. All of the tasks are inside the function get tap amount

out. For the input, it's going to take in token in amount in and the time interval to take the T-w. And this function should return the amount of token out calculated from the T-w and amount in. For the first task, check that token in is either token zero or token one. And again, this token zero and token one are initialized inside the constructor. Once you check that token in is token zero or token one. Next, figure out what token out is. Next, a dynamic array of type in 32 is initialized. This will store two elements. For the element at index zero, put in dt. This comes from the input.

And for the element at index one, put in zero. This dynamic array will be passed to the function pool. To get the tick cumulatives. Now, if you need a refresher on how to call observe on the pool contract, you can scroll up and then navigate to this interface. And inside the interface of the I unisoft B3 pool you can see how to call the function observe. Okay going back to our TWOP contract once you get two observations one for from 0 seconds ago and another from dt seconds ago. Next you need to calculate the tick cumulative delta. This is calculated by taking the difference of the tick cumitive at zero minus the tick cumulative at dt. After that the next task is to calculate the average tick.

Remember that after we calculate tick cumulative delta, we divide this by dt to calculate the average tick. And the next part of the code handles a logic for rounding down numbers. This works both for positive number and for negative number. Here what it's saying is that if tick cumitive delta is less than zero and if it does not divide evenly by dt then round down to negative infinity by doing tick minus minus. And the last task is to call the function get quote at tick to return the amount of token out that will come out for amount of token in. Okay, let's go over the solutions. Let's start with the first task. The first task is to require that token in is either token zero or token one. I'll type require token n is

equal to token zero or token in is equal to token one. And with the error message, I'll just say in valid token. Okay, moving on to task two. Assign token out. So at this stage, we know that token in is either token zero or token one. So how do we figure out what token out is? So this is equal to we can say if token in is equal to token zero, then we know that token out should be token one. Otherwise token in is token one. So token out will be token zero.

Okay, let's move on to the next task. The next task is to fill out time deltas with dt and zero. So say time deltas of zero is dt and then time deltas of 1 is equal to zero. Okay, the next task is to call pool.observe. How do we call this function? I'm going to navigate to the interface for unis bull contract and look at how to call this function observe. So to call this function we pass in a dynamic array of type32 and then we'll get back two dynamic arrays. We're only interested in the first dynamic array that is returned. So say pool dot observe and

then pass in this time deltas. And it's going to return two outputs. But we're only interested in the first output. So we'll ignore the second output. The output type for the first output is a dynamic array int 56. So here I'll type in 56 memory. I'll call it tick cumulatives. So that's task four. Let's move on to task number five. Calculate tick cumulative delta. This is equal to the latest tick cumulative is stored in tick cumulatives of zero. And this is because when we call the function observe, we passed in a time delta and the element at the first index tells unisaw B3 to get the tick cumitive from 0 seconds ago. Say tick cumatives at 1

minus tick cumulatives at zero. Tick cumatives of zero will correspond to a tick cumitive from dt seconds ago. Okay, the next task is to calculate the average tick. Now notice that we have several data types. For tick cumulative it's int 56 and for dt what's dt dt is unintent 32. So we need to cast both of these data types into int 24. To calculate the average tick we'll need to take tick cumulative delta and then divide this by dt. So type take cumitive delta divide by dt. Now dt is 32 and tick cumulative delta is int 56. So let's first cast dt into int 56 so that

we can do a division of int 56. So say int 56 cast dt into int 56. But before we can do this we first need to cast this into u int 56. Okay. So now this division works and this data type is int 56. We need to cast this into int24. So say int 24. Okay that's task number six. Task number seven is to call the function get quote at tick. And how do we call this function? We pass in tick amount of token in and the token in and then token out. Okay. So say return get quote that tick pass in the tick. This will be the average tick and then amount

in amount in token in token in and token out. Okay, that completes this exercise. Let's try compiling the contract and then running the test. Okay, I'll try to compile the contract by typing forge build. Okay, so there was an error, there was a typo. Change this to get code tactic. Try compiling again. Okay, and our contract compiles. Let's now execute the test. I'll first set the environment variable for the fork URL. And then we'll execute the test by typing forge test dash fork url fork url matchpath test unis swap b3 unis swap b3

twap.ests soul and then bb. Okay. And our test passed. Let's take a look at the test. The test contracts creates a tap contract for the unisaw b3 pool for USDC with with 0.0. 05% swap fee and then it simply calculates the price of W in terms of USDC for token and we pass in W and amount we pass in one W the T-w is taken over 3,600 seconds this is 1 hour and then it prints out the amount of USDC that we'll get back inside our terminal we can see that the time weighted average price of W over the period of 1 hour is roughly 3,000 USDC in this video I'll explain about just in time

liquidity in UNISOB D3 Let's say that Alice is a liquidity provider and her position is in the current price. I've highlighted this in purple. Next, Bob swaps tokens. This will move the price from P 0 to P1. From this trade, Alice earns on swap fees and she is happy. This is how normally a liquidity provider will earn some fees. Next, let's take a look at how just in time liquidity will change how the liquidity providers earn fees. Again, we'll say that Ellis is a liquidity provider and her position is in the current price. And again, Bob submits a transaction to swap tokens. Here is where things get different from the first example. Here, Justin sees Bob's transaction in the mele and then front

runs Bob's transaction to add liquidity. Let's say that this is a transaction mele and inside it there are some pending transactions. Inside here, Bob submits his transaction to swap tokens. Justin sees that Bob has submitted a transaction to swap tokens and then he submits a transaction to add liquidity. He makes sure that his gas price is higher than Bob's transaction so that his transaction to add liquidity comes before Bob's transaction to swap tokens. Justin's transaction to add liquidity is processed and then next Bob's transaction to trade tokens is processed. Let's say that this will move the price from P 0 to P star 1. Let's take a look at what this looks like on a graph. Before Bob submits his

transaction, the current price, let's say, is at P 0. Justin sees that Bob submitted his transaction and then front runs Bob's transaction. Let's say Justin has a lot of liquidity to a narrow price range, including the current price. This is shown in red. Let's compare the liquidity provided by Alice near the current price and how much Justin has provided. Close to the current price P 0, Alice has provided about this much liquidity. Whereas in the same price range, Justin provided this much liquidity, a lot more than Alice. So what this means is that when a trade executes between this price range, Justin will earn the majority of the fees. Bob's trade is processed and the price moves from P 0 to P star 1. Take a

note here that the price change from P 0 to P star 1 is less than the price change from P 0 to P1. Here there is less liquidity, so the price moves a lot. Whereas over here there is a lot of liquidity around the current price range. So the price moves very little. This is called just in time liquidity. Justin sees that Bob has submitted a transaction to do a trade and front runs the transaction to add liquidity so that he can earn a lot of the trading fees. With just in time liquidity, Alice earns very little fees. So this is not good news for Alice. On the other hand, Justin earned most of the fees. So he is happy. How about Bob? Well, Bob got a great price for his trade, so he is also

happy. Well, why can we say that Bob got a great price? This is because when there is more liquidity, there's less price change. To put this in math, P star 1 minus P 0. The price change from P 0 to P star 1 when Justin liquidity is less than P1 minus P 0. This is the price change when Bob traded on this liquidity without just in time liquidity. So in summary, just in time liquidity is bad news for Alice, good news for Justin, and also good news for the trader Bob. In a constant product AMM, higher liquidity means less price impact. And for a trader, less price impact means they'll get more token out for the token

that they put in. In this video, I'll illustrate this example that higher liquidity means lower price impact. In this example, we'll compare to constant product AMM. The constant product AMM on the right has a higher liquidity than the one on the left. We'll put in the same amount of tokens and then compare several things. We'll compare the final price, the amount of tokens that we get, and the execution price. So, we have two constant product AMMs. X * Y = L² where this L² is equal to 20. And we have another constant product AMM X * Y= L² where L is equal to 50. over here the one on the right has a higher liquidity on the two constant product AMMs that we're comparing let's say that we

initially start with the price equal to one and in both cases we'll put in 20 token X for the constant product AMM with a lower liquidity when we put in 20 of token X we get back 10 token Y the resulting price after the swap is 0.25 25. Initially, we started out with price equal to one. And for putting in 20 tokens and swapping out with 10 token Y, the price will become 0.25. If we were to swap this same amount of token on a constant product curve with higher liquidity, again, we put in 20 token X and this time we get approximately 14 token Y. Again, we started out with price equal to 1 and after the swap, the price is approximately 0.51. Okay, let's

compare the numbers. On a constant product with lower liquidity, we put in 20 token and got back out 10 token. On the constant product curve for higher liquidity, we put in the same exact amount of token, 20 token X. And this time we got approximately 14 token Y. So first thing to notice is that when we swap on the constant product curve with higher liquidity, we get more token out. Here we get approximately 14, but one with the lower liquidity, we get 10 token out. The other thing to notice is that the price after the swap on the low liquidity, it changed the price from 1 to 0.25. The difference is 0.75. On the curve with a higher liquidity, we started out with price equal to 1 and

the resulting price is approximately 0.51. In this case, the price difference is approximately 0.49. 0.75 over here and 0.49 over here. So in a constant product curve, higher liquidity means less price impact. And the amount of token that you'll get for putting in the same amount of token is greater for a constant product curve with higher liquidity. Let's also compare the execution price. The execution price is simply the amount of token that came out divided by the amount of token that came in. In other words, it is the exchange rate for putting in one of these tokens. The execution price on the constant power curve with a lower liquidity is 0.5. 10 / 20 is 0.5. On the curve with a higher

liquidity, the execution price is approximately 0.71. Again, we divide dy by dx to get this price. What the execution price tells us is the exchange rate for one of these tokens for one of these tokens. For putting in one of token x, we'll get back 0.5 amount of token y. On the other hand, when we swapped on the constant product curve with higher liquidity, for each token X, we get back roughly 0.71 token Y. If you're a trader, would you rather get 0.5 token Y for putting in one token X, or is it a better deal if for every token X that you put in, you get back 0.71 token Y? Here, the better deal is the one with the higher execution price,

swapping on the curve with a higher liquidity. So this is how when we swap on a constant product curve with a higher liquidity, we get a better deal for our swap and there's less price impact. And finally, if we increase the liquidity to a higher number, you can see that the execution price increases. So this means that it is even a better deal to swap on and the price impact becomes less.