Swap tokens on Uniswap using a smart contract

Use a Solidity smart contract to swap tokens on Uniswap. Uniswap is a decentralized exchange running on the Ethereum blockchain. It is a set of Solidity smart contracts that work together to create an automated market marker environment that requires no human intervention. Automated market maker exchanges allow digital assets to be traded without permission and automatically. They use liquidity pools instead of a traditional order book of buyers and sellers. 

Since Uniswap is a set of smart contracts you can integrate with it by creating your own application using Web3 or your own Solidity smart contract. The Solidity smart contract code below will facilitate swapping two tokens on Uniswap. It will allow you to swap your tokens through WETH or not through WETH. A lot of times you can get a better price swapping from Token A -> WETH -> Token B rather then Token A -> Token B.

uniswap token swap route

Create swap contract

To swap tokens on Uniswap using a smart contract copy the code below. Create the contract and deploy it to the blockchain then pass it the required parameters and it will perform a token swap. After you deploy the contract you can use Remix or Etherscan to perform a swap or build a simple program in web3.py.

This contract called tokenSwap and contains two functions getAmountOutMin and swap. First call getAmountOutMin to get the minimum amount of tokens you will receive if you performed the swap Then call the swap function in the contract and pass in AmountOutMin as one of the parameters. Read the detailed comments in the code to get a better understanding of what the contract does.

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


//import the ERC20 interface

interface IERC20 {
    function totalSupply() external view returns (uint);
    function balanceOf(address account) external view returns (uint);
    function transfer(address recipient, uint amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint);
    function approve(address spender, uint amount) external returns (bool);
    function transferFrom(
        address sender,
        address recipient,
        uint amount
    ) external returns (bool);
    event Transfer(address indexed from, address indexed to, uint value);
    event Approval(address indexed owner, address indexed spender, uint value);
}


//import the uniswap router
//the contract needs to use swapExactTokensForTokens
//this will allow us to import swapExactTokensForTokens into our contract

interface IUniswapV2Router {
  function getAmountsOut(uint256 amountIn, address[] memory path)
    external
    view
    returns (uint256[] memory amounts);
  
  function swapExactTokensForTokens(
  
    //amount of tokens we are sending in
    uint256 amountIn,
    //the minimum amount of tokens we want out of the trade
    uint256 amountOutMin,
    //list of token addresses we are going to trade in.  this is necessary to calculate amounts
    address[] calldata path,
    //this is the address we are going to send the output tokens to
    address to,
    //the last time that the trade is valid for
    uint256 deadline
  ) external returns (uint256[] memory amounts);
}

interface IUniswapV2Pair {
  function token0() external view returns (address);
  function token1() external view returns (address);
  function swap(
    uint256 amount0Out,
    uint256 amount1Out,
    address to,
    bytes calldata data
  ) external;
}

interface IUniswapV2Factory {
  function getPair(address token0, address token1) external returns (address);
}



contract tokenSwap {
    
    //address of the uniswap v2 router
    address private constant UNISWAP_V2_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
    
    //address of WETH token.  This is needed because some times it is better to trade through WETH.  
    //you might get a better price using WETH.  
    //example trading from token A to WETH then WETH to token B might result in a better price
    address private constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
    

    //this swap function is used to trade from one token to another
    //the inputs are self explainatory
    //token in = the token address you want to trade out of
    //token out = the token address you want as the output of this trade
    //amount in = the amount of tokens you are sending in
    //amount out Min = the minimum amount of tokens you want out of the trade
    //to = the address you want the tokens to be sent to
    
   function swap(address _tokenIn, address _tokenOut, uint256 _amountIn, uint256 _amountOutMin, address _to) external {
      
    //first we need to transfer the amount in tokens from the msg.sender to this contract
    //this contract will have the amount of in tokens
    IERC20(_tokenIn).transferFrom(msg.sender, address(this), _amountIn);
    
    //next we need to allow the uniswapv2 router to spend the token we just sent to this contract
    //by calling IERC20 approve you allow the uniswap contract to spend the tokens in this contract 
    IERC20(_tokenIn).approve(UNISWAP_V2_ROUTER, _amountIn);

    //path is an array of addresses.
    //this path array will have 3 addresses [tokenIn, WETH, tokenOut]
    //the if statement below takes into account if token in or token out is WETH.  then the path is only 2 addresses
    address[] memory path;
    if (_tokenIn == WETH || _tokenOut == WETH) {
      path = new address[](2);
      path[0] = _tokenIn;
      path[1] = _tokenOut;
    } else {
      path = new address[](3);
      path[0] = _tokenIn;
      path[1] = WETH;
      path[2] = _tokenOut;
    }
        //then we will call swapExactTokensForTokens
        //for the deadline we will pass in block.timestamp
        //the deadline is the latest time the trade is valid for
        IUniswapV2Router(UNISWAP_V2_ROUTER).swapExactTokensForTokens(_amountIn, _amountOutMin, path, _to, block.timestamp);
    }
    
       //this function will return the minimum amount from a swap
       //input the 3 parameters below and it will return the minimum amount out
       //this is needed for the swap function above
     function getAmountOutMin(address _tokenIn, address _tokenOut, uint256 _amountIn) external view returns (uint256) {

       //path is an array of addresses.
       //this path array will have 3 addresses [tokenIn, WETH, tokenOut]
       //the if statement below takes into account if token in or token out is WETH.  then the path is only 2 addresses
        address[] memory path;
        if (_tokenIn == WETH || _tokenOut == WETH) {
            path = new address[](2);
            path[0] = _tokenIn;
            path[1] = _tokenOut;
        } else {
            path = new address[](3);
            path[0] = _tokenIn;
            path[1] = WETH;
            path[2] = _tokenOut;
        }
        
        uint256[] memory amountOutMins = IUniswapV2Router(UNISWAP_V2_ROUTER).getAmountsOut(_amountIn, path);
        return amountOutMins[path.length -1];  
    }  
}

Try it in Remix

This contract can be modified to support swapping tokens on other Uniswap clones on the Ethereum blockchain, the Binance Smart Chain, Polygon, etc. Binance Smart Chain, Polygon, Ubiq, CheapEth, etc. are all copies of Ethereum (any EVM compatible blockchain).

  • Uniswap – Ethereum
  • Mooniswap – Ethereum
  • 1Inch Exchange – Ethereum
  • Sushiswap – Ethereum
  • Sashimiswap – Ethereum
  • Binance Smart Chain Pancake Swap
  • CheapEth CheapSwap
  • Ubiq Shinobi
  • Polygon SwapMatic

To make this contract work in other environments you will need to:

  • Change the router address for the Uniswap clone
  • Change WETH (if necessary) for the equivalent tokens on the other blockchains

This code is for learning and entertainment purposes only. The code has not been audited and use at your own risk. Remember smart contracts are experimental and could contain bugs.

Click here for more information about how to use the Ethereum test network and how to obtain test ETH.

Resources

Blockchain Networks

Below is a list of EVM compatible Mainnet and Testnet blockchain networks. Each link contains network configuration, links to multiple faucets for test ETH and tokens, bridge details, and technical resources for each blockchain. Basically everything you need to test and deploy smart contracts or decentralized applications on each chain. For a list of popular Ethereum forums and chat applications click here.

Ethereum test network configuration and test ETH faucet information
Optimistic Ethereum Mainnet and Testnet configuration, bridge details, etc.
Polygon network Mainnet and Testnet configuration, faucets for test MATIC tokens, bridge details, etc.
Binance Smart Chain Mainnet and Testnet configuration, faucets for test BNB tokens, bridge details, etc.
Fanton networt Mainnet and Testnet configuration, faucets for test FTM tokens, bridge details, etc.
Kucoin Chain Mainnet and Testnet configuration, faucets for test KCS tokens, bridge details, etc.

Web3 Software Libraries

You can use the following libraries to interact with an EVM compatible blockchain.

Nodes

Learn how to run a Geth node. Read getting started with Geth to run an Ethereum node.

Fix a transaction

How to fix a pending transaction stuck on Ethereum or EVM compatible chain

Next Review – Create a Defi Bank that pays interest (Yield Farm)

Ledger Nano X - The secure hardware wallet

1 thought on “Swap tokens on Uniswap using a smart contract

Leave a Reply