Deploy Uniswap V2 Periphery with EVM
Introduction
Section titled “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
Section titled “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
Section titled “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:
-
Clone the repository and navigate to the Uniswap V2 Periphery project:
Terminal window git clone https://github.com/polkadot-developers/revm-hardhat-examples.gitcd revm-hardhat-examplesgit checkout a871364c8f4da052855b5c8ee4ed6b89fd182cb1cd uniswap-v2-periphery-hardhat/ -
Install the required dependencies:
Terminal window npm install -
Compile the contracts:
Terminal window npx hardhat compileIf 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 filesAfter running this command, the compiled artifacts (ABI and bytecode) appear in the
artifactsdirectory.
Configure Secure Key Management
Section titled “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_KEYWhen prompted, paste your private key. Hardhat stores it securely and makes it available through vars.get("TESTNET_PRIVATE_KEY") in the configuration file.
The hardhat.config.ts file references the variable conditionally, so the project works without it for local development:
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")] : [], },},Uniswap V2 Periphery Architecture
Section titled “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
addLiquidityETHandswapExactETHForTokens), 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
swapExactTokensForTokensSupportingFeeOnTransferTokenshandle 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.jsonKey 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
Section titled “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:
-
Start the local development node. Follow the steps in the Local Development Node guide to set it up.
-
In a new terminal, run the test suite against the local node:
Terminal window npx hardhat test --network localNodeThe 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)
Deploy the Contracts
Section titled “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 polkadotTestnetWhen 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:
Where to Go Next
Section titled “Where to Go Next”-
Uniswap V3 Core
Deploy unmodified Uniswap V3 Core contracts on Polkadot Hub using Hardhat and the EVM execution path.
-
Hardhat on Polkadot
Learn how to create, compile, test, and deploy smart contracts on Polkadot Hub using Hardhat.
-
Local Development Node
Set up and run a local development node for testing your smart contracts against Polkadot.