LOADING...
LOADING...
LOADING...
当前位置: 玩币族首页 > 区块链资讯 > 在以太坊上建立一个迷你版去中心化交易所

在以太坊上建立一个迷你版去中心化交易所

2020-06-06 区块链研究员 来源:区块链网络

????简介

在Ethereum上打造的第一个杀手级应用就是token。一个名为ERC20的标准出现了,现在任何人都可以在几秒钟内在Ethereum上部署一个通根。

通常情况下,一个通根需要交换价值或另一个通根,传统上这是由不安全的中心化实体促成的。

2017年,Vitalik Buterin提出了一种方法,允许智能合约使用基于储备的流动性比率来执行两种资产之间的交换。最终,这成为了????Uniswap,现在任何人都可以使用uniswap.exchange在Ethereum上交换通根。

Uniswap合约已经集体转移了超过12亿美元。????

在2019年期间,Uniswap流动性提供商赚取了超过120万美元的费用。- 2019年的以太坊

在本教程中,我们将尝试在一个易于消化的智能合约中,将一个去中心化的交易所归纳为几个简单的Solidity函数。值得庆幸的是,我的好友Philippe Castonguay创建了uniswap-solidity,本教程将使用这个代码的瘦身版。

我们将构建一个去中心化的交易所,使用任何人都可以参与的流动性池将任意通根换成ETH。这个构建将展示智能合约如何使用加密经济激励机制创建 ???? 自动的去中心化系统。

????"♀? 快速展示

https://youtu.be/eP5w6Ger1EQ

????????? 前提

你需要安装NodeJS>=10,Yarn和Git。

本教程将假设您对Web应用开发有基本的了解,并对Ethereum的核心概念有一定的接触。

?????♀? 开始

在????去中心化货币编程中,我们介绍了 ???? scaffold-eth。本教程将使用Ethereum开发scaffolding的dex分支。


git clone https://github.com/austintgriffith/scaffold-eth.git dex

cd dexgit checkout dexyarn installyarn start

我们还将希望引入我们的本地区块链,并部署我们的合同。在一个新的终端窗口中运行。


yarn run chain

在第三个终端窗口,我们可以用以下方法编译和部署。


yarn run deploy

该应用程序应该出现在http://localhost:3000,你应该看到。


??. 如果你看到的不是这个开头,你可能上错了git分支。

我们还会看到显示两个智能合约,分别叫做DEX和Balloons。


我们可以在package/buidler/contracts中找到这些智能合约。

Balloons.sol只是一个ERC20合约的例子,它可以向任何部署它的地址发送1000个硬币。

DEX.sol是我们将在本教程中构建的,你可以看到它开始使用一个SafeMath库来帮助我们防止溢出和不足,并且还跟踪我们在构造函数中设置的一个token(ERC20接口)(在部署时)。


??你可以在package/buidler/contracts中找到智能合约。还有其他的contracts文件夹,所以请确保你能用DEX.sol找到正确的文件夹。

???? 储备金

正如在介绍中提到的,我们希望创建一个自动市场,在这个市场中,我们的合约将同时持有ETH和????Balloons的储备。这些储备将提供流动性,允许任何人在资产之间进行交换。让我们在DEX.sol中添加几个新变量。


uint256 public totalLiquidity;mapping (address => uint256) public liquidity;

这些变量用来跟踪总的流动性,但也可以通过单个地址来跟踪。

然后,让我们在DEX.sol中创建一个应付payable的init()函数,然后我们可以定义一个token的数量,它将转移给自己。

function init(uint256 tokens) public payable returns (uint256) {
require(totalLiquidity==0,"DEX:init - already has liquidity");
totalLiquidity = address(this).balance;
liquidity[msg.sender] = totalLiquidity;
require(token.transferFrom(msg.sender, address(this), tokens));
return totalLiquidity;
}

调用init()会将我们的合约同时加载ETH和????Balloons。

你可以用yarn run compile命令编译你的合约,现在,只要忽略任何警告即可。当你准备好后部署你的合约。


yarn run deploy

您的应用程序应该应该在一个新的地址重新热加载DEX合约。另外,我们新的流动性变量会自动加载到前端。


我们可以看到,DEX开始是空的。我们希望能够调用init()来启动它的流动性,但我们还没有任何资金或通根。

???? Scaffold-eth在页面加载时,每个用户都会以一个临时账户开始。让我们把我们的地址复制到右上方。


并从左下角的faucet给我们的账户发一些测试ETH。


现在我们需要一些????Ballon通根! 在packages/buidler/scripts中找到deploy.js文件,让我们添加一行,在合同部署时给我们的账户发送10个通根(10乘以10??,因为没有小数)。


现在重新部署一切,我们会看到新的地址合同,但更重要的是,在部署时应该有10个通根发送给我们。


yarn run deploy

要在前端看到我们的????balloons,你会看到我们在App.js中的<Account>组件下面使用了一个<TokenBalance>组件。你可以在packages/react-app/src目录下找到App.js)。


我们还不能直接调用init(),因为DEX合约不允许从我们的账户中转移通根。我们需要用Ballons的用户界面来批准approve()我们的DEX合约。复制并粘贴DEX地址,然后将金额设置为500000000000000(5*10??)。


如果你点击了????图标,它应该会启动一个交易,批准DEX拿走你的5个通根。你可以用allowance格式测试一下。


现在我们准备在DEX上调用init()。我们将告诉它取走5(*10??)我们的通根,我们也将发送0.01 ETH与交易。你可以通过输入 "0.01 "作为交易值,然后点击??进行**10??,然后点击#??将其转换为十六进制。


一旦你点击了????按钮,你的交易就会送入ETH,合约会抓取5个你的通根。


您可以使用用户界面查看DEX有多少个????balloons。


干的不错,但如果我们在部署合约时调用init()函数就会简单很多。在deploy.js脚本中,尝试取消对init部分的注释,这样我们的DEX将以5个ETH和5个Balloons的流动性开始。


现在,当我们yarn run deploy时,我们的合约应该在部署后立即被初始化,并且我们应该有相等的ETH和通根储备。


???? 价格

现在我们的合约同时持有ETH和通根的储备,我们想用一个简单的公式来确定两者之间的汇率。

让我们从公式x * y = k开始,其中x和y是储备量。

( amount of ETH in DEX ) * ( amount of tokens in DEX ) = k

k被称为不变量,因为它在交易过程中不会改变。(k只有在增加流动性时才会发生变化。) 如果我们绘制这个公式,我们会得到一条看起来像这样的曲线。


????我们只是把一种资产换成另一种资产,"价格 "基本上是指你投入一定量的投入资产,就能得到多少产出资产。

????噢! 基于这样一条曲线的市场,总会有流动性,但随着比例越来越不平衡,同样的交易金额,你得到的弱资产会越来越少。同样,如果智能合约的ETH太多,而通根不足,那么将通根换成ETH的价格应该是比较理想的。

当我们调用init()时,我们以1:1的比例传递了ETH和通根,这个比例必须保持不变。当一种资产的储备量发生变化时,另一种资产也必须反过来变化。

我们来编辑一下我们的DEX.sol智能合约,带入一个这个价格函数。

function price(uint256 input_amount, uint256 input_reserve, uint256 output_reserve) public view returns (uint256) {
uint256 input_amount_with_fee = input_amount.mul(997);
uint256 numerator = input_amount_with_fee.mul(output_reserve);
uint256 denominator = input_reserve.mul(1000).add(input_amount_with_fee);
return numerator / denominator;
}

我们用投入与产出准备金的比例来计算换取任何一种资产的价格。让我们来部署一下这个,并进行摸索。


yarn run deploy

比如说我们有100万ETH和100万个通根,如果把这个放到我们的价格公式里,问它1000ETH的价格,那几乎是1:1的比例。


如果我们投入1000ETH,我们将收到996个代币。如果我们支付0.3%的费用,如果一切都很完美,应该是997。但是,当我们的合约远离原来的比例时,会有一点点的滑点。让我们再深入了解一下,真正了解这里的情况。

假设有500万ETH,只有100万代币。那么,我们要投入1000个代币。这意味着我们应该收到大约5000个ETH。


最后,我们假设比例是一样的 但我们要交换10万个通根,而不是1000个。我们会注意到,滑点的数量要大得多。我们将只得到498,000个,而不是453,305个,因为在储备上发生了这么大的变动。


????当准备金比例偏离平衡点时,合约会自动调整价格。这就是所谓的????自动做市商。

??交易

让我们编辑DEX.sol智能合约,并添加两个新函数,用于从每个资产交换到另一个资产。

function ethToToken() public payable returns (uint256) {
uint256 token_reserve = token.balanceOf(address(this));
uint256 tokens_bought = price(msg.value, address(this).balance.sub(msg.value), token_reserve);
require(token.transfer(msg.sender, tokens_bought));
return tokens_bought;
}function tokenToEth(uint256 tokens) public returns (uint256) {
uint256 token_reserve = token.balanceOf(address(this));
uint256 eth_bought = price(tokens, token_reserve, address(this).balance);
msg.sender.transfer(eth_bought);
require(token.transferFrom(msg.sender, address(this), tokens));
return eth_bought;
}

这些函数中的每一个都会使用我们的价格函数计算所产生的输出资产的数量,该函数关注储备与输入资产的比例。

我们可以调用tokenToEth,它会取走我们的通根并发送给我们ETH,或者我们可以调用ethToToken,在交易中加入一些ETH,它将向我们发送通根。

让我们编译和部署我们的合约,然后转移到前端。


yarn run deploy

你的应用界面应该重新热加载并显示两个新功能。



用faucet给我们的账户发了一些ETH后,我们可以尝试用通根换一些ETH。我们先从0.001开始,然后点??,再点#?? 。然后,如果我们点击????就会进行交易,调用ethToToken()。


而我们的账户应该会收回0.001的通根。


把通根换成ETH比较麻烦,因为我们要先做一笔交易,approve() DEX取走我们的通根。让我们批准DEX地址取1(* 10??)通根(100000000000000)。


那我们就试着把这个数量的通根换成ETH。


那么我们的ETH余额应该会增加0.85左右。

(它显示的是您的美元余额,但您可以点击它查看确切的金额:)


???? 我们正在交易资产! ????用一些表情符号来庆祝吧! ???? ???? ????

???? 流动性

到目前为止,只有init()函数控制流动性。为了使其更加去中心化,如果任何人都能以正确的比例向DEX发送ETH和通根来增加流动性池,那就更好了。

让我们创建两个新函数,让我们存入和提取流动性。


function deposit(uint256 tokens) public payable returns (uint256) { {
uint256 eth_reserve = address(this).balance.sub(msg.value);
uint256 token_reserve = token.balanceOf(address(this));
uint256 token_amount = (msg.value.mul(token_reserve) / eth_reserve).add(1);
uint256 liquidity_minted = msg.value.mul(totalLiquidity) / eth_reserve;
liquidity[msg.sender] = liquidity[msg.sender].add(liquidity_minted);
totalLiquidity = totalLiquidity.add(liquidity_minted);
require(token.transferFrom(msg.sender, address(this), token_amount))。
return liquidity_minted.token.transferFrom(msg.sender, address(this), token_amount); return liquidity_minted;
}function withdraw(uint256 amount) public returns (uint256, uint256) {
uint256 token_reserve = token.balanceOf(address(this))。
uint256 eth_amount = amount.mul(address(this).balance) / totalLiquidity;
uint256 token_amount = amount.mul(token_reserve) / totalLiquidity;
liquidity[msg.sender] = liquidity[msg.sender].sub(eth_amount);
totalLiquidity = totalLiquidity.sub(eth_amount);
msg.sender.transfer(eth_amount);
require(token.transfer(msg.sender, token_amount))。
return (eth_amount, token_amount);
}

把这些函数粘贴到packages/buidler/contracts中的DEX.sol中后,花点时间了解一下这些函数的作用。

deposit()函数负责接收ETH,并按正确的比例将token从调用者转移到合约中。合约也会跟踪存款地址拥有的流动性liquidity与totalLiquidity的数量。

withdraw()函数可以让用户按照正确的比例同时取出ETH和通根。由于从每笔交易中收取0.3%的费用,流动性提供者实际提取的ETH和通根数量会高于他们存入的数量。这激励了第三方提供流动性。

编译并将你的合约部署到前端。

yarn run deploy

????接口

用户体验非常糟糕/丑陋,而且还有难以视觉化的滑点这种事。让我们做一些前端工作来清理界面,让它更容易理解。

让我们在packages/react-app/src中编辑App.js。

在这个代码分支中包含了一个自定义的<DEX>组件。删除DEX的通用<Contract>组件,并引入<DEX>。

<DEX
address={address}
injectedProvider={injectedProvider}
localProvider={localProvider}
mainnetProvider={mainnetProvider}
readContracts={readContracts}
price={price}
/>

让我们清理一下Ballon的<contract>组件,给它一个标题,并选择只显示balanceOf和approval()动作。

<Contract
title={"???? Balloons"}
name={"Balloons"}
show={["balanceOf","approve"]}
provider={localProvider}
address={address}
/>

酷毙了,我们的前端正在寻找???? AF。


????试试

现在,用户只需输入他们想要交换的ETH或通根数量,图表就会显示价格是如何计算的。用户还可以直观地看到较大的互换如何导致更多的滑点和更少的资产输出。


用户还可以从流动资金池中存入和提取,赚取费用。


???? 庆祝!

我们已经修补好了一个可行的迷你版去中心化交易所。我们可以为任何人提供交换资产的流动性,流动性提供者将赚取费用。这一切都发生在链上,不能被审查或篡改。

这是一个???? 不可阻挡的市场unstoppable market??!!!

这是我们最后的光彩夺目的交易合约。



~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

作者:Austin Thomas Griffith翻译:区块链RobinBTC:1Robin84SWtzSxnU1v8CE9rzQtcfUsGeN 微信:chanhai13;公众号:链学园译文有编辑及删减,如有侵权,请联系译者删除中文版权所有,转载需完整注明以上内容

—-

编译者/作者:区块链研究员

玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。

LOADING...
LOADING...