DTeam 技术日志

Doer、Delivery、Dream

Uniswap 非权威开发指南(v1 版)

胡键 Posted at — Aug 4, 2020 阅读
<p>作为 defi 系列的第一篇(同时也是微信公众号付费文章的第一篇),我想写写 <a href="https://uniswap.org/">uniswap</a>,并且从 v1 开始写起。这里面的原因很简单:</p> <ul> <li>uiniswap 的名气足够大。</li> <li>虽然 v2 版已经发布,但并不影响 v1 版的运行。并且,相对于 v2 来讲,v1 要简单很多,作为系列开篇是一个不错的选择。</li> <li>关于 uniswap 的文章并不少,但真正对开发有价值的文章并不多。有感于自己在近期开发过程中的各种抓瞎,觉得有必要将一些经验和解决办法分享出来。</li> </ul> <p>这是一篇面向开发者的文章,从中你可以学到:</p> <ul> <li>uiniswap 的协议</li> <li>sdk 接入指南和关键代码</li> <li>基于 ganache 的自动化测试</li> <li>相关公式</li> </ul> <p>关于 uniswap 的好处和优点,外面的文章已经说的很多了,我就不在这里浪费口舌,直接进入正题,从协议说起吧。</p> <h2 id="uniswap-协议v1">uniswap 协议(v1)</h2> <p>uniswap v1 的协议并不复杂,这里<a href="https://docs.ethhub.io/guides/graphical-guide-for-understanding-uniswap/">有篇图解</a>可以帮助开发很快了解它。简单来讲,这里涉及到三个对象:工厂合约、交易所合约和 ERC20 合约。主要的过程如下:</p> <ol> <li>为要实现兑换的 ERC20 合约创建交易所合约 <ul> <li>这是一次性操作。</li> </ul> </li> <li>增加流动性,第一次放入的流动性决定了交易所的兑换比率。 <ul> <li>任何人都提供流动性,成为 provider,但需按同样比例</li> </ul> </li> <li>兑换,分两种: <ul> <li>直接兑换:进自己的账户</li> <li>兑换并转账:进第三方账户</li> </ul> </li> <li>当 provider 希望撤出时,可以移除流动性。</li> </ol> <p>这几个合约之间的关系:</p> <ul> <li>工厂合约负责创建交易所合约。</li> <li>交易所合约与 ERC20 合约一一对应,其作用有两个: <ul> <li>兑换 ETH 和 ERC20</li> <li>管理流动性</li> </ul> </li> </ul> <p>由此可知,在前面的步骤中,除了第一步是与工厂合约交互之外,其余的操作都是与新创建出来的交易所合约进行交互。</p> <h3 id="流动性挖矿">流动性挖矿</h3> <p>从<a href="https://uniswap.org/docs/v1/smart-contracts">合约的接口</a>可以看出:交易所合约本身也是 ERC20 合约,这是起什么作用呢?这涉及到一个概念:流动性挖矿。名字虽然起得高大上,但其实说白了就是:<strong>作为流动性提供者,可以收取交易过程的手续费</strong>。关于手续费:</p> <ul> <li>ETH &lt;-&gt; ERC20,3bp(1bp = 1‰)</li> <li>ERC20 &lt;-&gt; ERC20,6bp <ul> <li>在 v1 中,这种兑换形式借助 ETH 来完成,相当于两次交易所合约调用。即 ERC20 &lt;-&gt; ETH &lt;-&gt; ERC20。</li> </ul> </li> </ul> <p>前面说过:任何人都可以成为流动性提供者,这时就需要一种技术手段来决定每次交易的手续费如何在这些流动性提供者中进行分配。将交易所合约实现为 ERC20 合约则是在这样一个背景下得出的技术选择:</p> <ul> <li>合约会在每位 provider 提供流动性时为他们分配一定份额的 token(具体分配公式没有必要了解,详见合约代码),这个 token 代表了未来能参与利益分配的权益。</li> <li>provider 持有的 token 数与合约的总发行量之比则为其预期可得的利益(ETH 和合约负责兑换的 ERC20)</li> </ul> <p>每次兑换的手续费并不会实时反映在 provider 的钱包中,而是记录在交易所合约中(以输入 * 997 bp 的形式体现,剩下的 3bp 就是交易费)。<strong>只有在 provider 移除流动性时,合约才会兑现这部分收益,退回等比例的(amount/totalSupply)ETH 和对应的 ERC20</strong>。</p> <p>看起来流动性挖矿是一门不错的生意,只要投入本金,接下来就可以坐地分成,有百利而无一害。</p> <p>可事实是如此吗?这里面需要讲一讲 uniswap 的定价模型。</p> <h3 id="定价模型和-provider-的风险">定价模型和 provider 的风险</h3> <p>uniswap 采用恒定乘积模型来确定兑换价格,对于每一个接触 uniswap 的来讲估计都已经听滥了。但这只是针对 uniswap 自身而言。在开放的市场,一般来讲不会只有一家交易所。虽然 uniswap 工厂合约限定了每个 ERC20 只能对应一个交易所合约,但是脱离于 uniswap 体系,还有其他交易所存在(不论去中心化的,还是中心化的)。</p> <p>多个交易所存在的事实决定了价格存在差异,而这种差异则为投机者提供了套利空间,它们则是 provider 必须面对的风险。看一下例子演示。</p> <p>为了简单起见,这里设定一些假设:</p> <ul> <li>只有一个 provider</li> <li>不考虑 3bp 的手续费</li> </ul> <p>假定一个 provider 向 uniswap 交易所合约(ETH &lt;-&gt; A)内注入的流动性是:100 ETH : 100 A。此时,交易所 B 中,1 ETH = 10 A。显然,按照下面的方式进行操作就存在套利空间:</p> <ul> <li>在交易所 B 中,用 ETH 换 A</li> <li>在 uniswap 交易所合约中,用 A 换 ETH</li> <li>循环操作,直至两者兑换比例接近</li> </ul> <p>具体演示计算:</p> <ul> <li>交易所 B,10 ETH -&gt; 100 A</li> <li>Uniswap 交易所合约:+100 A <ul> <li>返 50 ETH(100 - 10000/200)</li> <li>此时两个交易池为:50 ETH : 200 A</li> </ul> </li> <li>交易所 B,20 ETH -&gt; 200 A</li> <li>Uniswap 交易所合约:+200 A <ul> <li>返 25 ETH(50 - 10000/400)</li> <li>此时两个交易池为:25 ETH : 400 A</li> </ul> </li> </ul> <p>两轮下来,即便 provider 是 100% 获得交易的手续费,但其是以损失投入的本金为代价的。以上为例,provider 前后资产的变化,为了方便比较,全部按交易所 B 的价格换算成 A 计:</p> <ul> <li>交易前:100 * 10 + 100 = 1100</li> <li>交易后:25 * 10 + 400 = 650</li> </ul> <p>其损失是显然的。</p> <p>从另一个方面来讲,这也说明放在 uniswap 交易所合约中的流动性有必要尽可能与公认的价格保持一致。</p> <h3 id="协议小结">协议小结</h3> <p>那么最后小节一下,总的来讲,uniswap v1 协议涉及:</p> <ul> <li>3 种合约:工厂合约、交易所合约和 ERC20 合约。</li> <li>2 类角色:交易用户和流动性提供者。</li> <li>采用恒定乘积定价,当交易所合约内价格与外部交易所价格之间存在差异时,存在套利空间,作为流动性提供者有可能面临损失。</li> </ul>

本文是付费文章,剩余内容请访问以下链接支付之后继续阅读:

付费链接 (已付费:33)

友情链接


相关文章