# Uniswap V2 交易所部署详解 **Published by:** [cyptoJune](https://paragraph.com/@cyptojune/) **Published on:** 2022-09-15 **URL:** https://paragraph.com/@cyptojune/uniswap-v2 ## Content 在DeFi世界中,Dex(去中心化交易所)是最核心的一块,Uniswap是整个Dex的龙头,SushiSwap,PancakeSwap 等都是参考,甚至完全fork了Uniswap的整个产品逻辑和代码,也因此好多人也想部署快速部署一个属于自己的Uniswap,个人觉得也是很有必要的,通过自己从零搭建,一步一步完成,在这个过程可以清楚知道Uniswap整个项目工程的结构和产品逻辑,将来也能站在巨人的肩膀上,开发出自己的DeFi乐高! 前置说明:本次部署是参考Uniswap V2的线上版本,同时结合催眠大师的教程总结来的。本次部署的一些前置工作还需要自己提前准备,比如github账号,钱包,测试网代币水龙头,准备部署账户等部署流程步骤:从浏览器中下载合约源码准备部署账户使用remix编译部署合约部署前端代码安装依赖库修改路由地址将代码部署到Github Pages生成自定义的token自定义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前端的路由地址将代码部署到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完成之后,在前端代码目录运行依次运行以下命令git add .git commit -m ‘first commit‘git pushyarn deploy ---- 在deploy运行的时候,首次部署会比较慢,如果出现错误,建议多次尝试部署命令部署成功之后,打开浏览器输入地址 https://用户名.github.io/项目名称 就可以看到部署的效果页面了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的发布过程。需要注意的是在Remix中要切换到Goerli测试环境账户中要有测试币自定义token导入Uniswap交易所 将上述生成的token的合约保存下来,可以在etherscan.io上查看该币的相关信息 https://goerli.etherscan.io/token/0x7E9bc6163Dfdc63eb53E40DE41488BeC4C53372e 通过合约地址进行导入导入自定义token流动性之后可以通过添加流动性,在多个账户之间进行转账和Swap,同时注意看每次交换或者添加流动性和销毁流动性的时候,手续费是如何变换的。 总结 以上步骤就是整个搭建UniswapV2去中心化交易所Dex的流程步骤,其实步骤还是比较简单的,通过搭建过程,大家可以更好的了解DeFi中Dex的技术栈和工具,在进行测试的时候,也能更好的了解Uniswap V2产品的运行机制和逻辑。 ## Publication Information - [cyptoJune](https://paragraph.com/@cyptojune/): Publication homepage - [All Posts](https://paragraph.com/@cyptojune/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@cyptojune): Subscribe to updates