Skip to content

Assignment 2

takundachirema edited this page Apr 24, 2025 · 7 revisions

In this assignment we'll go through some simple interactions with the Uniswap V3 smart contracts. It'll give you a basic understanding of a DEX, Liquidity Pools and Automated Market Makers. The

Uniswap V3 Smart Contracts

Uniswap V3 smart contracts are divided into 2 repositories; Core smart contracts and Periphery smart contracts.

Core

  • UniswapV3Factory: provide the interface for pool creation and tracking.
  • UniswapV3Pool: provide the core functionalities, like swap, mint, burn.

Periphery

  • SwapRouter: provide the interface for token trade.
  • NonfungiblePositionManager: provide functionalities of adding/ removing/ modifying pool’s liquidity, and tokenize liquidity through NFT

Liquidity Custodian

In this assignement we have a contract called LiquidityCustodian. This smart contract acts like a Liquidity Locker although we are not doing any locking for this assignment. The contract will simply hold the token that represents the Liquidity Providers' liquidity. It can be extended to be a liquidity locking smart contract. The LiquidityCustodian smart contract is going to have logic for:

  1. Creating a liquidity pool for our MC/WETH token
  2. Mint or create liquidity for the liquidity pool
  3. Removing custody of the liquidity token and giving it back to the owner

Setup

To avoid the complexities in deploying the Uniswap V3 smart contracts locally, we will use a uniwap local deployment repository created specifically for that.

  1. On your terminal, navigate to a directory/folder of your choice using cd example/directory and run the following git command in your terminal:
git clone https://github.com/FinHubSA/hardhat-uniswapV3-deploy.git
  1. Navigate into the hardhat-uniswapV3-deploy then run the command npm install to install the nodejs libraries
cd hardhat-uniswapV3-deploy
npm install

This command will:

  1. Now you will be able to deploy Uniswap V3 smart contracts on your local hardhat network which we will do in the assignment.

Assignment

We'll use the uniswap-pool branch for Part 2 of the assignment.

NOTE: We are using an earlier version of solidity and OpenZeppelin libraries. This is because we are using the @uniswap/v3-core and @uniswap/v3-periphery libraries (check packages/hardhat/package.json). These libraries require a lower version of OpenZeppelin and Solidity. We could have made our own interfaces for the Uniswap smart contracts we interact with and used latest versions of Solidity and OpenZeppelin.

  1. First fetch the uniswap-pool branch from upstream and create a new local branch using the remote branch you fetched:
git fetch upstream uniswap-pool
git checkout -b uniswap-pool upstream/uniswap-pool
  1. Run yarn install to make sure all dependencies are installed
yarn install
  1. Start your local hardhat chain.
yarn chain
  1. Deploy the Uniswap smart contracts.
  • In a new VS code window, open up the hardhat-uniswapV3-deploy project from the setup step.
  • Open a terminal in VS code and run the command below:
npx hardhat deploy-uniswap

This command will deploy the uniswap smart contracts on your local chain. So make sure yarn chain is running in your project's VS code window i.e. the VS code project you are writing code in.

  1. After successfully going through step 4, the terminal will output the addresses of important Uniswap V3 smart contracts that you can interact with.
  • TODO: Copy the weth9, factory, router and positionManager addresses. Paste then in packages/hardhat/contracts/test/Assignment2.ts in the variables WETHTokenAddress, factoryAddress, swapRouterAddress and positionManagerAddress respectively
  1. Now in your project's VS code terminal, run the tests. The tests should all fail.
yarn test:local test/Assignment2.ts 
  1. We'll first fix the MemeCoin.sol smart contract
  • TODO: create a _totalSupply of 1000 tokens which have 18 decimal places

NOTE: ETH also has 18 decimal places for divisibility. The smallest unit is called Wei. All values in smart contracts are measured in the smallest units. This is true for tokens as well.

  • TODO: mint the _totalSupply of tokens to the owner
  1. We'll fix the LiquidityCustodian.sol smart contract
  • TODO: make the LiquidityCustodian contract an IERC721Receiver
  • TODO: create the onERC721Received function

NOTE: the function should create an NFT deposit for the sender of NFT to this smart contract

  1. We'll fix the _createDeposit method
  • TODO: get the details of the liquidity position from the uniswap NFT manager
  • TODO: create Deposit object using the detail above and store it in the deposits mapping

NOTE: the owner of the deposit is whoever has created the liquidity position through this contract or elsewhere and sent this contract their NFT

  • TODO: store the tokenId in the owners' token array that is in the liquidityTokens mapping
  1. We'll fix the createPool method
  • TODO: assign WETH and MC addresses to new variables token0_ and token1_ addresses

NOTE: for a uniswap pool token0 address should be strictly less than token1 by sort order.

  • TODO: create a liquidity pool of WETH and MC token using the uniswap factory
  • TODO: assign the liquidityPoolAddress
  • TODO: get the square of the price using at the _poolTick TickMath library from Uniswap

NOTE: sqrtPriceX96 is a A Fixed point number representing the square root of the ratio of the two assets (token1/token0)

  • TODO: initialize the liquidity pool with the sqrtPriceX96
  • TODO: emit the PoolCreate event
  1. We'll fix the mintNewPosition method
  • TODO: transfer the token0, amount0ToMint, from the msg.sender to this contract
  • TODO: transfer the token1, amount1ToMint, from the msg.sender to this contract
  • TODO: approve the uniswap position manager to transfer amount0ToMint of token0
  • TODO: approve the uniswap position manager to transfer amount1ToMint of token1
  • TODO: mint the liquidity position in the uniswap position manager using the params above

NOTE: this returns the tokenId of the minted NFT that represents the liquidity position

  • TODO: create the deposit record for the minter/msg.sender
  1. We'll complete the _deleteLiquidityToken method
  • TODO: complete the functions _deleteLiquidityToken

NOTE: we implemented a similar method during tutorials

  1. Run the tests. They should all pass.
yarn test test/Assignment2.ts 

Clone this wiki locally