Cover photo

Uniswap V2 交易所部署详解

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

前置说明:

  1. 本次部署是参考Uniswap V2的线上版本,同时结合催眠大师的教程总结来的。

  2. 本次部署的一些前置工作还需要自己提前准备,比如github账号,钱包,测试网代币水龙头,准备部署账户等

部署流程步骤:

  1. 从浏览器中下载合约源码

  2. 准备部署账户

  3. 使用remix编译部署合约

  4. 部署前端代码

  5. 安装依赖库

  6. 修改路由地址

  7. 将代码部署到Github Pages

  8. 生成自定义的token

  9. 自定义token导入Uniswap交易所

正文

从浏览器中下载合约源码

这次用的是线上版本

工厂合约 路由合约2 路由合约1是可选的,部署的流程是先部署工厂合约,然后将工厂合约的地址复制给路由合约2的构造函数。

准备部署账户

Uniswap的路由合约部署在以太坊主网和其他测试网的合约地址都是相同的,这样的结果就是无论前端切换到哪个网络,路由地址都是不变的。要想实现这个相同的地址的部署,我们需要准备一个全新的账户进行合约部署。全新的账户是指 部署之前的nonce值为0 .这个可以参考以太坊账户章节的合约账户来了解!

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

使用remix编译部署合约

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

先准备一个全新的账户,并且通过Goerli水龙头接收测试币,每次是0.5个ETH,每24小时接收一次,没事接接水,关键时候可以解决大问题

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

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

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

工厂合约
工厂合约

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

Goerli : 0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6

     路由合约
路由合约

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

部署前端代码

克隆前端代码

git clone 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前端的路由地址
修改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
修改package.json

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

  1. git add .

  2. git commit -m ‘first commit‘

  3. git push

  4. yarn deploy ---- 在deploy运行的时候,首次部署会比较慢,如果出现错误,建议多次尝试部署命令

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

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

Uniswap 效果页面
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可以用这个,也可以通过线上版本 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

通过合约地址进行导入

导入自定义token
导入自定义token
流动性
流动性

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

总结

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