在Fabric实现类似Uniswap的去中心化交易所
1.合约简介
Uniswap是以太坊上最火爆的去中心化交易所DApp,其操作简单,原理也很容易理解,安全而且费用低,所以被广泛使用。
由于Fabric是基于KeyValue世界状态的特点,没有原生Token,没有Gas手续费,所以所有自定义的Token都是在状态中存储的,而我们可以参考ERC20合约标准,创建同样接口的合约,具体可以参考Fabric官方示例:https://github.com/hyperledger/fabric-samples/tree/master/token-erc-20 。
因为Fabric采用Docker作为合约虚拟机,所以不需要像Uniswap一样通过工厂合约创建交易对合约来实现,而是由一个合约实现所有交易对。我们假设在这个Uniswap合约中,需要支付互换的手续费,所以我们先定义了PTN作为手续费的Token,然后定义了ABC和PETH的通证作为互换要用到的ERC20通证,接下来进行互换。
2 创建交易对
创建交易对或提供Token给流动性池的叫做市商。做市商A要创建一个合约中不存在的交易对时(比如ABC和PETH互换),发起如下Invoke合约的创建交易对方法的交易请求:
参数0:Payment PTN作为手续费
参数1:Payment 1000 ABC给合约
参数2:Payment 10 PETH给合约
合约执行后会在状态数据库中记录下ABC:PETH的余额1000和100,乘积为10000
3 Token互换交易
现在用户B持有ABC,想换PETH,那么他发起如下Invoke合约的互换方法的交易请求:
参数0:Payment PTN作为手续费
参数1:Payment 100.3 ABC给合约(其中0.3为手续费)
参数2:交易对ABC、PETH。
合约执行后,记录ABC余额为1100,而为了保持池子中的乘积不变,所以PETH余额=10000/1100=9.09,所以合约会付给用户B 0.91 PETH 。另外手续费池记录下0.3分配给A。
4 增加流动性池量
现在做市商C也想参与ABC和PETH的互换,于是他需要按现在的比值 1100:9.09往池子注入。于是C发起Invoke合约的增加交易对流动池方法的交易请求:
参数0:Payment PTN作为手续费
参数1:Payment 2200 ABC给合约
参数2:Payment 18.18 PETH给合约
合约会检查本交易中ABC和PETH的比值,如果和合约余额的比值不一致,那么Token退回。如果一致,那么记录状态数据库:ABC余额3300,PETH余额27.27,乘积:89991
5 反向交易
现在用户D持有PETH,想买入ABC,那么他发起如下Invoke合约的互换方法的交易请求:
参数0:Payment PTN作为手续费
参数1:Payment 1.003 PETH给合约(其中0.003为手续费)
参数2:交易对参数PETH,ABC。
合约之后,PETH变成28.27,乘积保持89991不变的话,所以ABC=89991/28.27=3183.27,也就是说合约会转给用户D 3300-3183.27=116.73 ABC 【最新状态余额:ABC 3183.27, PETH 28.27】
那么我们假设做市商C并没有增加流动性池,那么会怎么样?PETH变成10.09,ABC余额=10000/10.09=991.08,所以ABC会付出1100-991.08=108.92 ABC
我们可以看到因为池子变大了,所以汇率的波动性变小了,于是用户D获得了更多的ABC,如果池子是无限大,也就是说汇率是1100:9.09的话,用户D应该是买到121.01个ABC。
6 手续费分配
如果只有做市商A,那么手续费就给A了,现在有AC两个做市商,A出了1000ABC,C出了2200ABC,所以如果收到ABC手续费的时候,按这个比例进行分配。A出了10PETH,C出了18.18PETH,所以在收到用户D的0.003 PETH手续费时,A和C应该按他们出的PETH比例分手续费。
7 路由
如果有现在有以下交易对:
ABC<->PETH PTN <-> PETH
那么用户在发起ABC换PTN时,合约能够发现其中的路由:ABC-》PETH-》PTN
因为经过了两次交换,所以用户要付0.6%的手续费,每个0.3%分给其中参与了的做市商。
8 赎回流动性池
如果做市商A想赎回自己质押到流动性池中的Token,那么他可以发起Invoke合约的赎回方法的赎回交易:
参数0:Payment PTN作为手续费
参数1:交易对参数ABC、PETH、赎回ABC的量、赎回PETH的量。
注意这里赎回的量的比例必须是当前流动性池的比例,如果比例不对,赎回失败。另外赎回数量必须<=当时该用户增加流动性时的质押数量。按照当前最新汇率ABC 3183.27: PETH 28.27=112.60,所以ABC的量最大为1000,ETH量为8.88
合约执行时,检查是否满足前面说的条件,如果满足,则合约付出对应数量Token给A,并更新合约状态余额
ABC余额 2183.27,PETH余额19.39
9 提取手续费收益
如果做市商A积攒了不少手续费了,那么他可以申请提取手续费。A发起Invoke合约的手续费提取方法的交易请求:
参数0:Payment PTN作为手续费
参数1:交易对ABC、PETH、提取ABC的量、提取PETH的量。
合约检查合约状态中A地址的手续费余额,如果余额>=申请数量,则可以提取,生成从合约付出给A对应数量Token的Payment,并更新状态数据。
10 各种查询
用户要进行交易需要对当前状态进行查询,查询的内容包括:
10.1 交易对列表查询
返回所有的交易对列表的Token名和流动性池中的余额
10.2 某交易对的当前状态查询
传入交易对TokenID,返回各Token余额(也就可以计算汇率),做市商列表及他们提供的流动性数量,手续费分配列表
10.3 某交易对的交易历史查询
传入交易对TokenID,返回该交易对的所有成交记录,可以基于此绘制K线图
10.4 路由查询
传入交易对TokenID,返回要完成该交易需要经过的路由以及路由中的每个交易对的当前余额