Set Up Your Local Environment
One of the most common questions we get asked is what development toolset to use to build on-chain integrations with Uniswap. There’s no right answer to this question but for this guide we’ll recommend a common one: Node.js
, NPM
and Hardhat
.
At the end of this guide you’ll have a development environment set up that you can use to build the rest of the examples in the Guides section of the docs, or start your own integration project!
To get you started as quickly as possible, we have provided the Quick Start
section below where you can clone some boiler plate and get building. To start from scratch and learn the underlying concepts, jump to the Start from Scratch
section.
Quick Start
The Uniswap boilerplate repo provides a basic Hardhat environment with required imports already pre-loaded for you. You can simply clone it and install the dependencies:
git clone https://github.com/Uniswap/uniswap-first-contract-example
cd uniswap-first-contract-example
npm install
Then hop to the Local Node with a Mainnet Fork
to complete your set up and start developing.
Start from Scratch
In the following sections, we’ll walk through the steps to create the same environment set up as the boiler plate from scratch and learn the underlying concepts.
Set Up Dependencies
Node is one of the most common Javascript runtimes. For our purposes it will provide scripting we can use to compile and test our contracts. If you haven’t already, install NodeJS and its package manager NPM (instructions). Once those dependencies are set up, we can initialize our project:
$ npm init
Hardhat is an Ethereum development toolset that provides a number of powerful features including Solidity compilation, testing and deployment, all in a single convenient wrapper. We’ll use NPM to add Hardhat to our project:
$ npm add --save-dev hardhat
With Hardhat installed we can invoke it to scaffold our development environment. When you first run Hardhat you’ll have the option of starting with a templated Javascript or Typescript project or an empty project. Since Hardhat relies heavily on folder structure, we recommend starting with either of the templated options. Initialize Hardhat and follow the prompts to make your selection and answer yes to the follow up prompts:
$ npx hardhat init
Once the Hardhat initialization completes, take a look around at what got set up. The folder structure should be intuitive, ./contracts
is where you’ll write your Solidity contracts, ./test
is where you’ll write your tests and ./scripts
is where you can write scripts to perform actions like deploying. Out of the box, Hardhat is configured to use this folder structure so don’t change it unless you know what you’re doing!
Next we’ll use NPM to add the Uniswap V3 contracts which will allow us to seamlessly integrate with the protocol in our new contracts:
$ npm add @uniswap/v3-periphery @uniswap/v3-core
The Uniswap V3 contracts were written using a past version of the solidity compiler. Since we’re building integrations on V3 we have to tell Hardhat to use the correct compiler to build these files. Go to the ./hardhat.config.js
file and change the Solidity version to “0.7.6”:
// ...
module.exports = {
solidity: "0.7.6",
};
That’s it! You should now have a functional development environment to start building on chain Uniswap integrations. Let’s run a quick test to confirm everything is set up properly.
Compile a Basic Contract
To confirm that our environment is configured correctly we’ll attempt to compile a basic Swap contract. Create a new file, ./contracts/Swap.sol
and paste the following code into it (a detailed guide to this contract can be found here):
// 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 {
ISwapRouter public immutable swapRouter;
address public constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address public constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
uint24 public constant feeTier = 3000;
constructor(ISwapRouter _swapRouter) {
swapRouter = _swapRouter;
}
function swapWETHForDAI(uint256 amountIn) external returns (uint256 amountOut) {
// Transfer the specified amount of WETH9 to this contract.
TransferHelper.safeTransferFrom(WETH9, msg.sender, address(this), amountIn);
// Approve the router to spend WETH9.
TransferHelper.safeApprove(WETH9, address(swapRouter), amountIn);
// Note: To use this example, you should explicitly set slippage limits, omitting for simplicity
uint256 minOut = /* Calculate min output */ 0;
uint160 priceLimit = /* Calculate price limit */ 0;
// Create the params that will be used to execute the swap
ISwapRouter.ExactInputSingleParams memory params =
ISwapRouter.ExactInputSingleParams({
tokenIn: WETH9,
tokenOut: DAI,
fee: feeTier,
recipient: msg.sender,
deadline: block.timestamp,
amountIn: amountIn,
amountOutMinimum: minOut,
sqrtPriceLimitX96: priceLimit
});
// The call to `exactInputSingle` executes the swap.
amountOut = swapRouter.exactInputSingle(params);
}
}
To compile all the contracts in the ./contracts
folder, we’ll use the Hardhat compile command:
$ npx hardhat compile
If the environment is compiled correctly you should see the message:
Compiled { x } Solidity files successfully
Local Node with a Mainnet Fork
When building and testing integrations with on chain protocols, developers often hit a problem: the liquidity on the live chain is critical to thoroughly testing their code but testing against a live network like Mainnet can be extremely expensive.
See the SDK getting started guide for a full example on how to use forks.
With your local node up and running, you can use the --network localhost
flag in tests to point the Hardhat testing suite to that local node:
$ npx hardhat test --network localhost
Next Steps
With your environment set up you’re ready to start building. Jump over to the guides section to learn about the Uniswap functions you can integrate with. Remember to add all contracts (.sol files) to the ./contracts
folder and their subsequent tests to the ./tests
folder. You can then test them against your local forked node by running:
$ npx hardhat test --network localhost