BANCOR学习:如何开发自己的BANCOR去中心化交易平台?

Posted by

BANCOR学习:如何开发自己的BANCOR去中心化交易平台?

本文作者:HiBlock区块链技术布道群-辉哥

原文发布于简书

加微信baobaotalk_com,加入技术布道群

BANCOR学习:如何开发自己的BANCOR去中心化交易平台?

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

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

2.1 BancorNetwork.sol

功能描述:

BancorNetwork合约是bancor通证转换的主入口。

通过提供转换路径,它允许通过唯一的方法在bancor network中的任何通证转换为其他的通证。

转换路径注意点:

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 payablefunction convertFor(…) public payablefunction 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,增加发行总量_amount2)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 创建转换器及合约注册

BANCOR学习:如何开发自己的BANCOR去中心化交易平台?创建转换器及合约注册工作

对应的代码:

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

BANCOR学习:如何开发自己的BANCOR去中心化交易平台?

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

BANCOR学习:如何开发自己的BANCOR去中心化交易平台?

初始化结束后的智能通证和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的兑换函数实现

BANCOR学习:如何开发自己的BANCOR去中心化交易平台?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从入门到实战》(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算法在以太坊环境的实现。

BANCOR学习:如何开发自己的BANCOR去中心化交易平台?

BANCOR学习:如何开发自己的BANCOR去中心化交易平台?

原文始发于微信公众号( 区块链社区HiBlock ):BANCOR学习:如何开发自己的BANCOR去中心化交易平台?