1. 筹备工作
Uniswap 是以太坊最为风行的去中心化交易所,它的代码齐全开源,本文将以 uniswap v2 版本为例,解说如何将 uniswap v2 智能合约部署到以太坊 goerli 测试网络,并且搭建前端进行操作。uniswap-v2 版本智能合约局部的代码寄存在 uniswap-v2-core 和 uniswap-v2-periphery 两个仓库,编译智能合约须要 node@>=10
版本。
首先装置 nodejs,并指定版本 node@>=10
:
sudo apt update -y
sudo apt install curl git npm -y
sudo npm install -g n yarn -y
sudo n 10 && PATH="$PATH"
而后将 clone 两个智能合约的代码仓库到本地:
git clone https://github.com/Uniswap/uniswap-v2-core.git
git clone https://github.com/Uniswap/uniswap-v2-periphery.git
以及 clone uniswap-interface 前端仓库,把 tag 切换到 v2.6.5
,因为后续的版本推出了 UNI 代币和治理性能,这里不进行部署。
git clone https://github.com/Uniswap/uniswap-interface.git
cd uniswap-interface && git checkout v2.6.5
咱们还须要筹备一个凋谢了 JSON RPC API 的以太坊节点,嫌麻烦能够去 https://infura.io 申请一个收费的 API Key。以及一个领有足够 ETH 余额的以太坊地址,goerli 测试网络能够关上 https://faucet.goerli.mudit.blog 水龙头为你的地址获取测试的 ETH 代币。
当初筹备工作实现了,上面开始编译并且部署智能合约。
2. 部署合约
因为智能合约代码寄存在两个仓库,不便对立部署,咱们先创立一个文件夹 uniswap-contracts
保留后续编译的智能合约代码。
mkdir uniswap-contracts
以后的目录构造如下:
root@54ab88b47042:~# ls
uniswap-contracts uniswap-interface uniswap-v2-core uniswap-v2-periphery
接下来咱们别离编译两个我的项目的智能合约代码,而后拷贝到 uniswap-contracts
目录。
2.1 编译合约
首先是 uniswap-v2-core
我的项目,进入目录后拉取依赖而后编译:
cd uniswap-v2-core
yarn && yarn compile
编译后的代码寄存在 build
目录,咱们须要把它拷贝至之前创立的 uniswap-contracts
目录。
cp -r build ../uniswap-contracts
cd ..
接下来编译 uniswap-v2-periphery
我的项目,也是雷同的步骤,最初将编译后的代码拷贝到 uniswap-contracts
目录:
cd uniswap-v2-periphery
yarn && yarn compile
cp -r build ../uniswap-contracts
cd ..
2.2 部署合约
编译好的合约代码咱们曾经全副拷贝到 uniswap-contracts
目录。接下来就是部署合约了,这一步略微麻烦一些,须要咱们编写一个脚本。
首先在 uniswap-contracts
目录下创立一个文本文件 deploy.js
,并将上面的代码拷贝进去。
留神:常量 endpoint 和 hexPrivateKey 请自行批改,并保障地址外面有足够的 ETH 用于领取 GAS 费用。
const Web3 = require('web3')
const WETH9 = require('./build/WETH9.json')
const UniswapV2Pair = require('./build/UniswapV2Pair.json')
const UniswapV2Factory = require('./build/UniswapV2Factory.json')
const UniswapV2Router01 = require('./build/UniswapV2Router01.json')
const UniswapV2Router02 = require('./build/UniswapV2Router02.json')
const endpoint = 'https://goerli.infura.io/v3/5c5a4a14c82f4d6e852b7cc29b2cbb6e';
const hexPrivateKey = '0xfad9c8855b740a0b7ed4c221dbad0f33a83a49cad6b3fe8d5817ac83d38b6a19';
async function sendTransaction(web3, chainId, account, data, nonce, gasPrice) {
const message = {
from: account.address,
gas: 5000000,
gasPrice: gasPrice,
data: data.startsWith('0x') ? data : '0x' + data,
nonce: nonce,
chainId: chainId
}
const transaction = await account.signTransaction(message)
return web3.eth.sendSignedTransaction(transaction.rawTransaction)
}
(async () => {const options = { timeout: 1000 * 30}
const web3 = new Web3(new Web3.providers.HttpProvider(endpoint, options))
const account = web3.eth.accounts.privateKeyToAccount(hexPrivateKey)
const chainId = await web3.eth.getChainId()
const gasPrice = await web3.eth.getGasPrice()
let nonce = await web3.eth.getTransactionCount(account.address)
// deploy WETH contract
let weth = null
{const contract = new web3.eth.Contract(WETH9.abi)
const data = contract.deploy({data: WETH9.bytecode}).encodeABI()
const receipt = await sendTransaction(web3, chainId, account, data, nonce, gasPrice)
console.info('WETH:', weth = receipt.contractAddress)
nonce = nonce + 1
}
// deploy UniswapV2Factory contract
let factory = null
{const contract = new web3.eth.Contract(UniswapV2Factory.abi)
const options = {data: UniswapV2Factory.bytecode, arguments: [account.address] }
const data = contract.deploy(options).encodeABI()
const receipt = await sendTransaction(web3, chainId, account, data, nonce, gasPrice)
console.info('UniswapV2Factory:', factory = receipt.contractAddress)
nonce = nonce + 1
}
// deploy UniswapV2Router01 contract
{const contract = new web3.eth.Contract(UniswapV2Router01.abi)
const options = {data: UniswapV2Router01.bytecode, arguments: [factory, weth] }
const data = contract.deploy(options).encodeABI()
const receipt = await sendTransaction(web3, chainId, account, data, nonce, gasPrice)
console.info('UniswapV2Router01:', receipt.contractAddress)
nonce = nonce + 1
}
// deploy UniswapV2Router02 contract
{const contract = new web3.eth.Contract(UniswapV2Router02.abi)
const options = {data: UniswapV2Router02.bytecode, arguments: [factory, weth] }
const data = contract.deploy(options).encodeABI()
const receipt = await sendTransaction(web3, chainId, account, data, nonce, gasPrice)
console.info('UniswapV2Router02:', receipt.contractAddress)
nonce = nonce + 1
}
let data = UniswapV2Pair.bytecode
if (!data.startsWith('0x')) data = '0x' + data
console.info('INIT_CODE_HASH:', web3.utils.keccak256(data))
})()
而后再拉取依赖:
npm init -f && npm install web3
最初执行部署合约脚本:
node deploy.js
稍等片刻终端就会输出部署后的合约地址了,如下所示:
root@7f704ee78d9d:~/uniswap-contracts# node deploy.js
WETH: 0x3bBb875C856b5607DF7740fBd3a40B2B443D6597
UniswapV2Factory: 0xf94B5efD90972e5a5e77b5E3dE5236333CedCe6F
UniswapV2Router01: 0x41Db8E670e03d864A449ef1106537E6ca0C18dEC
UniswapV2Router02: 0x81A14364BF285aeA0BAFf5925670a4bDBD575E99
INIT_CODE_HASH: 0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f
到这里合约就部署实现了,把终端输入的合约地址记录下来,部署前端的时候须要进行配置。
3. 部署前端
智能合约曾经部署到测试网络,最初咱们运行前端看看是否失常工作了吧。首先进入 uniswap-interface
目录而后拉取依赖:
cd uniswap-interface
yarn
因为咱们部署了新的合约,而前端配置外面还是 uniswap 官网的合约地址,所以须要进行如下批改:
- 批改
uniswap-interface/src/constants/index.ts
文件中 ROUTER_ADDRESS 的值为${UniswapV2Router02}
。 - 批改
uniswap-interface/src/state/swap/hooks.ts
文件中 BAD_RECIPIENT_ADDRESSES 数组的值为 [${UniswapV2Factory}
,${UniswapV2Router01}
,${UniswapV2Router02}
]。 - 批改
uniswap-interface/node_modules/@uniswap/sdk/dist/sdk.cjs.development.js
和uniswap-interface/node_modules/@uniswap/sdk/dist/sdk.esm.js
文件中 FACTORY_ADDRESS 为${UniswapV2Factory}
。 - 批改
uniswap-interface/node_modules/@uniswap/sdk/dist/sdk.cjs.development.js
和uniswap-interface/node_modules/@uniswap/sdk/dist/sdk.esm.js
文件中 INIT_CODE_HASH 为${INIT_CODE_HASH}
。 - 批改
uniswap-interface/node_modules/@uniswap/sdk/dist/sdk.cjs.development.js
和uniswap-interface/node_modules/@uniswap/sdk/dist/sdk.esm.js
文件中全局变量 WETH,将其中key
为 GÖRLI 的Token
类型的地址批改为${WETH}
。
批改实现之后运行前端程序:
yarn start
Starting the development server...
Browserslist: caniuse-lite is outdated. Please run:
npx browserslist@latest --update-db
Files successfully emitted, waiting for typecheck results...
Compiled successfully!
You can now view @uniswap/interface in the browser.
Local: http://localhost:3000
On Your Network: http://172.23.227.86:3000
Note that the development build is not optimized.
To create a production build, use yarn build.
最初关上浏览器拜访地址 http://localhost:3000 查看成果。
- 点击 Connect to a wallet,抉择 MetaMask 钱包 (须要事后装置浏览器插件)。
- 切换钱包网络至 Goerli 测试网络,因为咱们的智能合约部署在下面。
- 当初能够开始增加流动性或者交易了。
4. 增加代币列表
当初 uniswap v2 曾经胜利部署了,如果咱们想要在交易所增加本人的代币该怎么办呢?上面我就来一步一步解说如何增加自定义代币。
uniswap v2 前端显示的代币列表配置在 uniswap-interface/src/constants/lists.ts
文件中的 DEFAULT_LIST_OF_LISTS 常量数组,数组元素的值能够是一个 http 地址 、ifps 地址 和 ENS name。地址返回后果必须是指定构造的 json 文件,咱们能够通过向 DEFAULT_LIST_OF_LISTS 常量数组增加新的地址达到增加自定义代币的目标。
上面就来通过增加一个代币详细描述这个过程。
1. 创立 tokens.json 文件
文件格式如下:
{
"name": "Test Tokens List",
"version": {
"major": 1,
"minor": 0,
"patch": 0
},
"logoURI": "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0/logo.png",
"timestamp": "2021-07-25 00:00:00.000+00:00",
"tokens": [
{
"chainId": 5,
"address": "0x499d11E0b6eAC7c0593d8Fb292DCBbF815Fb29Ae",
"name": "Matic Token",
"symbol": "MATIC",
"decimals": 18,
"logoURI": "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0/logo.png"
}
]
}
tokens
字段是一个数组类型,它负责形容代币列表蕴含的所有代币。咱们在外面增加了一个名为 Matic Token
的代币 (当然也能够增加多个代币),符号是 MATIC
,合约地址是 0x499d11E0b6eAC7c0593d8Fb292DCBbF815Fb29Ae
。请留神外面有一个 chainId
字段,值为 5
,这是因为 goerli 测试网络的 chainId 是 5,前端只有在钱包连贯网络的 chainId 为 5 时才会显示这个代币。其它以太坊网络 chainId 的值请参考:https://besu.hyperledger.org/en/stable/Concepts/NetworkID-And-ChainID。
2. 上传 tokens.json 文件
tokens.json 文件实现编辑后就能够上传至服务器了。轻易上传到哪里都能够,比方你本人的 HTTP 文件服务器,只有可能公网拜访就行。我将它上传到了 gist.github.com (须要翻墙),拜访地址是:https://gist.githubusercontent.com/pygdev/ec497ed8bba8008c2512b3f241bfb5ef/raw/ac6d0286e3e5a39499a71575a065f16787782a70/tokens.json。
3. 在前端增加 Tokens List
首先关上 uniswap v2 前端页面,连贯钱包,并切换至 goerli 网络,而后点击 抉择通证 按钮。
而后在输入框输出 tokens.json
的地址,点击 Add 按钮。
增加 tokens.json
胜利后 Tokens List 就会呈现在列表外面了,点击 Select 按钮增加代币列表。
增加胜利,当初能够在交易所外面为 MATIC 代币增加流动性或者进行兑换了。
留神 :增加流动性须要获取帐户里有一些 MATIC 代币,能够到 MATIC Faucet 进行支付。