第二十五课 如何开发自己的BANCOR去中心化交易平台?1,摘要2,BancorNetwork网络的文件框架和功能3,2个连接器通证兑换测试场景4,CLB(一种ERC20)和ETH兑换测试场景4,总结

1,摘要

《第二十四课 基于以太坊的交易所BANCOR算法实现-转换算法框架》 讲解了以太坊solidity实现的BancorConverter转换主合约的逻辑和代码,但是没有涉及核心互换及计算代码,而是通过interface类的方式进行隔离。 本文详细描述一下内容,能跑的程序才是真分享: (1)BancorNetwork网络的文件框架和功能; (2)BancorConverter合约测试执行流程; (3)2个连接器通证ERC1-ERC22的转换验证结果; (4)ETH-CLB(彩贝)的转化验证结果

2,BancorNetwork网络的文件框架和功能

BancorProtocol工程是一个带有TRUFFLE框架的solidity智能合约Bancor算法实现框架。文件列表如下:

|   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

其中的智能合约代码量实在繁多,限于篇幅限制,就不一一介绍了,辉哥介绍其中主要的几个文件。

1,BancorNetwork.sol

(1),功能描述: BancorNetwork合约是bancor通证转换的主入口。 通过提供转换路径,它允许通过唯一的方法在bancor network中的任何通证转换为其他的通证。 转换路径注意点: 1>,转换路径是一种数据结构,用于在bancor network中把一种通证转换为另一种通知。有时一次转换可能不够,需要多个跳转。 这个路径定义了哪些转换会被使用,每个步骤会做哪一种转换。 2>,这个路径格式不包含复杂的结构。相反,它已单一数组的方式呈现,其中每一个跳转(hop)包含2个数组元素 -智能通证和目标通证。 另外,第一个元素总是源通证。智能通证只作为指向转换器的指针使用(因为转换器地址很可能会变)。 (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,ContractIds.sol

(1),功能描述: 定义一些常量 (2),关键函数: 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";

3,BancorNetwork.sol

(1),功能描述: Bancor Network interface,3个空函数定义 (2),关键函数: function convert(…) public payable function convertFor(…) public payable function convertForPrioritized2(…) public payable

3, BancorConverter.sol

见《第二十四课 基于以太坊的交易所BANCOR算法实现-转换算法框架》文件描述。

4,BancorConverterFactory.sol

(1),功能描述: 根据参数增加一个新的转换器,把所有权和管理权限转给发送者。 (2),关键函数: function createConverter(_token,_registry,_maxConversionFee, _connectorToken,_connectorWeight) public returns(converterAddress)

5,BancorConverterUpgrader.sol

1,功能描述: Bancor转换升级器允许把旧的Bancor转换器(0.4 或者更高)升级到最新的版本。 为了开始升级流程,首先把转换器的所有权转让给升级合约,然后调用升级函数。 在升级流程的最后,最新升级的转换器的所有权要转让归还给原始所有者。新转换器的地址在ConverterUpgrade事件中是有效的。 2,核心函数: 1) function upgrade(IBancorConverterExtended _oldConverter, bytes32 _version) 把旧的转换器升级到新的版本。 在调用本函数前,如果所有权没有被转移给升级器合约将会抛出异常。新转换器的所有权将会被转移给原始的所有者。 2) function readConnector(IBancorConverterExtended _converter, _address, _isLegacyVersion) 读取连接器的配置

6,BancorFormula.sol

(1),功能描述: 转换器的算法。 (2),核心函数: 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))

7,BancorGasPriceLimit.sol

1,功能描述: BancorGasPriceLimit合约充当一个额外的前台运行的攻击减缓机制。它在所有的bancor转换器上设置了一个最大的gas费用, 以便阻止想抢先交易的用户插队。gas费用上限对所有的转换器都适用。并且它可以被所有者更新,以便能跟当前网络的gas费用相符合。 2,核心函数: 1) function setGasPrice(uint256 _gasPrice) public ownerOnly 更新gas上限; 2)function validateGasPrice(uint256 _gasPrice) 判断输入gas是否不超过gas上限。

8, CrowdsaleController.sol

1,功能描述: 智能通证控制器的众筹版本,允许捐赠者用ether交换Bancor通证。众筹期间价格恒定。 注意:20%的捐赠者是用ETH连接器通证余额的BNT通证。 2,核心函数: 1) function() payable public -> function processContribution() private 转移ETH给收益账户;发行智能代币给捐赠者;1个ETH反回100个智能代币。

9, BancorPriceFloor.sol

1,功能描述 bancor底价合约是一个简单的合约,以一个恒定的ETH价格售卖智能代币。 2,核心函数

  1. function sell() public returns (uint256 amount) 把发送者的所有智能代币转给底价合约,发送(智能代币/100)给发送者 2) function withdraw(uint256 _amount) public ownerOnly 管理员提取一定数量的ETH

10,SmartToken.sol

1,功能描述: 智能代币 2,核心函数: 1) function issue(address _to, uint256 _amount) 对某个账户地址增加智能代币余额 _amount,增加发行总量_amount 2)function destroy(address _from, uint256 _amount) 对某个账户地址销毁智能代币余额_amount,减少发行总量_amount

  1. function transfer(address _to, uint256 _value) public transfersAllowed 智能代币转账函数 4)function transferFrom(address _from, address _to, uint256 _value) public transfersAllowed 授权后的转移

11,SmartTokenController.sol

1,功能描述: 智能合约控制器是智能合约可升级的一部分,它允许修改BUG,增加功能。 一旦接受了TOKEN的管理权限,它就变成了该TOKEN的唯一控制器,可以执行任何TOKEN的相关函数。 为了升级控制器,管理权限包括任何相关数据,必须转移给新的控制器。 智能代币必须在构建函数设置,而且之后不可修改。 2,核心函数: 1) function transferTokenOwnership(address _newOwner) public ownerOnly: 管理账号操作,更新控制权 2) function acceptTokenOwnership() public ownerOnly 管理账号操作,接受控制权 3)function withdrawFromToken(IERC20Token _token, address _to, uint256 _amount ) public ownerOnly 管理账号操作,收回代币到特定账号

12,ContractFeatures.sol

1,功能描述: 一般合约允许区块链上的每个合约定义它支持的功能。 其他合约可以查询这个合约,找出一个区块链上的特定合约是否支持特定的功能。 每个合约类型可以定义它自己的功能列表标志。合约定义的功能只能够被标识为可以/不可以。 可以使用bit位标识函数功能,例如: uint256 public constant FEATURE1 = 1 << 0; uint256 public constant FEATURE2 = 1 << 1; uint256 public constant FEATURE3 = 1 << 2; 2,关键函数: function enableFeatures(uint256 _features, bool _enable) public

13,ContractRegistry.sol

1,功能描述: 合约注册器可以根据名字保持合约地址。owner能更新合约地址,以便合约名称总是指向最新版本的给定合约。 其他合约可以查询合约注册器获得更新的地址,而不是依赖于固定的地址。注意:合约名称现在限制在32个字节,以便优化GAS费用。 2,核心函数: 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 创建转换器及合约注册

1. 创建转换器及合约注册工作

对应的代码:

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 智能通证和连接器通证初始化

2. 转换器初始化,供第三步骤函数调用

2.1 初始化结束后的智能通证和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) {
        await token.transferOwnership(converterAddress);
        await converter.acceptTokenOwnership();
    }

    return converter;
}

3.2.3 ERC1和ERC2的兑换函数实现

3.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 : 1175
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从入门到实战》

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,同手工计算结果。

4,总结

从白皮书,算法公式验证到代码实现,辉哥从技术穿刺的角度讲透了BANCOR算法在以太坊环境的实现。 辉哥整理了BANCOR的系列知识分享,列表如下: (1)【白皮书】Bancor协议:通过智能合约为加密货币提供持续流动性(附PDF下载) (2)【易错概念】以实例形式深入浅出讲透BANCOR算法 (3)第二十四课 基于以太坊的交易所BANCOR算法实现-转换算法框架 (4)第二十五课 如何开发自己的BANCOR去中心化交易平台?

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏区块链大本营

“危机四伏”的以太转账操作|以太转账安全风险——漏洞分析连载之八期

Solidity语言的默认存储规则和引用未初始化变量带来的特殊性共同导致了未初始化变量将原有状态变量覆盖,占用了状态变量在Storage中的位置,重演了最近“高...

1032
来自专栏全栈数据化营销

用python从0开始创建一个区块链,从代码深入理解区块链

本文主要内容翻译自Learn Blockchains by Building One 作者认为最快的学习区块链的方式是自己创建一个,本文就跟随作者用Python...

42010
来自专栏汇智网教程

以太坊中的iban概念解析

2505
来自专栏SAP最佳业务实践

SAP最佳业务实践:FI–资产会计(162)-5 ABAVN 资产处置

4.4 资产处置 固定资产清理是指从资产组合中移除某项资产或部分资产。复杂固定资产(或部分复杂固定资产)的移除是从帐面上将其作为资产清理过帐。 在中国资产会计中...

4318
来自专栏Android Note

bitfinex币 接口翻译整理

1612
来自专栏区块链大本营

@程序员,如何淋漓尽致地敲出Solidity安全代码?

区块链技术的发展要与安全挂钩,齐头并进,让迅速的发展约束在可靠的范围之内,才能真正让新科技稳步推广,深入人心。

891
来自专栏jouypub

迷恋猫CryptoKitties源码分析

https://etherscan.io/address/0x06012c8cf97bead5deae237070f9587f8e7a266d#code

1651
来自专栏区块链入门

【易错概念】UTXO 和 Account 模型对比

在当前区块链世界中,主要有两种记录保存方式,UTXO 模式(Unspent Transaction Output) 和 Account 模式。Bitcoin 采...

1441
来自专栏PPV课数据科学社区

如何用 Python 从 0 开始创建一个区块链?

关键词:区块链、python、 正文如下: 在数字货币盛行的档口,比特币,这币那币到底值不值得信赖呢?也许你像很多人一样感到新奇,想接近它,但只因背后的区块链...

3926
来自专栏圆方圆学院精选

【许晓笛】开发第一个 EOS 智能合约

稍微了解 EOS 系统,你就会知道 EOS 的智能合约基于 WebAssembly(WASM) 技术,这种技术在性能和跨平台兼容性之间取得了很好的平衡,通过将原...

1274

扫码关注云+社区

领取腾讯云代金券