主页 > 最新版官网imtoken钱包下载 > 区块链智能合约:去中心化交易所Bancor商业合约解析(一)
区块链智能合约:去中心化交易所Bancor商业合约解析(一)
Bancor的github上发布的代码在我看过的项目中算是比较规范的了,而且还提供了很多测试例子,着实费了一番功夫。 最近一段时间,我会注意分析这个项目的代码,和大家分享一下Solidity语言是如何实现项目的标准化的。
Github地址:
如何开始?
正好这个项目用的是truffle框架。 先解释下truffle项目部署的操作流程(只涉及合约部分):
truffle框架下一般有contracts、migration、test三个文件夹比特币合约软件程序交易流程比特币合约软件程序交易流程,还有一个truffle-config.js文件。 Contracts为智能合约文件*.sol; migration是合约部署的设置js文件; test 是测试事件。 一般来说,写好合约后,会在项目目录下运行truffle compile,目录下会生成一个build文件夹,里面存放编译好的字节码和abi。 然后需要运行truffle migrate将合约上链(一般情况下会是本地的Ganache/老版本叫testrpc)然后运行truffle test执行测试事件,终端会实时输出结果.
Bancor 的项目是用比较标准的方式编写的。 我们可以直接去migration/2_deploy_contract.js看看Bancor整套合约的部署过程,然后一一分析。
/* global artifacts */
/* eslint-disable prefer-reflect */
const Utils = artifacts.require('Utils.sol');
const Owned = artifacts.require('Owned.sol');
const Managed = artifacts.require('Managed.sol');
const TokenHolder = artifacts.require('TokenHolder.sol');
const ERC20Token = artifacts.require('ERC20Token.sol');
const EtherToken = artifacts.require('EtherToken.sol');
const SmartToken = artifacts.require('SmartToken.sol');
const SmartTokenController = artifacts.require('SmartTokenController.sol');
const BancorFormula = artifacts.require('BancorFormula.sol');
const BancorGasPriceLimit = artifacts.require('BancorGasPriceLimit.sol');
const BancorQuickConverter = artifacts.require('BancorQuickConverter.sol');
const BancorConverterExtensions = artifacts.require('BancorConverterExtensions.sol');
const BancorConverter = artifacts.require('BancorConverter.sol');
const CrowdsaleController = artifacts.require('CrowdsaleController.sol');
module.exports = async (deployer) => {
deployer.deploy(Utils);
deployer.deploy(Owned);
deployer.deploy(Managed);
deployer.deploy(TokenHolder);
deployer.deploy(ERC20Token, 'DummyToken', 'DUM', 0);
deployer.deploy(EtherToken);
await deployer.deploy(SmartToken, 'Token1', 'TKN1', 2);
deployer.deploy(SmartTokenController, SmartToken.address);
deployer.deploy(BancorFormula);
deployer.deploy(BancorGasPriceLimit, '22000000000');
deployer.deploy(BancorQuickConverter);
deployer.deploy(BancorConverterExtensions, '0x125463', '0x145463', '0x125763');
deployer.deploy(BancorConverter, SmartToken.address, '0x124', 0, '0x0', 0);
deployer.deploy(CrowdsaleController, SmartToken.address, 4102444800, '0x125', '0x126', 1);
};
从名字可以看出Bancor的合约分为三类:
分类名称
基本支持
Utils.sol、Owned.sol、Managed.sol
令牌实现
TokenHolder.sol, ERC20Token.sol, EtherToken.sol, SmartToken.sol
交易逻辑
SmartTokenController.sol, BancorFormula.sol, BancorGasPriceLimit.sol, BancorQuickConverter.sol,
BancorConverterExtensions.sol、BancorConverter.sol、CrowdsaleController.sol
这次第一季快过半一二类了XD
基本支持合同
实用工具
pragma solidity ^0.4.18;
/* Utilities & Common Modifiers */
contract Utils {
/** constructor **/
function Utils() public {
}
// verifies that an amount is greater than zero
modifier greaterThanZero(uint256 _amount) {
require(_amount > 0);
_;
}
// validates an address - currently only checks that it isn't null
modifier validAddress(address _address) {
require(_address != address(0));
_;
}
// verifies that the address is different than this contract address
modifier notThis(address _address) {
require(_address != address(this));
_;
}
// Overflow protected math functions
/** @dev returns the sum of _x and _y, asserts if the calculation overflows
@param _x value 1
@param _y value 2
@return sum
*/
function safeAdd(uint256 _x, uint256 _y) internal pure returns (uint256) {
uint256 z = _x + _y;
assert(z >= _x);
return z;
}
/** @dev returns the difference of _x minus _y, asserts if the subtraction results in a negative number
@param _x minuend
@param _y subtrahend
@return difference
*/
function safeSub(uint256 _x, uint256 _y) internal pure returns (uint256) {
assert(_x >= _y);
return _x - _y;
}
/** @dev returns the product of multiplying _x by _y, asserts if the calculation overflows
@param _x factor 1
@param _y factor 2
@return product
*/
function safeMul(uint256 _x, uint256 _y) internal pure returns (uint256) {
uint256 z = _x * _y;
assert(_x == 0 || z / _x == _y);
return z;
}
}
一般来说,它没有什么特别之处。 所有修改器确认是数字格式和地址问题。 加减乘法的方法全部封装在内部pure中,完全没有外部攻击。
Owned.sol 和 Managed.sol
这两个文件内容基本相同,具体功能不同,所以分开来。 我只会在这里张贴一份。
pragma solidity ^0.4.18;
/* Provides support and utilities for contract management */
contract Managed {
address public manager;
address public newManager;
event ManagerUpdate(address indexed _prevManager, address indexed _newManager);
/** @dev constructor */
function Managed() public {
manager = msg.sender;
}
// allows execution by the manager only
modifier managerOnly {
assert(msg.sender == manager);
_;
}
/** @dev allows transferring the contract management
the new manager still needs to accept the transfer
can only be called by the contract manager
@param _newManager new contract manager
*/
function transferManagement(address _newManager) public managerOnly {
require(_newManager != manager);
newManager = _newManager;
}
/** @dev used by a new manager to accept a management transfer */
function acceptManagement() public {
require(msg.sender == newManager);
ManagerUpdate(manager, newManager);
manager = newManager;
newManager = address(0);
}
}
这个合约其实很像OpenZeppelin()项目中的Owner.sol。 基本功能是在创建时自动将创建者设置为合约所有者,并在后续函数中添加ownerOnly修饰符提供交易提议者的身份验证。 唯一的区别是转让所有权的方式。
代币执行合约:接口
这里事情开始变得有点复杂,我们需要引入一个新的概念:接口。
该接口在编译时实际上并不会生成任何字节码,但会在编码过程中起到代码规范的作用。 Bancor的接口文件夹中一共有10个接口,其中与token实现相关的接口有4个(或5个,因为IOwned.sol也包含在内):
/* Owned contract interface */
contract IOwned {
// this function isn't abstract since the compiler emits automatically generated getter functions as external
function owner() public view returns (address) {}
function transferOwnership(address _newOwner) public;
function acceptOwnership() public;
}
/* Token Holder interface */
contract ITokenHolder is IOwned {
function withdrawTokens(IERC20Token _token, address _to, uint256 _amount) public;
}
/* ERC20 Standard Token interface */
contract IERC20Token {
// these functions aren't abstract since the compiler emits automatically generated getter functions as external
function name() public view returns (string) {}
function symbol() public view returns (string) {}
function decimals() public view returns (uint8) {}
function totalSupply() public view returns (uint256) {}
function balanceOf(address _owner) public view returns (uint256) { _owner; }
function allowance(address _owner, address _spender) public view returns (uint256) { _owner; _spender;
function transfer(address _to, uint256 _value) public returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
function approve(address _spender, uint256 _value) public returns (bool success);
}
/* Ether Token interface */
contract IEtherToken is ITokenHolder, IERC20Token {
function deposit() public payable;
function withdraw(uint256 _amount) public;
function withdrawTo(address _to, uint256 _amount) public;
}
/* Smart Token interface */
contract ISmartToken is IOwned, IERC20Token {
function disableTransfers(bool _disable) public;
function issue(address _to, uint256 _amount) public;
function destroy(address _from, uint256 _amount) public;
}
根据这些接口,可以画出一个简单的结构图。 从图中可以看出SmartToken是ERC20Token的一种,增加了Owned功能封装; 而EtherToken中的附加功能包括:提取token,eth充值,见 也就是承担了token和对外eth转账的功能,可以直接应用在下面的众筹合约中。
令牌结构.png