Marketplace has launched, further enabling blockchain developers! Learn more

How to Swap Tokens on Uniswap with Ethers.js

October 25, 2022

Overview

Not all users interact via the front-end UI when trading tokens on a decentralized exchange. Some users (or entities) trade programmatically via a smart contract or server-side scripts. This guide will demonstrate how to swap tokens on Uniswap using Javascript and the Ethers.js library. Our technical demonstration will include a code walk-through and an example of a token swap from ETH to DAI on the Rinkeby test-net.

Prerequisites:

What's Uniswap?

Uniswap is one of the leading decentralized exchanges (DEX) that uses an automated market maker (AMM) design to facilitate trading. Since the inception of V1 in 2018, Uniswap has continued to push the limits in DeFi. The latest production version is V3, which uses a robust liquidity design allowing LPs more efficiency of their capital while providing variable fee structures across different pairs. The Uniswap protocol was initially deployed on Ethereum but is now serving many chains such as Polygon, Arbitrum, and Optimism.

Uniswap's V2 version is what we will be covering today. Although it's not the latest tech compared to V3, it's still relevant as many DeFi protocols use the same AMM architecture; therefore, what we build today should be operable with other DeFi projects that clone the Uniswap codebase (such as QuickSwap).

Uniswap for Developers

Uniswap has its V2 contracts categorized into two repositories, Core & Periphery. Uniswap also offers a helpful SDK for developing on and interacting with its protocol. The core contracts cover creating pairs (pools) and maintaining track of balances, while the periphery helps us interact with these core contracts. If you want an overview or want to learn how to fetch the market price of a token, check out one of our earlier guides - How to Interact with Uniswap using Javascript.

Uniswap Router
This section will explain our interaction with the Router contract a bit more. Before any swap method can successfully be called, the trader must first approve the router to N amount of tokens they wish to swap. It's common for protocols to request an infinite approval amount (to lower transaction costs); however, this is not required, and you can approve only a specific amount if needed. An approve() function looks like this:

uniswap for developers

Copy
function approve(address usr, uint wad) external returns (bool) {
    allowance[msg.sender][usr] = wad;
    emit Approval(msg.sender, usr, wad);
    return true;
}

Swapping tokens on Uniswap consists of using one of several swap methods in the Router smart contract. The methods used most often are swapExactETHForTokens and swapExactTokensForTokens. Each of these methods has different use cases.

  • swapExactETHForTokens: This function is used when you want to swap an exact amount of ETH for as many output tokens as possible along the route determined by the path. Note that this function wraps your ETH to WETH.

uniswap for developers

Copy
function swapExactETHForTokens(
  uint amountOutMin, // The minimum amount of output tokens that must be received for the transaction not to revert
  address[] calldata path, //An array of token addresses
  address to, // Destination address
  uint deadline) // Unix timestamp after which the transaction will revert
  external payable returns (uint[] memory amounts); 

  • swapExactTokensForTokens: This function is used when you want to swap an exact amount of input tokens for as many output tokens as possible along the route determined by the path. The first path element is the input token, and the last is the output token.

uniswap for developers

Copy
function swapTokensForExactTokens(
  uint amountOut, // Given an input asset amount, returns the maximum output amount of the other asset
  uint amountInMax, // The maximum amount of input tokens that can be required before the transaction reverts
  address[] calldata path, // An array of token addresses
  address to, // Destination address
  uint deadline // Unix timestamp after which the transaction will revert
) external returns (uint[] memory amounts); //

For an in-depth description of each of the parameters for this function, check out the Uniswap V2 Reference Glossary.

Booting our Ethereum Node

Now that we're familiar with Uniswap and its swapping techniques, let us walk through swapping tokens programmatically. We will first need to set up a Rinkeby test node. While we could run our own node, here at QuickNode, we make it quick and easy to fire up blockchain nodes. You can register for a free trial, as well as see pricing here. Once you boot up a node, retrieve the HTTP URL. It should look like this:

Screenshot of Quicknode Rinkeby endpoint

Using Ethers.js to Swap Tokens

Keep in mind, if the token you want to swap has no liquidity, a pair with liquidity must be created before you can swap.

Time to get our swap on! We will be swapping ETH for DAI in our code example. Let us start by initiating our project. Open a terminal window and run the following commands to create your project directory:

mkdir swapTokensWithEthers && cd swapTokensWithEthers && mkdir abis && npm init -y

Then, run this command to create the required files:

touch .secret && touch index.js && touch ./abis/router.json

Installed required dependencies:

npm i ethers @uniswap/sdk

Before moving on to the next step, complete these three steps:

  1. Import your private key into the .secret file (to find out how, take a look at this guide).
  2. Navigate to the source code for the Router address on Etherscan and copy the ABI into your ./abis/router.json file (the ABI can be found on the Contract tab)
  3. Retrieve some test ETH on Rinkeby (Make sure you have your wallet configured to the Rinkeby test-net. You can get some free test ETH from this faucet.)

Now we'll cover the code needed to swap tokens programmatically. Open the swapTokensWithEthers directory within an editor of your choice and navigate to the index.js file. Add the following code snippets in order to complete the script.

Importing Dependencies
We will first need to add the necessary dependencies for our project. We'll import the ethers library to interact with the smart contract and the Uniswap SDK to fetch and create our swap structure. The fs and utils libraries will be helpful when reading or modifying data.

using ethers js to swap tokens

Copy
const { ethers } = require("ethers")
const UNISWAP = require("@uniswap/sdk")
const fs = require('fs');
const { Token, WETH, Fetcher, Route, Trade, TokenAmount, TradeType, Percent} = require("@uniswap/sdk");
const { getAddress } = require("ethers/lib/utils");

Configure Infra Provider
Using our QuickNode HTTP URL and Ethers, we will instantiate a Provider object representing our communication with the blockchain.

using ethers js to swap tokens

Copy
const QUICKNODE_HTTP_ENDPOINT = "YOUR_QUICKNODE_HTTP_URL"
let provider = new ethers.providers.getDefaultProvider(QUICKNODE_HTTP_ENDPOINT)

Import Wallet
To import the account we will use for swapping tokens, use the fs module to read from the .secret file and then instantiate a Wallet object using Ethers.

using ethers js to swap tokens

Copy
const privateKey = fs.readFileSync(".secret").toString().trim()
const wallet = new ethers.Wallet(privateKey, provider)

Instantiate Router Contract
Ethers has a Contract module we can use to instantiate instances of smart contracts. To create an instance of the Router contract, we will need to input a smart contract address, ABI and a Provider object.

using ethers js to swap tokens

Copy
UNISWAP_ROUTER_ADDRESS = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"
UNISWAP_ROUTER_ABI = fs.readFileSync("./abis/router.json").toString()
UNISWAP_ROUTER_CONTRACT = new ethers.Contract(UNISWAP_ROUTER_ADDRESS, UNISWAP_ROUTER_ABI, provider)

Import Token Data
To import token data, we will need to create an instance of the Token class and pass in required inputs such as a chain ID, smart contract address, and decimal places. Note that the contract address and decimal figures can vary depending on the token.

using ethers js to swap tokens

Copy
const DAI = new Token(
    UNISWAP.ChainId.RINKEBY,
    "0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa",
    18
);

We don't need to create a WETH instance since the SDK has a handy module we can use to return the WETH address on the Ethereum main-net, Ropsten, Rinkeby, Görli, or Kovan test-nets.

Swapping ETH for Tokens
Our core logic will lie in a swapTokens() function that will take both tokens as arguments and an amount to be swapped. Note the slippage amount is set to %0.50 by default. Refer to the comments throughout the function to understand what each line achieves.

using ethers js to swap tokens

Copy
async function swapTokens(token1, token2, amount, slippage = "50") {


    try {
        const pair = await Fetcher.fetchPairData(token1, token2, provider); //creating instances of a pair
        const route = await new Route([pair], token2); // a fully specified path from input token to output token
        let amountIn = ethers.utils.parseEther(amount.toString()); //helper function to convert ETH to Wei
        amountIn = amountIn.toString()
        
        const slippageTolerance = new Percent(slippage, "10000"); // 50 bips, or 0.50% - Slippage tolerance
    
        const trade = new Trade( //information necessary to create a swap transaction.
                route,
                new TokenAmount(token2, amountIn),
                TradeType.EXACT_INPUT
        );

        const amountOutMin = trade.minimumAmountOut(slippageTolerance).raw; // needs to be converted to e.g. hex
        const amountOutMinHex = ethers.BigNumber.from(amountOutMin.toString()).toHexString();
        const path = [token2.address, token1.address]; //An array of token addresses
        const to = wallet.address; // should be a checksummed recipient address
        const deadline = Math.floor(Date.now() / 1000) + 60 * 20; // 20 minutes from the current Unix time
        const value = trade.inputAmount.raw; // // needs to be converted to e.g. hex
        const valueHex = await ethers.BigNumber.from(value.toString()).toHexString(); //convert to hex string
    
        //Return a copy of transactionRequest, The default implementation calls checkTransaction and resolves to if it is an ENS name, adds gasPrice, nonce, gasLimit and chainId based on the related operations on Signer.
        const rawTxn = await UNISWAP_ROUTER_CONTRACT.populateTransaction.swapExactETHForTokens(amountOutMinHex, path, to, deadline, {
            value: valueHex
        })
    
        //Returns a Promise which resolves to the transaction.
        let sendTxn = (await wallet).sendTransaction(rawTxn)
        

        //Resolves to the TransactionReceipt once the transaction has been included in the chain for x confirms blocks.
        let reciept = (await sendTxn).wait()

        //Logs the information about the transaction it has been mined.
        if (reciept) {
            console.log(" - Transaction is mined - " + '\n' 
            + "Transaction Hash:", (await sendTxn).hash
            + '\n' + "Block Number: " 
            + (await reciept).blockNumber + '\n' 
            + "Navigate to https://rinkeby.etherscan.io/txn/" 
            + (await sendTxn).hash, "to see your transaction")
        } else {
            console.log("Error submitting transaction")
        }

    } catch(e) {
        console.log(e)
    }
}

Once we compile all the code together in our index.js file , we then need to call the function in order for our swap logic to execute. To do this, add the following line of code to the bottom of your script:

using ethers js to swap tokens

Copy
swapTokens(DAI, WETH[DAI.chainId], .02) //first argument = token we want, second = token we have, the amount we want

Save the file and run the command node index.js in a terminal window to execute the code. The terminal output should look like this:

Log of swap output

We can confirm the transaction was successful by looking up the hash in a block explorer:

Transaction Detail on Etherscan


If you want to conduct this swap on another chain such as Ethereum or Polygon, you will need to replace the token and router address as they can have different addresses across chains. You will also need access to a Node for each chain you want to swap on. Remember that each blockchain has its own native token used for paying transactions.

Conclusion

That concludes the guide for today. To recap, this guide briefly went over the mechanics of Uniswap V2 and demonstrated how to swap tokens with Javascript and the Ethers.js library. Subscribe to our newsletter for more articles and guides on Ethereum. Feel free to reach out to us via Twitter if you have any feedback. You can always chat with us on our Discord community server, featuring some of the coolest developers you'll ever meet :)

Related articles 9

What is DeFi?
Published: Aug 26, 2022
Updated: Sep 14, 2022

DeFi, a concept originally introduced in 2017, has led to the growth of over 500 cryptocurrency protocols and a combined asset value of over 50 billion dollars (

Continue reading
Interacting with 0x API using JavaScript
Published: Jul 23, 2021
Updated: Sep 9, 2022

We have seen tremendous growth in trade volume in DEXs. With many of these coming to the market, it is tough to decide which DEX to choose when you want to swap your token for another. That's...

Continue reading