How to Swap Tokens on Uniswap V3

Posted By : Suchit

May 31, 2024

In the fast-paced world of decentralized finance (DeFi), swapping tokens , as a part of cryptocurrency development, is essential for providing liquidity and allowing smooth asset exchanges between different platforms. Uniswap, a top decentralized exchange (DEX), has led the way with its innovative V3 version, offering advanced features and better efficiency. In this blog, we'll explore and develop a smart contract, which makes it easy to swap tokens on Uniswap V3 using the SwapRouter02 interface.

 

The UniswapV3Swap contract facilitates token swaps on the Uniswap V3 protocol. It allows users to perform single-token and multi-step swaps with exact input and output conditions. This contract integrates with Uniswap's SwapRouter and handles transfers and approvals of ERC20 tokens, specifically WETH, DAI, and USDC.

 

Check out | How to Develop Programmable Non-Fungible Tokens on Solana
 

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "https://github.com/Uniswap/swap-router-contracts/blob/main/contracts/interfaces/ISwapRouter02.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract UniswapV3Swap {

    address public SWAP_ROUTER_02;
    address public WETH;
    address public DAI;
    address public USDC;

    ISwapRouter02 private router = ISwapRouter02(SWAP_ROUTER_02);
    IERC20 private weth = IERC20(WETH);
    IERC20 private dai = IERC20(DAI);

    constructor(
        address _swapRouter,
        address _weth,
        address _dai,
        address _usdc
    ) {
        SWAP_ROUTER_02 = _swapRouter;
        WETH = _weth;
        DAI = _dai;
        USDC = _usdc;
    }

    function swapExactInputSingle(uint256 amountIn, uint256 amountOutMin)
        external
    {
        weth.transferFrom(msg.sender, address(this), amountIn);
        weth.approve(address(router), amountIn);

        ISwapRouter02.ExactInputSingleParams memory params = IV3SwapRouter
            .ExactInputSingleParams({
            tokenIn: WETH,
            tokenOut: DAI,
            fee: 3000,
            recipient: msg.sender,
            amountIn: amountIn,
            amountOutMinimum: amountOutMin,
            sqrtPriceLimitX96: 0
        });

        router.exactInputSingle(params);
    }

    function swapExactOutputSingle(uint256 amountOut, uint256 amountInMax)
        external
    {
        weth.transferFrom(msg.sender, address(this), amountInMax);
        weth.approve(address(router), amountInMax);

        ISwapRouter02.ExactOutputSingleParams memory params = IV3SwapRouter
            .ExactOutputSingleParams({
            tokenIn: WETH,
            tokenOut: DAI,
            fee: 3000,
            recipient: msg.sender,
            amountOut: amountOut,
            amountInMaximum: amountInMax,
            sqrtPriceLimitX96: 0
        });

        uint256 amountIn = router.exactOutputSingle(params);

        if (amountIn < amountInMax) {
            weth.approve(address(router), 0);
            weth.transfer(msg.sender, amountInMax - amountIn);
        }
    }

    function swapExactInputMultiStep(uint256 amountIn, uint256 amountOutMin)
        external
    {
        weth.transferFrom(msg.sender, address(this), amountIn);
        weth.approve(address(router), amountIn);

        bytes memory path =
            abi.encodePacked(WETH, uint24(3000), USDC, uint24(100), DAI);

        ISwapRouter02.ExactInputParams memory params = IV3SwapRouter
            .ExactInputParams({
            path: path,
            recipient: msg.sender,
            amountIn: amountIn,
            amountOutMinimum: amountOutMin
        });

        router.exactInput(params);
    }

    function swapExactOutputMultiStep(uint256 amountOut, uint256 amountInMax)
        external
    {
        weth.transferFrom(msg.sender, address(this), amountInMax);
        weth.approve(address(router), amountInMax);

        bytes memory path =
            abi.encodePacked(DAI, uint24(100), USDC, uint24(3000), WETH);

        ISwapRouter02.ExactOutputParams memory params = IV3SwapRouter
            .ExactOutputParams({
            path: path,
            recipient: msg.sender,
            amountOut: amountOut,
            amountInMaximum: amountInMax
        });

        uint256 amountIn = router.exactOutput(params);

        if (amountIn < amountInMax) {
            weth.approve(address(router), 0);
            weth.transfer(msg.sender, amountInMax - amountIn);
        }
    }
}

Variables

Constant Addresses

 

  • SWAP_ROUTER_02: The address of Uniswap V3's SwapRouter02 contract.
  • WETH: The address of the Wrapped Ether (WETH) ERC20 token.
  • DAI: The address of the DAI stablecoin ERC20 token.
  • USDC: The address of the USDC stablecoin ERC20 token.

     

Interfaces

 

  • router: An instance of the ISwapRouter02 interface used to interact with the Uniswap V3 SwapRouter.
  • weth: An instance of the IERC20 interface representing the WETH token.
  • dai: An instance of the IERC20 interface representing the DAI token.

     

Functions

 

swapExactInputSingle

Swaps an exact amount of WETH for DAI, ensuring at least a minimum amount of DAI is received. It transfers the specified amount of WETH from the sender to the contract, approves the router to spend that amount, sets up the swap parameters, and executes the swap using the router's exactInputSingle method.

swapExactOutputSingle

Swaps WETH for an exact amount of DAI, ensuring no more than a maximum amount of WETH is spent. It transfers the maximum amount of WETH from the sender to the contract, approves the router to spend that amount, sets up the swap parameters, executes the swap using the router's exactOutputSingle method, and refunds any excess WETH to the sender.

swapExactInputMultiStep

Swaps an exact amount of WETH for DAI through a multi-step path (WETH -> USDC -> DAI). It transfers the specified amount of WETH from the sender to the contract, approves the router to spend that amount, constructs the multi-step path, sets up the swap parameters, and executes the swap using the router's exactInput method.

swapExactOutputMultiStep

Swaps WETH for an exact amount of DAI through a multi-step path (DAI -> USDC -> WETH), ensuring no more than a maximum amount of WETH is spent. It transfers the maximum amount of WETH from the sender to the contract, approves the router to spend that amount, constructs the multi-step path, sets up the swap parameters, executes the swap using the router's exactOutput method, and refunds any excess WETH to the sender.

Read Also | How to Create a Token Swap dApp

Conclusion

 

With the UniswapV3Swap smart contract, token swaps on Uniswap V3 become straightforward and efficient. By leveraging the SwapRouter02 interface, users can easily perform single-token and multi-step swaps, ensuring optimal outcomes with minimal effort. This contract handles ERC20 token transfers and approvals seamlessly, making it a valuable tool in the DeFi ecosystem. Contact our blockchain developers today!

Leave a

Comment

Name is required

Invalid Name

Comment is required

Recaptcha is required.

blog-detail

July 16, 2024 at 01:52 pm

Your comment is awaiting moderation.

By using this site, you allow our use of cookies. For more information on the cookies we use and how to delete or block them, please read our cookie notice.

Chat with Us
Contact Us

Oodles | Blockchain Development Company

Name is required

Please enter a valid Name

Please enter a valid Phone Number

Please remove URL from text