前沿#
既然是一个循序渐进的教程,那么肯定不能一上来就开始写代码。就好比你想造一台永動機,你至少要知道這個永動機動起來是什麼樣子,你才能更好的去分解它。
所以這一章節我們主要是部署一個 UniswapV3,所以這章節的目的是快速並且簡單的部署好一個 UniswapV3,用於未來我們程序和 Uni 的聯調。
安裝 Uni 包#
不過,在安裝之前,我推薦你把第二章配置好的模板保存起來,以後就不用重新配置了。當然,這是可選內容。
首先安裝 UniswapV3,我們要知道一件事。Uniswap 的合約分為兩個,一個是v3-periphery
另外一個是v3-core
。現在簡單介紹一下這兩個倉庫的合約是代表什麼。
v3-core#
core 合約是 uniswap 中負責掌管 pool 和 factory 的倉庫。
pool:是資金存儲和交換運算的合約。
factory:用於批量創造 Pool 的合約。
這兩個合約是整個 uniswap 的核心。就算在沒有 periphery 的情況下,也能正常運行的最小合約。
v3-periphery#
periphery 存放的是外圍合約,這些合約是給用戶和開發者一個統一的接口或者是便捷的通證。核心合約有 NFTManager 和 SwapRouter。
NFTManager:一個用於記錄用戶創建的流動性各類數據的合約。
SwapRouter:包裝類,將交換的各種邏輯進行包裝抽象。
這裡我們不過度展開 UniswapV3 的邏輯。我們重點是如何去部署它。
通過執行
yarn add @uniswap/v3-core @uniswap/[email protected]
先安裝好兩個必要的合約倉庫。要注意的是,@uniswap/[email protected]
是帶了版本號的,這是因為在編寫本文的時候,1.4.2 版本缺少 artifacts 文件夾,相關 issue 如下。github-issue,如果當你看到這篇文章時,這個 issue 已經被解決了,那麼就不用加上末尾的版本號指定了。
通過 ByteCode 部署#
部署合約其實只有一種方式,就是從 bytecode 進行部署,但是不同的工具會提供不同等級的封裝。以至於封裝到極致後,你只需要輸入一個合約名稱就可以部署。不過為了方便了解原理,我們就使用最為基礎的部署方式進行部署。
我們先創建一個 deploy 文件。在 deploy 文件夾下創建一個名為 00_deploy_univ3.ts 的文件。
代碼內容如下。
import { DeployFunction } from "hardhat-deploy/types";
const func: DeployFunction = async function () {
}
export default func;
這是一個 deploy 文件最基礎的框架函數,我們首先要部署的是 core 中的 factory 合約。所以我們修改代碼為。
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;
加了” 一點點” 細節後,我們的代碼豐富了起來。這裡先解釋一下關鍵內容。
import {
abi as FACTORY_ABI,
bytecode as FACTORY_BYTECODE,
} from '@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json'
這段代碼的內容是從 uniswap 提供的官方包中,引入 bytecode 和 abi 數據,這樣我們就能直接在下面進行內容填充。
await deployments.deploy("UniV3Factory", {
from: deployer.address,
contract: {
bytecode: FACTORY_BYTECODE,
abi: FACTORY_ABI
},
})
這段代碼是部署 V3Factory 合約的代碼。其中 deploy 是 hardhat-deploy 插件提供的函數,我們在第二個參數中指定了 bytecode 和 abi—— 這兩個必須都要有。
當然,我們還要修改 tsconfig.json 文件,添加 "resolveJsonModule": true 的選項。修改後文件如下。
{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"resolveJsonModule": true
},
}
接下來是 SwapRouter 合約,我們如法炮製,修改代碼如下。當然你也可以嘗試自己動手試試。
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]
// 上面是部署合約的參數,第一个參數為factory地址,第二個為WETH地址,這裡為了圖方便就直接用0地址啦😁
})
}
export default func;
那麼我們的部署腳本到這裡就編寫完成了。通過命令yarn hardhat deploy
即可將代碼部署到任何網絡上。
不過,通過 bytecode 直接部署會有一些不好的地方,比如在出錯的時候,你無法獲得源碼級別的錯蹤追蹤。並且,我們部署的也是一個殘缺的版本,因為我們還缺少 NonfungiblePositionManager,NonfungibleTokenPositionDescriptor,NFTDescriptor 合約,不過,它們的部署方式都是一樣的。你可以試著用上述的方法添加它們。就當是課後作業啦。
结语#
這一個章節只構建了通過 bytecode 部署 uniswap 的基礎文件,但是我們的內容其實是不夠一個實際的 uniswap 運行的。所以在下一章節,我們會使用另外一種方式部署 uniswapv3,並且編寫測試用例。等測試用例通過後,我們再用源碼編譯的方式對 UniswapV3 進行部署。
PS:我發現 mirror 不太適合寫這種技術類文章,後續會切換到其他平台。