Integrating with decentralized finance (DeFi) protocols like Uniswap is a powerful way for developers to build innovative blockchain applications. If you're new to the ecosystem, getting started can feel overwhelming — from setting up your environment to executing your first on-chain swap. This guide walks you through building, deploying, and testing a smart contract that performs a WETH-to-DAI swap on Uniswap V3, using industry-standard tools and best practices.
By the end, you’ll have a fully functional integration tested against a local fork of Ethereum Mainnet — all without spending real gas.
Setting Up Your Development Environment
Before writing any code, you need a reliable development stack. The ideal setup includes tools for compiling, testing, and interacting with Ethereum smart contracts. In this tutorial, we use:
- Hardhat: A comprehensive development environment for Ethereum that supports local node management, script execution, and automated testing.
- Alchemy: A robust RPC provider offering free-tier support for Mainnet forking — essential for simulating real-world conditions locally.
These tools form the backbone of modern DeFi development, enabling rapid iteration and accurate testing.
Create an Alchemy Account
To interact with Ethereum, your local node needs access to the blockchain via an RPC (Remote Procedure Call) endpoint. Alchemy provides high-performance nodes with advanced debugging and analytics.
- Visit alchemy.com and sign up for a free account.
- Click “Create App” and choose Ethereum Mainnet as the network.
- Copy your unique API key — you’ll use it to fork Mainnet in Hardhat.
This API key grants your local environment access to a complete snapshot of Ethereum, including deployed DeFi protocols like Uniswap.
Clone the Starter Project
To accelerate development, Uniswap Labs provides a boilerplate repository with preconfigured dependencies:
git clone https://github.com/Uniswap/uniswap-first-contract-example
cd uniswap-first-contract-example
npm installThis initializes a Hardhat project with:
- Solidity compiler settings
- Pre-installed Uniswap V3 Periphery libraries
- Sample contract and test files
You now have everything needed to start coding.
Forking Ethereum Mainnet Locally
One of Hardhat’s most powerful features is its ability to fork Ethereum Mainnet. Instead of starting from an empty blockchain, your local node replicates the current state of Ethereum — including all deployed contracts, balances, and liquidity pools.
This means Uniswap V3 exists exactly as it does in production, allowing realistic integration testing.
Start the forked node using your Alchemy API key:
npx hardhat node --fork https://eth-mainnet.alchemyapi.io/v2/YOUR_API_KEYYour terminal will display account addresses preloaded with test ETH. These simulate real user wallets and let you execute transactions without cost.
With this live-like environment running, you're ready to write your first swap contract.
Writing a Smart Contract to Execute a Swap
Our goal: build a contract that swaps Wrapped Ether (WETH) for DAI using Uniswap V3’s SwapRouter.
Open contracts/SimpleSwap.sol. The initial file contains standard Solidity boilerplate:
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity =0.7.6;
pragma abicoder v2;
import '@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol';
import '@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol';
contract SimpleSwap {
constructor() {}
}Let’s break this down:
SPDX-License-Identifier: Declares open-source licensing.pragma solidity =0.7.6: Specifies compiler version compatibility.ISwapRouter: Interface for interacting with Uniswap’s swap functionality.TransferHelper: Utility library for safely transferring ERC-20 tokens.
Now extend the contract with constants and constructor:
contract SimpleSwap {
ISwapRouter public immutable swapRouter;
address public constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address public constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
uint24 public constant feeTier = 3000;
constructor(ISwapRouter _swapRouter) {
swapRouter = _swapRouter;
}
}Here:
DAIandWETH9are verified token addresses on Ethereum.feeTier = 3000refers to the 0.3% liquidity pool — the most liquid market for WETH/DAI.- The constructor injects the SwapRouter address for flexibility across networks.
Implementing the Swap Logic
Now define the function that executes the trade:
function swapWETHForDAI(uint amountIn) external returns (uint amountOut) {
TransferHelper.safeTransferFrom(WETH9, msg.sender, address(this), amountIn);
TransferHelper.safeApprove(WETH9, address(swapRouter), amountIn);
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
tokenIn: WETH9,
tokenOut: DAI,
fee: feeTier,
recipient: msg.sender,
deadline: block.timestamp,
amountIn: amountIn,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
});
amountOut = swapRouter.exactInputSingle(params);
return amountOut;
}Key components:
safeTransferFrom: Moves WETH from caller to contract.safeApprove: Grants SwapRouter permission to spend WETH.exactInputSingle: Executes the swap with precise input and max output.amountOutMinimumandsqrtPriceLimitX96are set to zero for simplicity but should be used in production to prevent slippage.
Testing the Contract on a Forked Node
Hardhat’s built-in testing framework makes validation straightforward. Open test/SimpleSwap.test.js.
The test performs these steps:
- Deploys
SimpleSwapusing the Mainnet-forked node. - Wraps ETH into 10 WETH for testing.
- Approves the contract to spend WETH.
- Calls
swapWETHForDAI(0.1 WETH). - Confirms DAI balance increases post-swap.
Run the test:
npx hardhat test --network localhostUsing --network localhost ensures the test connects to your forked node — where Uniswap contracts exist. Without this flag, the test fails due to missing protocol addresses.
When successful, you’ll see:
SimpleSwap
✔ Should provide a caller with more DAI than they started with after a swap (1999ms)
1 passing (2s)Congratulations — you’ve executed your first real-world DeFi interaction.
Frequently Asked Questions
What is Mainnet forking and why is it useful?
Mainnet forking creates a local copy of Ethereum’s current state, including all deployed contracts and balances. It allows developers to test integrations in a realistic environment without risking real funds or relying on potentially outdated testnets.
Can I use this method to interact with other DeFi protocols?
Yes! Any protocol deployed on Ethereum — such as Aave, Compound, or Curve — is available on your forked node. Simply import their interfaces and interact as needed.
Why do I need to approve token transfers before swapping?
ERC-20 tokens require explicit approval before a third party (like a router contract) can spend them. This security mechanism prevents unauthorized spending and is mandatory for all token interactions.
How can I reduce slippage in production swaps?
Set amountOutMinimum to a calculated minimum based on current price and acceptable deviation (e.g., 1–3%). This reverts the transaction if market movement causes unfavorable rates.
Is it safe to hardcode token addresses and fee tiers?
For learning purposes, yes — but avoid hardcoding in production. Use dynamic inputs or oracle-fed configurations to support multiple pairs and adapt to changing markets.
Can I deploy this contract on a testnet or mainnet?
Absolutely. After testing locally, update your Hardhat config with network details (e.g., Goerli or Ethereum Mainnet) and deploy using a wallet like MetaMask or programmatically via Alchemy.
What’s Next?
Now that you’ve built and tested a working integration, consider expanding its capabilities:
- Build a frontend dApp using React and Ethers.js.
- Add support for arbitrary token pairs in a generalized
UniversalSwapcontract. - Implement price quoting without execution using Uniswap’s Quoter contract.
- Integrate gas estimation and error handling for user-facing applications.
- Deploy to Goerli or Sepolia for broader testing.
Explore the official Uniswap Documentation for deeper dives into advanced features like concentrated liquidity, flash swaps, and NFT-based positions.
Core Keywords: Uniswap integration, Ethereum Mainnet fork, smart contract development, DeFi swap, Hardhat tutorial, ISwapRouter, WETH to DAI swap, Solidity programming