BANCOR學習:如何開發本身的BANCOR去中心化交易平臺?

image

1

摘要

 基於以太坊的交易所BANCOR算法實現-轉換算法框架》 講解了以太坊solidity實現的BancorConverter轉換主合約的邏輯和代碼,可是沒有涉及核心互換及計算代碼,而是經過interface類的方式進行隔離。python

本文詳細描述一下內容,能跑的程序纔是真分享:web

(1)BancorNetwork網絡的文件框架和功能; (2)BancorConverter合約測試執行流程; (3)2個鏈接器通證ERC1-ERC22的轉換驗證結果; (4)ETH-CLB(彩貝)的轉化驗證結果算法

2

BancorNetwork網絡的文件框架和功能

BancorProtocol工程是一個帶有TRUFFLE框架的solidity智能合約Bancor算法實現框架。文件列表以下:json

|   package.json

|   README.md

|   trace.log

|   

|   |   BancorProtocol.iml

|   |   encodings.xml

|   |   misc.xml

|   |   modules.xml

|   |   workspace.xml

|   |

   |   \---copyright

|           profiles_settings.xml

|           \---solidity

    |   truffle-config.js

    |

       +---contracts

    |   |   BancorNetwork.sol

    |   |   ContractIds.sol

    |   |   FeatureIds.sol

    |   |   IBancorNetwork.sol

    |   |

       |   +---build

    |   |       BancorConverter.abi

    |   |       BancorConverter.bin

    |   |       BancorConverterFactory.abi

    |   |       BancorConverterFactory.bin

    |   |       BancorConverterUpgrader.abi

    |   |       BancorConverterUpgrader.bin

    |   |       BancorFormula.abi

    |   |       BancorFormula.bin

    |   |       BancorGasPriceLimit.abi

    |   |       BancorGasPriceLimit.bin

    |   |       BancorNetwork.abi

    |   |       BancorNetwork.bin

    |   |       BancorPriceFloor.abi

    |   |       BancorPriceFloor.bin

    |   |       ContractFeatures.abi

    |   |       ContractFeatures.bin

    |   |       ContractIds.abi

    |   |       ContractIds.bin

    |   |       ContractRegistry.abi

    |   |       ContractRegistry.bin

    |   |       CrowdsaleController.abi

    |   |       CrowdsaleController.bin

    |   |       ERC20Token.abi

    |   |       ERC20Token.bin

    |   |       EtherToken.abi

    |   |       EtherToken.bin

    |   |       FeatureIds.abi

    |   |       FeatureIds.bin

    |   |       IBancorConverter.abi

    |   |       IBancorConverter.bin

    |   |       IBancorConverterExtended.abi

    |   |       IBancorConverterExtended.bin

    |   |       IBancorConverterFactory.abi

    |   |       IBancorConverterFactory.bin

    |   |       IBancorFormula.abi

    |   |       IBancorFormula.bin

    |   |       IBancorGasPriceLimit.abi

    |   |       IBancorGasPriceLimit.bin

    |   |       IBancorNetwork.abi

    |   |       IBancorNetwork.bin

    |   |       IContractFeatures.abi

    |   |       IContractFeatures.bin

    |   |       IContractRegistry.abi

    |   |       IContractRegistry.bin

    |   |       IERC20Token.abi

    |   |       IERC20Token.bin

    |   |       IEtherToken.abi

    |   |       IEtherToken.bin

    |   |       IOwned.abi

    |   |       IOwned.bin

    |   |       ISmartToken.abi

    |   |       ISmartToken.bin

    |   |       ITokenHolder.abi

    |   |       ITokenHolder.bin

    |   |       IWhitelist.abi

    |   |       IWhitelist.bin

    |   |       Managed.abi

    |   |       Managed.bin

    |   |       Owned.abi

    |   |       Owned.bin

    |   |       SmartToken.abi

    |   |       SmartToken.bin

    |   |       SmartTokenController.abi

    |   |       SmartTokenController.bin

    |   |       TokenHolder.abi

    |   |       TokenHolder.bin

    |   |       Utils.abi

    |   |       Utils.bin

    |   |       Whitelist.abi

    |   |       Whitelist.bin

    |   |

           |   +---converter

    |   |   |   BancorConverter.sol

    |   |   |   BancorConverterFactory.sol

    |   |   |   BancorConverterUpgrader.sol

    |   |   |   BancorFormula.sol

    |   |   |   BancorGasPriceLimit.sol

    |   |   |

       |   |   \---interfaces

    |   |           IBancorConverter.sol

    |   |           IBancorConverterFactory.sol

    |   |           IBancorFormula.sol

    |   |           IBancorGasPriceLimit.sol

    |   |

    |   +---crowdsale

    |   |       CrowdsaleController.sol

    |   |       

    |   +---helpers

    |   |       Migrations.sol

    |   |       TestBancorFormula.sol

    |   |       TestCrowdsaleController.sol

    |   |       TestERC20Token.sol

    |   |       TestFeatures.sol

    |   |       TestUtils.sol

    |   |       

    |   +---legacy

    |   |       BancorPriceFloor.sol

    |   |       

    |   +---token

    |   |   |   ERC20Token.sol

    |   |   |   EtherToken.sol

    |   |   |   SmartToken.sol

    |   |   |   SmartTokenController.sol

    |   |   |    

    |   |   \---interfaces

    |   |           IERC20Token.sol

    |   |           IEtherToken.sol

    |   |           ISmartToken.sol

    |   |         

    |   \---utility

    |       |   ContractFeatures.sol

    |       |   ContractRegistry.sol

    |       |   Managed.sol

    |       |   Owned.sol

    |       |   TokenHolder.sol

    |       |   Utils.sol

    |       |   Whitelist.sol

    |       |   

    |       \---interfaces

    |               IContractFeatures.sol

    |               IContractRegistry.sol

    |               IOwned.sol

    |               ITokenHolder.sol

    |               IWhitelist.sol

    |               

    +---migrations

    |       1_initial_migration.js

    |       2_deploy_contracts.js

    |       

    +---python

    |   |   BenchmarkTestPurchase.py

    |   |   BenchmarkTestSale.py

    |   |   CoverageExpTestPurchase.py

    |   |   CoverageExpTestSale.py

    |   |   CoverageUniTestPurchase.py

    |   |   CoverageUniTestSale.py

    |   |   EmulationExpTestCrossConnector.py

    |   |   EmulationExpTestPurchase.py

    |   |   EmulationExpTestSale.py

    |   |   EmulationUniTestCrossConnector.py

    |   |   EmulationUniTestPurchase.py

    |   |   EmulationUniTestSale.py

    |   |   MongoExpTestPurchase.py

    |   |   MongoExpTestSale.py

    |   |   MongoUniTestPurchase.py

    |   |   MongoUniTestSale.py

    |   |   PerformanceExpTestCrossConnector.py

    |   |   PerformanceExpTestPurchase.py

    |   |   PerformanceExpTestSale.py

    |   |   PerformanceUniTestCrossConnector.py

    |   |   PerformanceUniTestPurchase.py

    |   |   PerformanceUniTestSale.py

    |   |   RandomTestCrossConnector.py

    |   |   RandomTestPower.py

    |   |   RandomTestPurchase.py

    |   |   RandomTestSale.py

    |   |   RandomTestTrade.py

    |   |  

    |   +---AutoGenerate

    |   |   |   PrintFileFormulaConstants.py

    |   |   |   PrintFunctionBancorFormula.py

    |   |   |   PrintFunctionGeneralExp.py

    |   |   |   PrintFunctionOptimalExp.py

    |   |   |   PrintFunctionOptimalLog.py

    |   |   |   PrintIntScalingFactors.py

    |   |   |   PrintLn2ScalingFactors.py

    |   |   |   PrintMaxExpPerPrecision.py

    |   |   |   

    |   |   \---common

    |   |           constants.py

    |   |           functions.py

    |   |           __init__.py

    |   |              

    |   +---FormulaNativePython

    |   |       __init__.py

    |   |          

    |   +---FormulaSolidityPort

    |   |       __init__.py

    |   |       

    |   +---InputGenerator

    |   |       __init__.py

    |   |       

    |   +---Utilities

    |   |   +---Changer

    |   |   |       Decrease.py

    |   |   |       Increase.py

    |   |   |       

    |   |   \---Converter

    |   |     

    |   example_commands.json

    |   |       |   example_model.json

    |   |       |   run.py

    |   |       |       

    |   |       \---engine

    |   |               __init__.py

    |   |

    |   \---Web3Wrapper

    |           __init__.py

    |         

    \---test

        |   BancorConverter.js

        |   BancorConverterUpgrader.js

        |   BancorFormula.js

        |   BancorNetwork.js

        |   ContractFeatures.js

        |   ContractRegistry.js

        |   CrowdsaleController.js

        |   ERC20Token.js

        |   EtherToken.js

        |   Managed.js

        |   Owned.js

        |   SmartToken.js

        |   SmartTokenController.js

        |   TokenHolder.js

        |   Utils.js

        |   Whitelist.js

        |    

       \---helpers

                FormulaConstants.js

                Utils.js

其中的智能合約代碼量實在繁多,限於篇幅限制,就不一一介紹了,輝哥介紹其中主要的幾個文件。數組

2.1 BancorNetwork.sol微信

功能描述:網絡

BancorNetwork合約是bancor通證轉換的主入口。數據結構

經過提供轉換路徑,它容許經過惟一的方法在bancor network中的任何通證轉換爲其餘的通證。app

轉換路徑注意點:框架

1>,轉換路徑是一種數據結構,用於在bancor network中把一種通證轉換爲另外一種通知。有時一次轉換可能不夠,須要多個跳轉。 這個路徑定義了哪些轉換會被使用,每一個步驟會作哪種轉換。 2>,這個路徑格式不包含複雜的結構。相反,它已單一數組的方式呈現,其中每個跳轉(hop)包含2個數組元素 -智能通證和目標通證。 另外,第一個元素老是源通證。智能通證只做爲指向轉換器的指針使用(由於轉換器地址極可能會變)。

關鍵函數:

1) function registerEtherToken(IEtherToken _token, bool _register) 註冊EtherToken。若是轉換路徑包括ETH,則須要定義EtherToken來替換。 2)function verifyTrustedSender(IERC20Token[] _path, uint256 _amount, uint256 _block, address _addr, uint8 _v, bytes32 _r, bytes32 _s) private 經過從橢圓簽名算法還原關聯的公鑰,驗證簽名地址是可信的。若是有錯誤則返回0值。 注意:簽名只在一次轉換有效,這個給定的區塊後會失效。 3) function convertFor(IERC20Token[] _path, uint256 _amount, uint256 _minReturn, address _for) public payable 在bancor網絡中,根據預約義的轉換路徑,把通證轉換爲其餘通證,並把轉換獲得的通證打給目標帳戶。 注意:轉換器必須已經有源通證的管理權限。 4) function getReturnByPath(IERC20Token[] _path, uint256 _amount) public view returns (uint256) 返回給定轉換路徑的目標通證的數量 5)function convertForMultiple(IERC20Token[] _paths, uint256[] _pathStartIndex, uint256[] _amounts, uint256[] _minReturns, address _for) public payable 經過預約義的轉換路徑,把計算出來的結果通證給目標帳號。該函數在一個單一的原子轉換中也容許屢次轉換。 注意:轉換器應該已經控制源通證。 6) function claimAndConvert(IERC20Token[] _path, uint256 _amount, uint256 _minReturn) public returns (uint256) 聲明調用者的通知,經過預約義的轉換路徑把通證轉換爲其餘通證 。

2.2 ContractIds.sol

功能描述: 定義一些常量

關鍵函數:

bytes32 public constant CONTRACT_FEATURES = "ContractFeatures";
bytes32 public constant BANCOR_NETWORK = "BancorNetwork";
bytes32 public constant BANCOR_FORMULA = "BancorFormula";
bytes32 public constant BANCOR_GAS_PRICE_LIMIT = "BancorGasPriceLimit";
bytes32 public constant BANCOR_CONVERTER_FACTORY = "BancorConverterFactory";

2.3 BancorNetwork.sol

功能描述:

Bancor Network interface,3個空函數定義

關鍵函數:

function convert(…) public payable
function convertFor(…) public payable
function convertForPrioritized2(…) public payable

2.4  BancorConverter.sol

見《基於以太坊的交易所BANCOR算法實現-轉換算法框架》文件描述。

2.5 BancorConverterFactory.sol

功能描述:

根據參數增長一個新的轉換器,把全部權和管理權限轉給發送者。

關鍵函數:

function createConverter(_token,_registry,_maxConversionFee,
_connectorToken,_connectorWeight) public returns(converterAddress)

2.6 BancorConverterUpgrader.sol

功能描述:

Bancor轉換升級器容許把舊的Bancor轉換器(0.4 或者更高)升級到最新的版本。

爲了開始升級流程,首先把轉換器的全部權轉讓給升級合約,而後調用升級函數。

在升級流程的最後,最新升級的轉換器的全部權要轉讓歸還給原始全部者。新轉換器的地址在ConverterUpgrade事件中是有效的。

核心函數:

1) function upgrade(IBancorConverterExtended _oldConverter, bytes32 _version) 把舊的轉換器升級到新的版本。 在調用本函數前,若是全部權沒有被轉移給升級器合約將會拋出異常。新轉換器的全部權將會被轉移給原始的全部者。 2) function readConnector(IBancorConverterExtended _converter, _address, _isLegacyVersion) 讀取鏈接器的配置

2.7 BancorFormula.sol

**功能描述:**轉換器的算法。

核心函數:

1) function calculatePurchaseReturn(uint256 _supply, uint256 _connectorBalance, uint32 _connectorWeight, uint256 _depositAmount) public view returns (uint256) 根據給定的一個token供應量,鏈接器餘額,權重和存入的數量(鏈接器代幣),計算出一個給定轉換的反饋。 公式: Return = _supply * ((1 + _depositAmount / _connectorBalance) ^ (_connectorWeight / 1000000) - 1)

2) function calculateSaleReturn(uint256 _supply, uint256 _connectorBalance, uint32 _connectorWeight, uint256 _sellAmount) public view returns (uint256) 根據給定的一個token供應量,鏈接器餘額,權重和賣出的數量(目標通證),計算出一個給定轉換的鏈接器通證的結果。公式: Return = _connectorBalance * (1 - (1 - _sellAmount / _supply) ^ (1 / (_connectorWeight / 1000000)))

3)function calculateCrossConnectorReturn(uint256 _fromConnectorBalance, uint32 _fromConnectorWeight, uint256 _toConnectorBalance, uint32 _toConnectorWeight, uint256 _amount) public view returns (uint256) 根據給定的2個鏈接器通證的餘額/權重,第一個鏈接器通證的售賣數量,計算出把第一個鏈接器通證轉換爲第二個鏈接器通證的轉換數量。

公式:

Return = _toConnectorBalance * (1 - (_fromConnectorBalance / (_fromConnectorBalance + _amount)) ^ (_fromConnectorWeight / _toConnectorWeight))

2.8 BancorGasPriceLimit.sol

功能描述:

BancorGasPriceLimit合約充當一個額外的前臺運行的攻擊減緩機制。它在全部的bancor轉換器上設置了一個最大的gas費用。

以便阻止想搶先交易的用戶插隊。gas費用上限對全部的轉換器都適用。而且它能夠被全部者更新,以便能跟當前網絡的gas費用相符合。

核心函數:

1) function setGasPrice(uint256 _gasPrice) public ownerOnly 更新gas上限; 2)function validateGasPrice(uint256 _gasPrice) 判斷輸入gas是否不超過gas上限。

2.9  CrowdsaleController.sol

功能描述:

智能通證控制器的衆籌版本,容許捐贈者用ether交換Bancor通證。衆籌期間價格恆定。

注意:20%的捐贈者是用ETH鏈接器通證餘額的BNT通證。

核心函數:

1) function() payable public  ->  function processContribution() private 轉移ETH給收益帳戶;發行智能代幣給捐贈者;1個ETH反回100個智能代幣。

2.10  BancorPriceFloor.sol

功能描述

bancor底價合約是一個簡單的合約,以一個恆定的ETH價格售賣智能代幣。

核心函數

1)function sell() public returns (uint256 amount) 把發送者的全部智能代幣轉給底價合約,發送(智能代幣/100)給發送者 2) function withdraw(uint256 _amount) public ownerOnly 管理員提取必定數量的ETH

2.11 SmartToken.sol

**功能描述:**智能代幣

核心函數:

1) function issue(address _to, uint256 _amount) 對某個帳戶地址增長智能代幣餘額 _amount,增長髮行總量_amount 2)function destroy(address _from, uint256 _amount) 對某個帳戶地址銷燬智能代幣餘額_amount,減小發行總量_amount

function transfer(address _to, uint256 _value) public transfersAllowed 智能代幣轉帳函數 4)function transferFrom(address _from, address _to, uint256 _value) public transfersAllowed 受權後的轉移

2.12 SmartTokenController.sol

功能描述:

智能合約控制器是智能合約可升級的一部分,它容許修改BUG,增長功能。    一旦接受了TOKEN的管理權限,它就變成了該TOKEN的惟一控制器,能夠執行任何TOKEN的相關函數。

爲了升級控制器,管理權限包括任何相關數據,必須轉移給新的控制器。 

智能代幣必須在構建函數設置,並且以後不可修改。

核心函數:

1) function transferTokenOwnership(address _newOwner) public ownerOnly: 管理帳號操做,更新控制權 2) function acceptTokenOwnership() public ownerOnly 管理帳號操做,接受控制權 3)function withdrawFromToken(IERC20Token _token, address _to, uint256 _amount )    public    ownerOnly 管理帳號操做,收回代幣到特定帳號

2.13 ContractFeatures.sol

功能描述:

通常合約容許區塊鏈上的每一個合約定義它支持的功能。

其餘合約能夠查詢這個合約,找出一個區塊鏈上的特定合約是否支持特定的功能。

每一個合約類型能夠定義它本身的功能列表標誌。合約定義的功能只可以被標識爲能夠/不能夠。

可使用bit位標識函數功能,例如: uint256 public constant FEATURE1 = 1 << 0; uint256 public constant FEATURE2 = 1 << 1; uint256 public constant FEATURE3 = 1 << 2;

關鍵函數:

function enableFeatures(uint256 _features, bool _enable) public

2.14 ContractRegistry.sol

功能描述:

合約註冊器能夠根據名字保持合約地址。owner能更新合約地址,以便合約名稱老是指向最新版本的給定合約。

其餘合約能夠查詢合約註冊器得到更新的地址,而不是依賴於固定的地址。注意:合約名稱如今限制在32個字節,以便優化GAS費用。

核心函數:

registerAddress(bytes32 _contractName, address _contractAddress)  - 註冊合約 function unregisterAddress(bytes32 _contractName) public ownerOnly  - 註銷合約

3

2個鏈接器通證兌換測試場景

3.1 場景:2個鏈接器通證ERC1和ERC2的兌換測試

假設有2個鏈接器代幣存在BANCOR轉換器中,其中

  • ERC1 5000個,25% CW權重;

  • ERC2 8000個, 15% CW權重;

  • 初始發行智能代幣 TKN1 20000個;

請問,500個ERC1能夠兌換多少個ERC2呢?

咱們先來手工拆解計算下,而後用程序運行來驗證正確性。

500個ERC1能夠兌換多少TKN1呢?

*   SmartTokenAmount = SmartTokenTokenSupply *((1 + ConnectorToken / ConnectorTokenBalance)^ CW - 1)

*   SmartTokenAmount = 20000 * (( 1 + 500 / 5000 )^ 0.25 - 1 )
    = 482(TKN1)

前一步所得的TKN1能夠兌換多少個ERC2呢?

*   connectorTokenAmount = ConnectorTokenBalance *(1 - (1 - SmartTokenAmount / SmartTokenTokenSupply)^ (1 / CW) )

*   connectorTokenAmount = 8000 * (1 - (1 - 482 / (20000+482))^ (1 / 0.15))
    = 8000 * (1 - 0.9765 ^ 6.6667)
    = 8000 * (1 - 0.853390)
    = 1173

兌換結論:500個ERC1 能夠兌換1173個ERC2

3.2 部署測試流程圖

輝哥帶領你們用truffle的框架進行測試驗證。因此,須要寫js測試函數。先整理下工程思路,完成流程圖的寫做。

3.2.1 建立轉換器及合約註冊

image

建立轉換器及合約註冊工做

對應的代碼:

before(async () => {

        /* 新建合約註冊器ContractRegistry,合約IDcontractIds,

 */

        contractRegistry = await ContractRegistry.new(); 

       contractIds = await ContractIds.new();

        /* 新建合約特徵contractFeatures,把合約名稱"ContractFeatures" 和合約地址註冊到合約註冊器 */

        contractFeatures = await ContractFeatures.new();

        let contractFeaturesId = await

contractIds.CONTRACT_FEATURES.call();

        await contractRegistry.registerAddress(contractFeaturesId, contractFeatures.address);

        /* 新建gas費用限制合約BancorGasPriceLimit,上限價格爲22Gwei,把合約名稱"BancorGasPriceLimit" 和合約地址註冊到合約註冊器 */

        let gasPriceLimit = await BancorGasPriceLimit.new(gasPrice);

        let gasPriceLimitId = await contractIds.BANCOR_GAS_PRICE_LIMIT.call();

        await contractRegistry.registerAddress(gasPriceLimitId, gasPriceLimit.address);

        /* 新建公式合約formula,把合約名稱"BancorFormula" 和合約地址註冊到合約註冊器 */ 

       let formula = await BancorFormula.new();

        let formulaId = await contractIds.BANCOR_FORMULA.call();

        await contractRegistry.registerAddress(formulaId, formula.address);

        /* 新建Bancor網絡合約BancorNetwork,參數爲合約註冊器地址,把合約名稱"BANCOR_NETWORK" 和合約地址註冊到合約註冊器 */

        /* bancorNetwork設置簽名者地址爲accounts[3] */

        let bancorNetwork = await BancorNetwork.new(contractRegistry.address); 
       let bancorNetworkId = await contractIds.BANCOR_NETWORK.call();        await contractRegistry.registerAddress(bancorNetworkId, bancorNetwork.address);

        await bancorNetwork.setSignerAddress(accounts[3]);

        /* 建立智能通證,名稱爲Token1,符號爲TKN1,數量爲2個 */ 

       //let token = await SmartToken.new('Token1', 'TKN1', 2);

                /* 建立一個鏈接器通證,名稱爲ERC Token 1,符號ERC1,數量爲10萬個 */ 

       //let connectorToken = await TestERC20Token.new('ERC Token 1', 'ERC1', 100000);

        //tokenAddress = token.address;

        //connectorTokenAddress = connectorToken.address;

    });

3.2.2 智能通證和鏈接器通證初始化

image

轉換器初始化,供第三步驟函數調用

image

初始化結束後的智能通證和ERC1/ERC2的分佈狀況

對應的實現代碼以下:

async function initConverter(accounts, activate, maxConversionFee = 0) {

    /* 建立智能通證,名稱爲TKN1,符號爲Token1  */ 

   token = await SmartToken.new('Token1', 'TKN1', 2);

    tokenAddress = token.address;

    /* 發行2種ERC20鏈接器通證 */

    connectorToken = await TestERC20Token.new('ERC Token 1', 'ERC1', 100000);

    connectorTokenAddress = connectorToken.address;
    connectorToken2 = await TestERC20Token.new('ERC Token 2', 'ERC2', 200000); 

   connectorTokenAddress2 = connectorToken2.address;

    /* 建立Bancor轉換器, */

    let converter = await BancorConverter.new( 

       tokenAddress,

        contractRegistry.address,

        maxConversionFee, 

       connectorTokenAddress,

        250000
    );

    /* 設置ERC2通證爲鏈接器通證,15%的權重 ,不容許虛擬餘額*/

    let converterAddress = converter.address;

    await converter.addConnector(connectorTokenAddress2, 150000, false); 

   /* 給帳號accounts[0]發行2萬個TKN1智能代幣 ,給轉換器地址轉帳5000個ERC1,給轉換器地址轉帳8000個ERC2,*/

    await token.issue(accounts[0], 20000);

    await connectorToken.transfer(converterAddress, 5000);

    await connectorToken2.transfer(converterAddress, 8000); 

   if (activate) {

r.acceptTokenOwnership();

    }

    return converter;

}

3.2.3 ERC1和ERC2的兌換函數實現

image

ERC1和ERC2的兌換函數

對應代碼:

 it('verifies that getReturn returns the same amount as buy -> sell when converting between 2 connectors', async () => {

        let converter = await initConverter(accounts, true);

        let returnAmount = await converter.getReturn.call(connectorTokenAddress, connectorTokenAddress2, 500);

        console.log("The returnAmount is : %d",returnAmount.toNumber()); 

               await connectorToken.approve(converter.address, 500);

        let purchaseRes = await converter.convert(connectorTokenAddress, tokenAddress, 500, 1);

        let purchaseAmount = getConversionAmount(purchaseRes);

        console.log("The purchaseAmount is : %d", purchaseAmount);

        let saleRes = await converter.convert(tokenAddress, connectorTokenAddress2, purchaseAmount, 1); 

       let saleAmount = getConversionAmount(saleRes); 

       console.log("The saleAmount is : %d",saleAmount);

        // converting directly between 2 tokens is more efficient than buying and then selling

        // which might result in a very small rounding difference  

      assert(returnAmount.minus(saleAmount).absoluteValue().toNumber() < 2);

    });

3.2.4 運行結果

在TRUFFLE下運行測試文件BanncorConverter2.js,能夠驗證算法代碼實現結果等同於上面的算法結果。

The returnAmount is : 117五、

The purchaseAmount is : 482

The saleAmount is : 1174

    ✓ verifies that getReturn returns the same amount as buy -> sell when converting between 2 connectors (1899ms)

若是對truffle命令和測試運行不瞭解的,可參考文檔《以太坊開發框架Truffle從入門到實戰》(https://www.jianshu.com/p/2e2b3b12eb0e)。

4

CLB(一種ERC20)和ETH兌換測試場景

4.1 場景:1種鏈接器通證CLOB和ETH的兌換測試

對於本身搭建的交易所,更常見的場景爲ERC20通證兌換爲ETH,解決長尾代幣的流通性問題。

假設有一種ERC20和ETH在BANCOR轉換器中,其中

  • CLB 90000個,90% CW權重,市價1元/個;

  • ETH 10個, 10% CW權重,市價1000元/個;

  • 初始發行智能代幣 TKN1 1000個,PRICE 0.1 (個/ETH);   PRICE 100 (個/CLOB);

請問,1000個CLOB能夠兌換多少個ETH呢?

咱們先來手工拆解計算下,而後用程序運行來驗證正確性。

1000個CLOB能夠兌換多少個TKN1?

  • SmartTokenAmount = SmartTokenTokenSupply *((1 + ConnectorToken / ConnectorTokenBalance)^ CW - 1) = 1000 * (( 1 + 1000 / 90000 )^ 0.9 - 1 ) =  9.99446694706181297191051400502(個TNK1)

9.994466947個TKN1能夠兌換多少個ETH呢?

  • connectorTokenAmount = ConnectorTokenBalance *(1 - (1 - SmartTokenAmount / SmartTokenTokenSupply)^ (1 / CW) )

  • connectorTokenAmount = 10 * (1 - (1 - (9.994466947 / (1000 + 9.994466947)))^ (1 / 0.1) ) = 10 * (1 - (1 - (9.994466947 / (1000 + 9.994466947)))^ (1 / 0.1) ) = 10 * (1 - (1 - (0.00989556603929837667128805564395))^ (1 / 0.1) ) = 10 * (1 - (1 - (0.00989556603929837667128805564395))^ (1 / 0.1) ) = 10 * (1 - 0.99010443396070162332871194435605 ^ 10 ) = 10 *  (1 - 0.90533655025365121589722721359431) = 0.94663449746348784102772786405694(個ETH)

兌換結論:1000個CLB能夠兌換0.946個ETH

按照假設的市價,二者的價值均爲1000元左右,符合指望。

4.2 測試代碼

針對上面兌換算法的公式描述以下:

/* 建立智能通證,名稱爲TKN1,符號爲Token1  */

    token = await SmartToken.new('Token1', 'TKN1', 2);

    tokenAddress = token.address;

    /* 發行ERC20鏈接器通證CLOB */ 

   connectorToken = await TestERC20Token.new('ColorBay Token', 'CLB', '1000000000000000000000000000');

    connectorTokenAddress = connectorToken.address;

    /* 從accounts[0]給etherToken存入10個ETH */

    etherToken = await EtherToken.new();

   /* 獲取以太坊的餘額 */

    let EtherBalance = await web3.eth.getBalance(accounts[0]); 

   console.log("The EtherBalance of accounts[0] is : %d",EtherBalance);
     //etherToken.address.transfer(1000);

    /* 往etherToken存10個ETH */

    await etherToken.deposit({ value: '10000000000000000000' });

    /* 建立Bancor轉換器,添加CLOB做爲鏈接器代幣,權重爲90% */

    let converter = await BancorConverter.new(

        tokenAddress,

        contractRegistry.address,

        maxConversionFee,

        connectorTokenAddress,

        900000

    );

    /* 設置ETH做爲鏈接器代幣,權重爲10%*/

    let converterAddress = converter.address;

    await converter.addConnector(etherToken.address, 100000, false);

    /* 給帳號accounts[0]發行1000個TKN1智能代幣 ,給轉換器地址轉帳90000個CLOB*/

    await token.issue(accounts[0], '1000000000000000000000');

    await connectorToken.transfer(converterAddress, '90000000000000000000000');

    /* 給轉換器地址轉帳10個ETH */

    await etherToken.transfer(converter.address, '10000000000000000000');    if (activate) {

        await token.transferOwnership(converterAddress); 

       await converter.acceptTokenOwnership();

    }

    /* 設置跟ETH的轉換路徑 */ 

   clobQuickBuyPath = [connectorTokenAddress, token.address, etherToken.address];

    /* 受權鏈接器通證CLOB 1000個 */ 

   await connectorToken.approve(converter.address, '1000000000000000000000');

    let purchaseRes = await converter.convert(connectorTokenAddress, tokenAddress, '1000000000000000000000', 1);

    let purchaseAmount = getConversionAmount(purchaseRes);   

 console.log("The purchaseAmount is : %d", purchaseAmount);

    let saleRes = await converter.convert(tokenAddress, etherToken.address, purchaseAmount, 1);

    let saleAmount = getConversionAmount(saleRes);

    console.log("The saleAmount is : %d",saleAmount);

4.3 運行結果

The EtherBalance of accounts[0] is : 82637441999919870000

The purchaseAmount is : 9994466947061813000

The saleAmount is : 946634497469028600

    ✓ verifies that user can get ETH through sell CLB (2408ms)

如上所示,此處代碼以wei爲單位,處於10^18,獲得的結果爲0.9466個ETH,同手工計算結果。

5

總結

從白皮書,算法公式驗證到代碼實現,輝哥從技術穿刺的角度講透了BANCOR算法在以太坊環境的實現。

本文做者:HiBlock區塊鏈技術佈道羣-輝哥

原文發佈於簡書

加微信baobaotalk_com,加入技術佈道羣

image

相關文章
相關標籤/搜索