# Uniswap V2 交易所部署详解

By [cyptoJune](https://paragraph.com/@cyptojune) · 2022-09-15

---

在DeFi世界中，Dex（去中心化交易所）是最核心的一块，Uniswap是整个Dex的龙头，SushiSwap,PancakeSwap 等都是参考，甚至完全fork了Uniswap的整个产品逻辑和代码，也因此好多人也想部署快速部署一个属于自己的Uniswap,个人觉得也是很有必要的，通过自己从零搭建，一步一步完成，在这个过程可以清楚知道Uniswap整个项目工程的结构和产品逻辑，将来也能站在巨人的肩膀上，开发出自己的DeFi乐高！

**前置说明：**

1.  本次部署是参考Uniswap V2的线上版本，同时结合[催眠大师](https://www.youtube.com/watch?v=XApzW-g57TI&list=PLV16oVzL15MRR_Fnxe7EFYc3MAykL-ccv&index=12)的教程总结来的。
    
2.  本次部署的一些前置工作还需要自己提前准备，比如github账号，钱包，测试网代币水龙头，准备部署账户等
    

**部署流程步骤：**

1.  从浏览器中下载合约源码
    
2.  准备部署账户
    
3.  使用remix编译部署合约
    
4.  部署前端代码
    
5.  安装依赖库
    
6.  修改路由地址
    
7.  将代码部署到Github Pages
    
8.  生成自定义的token
    
9.  自定义token导入Uniswap交易所
    

**正文**

**从浏览器中下载合约源码**

这次用的是线上版本

[工厂合约](https://cn.etherscan.com/address/0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f#code) [路由合约2](https://cn.etherscan.com/address/0x7a250d5630b4cf539739df2c5dacb4c659f2488d#code) [路由合约1](https://cn.etherscan.com/address/0xf164fc0ec4e93095b804a4795bbe1e041497b92a#code)是可选的，部署的流程是先部署工厂合约，然后将工厂合约的地址复制给路由合约2的构造函数。

**准备部署账户**

Uniswap的路由合约部署在以太坊主网和其他测试网的合约地址都是相同的，这样的结果就是无论前端切换到哪个网络，路由地址都是不变的。要想实现这个相同的地址的部署，我们需要准备一个全新的账户进行合约部署。全新的账户是指 **部署之前的nonce值为0** .这个可以参考[以太坊账户](https://learnblockchain.cn/books/geth/part1/account.html)章节的合约账户来了解！

本次我们用的是Goerli测试网。

**使用remix编译部署合约**

本次部署我们用的是在线的remix编译器进行在线编译。

先准备一个全新的账户，并且通过[Goerli水龙头](https://goerlifaucet.com/)接收测试币，每次是0.5个ETH,每24小时接收一次，**没事接接水，关键时候可以解决大问题**！

这个时候有人会问，为什么不用Truffle或者hardhat进行编译部署？其实是可以的，不过比较麻烦，主要是工厂合约和路由合约的**编译版本不一致**，导致在三方框架工具内编译起来比较麻烦，其次编译不是本文的主要目的。工具的使用后期会专门开一章进行讲解！

先将工厂合约copy下来进行编译。

其中红框的部分要注意和线上保持一致，istanbul EvmVersion和开启优化。

![工厂合约](https://storage.googleapis.com/papyrus_images/63a3881d6d200d210d320f928b8050a8b6d613b260273f31eeaa03b609f1231c.png)

工厂合约

其次将路由合约进行编译，注意这几个红色箭头，Gas Limit改成9000000,这是因为路由文件太大，导致部署消耗的gas太大，会超出限制。其次，下面的构造函数中需要两个入参，一个是需要填写工厂合约的地址，另外一个是基于Goerli的WETH地址合约。因为ETH不是erc20的token，因此必须使用WETH作为交换媒介！

**Goerli : 0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6**

![     路由合约](https://storage.googleapis.com/papyrus_images/47b6223f1b623b8d10ece86b040e1080adc69adaaf3a231e862b558abab23796.png)

路由合约

路由合约部署成功之后，将路由合约地址复制下来，替换React前端项目的主网的路由地址。该路由地址： **0x1762705FD51775b41701fAFCe8c90e4cF24e7a92**

**部署前端代码**

克隆前端代码

git clone [https://github.com/Uniswap/uniswap-interface.git](https://github.com/Uniswap/uniswap-interface.git)

**安装依赖库**

    cd uniswap-interface
    yarn
    

初次安装编译的过程会比较长，在安装的时候可能会出现许多的问题，建议可以尝试多次重新编译安装或者去git上的issue上去查找响应问题的解答，在此就不再详细展开了。

编译和安装依赖成功之后，运行

    yarn start   --- 运行成功，同时会打开一个本地地址的Uniswap的前端界面
    

**修改路由地址**

用编辑器打开React前端项目工程，找到\`

项目目录/uniswap-interface/src/constants/addresses.ts文件，找到V2\_ROUTER\_ADDRESS ，将值替换成上述编译好的路由合约地址变量

保存成功，重新运行即可 其实也看不出效果

    yarn start  
    

![修改React前端的路由地址](https://storage.googleapis.com/papyrus_images/19a756013567d0e9a5ca6de4d1a39ffb4de79bbc78c4068ef108ad4e22d4428c.png)

修改React前端的路由地址

**将代码部署到Github Pages**

这一步的目的是安装部署一个线上可执行的环境。

首先先将git clone下来的项目中的.git目录全部删除掉。

`rm -rf .git`

其次初始化git,将Uniswap 前端代码添加到自己的项目仓库中

依次执行

`git init`

`git remote add origin https://github.com/用户名/项目名.git`

在前端项目中安装gh-pages模块，从而将前端代码部署到github.io，在前端代码的目录运行

`yarn add gh-pages`

安装成功之后，接下俩编译react和部署gh-pages，在前端代码的目录运行

`yarn build`

修改前端代码目录中的package.json

按照下图中的红色箭头依次修改

将homepage 对应的值改为

`"homepage": "https://用户名.github.io/项目名称",//修改这里`

同时在scripts，添加

`"deploy": "gh-pages -d build" //添加这一行`

![修改package.json](https://storage.googleapis.com/papyrus_images/14524a25365fed68d9cc3d6092eb11012f41069f430f8b2f896d33d2ae7f98ff.png)

修改package.json

完成之后，在前端代码目录运行依次运行以下命令

1.  `git add .`
    
2.  `git commit -m ‘first commit‘`
    
3.  `git push`
    
4.  `yarn deploy ---- 在deploy运行的时候，首次部署会比较慢，如果出现错误，建议多次尝试部署命令`
    

部署成功之后，打开浏览器输入地址 `https://用户名.github.io/项目名称`

就可以看到部署的效果页面了

![Uniswap 效果页面](https://storage.googleapis.com/papyrus_images/1395ddb7b157941b9191783f79adb5ee1d3f732386c313cf824bae4ffc2e2d20.png)

Uniswap 效果页面

**生成自定义的token**

自己可以尝试进行发行ERC20的代币，通过发行，添加流动性和Swap等步骤来更好的理解Uniswap的运行机制

我先把自定义发行token的代码贴下来，大家可以自行取用。

发币的过程很简单，就是发行token的合约继承ERC20就可以了。

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.8;
    
    // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0/contracts/token/ERC20/IERC20.sol
    interface IERC20 {
        function totalSupply() external view returns (uint);
    
        function balanceOf(address account) external view returns (uint);
    
        function transfer(address recipient, uint amount) external returns (bool);
    
        function allowance(address owner, address spender) external view returns (uint);
    
        function approve(address spender, uint amount) external returns (bool);
    
        function transferFrom(
            address sender,
            address recipient,
            uint amount
        ) external returns (bool);
    
        event Transfer(address indexed from, address indexed to, uint value);
        event Approval(address indexed owner, address indexed spender, uint value);
    }
    

其中IERC20可以用这个，也可以通过[线上版本](https://docs.openzeppelin.com/contracts/4.x/api/token/erc20#IERC20) Import导入就行

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.8;
    import "./IERC20.sol";
    
    contract ERC20 is IERC20 {
        uint public totalSupply;
        mapping(address => uint) public balanceOf;
        mapping(address => mapping(address => uint)) public allowance;
        string public name = "LICECoin";
        string public symbol = "GOS";
        uint8 public decimals = 18;
    
        // constructor() public {
        //     mint(msg.sender, 100000000 * 10 ** 18);
        // }
    
        function transfer(address recipient, uint amount) external returns (bool) {
            balanceOf[msg.sender] -= amount;
            balanceOf[recipient] += amount;
            emit Transfer(msg.sender, recipient, amount);
            return true;
        }
    
        function approve(address spender, uint amount) external returns (bool) {
            allowance[msg.sender][spender] = amount;
            emit Approval(msg.sender, spender, amount);
            return true;
        }
    
        function transferFrom(
            address sender,
            address recipient,
            uint amount
        ) external returns (bool) {
            allowance[sender][msg.sender] -= amount;
            balanceOf[sender] -= amount;
            balanceOf[recipient] += amount;
            emit Transfer(sender, recipient, amount);
            return true;
        }
    
        function mint(uint amount) external {
            balanceOf[msg.sender] += amount;
            totalSupply += amount;
            emit Transfer(address(0), msg.sender, amount);
        }
    
        function burn(uint amount) external {
            balanceOf[msg.sender] -= amount;
            totalSupply -= amount;
            emit Transfer(msg.sender, address(0), amount);
        }
    }
    

这是ERC20合约，其实可以直接在这个合约通过构造器直接创建，但是为了代码很好的分离，建议还是再单独建个MyToken合约

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.8;
    import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.0.0/contracts/token/ERC20/ERC20.sol";
    contract MyToken is ERC20 {
    
         constructor(string memory name, string memory symbol) ERC20(name, symbol) {
            // Mint 100 tokens to msg.sender
            // Similar to how
            // 1 dollar = 100 cents
            // 1 token = 1 * (10 ** decimals)
            _mint(msg.sender, 100000000 * 10**uint(decimals()));
        }
        
    }
    

以上就完成了一个子定义Token的发布过程。需要注意的是

1.  在Remix中要切换到Goerli测试环境
    
2.  账户中要有测试币
    

**自定义token导入Uniswap交易所**

将上述生成的token的合约保存下来，可以在etherscan.io上查看该币的相关信息

[https://goerli.etherscan.io/token/0x7E9bc6163Dfdc63eb53E40DE41488BeC4C53372e](https://goerli.etherscan.io/token/0x7E9bc6163Dfdc63eb53E40DE41488BeC4C53372e)

通过合约地址进行导入

![导入自定义token](https://storage.googleapis.com/papyrus_images/f89a5dd00090e7647dfb48a40aaadd501a455619c138abcc15f94f7d4f1cada1.png)

导入自定义token

![流动性](https://storage.googleapis.com/papyrus_images/291959d16b04010caab50561d91a22afffb3034d1ae188e96896de5445d6287a.png)

流动性

之后可以通过添加流动性，在多个账户之间进行转账和Swap，同时注意看每次交换或者添加流动性和销毁流动性的时候，手续费是如何变换的。

**总结**

以上步骤就是整个搭建UniswapV2去中心化交易所Dex的流程步骤，其实步骤还是比较简单的，通过搭建过程，大家可以更好的了解DeFi中Dex的技术栈和工具，在进行测试的时候，也能更好的了解Uniswap V2产品的运行机制和逻辑。

---

*Originally published on [cyptoJune](https://paragraph.com/@cyptojune/uniswap-v2)*
