# Using the new Uniswap v2 in your contracts

Author: Markus Waas

Published: 2020-06-13T22:02:45.000Z

Updated: 2026-09-13T14:25:30.000Z

Source: [https://soliditydeveloper.com/uniswap2](<https://soliditydeveloper.com/uniswap2>)

## Compatibility and review

Before you start

Historical Solidity 0.7.1 / Uniswap v2 Router02 integration. Kovan is retired and deployment addresses are chain-specific. The old fee-activation statement, malformed snippets and floating-point wei calculation have been corrected; historical deployment and liquidity were not reproduced.

[Official reference](<https://raw.githubusercontent.com/Uniswap/uniswap-v2-periphery/master/contracts/UniswapV2Router02.sol>)

**Note**: For Uniswap 3 check out the tutorial [here](<https://soliditydeveloper.com/uniswap3>).

## What is UniSwap?

If you're not familiar with [Uniswap](<https://uniswap.exchange/>) yet, it's a fully decentralized protocol for automated liquidity provision on Ethereum. An easier-to-understand description would be that it's a decentralized exchange (DEX) relying on external liquidity providers that can add tokens to smart contract pools and users can trade those directly.

Since it's running on Ethereum, what we can trade are Ethereum ERC-20 tokens. Each pool represents a pair of tokens; in v3 a pair can also have pools at different fee tiers. Uniswap - being fully decentralized - has no restrictions to which tokens can be added. If no contracts for a token pair exist yet, anyone can create one using their factory and anyone can provide liquidity to a pool. The swap fee and any protocol share depend on the protocol version and pool configuration; see the [current fee documentation](<https://developers.uniswap.org/docs/protocols/protocol-fee/concepts/fees>).

The price of a token is determined by the liquidity in a pool. For example if a user is buying *TOKEN1* with *TOKEN2*, the supply of *TOKEN1* in the pool will decrease while the supply of *TOKEN2* will increase and the price of *TOKEN1* will increase. Likewise, if a user is selling *TOKEN1*, the price of *TOKEN1* will decrease. Therefore the token price always reflects the supply and demand.

And of course a user doesn't have to be a person, it can be a smart contract. That allows us to add Uniswap to our own contracts for adding additional payment options for users of our contracts. Uniswap makes this process very convenient, see below for how to integrate it.

![Uniswap UI](<https://cdn0.scrvt.com/b095ee27d37b3d7b6b150adba9ac6ec8/64fffff02c44018e/2b54bfc6c00f/v/f970f09c6aad/uniswap-ui.png>)

## What is new in UniSwap v2?

- **ERC20 / ERC20 Pairs**: In the first version any token had to be paired with ETH. To trade a token with another token, one had to first exchange the first token into ETH and then use that ETH to purchase the other token. Now you can directly trade those!
- **Price Oracles**: While theoretically one could use Uniswap v1 as an oracle, it wasn't recommended as prices could flucuate by a lot in a short time making it easy to manipulate. Now there are several mechanisms to prevent this like using the last block price and a cumulative-price that is weighted by the time previous prices existed.
- **Flash Swaps**: The Uniswap [Flash Swaps](<https://uniswap.org/docs/v2/guides/flash-swaps/>) are similar to the [Aave Flash Loans](<https://aave.com/flash-loans>) that you might be familiar with. The same concept is now possible in Uniswap allowing you to optimistically receive tokens as long as you either 1. return them 2. pay for them or 3. partially return/pay for them at the end of the transaction.
- Some [Minor Technical Improvements](<https://uniswap.org/blog/uniswap-v2/#technical-improvements>)
- **Path to Sustainability**: The v2 protocol fee takes a share of the existing 0.30% swap fee, rather than adding another fee on top. Current documentation reports 0.25% for LPs and 0.05% for the protocol; the original non-activation plan below is no longer current.

## Further Uniswap v2 resources

- [Live on Mainnet since May 18th, 2020](<https://uniswap.org/blog/launch-uniswap-v2/>)
- [Docs](<https://uniswap.org/docs/v2>)
- [Whitepaper](<https://uniswap.org/whitepaper.pdf>)

## What happens to UniSwap v1?

> Uniswap v1 is an automated, decentralized set of smart contracts. It will continue functioning for as long as Ethereum exists.
>
>
>
> Hayden Adams

## Integrating UniSwap v2

One of the reasons Uniswap is so popular may be the simple way of integrating them into your own smart contract. Let's say you have a system where users pay with DAI. With Uniswap in just a few lines of code, you could add the option for them to also pay in ETH. The ETH can be automatically converted into DAI before the actual logic. It would look something like this

```solidity
function pay(uint paymentAmountInDai, uint deadline) public payable {
      if (msg.value > 0) {
          convertEthToDai(paymentAmountInDai, deadline);
      } else {
          require(daiToken.transferFrom(msg.sender, address(this), paymentAmountInDai));
      }
      // do something with that DAI
      ...
}
```

A simple check at the beginning of your function will be enough. Now as for the `convertEthToDai` function, it will look like something this:

```solidity
function convertEthToDai(uint daiAmount, uint deadline) public payable {
    address[] memory path = new address[](2);
    path[0] = uniswapRouter.WETH();
    path[1] = address(daiToken);

    uint[] memory amounts = uniswapRouter.swapETHForExactTokens{value: msg.value}(daiAmount, path, address(this), deadline);
    
    // refund leftover ETH to user
    uint refund = msg.value - amounts[0];
    (bool success,) = msg.sender.call{value: refund}("");
    require(success, "Refund failed");
  }
```

There are several things to unpack here.

- **Uniswap Router**: The `uniswapRouter` will be a wrapper contract provided by Uniswap that has several safety mechanisms and convenience functions. Currently it is recommended to use the [Router02](<https://uniswap.org/docs/v2/smart-contracts/router02/>) contract. You can instantiate it using `IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D`) only on a chain where that exact Router02 deployment is documented. The interface code can be found [here](<https://github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/interfaces/IUniswapV2Router02.sol>).
- **Path**: Any swap needs to have a starting and end path. While in Uniswap v2 you can have direct token to token pairs, it is not always guaranteed that such a pair actually exists. But you may still be able to trade them as long as you can find a path, e.g., `Token1 → Token2 → WETH → Token3`. In that case you can still trade Token1 for Token3, it will only cost a little bit more than a direct swap.
- **WETH**: You might notice that we are using WETH here. In Uniswap v2 there are no more direct ETH pairs, all ETH must be converted to WETH first. In our case this is done by the router.
- **`swapETHForExactTokens`:**This function can be used to use ETH and receive and exact amount of tokens for it. Any leftover ETH will be refunded, so make sure you have a fallback function in your contract to receive ETH: `receive() payable external {}`. The `deadline` parameter will ensure that miners cannot withhold a swap and use it at a later, more profitable time. Make sure to pass this UNIX timestamp from your frontend, don't use `now` inside the contract.
- **Refund**: Once the trade is finished, we can return any leftover ETH to the user. Use the swap’s returned input amount to refund only this caller’s unused ETH; do not send the contract’s entire existing balance.

### How to use it in the frontend

One issue we have now is when a user calls the pay function and wants to pay in ETH, we don't know how much ETH he needs. We can use the [getAmountsIn](<https://uniswap.org/docs/v2/smart-contracts/router02/#getamountsin>) function to compute exactly that.

```solidity
function getEstimatedETHforDAI(uint daiAmount) public view returns (uint[] memory) {
    address[] memory path = new address[](2);
    path[0] = uniswapRouter.WETH();
    path[1] = multiDaiKovan;

    return uniswapRouter.getAmountsIn(daiAmount, path);
}
```

Now we can call `getEstimatedETHforDAI` in our frontend. To ensure we are sending enough ETH and that the transaction won't get reverted, we can increase the estimated amount of ETH by a little bit:

```javascript
// ethers v6; example 10% input cap, choose a deliberate slippage policy.
const requiredEth = (await myContract.getEstimatedETHforDAI(daiAmount))[0];
const sendEth = (requiredEth * 110n + 99n) / 100n;
```

## Historical Remix example and compatibility limits

This is the original Solidity 0.7.1 Router02 example with historical Kovan addresses. Kovan is retired. Reproduction requires an isolated, correctly configured historical environment; a current deployment needs verified chain-specific addresses, a caller-supplied deadline and an explicit price/slippage policy.

```solidity
pragma solidity 0.7.1;

import "https://github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/interfaces/IUniswapV2Router02.sol";

contract UniswapExample {
  address internal constant UNISWAP_ROUTER_ADDRESS = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D ;

  IUniswapV2Router02 public uniswapRouter;
  address private multiDaiKovan = 0x4F96Fe3b7A6Cf9725f59d353F723c1bDb64CA6Aa;

  constructor() {
    uniswapRouter = IUniswapV2Router02(UNISWAP_ROUTER_ADDRESS);
  }

  function convertEthToDai(uint daiAmount, uint deadline) public payable {
    uint[] memory amounts = uniswapRouter.swapETHForExactTokens{ value: msg.value }(daiAmount, getPathForETHtoDAI(), address(this), deadline);
    
    // refund leftover ETH to user
    (bool success,) = msg.sender.call{ value: msg.value - amounts[0] }("");
    require(success, "refund failed");
  }
  
  function getEstimatedETHforDAI(uint daiAmount) public view returns (uint[] memory) {
    return uniswapRouter.getAmountsIn(daiAmount, getPathForETHtoDAI());
  }

  function getPathForETHtoDAI() private view returns (address[] memory) {
    address[] memory path = new address[](2);
    path[0] = uniswapRouter.WETH();
    path[1] = multiDaiKovan;
    
    return path;
  }
  
  // important to receive ETH
  receive() payable external {}
}
```
