Frontiers#
Since this is a progressive tutorial, we definitely can't start writing code right away. It's like wanting to build a perpetual motion machine - you need to know what it looks like in order to break it down better.
So in this chapter, our main focus is to deploy a UniswapV3, so the purpose of this chapter is to quickly and simply deploy a UniswapV3 for future integration with our program and Uni.
Installing Uni Package#
However, before installing, I recommend saving the template configured in Chapter 2 so that you don't have to configure it again later. Of course, this is optional.
First, install UniswapV3. We need to know one thing - Uniswap's contracts are divided into two: v3-periphery
and v3-core
. Let's briefly explain what these two repositories represent.
v3-core#
The core contract is responsible for managing the pool and factory in Uniswap.
Pool: A contract for storing funds and performing exchange operations.
Factory: A contract for creating pools in batches.
These two contracts are the core of Uniswap. Even without the periphery, they can still function properly.
v3-periphery#
Periphery contains peripheral contracts that provide users and developers with a unified interface or convenient tokens. The core contracts include NFTManager and SwapRouter.
NFTManager: A contract for recording various data related to liquidity created by users.
SwapRouter: A wrapper that encapsulates various logic for exchanges.
We won't go into too much detail about the logic of UniswapV3 here. Our focus is on how to deploy it.
To do this, execute the following command:
yarn add @uniswap/v3-core @uniswap/[email protected]
This will install the two necessary contract repositories. Note that @uniswap/[email protected]
includes a version number. This is because at the time of writing this article, version 1.4.2 was missing the artifacts
folder. If you are reading this article and the issue has been resolved, you don't need to specify the version number at the end.
Deploying via ByteCode#
There is actually only one way to deploy contracts, which is through bytecode. However, different tools provide different levels of abstraction. In fact, when abstraction is taken to the extreme, you only need to enter the contract name to deploy it. However, for the purpose of understanding the principles, we will use the most basic deployment method.
First, create a deploy file. Create a file named 00_deploy_univ3.ts
under the deploy
folder.
The code should be as follows:
import { DeployFunction } from "hardhat-deploy/types";
const func: DeployFunction = async function () {
}
export default func;
This is the most basic framework function for a deploy file. The first contract we want to deploy is the factory contract in the core. So we modify the code as follows:
import { DeployFunction } from "hardhat-deploy/types";
import {
abi as FACTORY_ABI,
bytecode as FACTORY_BYTECODE,
} from '@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json'
import { HardhatRuntimeEnvironment } from "hardhat/types";
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const { deployments,ethers } = hre
const [deployer] = await ethers.getSigners()
await deployments.deploy("UniV3Factory", {
from: deployer.address,
contract: {
bytecode: FACTORY_BYTECODE,
abi: FACTORY_ABI
},
})
}
export default func;
With a few "minor" details added, our code becomes more complete. Let's explain the key points here.
import {
abi as FACTORY_ABI,
bytecode as FACTORY_BYTECODE,
} from '@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json'
This code imports the bytecode and ABI data from the official Uniswap package, allowing us to directly fill in the content below.
await deployments.deploy("UniV3Factory", {
from: deployer.address,
contract: {
bytecode: FACTORY_BYTECODE,
abi: FACTORY_ABI
},
})
This code deploys the V3Factory contract. The deploy
function is provided by the hardhat-deploy plugin, and we specify the bytecode and ABI in the second parameter - both of which are required.
Of course, we also need to modify the tsconfig.json
file and add the option "resolveJsonModule": true
. The modified file should look like this:
{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"resolveJsonModule": true
},
}
Next is the SwapRouter contract. We follow the same steps and modify the code as follows. You can also try it yourself.
import { DeployFunction } from "hardhat-deploy/types";
import {
abi as FACTORY_ABI,
bytecode as FACTORY_BYTECODE,
} from '@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json'
import {
abi as SWAP_ROUTER_ABI,
bytecode as SWAP_ROUTER_BYTECODE,
} from '@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json'
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { constants } from "ethers";
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const { deployments, ethers } = hre
const [deployer] = await ethers.getSigners()
const factory = await deployments.deploy("UniV3Factory", {
from: deployer.address,
contract: {
bytecode: FACTORY_BYTECODE,
abi: FACTORY_ABI
},
})
await deployments.deploy("UniV3SwapRouter", {
from: deployer.address,
contract: {
abi: SWAP_ROUTER_ABI,
bytecode: SWAP_ROUTER_BYTECODE
},
args:[factory.address,constants.AddressZero]
// The above are the parameters for deploying the contract. The first parameter is the factory address, and the second is the WETH address. Here, for convenience, we directly use the zero address 😁
})
}
export default func;
With this, our deployment script is complete. You can deploy the code to any network using the command yarn hardhat deploy
.
However, deploying directly via bytecode has some drawbacks. For example, when an error occurs, you cannot trace the error at the source code level. Also, what we have deployed is an incomplete version because we still lack the NonfungiblePositionManager, NonfungibleTokenPositionDescriptor, and NFTDescriptor contracts. However, the deployment method for these contracts is the same. You can try adding them using the method described above. Consider it as homework.
Conclusion#
This chapter only builds the basic files for deploying Uniswap via bytecode. However, our content is not enough for an actual Uniswap operation. Therefore, in the next chapter, we will deploy UniswapV3 using a different method and write test cases. Once the test cases pass, we will deploy UniswapV3 using the source code compilation method.
PS: I found that Mirror is not suitable for writing technical articles like this, so I will switch to another platform in the future.