如何在去中心化交易所中 (DEX) 集成 0x 协议
什么是 0x 协议,它的工作机制是怎样的?这个本文将介绍 0x 协议,包括它的链下订单中继(撮合)、去中心化交易中继器, 以及如何在以太坊公链或私链上通过 0x 智能合约构建自己的去中心化交易所(DEX)。
什么是 0x 协议
0x 是一种开放、以太坊上支持点对点资产交换的协议,其开源基础架构使开发人员和企业能够构建自己的交易所来交易所有 ERC-20 和 ERC-721 资产。
0x 协议特性
0x 协议有以下特性
*安全的非托管交易
无需存款或取款,就可以直接实现钱包对钱包的资产交易。
*灵活的订单类型
可以选择以当前价格卖出资产,或允许潜在买家出价。
*构建业务
通过在每次交易中收取费用,可以使产品货币化,还可加入 0x 生态系统中越来越丰富的中继器。
上面的 0x 协议特性可实现我们的去中心化兑换。
0x 协议优势
0x 协议使用模块化方式交易以太坊区块链上资产,优势有:
*可靠的智能合约
0x 协议的智能合约通过了两轮严格的安全审核。
*可扩展架构
0x 的模块化管道支持开发者通过扩展 API 嵌入自己的智能合约。
*高效设计
0x 协议的链下订单撮合、链上结算,是一种节省手续费的兑换方式。
0x 协议可用于很多场景,例如游戏、收藏品、预测市场、去中心化交易的订单簿、 去中心化贷款等等。
其次,0x 的智能合约,是模块化的,可以通过治理进行升级, 而不会影响系统的其他组件,也不会引起市场的中断。
0x 协议的智能合约
0x 协议的智能合约包含有:
*Exchange Contract:资产兑换合约
*ERC20 Proxy contract:ERC20 代理合约
*ERC721 Proxy contract:ERC721 代理合约
资产兑换合约
包含 0x 协议的业务逻辑,是以下功能的入口:
-
提供订单
-
订单取消
-
执行交易
-
签名验证
-
在系统中注册新资产
ERC20 代理合约
该合约代表用户要转让 ERC20 代币。因此,每个用户(ERC20 代币持有者)都必须授权(approve)该合约可以操作自己持有的 ERC20 代币。
ERC721 代理合约
该合约代表用户要转让 ERC721 代币。因此,每个用户(ERC721 代币持有者)都必须授权(approve)该合约可以操作自己持有的 ERC721 代币。
为了部署及使用 0x 协议智能合约,需要先安装 0x.js。0x.js 是一个与 0x 协议交互的 Javascript 库,利用它就可以轻松地调用 0x 协议的智能合约来创建、取消或验证订单,以及检查 ERC20 和 ERC721 代币持有者的授权额度和余额。
深入 0x 合约架构
0x 协议采用链下订单撮合、链上结算的模式,密码学签名的订单可以在链下通过任意渠道通信。感兴趣的对手方可以将这些订单中的一个或多个注入到 0x 的资产兑换合约中,进行链上交易结算。
img
0x 协议可以交换任何 ERC20 或 ERC721 资产。上图显示了当 Taker (吃单者)向 0x 资产兑换合约(Exchange)提交订单时资产转移的实际处理流程(以下需要对应的上图的标号):
注:兑换交易中,Maker (挂单者)和 Taker (吃单者)。挂单是提供流动性,其订单是被动成交的。吃单刚好相反,是利用流动性主动交易。
-
Taker (吃单者)调用资产兑换合约的
fillOrder()
方法提交签名订单。 -
资产兑换合约将订单传递给相应的 ERC20 代理合约,实际的代币转账是在代理合约上进行的。注意:Maker 和 Taker 必须先授权 ERC20 代理合约,然后再提交订单。
-
在 ERC20 代理合约中调用 (挂单者)ERC20 代币合约的
transferFrom()
方法 -
如果挂单者的 ERC20 合约调用失败,则整个交易回滚。
-
交易从代理返回到兑换合约。
-
资产兑换合约将订单传递到 ERC20 代理合同。
-
在资产代理合约中调用(吃单者) ERC20 合约的
transferFrom()
方法 -
如果吃单者的 ERC20 合约调用失败,则整个交易回滚。
-
交易从代理返回到兑换合约。
-
返回交易执行结果
接下来,我们将讨论使用 0x.js 库在以太坊上的部署 0x 智能合约,以便交易资产,使用 npm 安装 0x.js:
*
npm install 0x.js
部署 0x 智能合约
要与智能合约进行交互,我们需要部署 0x 智能合约,然后通过 0x.js 库用合约地址与合约进行交互。
资产兑换合约
资产兑换合约的源代码在 此 github[1] ,资产兑换合约构造函数没有参数,部署的时候不需要提供参数,部署者(msg.sender)将是合约的所有者(Owner)。所有者能够在兑换合约中设置代理合约的地址。
ERC20 代理合约
使用 ERC20 代理合约的源代码 [2] 进行部署,代理合约的构造函数不需要参数,部署者(msg.sender)将是合约的所有者。所有者将能够在 ERC20 代理合约中设置资产兑换合约的地址。
ERC721 代理合约
使用 ERC721 代理合约源代码 [3] 进行部署,代理合约的构造函数不需要参数,部署者(msg.sender)将是合约的所有者。所有者将能够在 ERC721 代理合约中设置资产兑换合约的地址。
与 0x 协议交互
与 0x 交互的最终目标是挂单者使用 0x.js 库创建订单,吃单者使用 fillOrder()
函数提交订单进行兑换。
注册合约
部署完以上合约后,需要在资产代理合约中设置兑换合约的地址,在兑换合约中设置资产代理合约的地址。
*调用资产兑换合约的 registerAssetProxy(ERC20 或 ERC71 代理合约地址)
方法将记录资产代理合约的地址,兑换代币交易是在代理合约中进行的。该方法只能由资产交换智能合约的所有者调用。
*调用 ERC20 代理合约的 addAuthorizedAddress(兑换合约)
方法注册兑换合约。
*调用 ERC20 代理合约的 removeAuthorizedAddress(兑换地址)
方法删除兑换合约。
合约配置
使用资产兑换合约和资产代理合约地址通过 0x.js 库 进行交互 :
let contractConfig = { contractAddresses: { erc20Proxy: proxyAddress.toLowerCase(), erc721Proxy: "0x1d7022f5b17d2f8b695918fb48fa1089c9f85401", exchange: exchangeAddress.toLowerCase() }, networkId: networkId}; const contractWrappers = new ContractWrappers(holderEngine, contractConfig);
现在就可以与部署在专用或测试网络上的 0x 协议智能合约进行交互。请记住添加 RPC 节点提供者以便与区块链进行交互。
实例化
为了与 0x.js 库进行交互,我们需要导入(import)如下所示相关的软件包
const { assetDataUtils,BigNumber,ContractWrappers, generatePseudoRandomSalt,orderHashUtils,signatureUtils} = require('0x.js'); const TX_DEFAULTS = { gas: 400000 };const { RPCSubprovider, Web3ProviderEngine } = require('0x.js'); let newWallet = new ethers.Wallet(wallet.signingKey.privateKey, prov);const holderWallet = new PrivateKeyWalletSubprovider(wallet.signingKey.privateKey.slice(2));
添加 RPC 订阅节点提供者:
*
const holderEngine = new Web3ProviderEngine();holderEngine.addProvider(holderWallet);// 订阅节点提供者可以使用自定义 URL 分别连接以太坊主网、测试网或私链。holderEngine.addProvider(new RPCSubprovider(providerUrl));holderEngine.start();
获取 0x 合约地址并实例化合约包装器:
*
const contractWrappers = new ContractWrappers(holderEngine, contractConfig);const web3Wrapper = new Web3Wrapper(providerEngine);const contractAddresses = getContractAddressesForNetworkOrThrow(100);//networkID
ERC20 合约授权
在挂单者(持有 tokenA)可以创建一个订单并且吃单者(持有 token B)将提交订单进行兑换之前,需要新进行授权。
先获取相关合约地址:
// 合约地址 const tokenAAddress = contractAddresses.tokenA;const tokenBAddress = contractAddresses.tokenB;const exchange = contractAddresses.exchange;
所有地址都可以从 0x.js 库获取到。
*
// 将有关资产的所有必要信息编码为十六进制字符串 const makerAssetData = assetDataUtils.encodeERC20AssetData(tokenAAddress);const takerAssetData = assetDataUtils.encodeERC20AssetData(tokenBAddress);const makerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100), DECIMALS);const takerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(200), DECIMALS);const NULL_ADDRESS = '0x0000000000000000000000000000000000000000';const ZERO = new BigNumber(0);const DECIMALS = 18;
现在挂单者和吃单者应该授权相应的资产代理合约,以便代理合约可以分别代表挂单者和吃单者转移代币:
*
// 授权 const makerApprovalTxHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync( tokenAAddress, maker,);await web3Wrapper.awaitTransactionSuccessAsync(makerApprovalTxHash); // 授权 const takerApprovalTxHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync( tokenBAddress, taker,);await web3Wrapper.awaitTransactionSuccessAsync(takerApprovalTxHash);
在挂单者和吃单者授权资产代理合约之后,代理合约就可以分别代表挂单者和吃单者转移代币了。
接下来,挂单者将创建一个委托订单并在链下签名,而吃单者将在链上执行订单。
创建订单、验证与吃单
创建订单:
*
const order = { exchangeAddress: exchangeAddress, makerAddress: maker,//address of maker takerAddress: taker,//address of taker senderAddress: taker,// address of sender feeRecipientAddress: NULL_ADDRESS,//fee in the form of native currency of platform expirationTimeSeconds: randomExpiration,// 订单过期时间 salt: generatePseudoRandomSalt(),// 随机数,用来区分订单 makerAssetAmount,// 挂单资产数量 takerAssetAmount,// taker asset amount makerAssetData,//encoded address of tokenA takerAssetData,//encoded address of tokenB makerFee: ZERO,//fee if required takerFee: ZERO,//fee if required};
现在我们创建了一个资产交换委托订单。接下来在调用 0x.js 库的 getOrderHash()
函数获得订单哈希值以便进行签名。这个哈希根据 EIP712[4] 对订单计算出来的:
*
const orderHashHex = orderHashUtils.getOrderHashHex(order);
获取订单的哈希后,挂单者使用 0x.js 库的 ecSignHashAsync()
方法对订单签名。
*
const signature = await signatureUtils.ecSignHashAsync(providerEngine, orderHashHex, maker);const signedOrder = { …order, signature };
吃单者可以使用资产交易合约的 validateFillOrderThrowIfInvalidAsync` 方法验证订单是否可以执行:
*
await contractWrappers.exchange.validateFillOrderThrowIfInvalidAsync( signedOrder, takerAssetAmount, taker);
最终,吃单者调用资产交易合约的 fillOrderAsync
方法执行订单:
*
try{ txHash = await contractWrappers.exchange.fillOrderAsync( signedOrder, takerAssetAmount, taker, {TX_DEFAULTS,} ); var transaction = await web3Wrapper.awaitTransactionSuccessAsync(txHash);}catch(error){}
让我们快速回顾一下到目前为止所学到的知识,然后通过介绍已经建立在 0x 上的项目来结束我们的讨论。
回顾
本文介绍了什么是 0x 协议,其特点是什么、它是如何工作的,以及如何挂单及吃单。
下面列出了已经使用 0x 协议实现 DEX 和订单簿的项目。
DEX 有:Radar Relay[5], paradex[6], Star bitex[7], LedgerDex[8]
订单簿有:open relay[9]
原文链接:How to integrate 0x(ZRX) Protocol to setup your own Decentralized Exchange (DEX)[10]
参考资料
[1]
此 github: https://github.com/0xProject/0x-monorepo/tree/development/contracts/exchange
[2]
[3]
[4]
EIP712: https://learnblockchain.cn/docs/eips/eip-712.html
[5]
Radar Relay: https://radarrelay.com/
[6]
paradex: https://paradex.io/
[7]
Star bitex: https://www.starbitex.com/
[8]
LedgerDex: https://www.ledgerdex.com/
[9]
open relay: https://openrelay.xyz/
[10]
How to integrate 0x(ZRX) Protocol to setup your own Decentralized Exchange (DEX): https://medium.com/hackernoon/how-to-integrate-0x-zrx-protocol-to-setup-your-own-decentralized-exchange-dex-584daea7a8f0
本文作者:张小风
来源链接:mp.weixin.qq.com
- 免责声明
- 世链财经作为开放的信息发布平台,所有资讯仅代表作者个人观点,与世链财经无关。如文章、图片、音频或视频出现侵权、违规及其他不当言论,请提供相关材料,发送到:2785592653@qq.com。
- 风险提示:本站所提供的资讯不代表任何投资暗示。投资有风险,入市须谨慎。
- 世链粉丝群:提供最新热点新闻,空投糖果、红包等福利,微信:juu3644。