Skip to content

Deploy Uniswap V2 Periphery with EVM

Introduction

The Uniswap V2 Periphery contracts provide the Router layer that sits on top of the Uniswap V2 Core Factory and Pair contracts. While V2 Core handles the low-level AMM logic, the Periphery Router contracts expose the user-facing functions for adding liquidity, removing liquidity, and executing token swaps safely with built-in deadline and slippage protection.

This tutorial follows the EVM execution path. With EVM (powered by REVM, a Rust implementation of the Ethereum Virtual Machine), you deploy the same unmodified Solidity contracts using the same standard Hardhat toolchain you already know. No special compiler plugins, no contract rewrites, and no porting effort. If your project compiles with vanilla Hardhat, it runs on Polkadot Hub through EVM.

This tutorial walks you through cloning, compiling, testing, and deploying the Uniswap V2 Periphery contracts on Polkadot Hub using Hardhat and TypeScript. By the end, you will have a fully functioning WETH contract, Factory, Router02, two ERC-20 test tokens, and a trading pair deployed to the Polkadot Hub TestNet.

Prerequisites

Before starting, make sure you have:

  • Node.js v22.0.0 or later and npm installed
  • Basic understanding of Solidity and TypeScript
  • Familiarity with the Hardhat development environment
  • Some test tokens to cover transaction fees, obtained from the Polkadot faucet. See Get Test Tokens for a guide to using the faucet
  • A wallet with a private key for signing transactions
  • Basic understanding of how AMMs and liquidity pools work
  • Completion of the Uniswap V2 Core tutorial, as the Periphery contracts depend on V2 Core

Set Up the Project

Start by cloning the Hardhat examples repository, which contains the Uniswap V2 Periphery project with a standard Hardhat and TypeScript configuration:

  1. Clone the repository and navigate to the Uniswap V2 Periphery project:

    git clone https://github.com/polkadot-developers/revm-hardhat-examples.git
    cd revm-hardhat-examples
    git checkout a871364c8f4da052855b5c8ee4ed6b89fd182cb1
    cd uniswap-v2-periphery-hardhat/
    
  2. Install the required dependencies:

    npm install
    

    Note

    The Periphery project depends on the V2 Core contracts through a local file reference ("@uniswap/v2-core": "file:../uniswap-v2-core-hardhat"). The npm install command resolves this automatically from the sibling directory in the repository.

  3. Compile the contracts:

    npx hardhat compile
    

    If the compilation is successful, you should see output similar to the following:

    npx hardhat compile Downloading solc 0.5.16 Downloading solc 0.6.6 Compiling 24 Solidity files Successfully compiled 24 Solidity files

    After running this command, the compiled artifacts (ABI and bytecode) appear in the artifacts directory.

Configure Secure Key Management

This project uses Hardhat Configuration Variables to manage private keys securely. Unlike .env files, configuration variables are stored outside your project directory and are never at risk of being committed to version control.

To set your private key for TestNet deployment, run:

npx hardhat vars set TESTNET_PRIVATE_KEY

When prompted, paste your private key. Hardhat stores it securely and makes it available through vars.get("TESTNET_PRIVATE_KEY") in the configuration file.

Warning

Keep your private key safe and never share it with anyone. If it is compromised, your funds can be stolen.

The hardhat.config.ts file references the variable conditionally, so the project works without it for local development:

hardhat.config.ts
networks: {
  hardhat: {
    allowUnlimitedContractSize: true,
  },
  localNode: {
    url: "http://127.0.0.1:8545",
  },
  polkadotTestnet: {
    url: "https://services.polkadothub-rpc.com/testnet",
    accounts: vars.has("TESTNET_PRIVATE_KEY")
      ? [vars.get("TESTNET_PRIVATE_KEY")]
      : [],
  },
},

Note

You only need the TESTNET_PRIVATE_KEY variable when deploying to the Polkadot Hub TestNet. Local development against the development node does not require any key configuration.

Uniswap V2 Periphery Architecture

Before interacting with the contracts, it is essential to understand how the Periphery layer extends the V2 Core system. While the V2 Core contracts handle low-level pool operations, the Periphery contracts provide a safe and convenient interface for end users and integrating applications.

The Periphery layer introduces three major components:

  • WETH9 contract: A standard Wrapped Ether contract that allows native ETH to be used as an ERC-20 token. The Router uses WETH to support functions that accept native ETH directly (such as addLiquidityETH and swapExactETHForTokens), wrapping and unwrapping it transparently.
  • Router01 contract: The original Router implementation providing core functions for adding and removing liquidity, and executing multi-hop token swaps through a path of pairs. It validates deadlines and minimum output amounts to protect users from slippage and front-running.
  • Router02 contract: The production Router that extends Router01 with additional support for fee-on-transfer tokens. Functions like swapExactTokensForTokensSupportingFeeOnTransferTokens handle tokens that deduct fees on every transfer, ensuring swaps complete correctly even when the received amount is less than the sent amount.

This architecture separates user-facing logic from the core AMM primitives, keeping the Core contracts simple and immutable while allowing the Periphery to evolve independently.

The project scaffolding is as follows:

uniswap-v2-periphery-hardhat/
├── contracts/
│   ├── interfaces/
│   │   ├── IERC20.sol
│   │   ├── IUniswapV2Router01.sol
│   │   ├── IUniswapV2Router02.sol
│   │   └── IWETH.sol
│   ├── libraries/
│   │   ├── SafeMath.sol
│   │   └── UniswapV2Library.sol
│   ├── test/
│   │   ├── CompileHelper.sol
│   │   ├── DeflatingERC20.sol
│   │   ├── ERC20.sol
│   │   ├── RouterEventEmitter.sol
│   │   └── WETH9.sol
│   ├── UniswapV2Router01.sol
│   └── UniswapV2Router02.sol
├── ignition/
│   └── modules/
│       └── UniswapV2Router02.ts
├── scripts/
│   └── deploy.ts
├── test/
│   ├── shared/
│   │   ├── fixtures.ts
│   │   └── utilities.ts
│   ├── UniswapV2Router01.test.ts
│   └── UniswapV2Router02.test.ts
├── hardhat.config.ts
├── package.json
└── tsconfig.json

Key differences from a typical Ethereum Hardhat project are minimal. The Solidity contracts are the original Uniswap V2 Periphery source, using both Solidity 0.5.16 (for the V2 Core dependency) and 0.6.6 (for the Router contracts) with no modifications. The Hardhat configuration includes a multi-compiler setup to handle both versions. The test files use TypeScript (.test.ts) and avoid loadFixture for compatibility with the Polkadot execution environment.

Test the Contracts

The project includes a comprehensive test suite with 50 tests across two test files. The Router01 test file covers 38 tests for liquidity operations, token swaps, ETH swaps, and permit-based liquidity removal. The Router02 test file covers 12 tests for fee-on-transfer token support and additional swap scenarios.

To run the tests locally:

  1. Start the local development node. Follow the steps in the Local Development Node guide to set it up.

  2. In a new terminal, run the test suite against the local node:

    npx hardhat test --network localNode
    

    The tests are configured with a 120-second Mocha timeout to accommodate Polkadot network block times. The result should look similar to the following:

    npx hardhat test --network localNode Compiling 24 Solidity files Successfully compiled 24 Solidity files UniswapV2Router{01,02} UniswapV2Router01 ✔ factory, WETH ✔ addLiquidity (12045ms) ✔ addLiquidityETH (11987ms) ✔ removeLiquidity (17234ms) ✔ removeLiquidityETH (17456ms) ✔ removeLiquidityWithPermit (12134ms) ✔ removeLiquidityETHWithPermit (17523ms) swapExactTokensForTokens ✔ happy path (12378ms) ✔ amounts (6145ms) swapTokensForExactTokens ✔ happy path (12401ms) ✔ amounts (6178ms) swapExactETHForTokens ✔ happy path (12367ms) ✔ amounts (6134ms) swapTokensForExactETH ✔ happy path (12489ms) ✔ amounts (6201ms) swapExactTokensForETH ✔ happy path (12356ms) ✔ amounts (6167ms) swapETHForExactTokens ✔ happy path (12412ms) ✔ amounts (6189ms) UniswapV2Router02 ✔ factory, WETH ✔ addLiquidity (12067ms) ✔ addLiquidityETH (11998ms) ✔ removeLiquidity (17289ms) ✔ removeLiquidityETH (17512ms) ✔ removeLiquidityWithPermit (12156ms) ✔ removeLiquidityETHWithPermit (17534ms) swapExactTokensForTokens ✔ happy path (12389ms) ✔ amounts (6156ms) swapTokensForExactTokens ✔ happy path (12423ms) ✔ amounts (6187ms) swapExactETHForTokens ✔ happy path (12378ms) ✔ amounts (6145ms) swapTokensForExactETH ✔ happy path (12501ms) ✔ amounts (6212ms) swapExactTokensForETH ✔ happy path (12367ms) ✔ amounts (6178ms) swapETHForExactTokens ✔ happy path (12423ms) ✔ amounts (6198ms) UniswapV2Router02 ✔ quote ✔ getAmountOut ✔ getAmountIn ✔ getAmountsOut (6123ms) ✔ getAmountsIn (6145ms) fee-on-transfer tokens ✔ removeLiquidityETHSupportingFeeOnTransferTokens (23456ms) ✔ removeLiquidityETHWithPermitSupportingFeeOnTransferTokens (23567ms) swapExactTokensForTokensSupportingFeeOnTransferTokens ✔ DTT -> WETH (12345ms) ✔ WETH -> DTT (12378ms) ✔ swapExactETHForTokensSupportingFeeOnTransferTokens (12367ms) ✔ swapExactTokensForETHSupportingFeeOnTransferTokens (12389ms) fee-on-transfer tokens: reloaded swapExactTokensForTokensSupportingFeeOnTransferTokens ✔ DTT -> DTT2 (12401ms) 50 passing (25m)

Tip

If tests time out, ensure your local development node is running and accessible at http://127.0.0.1:8545.

Deploy the Contracts

After successfully testing the contracts, you can deploy them to the Polkadot Hub TestNet using Hardhat Ignition. The Ignition module at ignition/modules/UniswapV2Router02.ts deploys WETH9, the UniswapV2Factory, and the UniswapV2Router02 contracts.

Make sure you have configured your private key and that your account has test tokens. Then run:

npx hardhat ignition deploy ./ignition/modules/UniswapV2Router02.ts --network polkadotTestnet

When prompted, confirm the target network name and chain ID. Ignition deploys the contracts in two batches (Factory and WETH9 in parallel, then Router02) and prints all deployed addresses. The output should look similar to the following:

npx hardhat ignition deploy ./ignition/modules/UniswapV2Router02.ts --network polkadotTestnet ✔ Confirm deploy to network polkadotTestnet (420420417)? … yes   Hardhat Ignition 🚀   Deploying [ UniswapV2Router02Module ]   Batch #1 Executed UniswapV2Router02Module#UniswapV2Factory Executed UniswapV2Router02Module#WETH9   Batch #2 Executed UniswapV2Router02Module#UniswapV2Router02   [ UniswapV2Router02Module ] successfully deployed 🚀   Deployed Addresses   UniswapV2Router02Module#UniswapV2Factory - 0x3Ca8f8C6De9d51B4e14e9Ab7D6d2e38A39C93B85 UniswapV2Router02Module#WETH9 - 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D UniswapV2Router02Module#UniswapV2Router02 - 0xC36442b4a4522E871399CD717aBDD847Ab11FE88

Where to Go Next

  • Tutorial Uniswap V3 Core


    Deploy unmodified Uniswap V3 Core contracts on Polkadot Hub using Hardhat and the EVM execution path.

    Get Started

  • Guide Hardhat on Polkadot


    Learn how to create, compile, test, and deploy smart contracts on Polkadot Hub using Hardhat.

    Reference

  • Guide Local Development Node


    Set up and run a local development node for testing your smart contracts against Polkadot.

    Set Up

Last update: June 4, 2026
| Created: April 14, 2026