Defi部署教程 Uniswap部署 搭建去中心化交易所

操作系统:MAC OS 10.14.x,需要科学上网

目前大家可以很容易的将自己发行的Token挂在Uniswap上创建交易对并进行交易.如果有些朋友的需求不是发行Token而是创建一个自己的市场,可以通过本文了解到如何部署Uniswap去中心化交易所.
本文将会下载Uniswap的合约源码和前端代码,使用自己的账号部署Uniswap合约到测试网,前端部署到GitHub Pages.

演示地址: https://walker1992.github.io/uniswap-interface/ (请在测试网使用)

准备Uniswap合约源码

源码结构

Uniswap在Github上面开源了全部合约代码,其中包括核心合约,周边合约两部分.Uniswap还开源了前端代码,前端代码使用React开发.

在Uniswap的核心代码中,主要包含3个合约:工厂(Factory)合约,配对(pair)合约,ERC20合约.其中配对合约继承了ERC20合约,我们可以把它们看作一个合约.工厂合约通过create2方法部署配对合约,所以在部署合约时只需要部署工厂合约.
周边合约中包括一些示例代码,例如价格预言机,闪电交换,其中最重要的是路由合约.在周边合约的代码库中,包含两个路由合约:UnsiwapV2Router01,UnsiwapV2Router02.工厂合约和配对合约需要通过路由合约调用才能更好的完成交易所的全部功能,所以我们还要部署路由合约.
两个合约大部分相同,有小部分不同,如果将两个合约的差异化合并成一个合约,部署的时候将会出现out of gas,所以才被分成了两个合约.常用功能两个合约中都包括,所以我们部署其中任意一个路由合约都可以.

合约关系

从浏览器中下载合约源码

如果对合约代码并不熟悉,可以直接从以太坊浏览器中拷贝线上版合约源码

部署合约

安装truffle

这里使用truffle作为部署合约的环境,其他的环境也可以

$ npm install truffle -g
创建项目
$ mkdir uniswap
$ cd uniswap
$ truffle init
目录结构
uniswap
└───contracts
    └───Migrations.sol
    └───(创建UniswapV2Factory.sol,将浏览器上的工厂合约源码拷贝进来)
    └───(创建UniswapV2Router02.sol,将浏览器上的路由合约源码拷贝进来)
└───migrations
    └───1_initial_migration.js
└───test
└───truffle-config.js

准备部署账户

Uniswap的路由合约在以太坊的主网和Ropsten,Rinkeby,Goerli,Kovan几个测试网的合约地址都是相同的,这样可以使Uniswap的前端不管切换到任何一个网络,路由地址都不会变.要想实现这个相同地址的部署,我们需要准备一个全新的账户用来部署合约.全新的账户指的是在部署合约之前的nonce值为0.因为合约的地址是根据你的账户地址和nonce值计算出来的,所以在不同网络中,如果nonce值相同,部署出的合约地址也相同.

通过助记词生成新账户

参考 BIP32 BIP39 BIP44 助记词 以太坊 账户
使用英文助记词,保存好助记词、对应的账户地址.

向新地址转帐ETH

通过一个已有Ether的账户向新账户转帐.测试网的Ether可以通过每个测试网的水龙头申请到测试币.

准备WETH合约地址

在部署路由合约时,构造函数中需要填入工厂合约的地址和WETH合约的地址,由于WETH合约的地址在主网和测试网的地址都不相同,所以需要找到每个网络中WETH合约的地址.

WETH合约用于将Eth交换为erc20的Eth,由于Eth不是erc20的token,所以我们必须使用WETH作为交换媒介.

{
    mainnet:'0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
    ropsten:'0xc778417E063141139Fce010982780140Aa0cD5Ab',
    rinkeby:'0xc778417E063141139Fce010982780140Aa0cD5Ab',
    goerli:'0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6',
    kovan:'0xd0A1E359811322d97991E03f863a0C30C2cF029C'
}

申请infuraKey

在部署合约之前,我们还需要使用infura作为免费节点,所以需要申请一个infuraKey

配置truffle-congif.js

安装@truffle/hdwallet-provider模块,用于打开助记词的钱包,在项目目录中运行命令:

$ npm install @truffle/hdwallet-provider

如果我们需要在每个网络中都部署上Uniswap合约,就需要配置truffle-congif.js,可以将以下代码全部拷贝粘贴到文件中,覆盖原有代码.修改infuraKeymnemonic助记词

$ vim truffle-config.js 
const HDWalletProvider = require('@truffle/hdwallet-provider');
const infuraKey = "填写infuraKey";
const mnemonic = "填写助记词";
module.exports = {
  networks: {
    mainnet: {
      provider: () => new HDWalletProvider(mnemonic, `https://mainnet.infura.io/v3/` + infuraKey),
      network_id: 1,
      gas: 5500000,
      confirmations: 2,
      timeoutBlocks: 200,
      skipDryRun: true
    },    
    ropsten: {
      provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/` + infuraKey),
      network_id: 3,
      gas: 5500000,
      confirmations: 2,
      timeoutBlocks: 200,
      skipDryRun: true
    },    
    rinkeby: {
      provider: () => new HDWalletProvider(mnemonic, `https://rinkeby.infura.io/v3/` + infuraKey),
      network_id: 4,
      gas: 5500000,
      confirmations: 2,
      timeoutBlocks: 200,
      skipDryRun: true
    },    
    goerli: {
      provider: () => new HDWalletProvider(mnemonic, `https://goerli.infura.io/v3/` + infuraKey),
      network_id: 5,
      gas: 5500000,
      confirmations: 2,
      timeoutBlocks: 200,
      skipDryRun: true
    },    
    kovan: {
      provider: () => new HDWalletProvider(mnemonic, `https://kovan.infura.io/v3/` + infuraKey),
      network_id: 42,
      gas: 5500000,
      confirmations: 2,
      timeoutBlocks: 200,
      skipDryRun: true
    },
  },
  mocha: {
    // "timeout": 100000,
  },
  compilers: {
    solc: {
      version: "0.5.16",    // Fetch exact version from solc-bin (default: truffle's version)
      // docker: true,        // Use "0.5.1" you've installed locally with docker (default: false)
      // settings: {          // See the solidity docs for advice about optimization and evmVersion
      //  optimizer: {
      //    enabled: false,
      //    runs: 200
      //  },
      //  evmVersion: "byzantium"
      // }
    }
  }
}

部署脚本

在编写truffle的部署脚本之前,先准备一个常用账户作为设置交易所手续费收取账户的管理员地址.
然后在项目目录中运行命令,或者用编辑器创建文件migrations/2_deploy_contract.js

$ vim migrations/2_deploy_contract.js
const UniswapV2Factory = artifacts.require("UniswapV2Factory");
const UniswapV2Router02 = artifacts.require("UniswapV2Router02");
const feeToSetter = '设置手续费账户的管理员地址';
const WETH = {
    mainnet:'0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
    ropsten:'0xc778417E063141139Fce010982780140Aa0cD5Ab',
    rinkeby:'0xc778417E063141139Fce010982780140Aa0cD5Ab',
    goerli:'0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6',
    kovan:'0xd0A1E359811322d97991E03f863a0C30C2cF029C'
};
module.exports = (deployer, network, accounts) => {
    // 由于合约版本不对,分开部署
    // deployer.deploy(UniswapV2Factory, feeToSetter).then((FactoryInstance)=>{
    //     return deployer.deploy(UniswapV2Router02,FactoryInstance.address,WETH[network]);
    // });

    //使用 solc vresion 0.5.16
    deployer.deploy(UniswapV2Factory, feeToSetter);

    //使用 solc vresion 0.6.6 
    //将UniswapV2Factory的合约地址替换掉
    deployer.deploy(UniswapV2Router02,'0x4207CD6E113E364220EC08e2Ff446973437859fd',WETH[network]);
    
}

部署合约

在项目目录运行命令:

$ truffle migrate -f 2 --network ropsten

$ truffle migrate -f 2 --network mainnet
$ truffle migrate -f 2 --network rinkeby
$ truffle migrate -f 2 --network goerli
$ truffle migrate -f 2 --network kovan

小知识

module.exports = {
  networks: {
    ropsten: {
      provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/xxx... infuraKey `),
      network_id: 3,
      gas: 7500000
    },  
  },
}

ropsten网络定义中的provider使用实例化的HDWalletProvider.HDWalletProvider以助记符和期望的网络为参数. Infura主页上提供Infura支持的网络列表.Provider值被封装在一个函数中,这可以确保它在需要之前不会被初始化,如果连接到多个网络,这一点尤为重要. 关于该主题的更多信息,请参阅Truffle文档的网络配置部分.
默认情况下,由助记符产生的第一个账户将负责执行合约迁移任务。 但如果需要的话,你可以传入参数以指定要使用的帐户.例如,要使用第三个帐户:
new HDWalletProvider(mnemonic, "https://ropsten.infura.io/xxx", 2);
账户索引是从零开始的,所以2表示第三个地址.

现在已经将Uniswap的路由合约和工厂合约都部署在所有的网络中了,你可以在控制台的信息中找到两个合约的地址,也可以在以太坊浏览器中找到,在以太坊浏览器中搜索新账户的地址,显示出来的新账户的交易信息中,将会显示两个创建合约的交易,第二个创建的合约是路由合约,将路由合约的地址记录下来,接下来会用到.

部署Uniswap前端

克隆前端代码

在项目目录运行命令:

//克隆前端代码
$ git clone https://github.com/Uniswap/uniswap-interface.git
$ cd uniswap-interface
//安装依赖库
$ yarn
//测试运行一下
$ yarn start

如果运行成功,将会打开一个浏览器,同时打开Uniswap的前端界面.

修改路由地址

在Uniswap的前端中以常量的形式定义了Uniswap的路由地址,我们只需要修改路由地址就可以让前端链接到你的路由合约中
修改文件: 项目目录/uniswap-interface/src/constants/index.ts第6行

import { AbstractConnector } from '@web3-react/abstract-connector'
import { ChainId, JSBI, Percent, Token, WETH } from '@uniswap/sdk'

import { fortmatic, injected, portis, walletconnect, walletlink } from '../connectors'

export const ROUTER_ADDRESS = '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D' //修改成你的路由合约地址
......

保存后运行yarn start即可看到效果

将代码部署到GitHub Pages

创建GitHub项目

创建项目的方法可以自行baidu

将前端代码添加到GitHub项目仓库

//删除原先Uniswap项目中的.git目录
$ cd uniswap-interface
$ rm -rf .git
//初始化git,并将Unsiwap前端代码添加到自己的项目仓库中
$ git init
$ git add .
$ git commit -m "init"
$ git branch -M main
$ git remote add origin https://github.com/用户名/项目名.git
$ git push -u origin main

安装并部署gh-pages

我们将通过gh-pages模块将前端代码部署到github.io,在前端代码的目录运行:

$ yarn add gh-pages
// 编译react和部署gh-pages
$ yarn build
//修改package.json
$ vim package.json
{
  "name": "@uniswap/interface",
  "description": "Uniswap Interface",
  "homepage": "https://用户名.github.io/项目名称",//修改这里
......

// 添加部署的脚本,还是在package.json中
......
"scripts": {
    ......
    "deploy": "gh-pages -d build" //添加这一行
  },

保存退出之后,在前端代码的目录运行:

$ git add .
$ git commit -m "gh-pages"
$ git push
$ yarn deploy

在浏览器中打开https://用户名.github.io/项目名称/index.html就可以打开自己的交易所啦.
如果不输入地址结尾的index.html在项目刚部署之后会报错,过一段时间就可以不输入了.

扩展

部署自己的weth

可以将以太坊浏览器中的weth源码拷贝下来,自己部署一个属于自己的weth合约

可信token列表

Uniswap有一个自己的可信token列表,同样被设置在项目目录/uniswap-interface/src/constants/index.ts文件中,在最后一行就是.你可以将这个链接地址的文件拷贝下来,设置成自己需要的可信token地址列表,然后上传到github目录中,再修改index.ts文件中的链接地址,这样就可以让你自己的交易所中拥有自己设置的可信token列表了

参考:
手把手教你部署自己的uniswap交易所
truffle 开发笔记(一)
uniswap(v2)接入快速入门总结
defi uniswapV3源代码分析之一 增加流动性add liquidity

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容