solidity 基础智能合约

​  今天来认识智能合约中常用的基础合约。

 

地址工具

用于检测某个地址是否为合约的工具

pragma solidity ^0.4.24library AddressUtils{    function isContract(address addr) internal view returns(bool){        uint256 size;        assembly{size:=extcodesize(addr)}//assembly 指明后面程序为内联汇编。extcodesizs取得参数addr对应账户关联地址的EVM字节码长度。               return size>0;//    }}

这个合约是一个librray,只有一个函数isContract,且被声明为internal view.internal 限制这个函数只能由import这个合约内部使用;view 声明这个函数不会改变状态

 

限制子合约的余额

限制子合约以太币余额的基础合约

pragam solidity ^0.4.24;contract LimitBlance{    uint256 public limit;    constructor(uint256 _limit) public{        limit=_limit;    }    modifier limitedPayable{        require(address(this).blance<=limit);        _;    }}

缺点:这种利用modifier来限制的方式,无法限制其它合约通过selfdestruct操作中指定合约地址而引发的转入操作;也没法限制没有使用limitedPayable来声明的合约函数进行转入操作。


 

安全算术(SafeMath.sol)

对uint256类型进行算术四则运算的库,也是最常用库,防止溢出。

pragma solidity ^0.4.24;library SafeMath{    function mul(uint256 _a, uint256 _b) internal pure returns(uint256 c){        if (_a == 0){//a==0比a!=0便宜。原因:=只执行了一个EVM判断            return 0;        }        c = _a * _b;        assert(c / _a == _b);//_a*_b结果可能超过最大值,判断有没有溢出。return c;    }        function div(uint256 _a, uint256 _b) internal pure returns(uint256 ){        return _a / _b;//结果不为整,小数会被舍弃。}        function sub(uint256 _a, uint256 _b) internal pure returns(uint256 c ){         assert(_a >= _b);//防止下溢(2^256+_a-_b)         return _a - _b;    }        function add(uint256 _a, uint256 _b) internal pure returns(uint256 c ){         c= _a + _b;         assert(c >= _b);//防止上溢((a+b)mod 2^256)         return c;    }}

 

自省(ERC165)

这是一个向外界提供一个特定函数的基础合约,这个函数可以用来查询合约支持的接口(函数)。

pragma solidity ^0.4.24;interface ERC165{    function supportsInterface(bytes64 _interfaceId)    external  //外部函数    view  //不会修改状态    returns(bool);}//gas 消耗控制在30000以内

_interfaceId函数选择器,是合约某个函数的标识(合约函数调用数据的前4个字节)

 

接口查找基础合约

pragma solidity ^0.4.24;contract SupportsInterfaceWithLiikUp is ERC165{    bytes4 public constant InterfaceId_ERC165 = 0x01ffc9a7;    //0x01ffc9a7 ===bytes4(keccak256('SupportsInterface(bytes4)'))    mapping(bytes4 => bool) internal supportsInterfaces;    constructor()         public    {    _registerInterface(InterfaceId_ERC165);    }        function _registerInterface(bytes4 _interfaceId)           internal{         require(interfaceId != 0xffffffff);         supportsInterface[_interfaceId] = true;     }   }

这是一个实现了ERC165的基础合约。

用一个mapping类型的状态变量持久化地保存了一个由函数接口(函数选择器)到布尔值的映射。它提供了一个internal函数来注册合约自身的接口函数,并在合约构造函数中直接注册了ERC165接口函数supportsInterfaces。注意_registerInterface断言基于ERC165的gas消耗。

 

归属权(Owner.sol)

这是一个用来给合约提供所属权特性的基础合约,这是一个非常重要的,大概也是最基础的合约。

pragma solidity ^0.4.24;contract Owner{    address public owner;        event OwnershipRenounced(address indexed previousOwner);    event OwnershipTransfered(         address indexed previousOwner,         address indexed newOwner );   constract() public{        owner = msg.sender;   }       modifier onlyOwner() {       require(msg.sender == owner);       _;   }      function renounceOwner() public onlyOwner {       emit OwnershipRenounced(owner);       owner = address(0);//没人再能调用声明为onlyOwner的函数。  }      function transferOwnership(address _newOwner) public onlyOwner{       _transferOwnership(_newOwner);   }      function _transferOwnership(address _newOwner) internal{       require(_newOwner != address(0));       emit OwnershipTransfered(owner, _newOwner);       owner = _newOwner;   }   }

这是一个非常通用的归属权基础合约。由一个状态变量来保存它的所有者地址,并在构造函数中将合约创建人设置为合约所有者。定义了两个事件:OwnershipRenounced 用来通知外部世界所有者放弃对合约的所有权;OwnershipTransfered 用来通知外部世界合约归属权发生转移。

 

用户角色(Roles.sol)

pragma solidity ^0.4.24;library Roles{    struct Role{        mapping (address => bool) bearer;    }        function add(Role storage role, address addr)         internal{//添加角色        role.bearer[addr] = true;    }        function remove(Role storage role,address addr)         internal{//移除角色        role.bearer[addr] = false;     }        function check(Role storage role,address addr)         view         internal{//验证角色         require(has(role,addr))    }        function has(Role storage role,address addr)         view         internal         returns(bool){//验证角色         return role.bearer[addr];    }                       }

 

定义结构体Role,其中保留一组地址到布尔值的映射,也就是保留“某个地址是否是当前Role”的信息。

 

基于角色的访问控制(RBAC.sol)

pragma solidity ^0.4.24;import"./Role.sol";contract RBAC{    using Role for Roles.Role;        mapping (string => Roles.Role) private roles;        event RoleAdded(address indexed operator, string role);   event RoleRemoved(address indexed operator, string role);      function chekRole(address _operator, string _role)        view        public   {        roles[_role].check(_operator);   }      function hasRole(address _operator, string _role)         view         internal         returns(bool)    {         return roles[_role].has(_operator);    }        function addRole(address _operator, string _role)         internal    {        roles[_role].add(_operator);        emit RoleAdded(_operator, _role);    }        function removeRole(address _operator, string _role)         internal    {        roles[_role].remove(_operator);        emit RoleRemoved(_operator, _role);    }        modifier onlyRole    {//特定角色可用的函数修改器        checkRole(msg.sender, _role);        _;    }         }

非常重要的基础合约。可以用来基于用户角色进行相应的访问控制。合约中定义了一个string到Roles.Role的private映射,也就是角色名称到与角色相关联的所有地址信息映射的对应关系。

 

超级用户(Superuser.sol)

pragma solidity ^0.4.24;import "./Ownable.sol";import "./rbac.RBAC.sol";contract Superuser is Ownable, RBAC {       string public constant ROLE_SUPERUSER = "superuser" ;              constructor() public{            addRole(msg.sender,ROLE_SUPERUSER);       }              modifier onlySuperuser(){            checkRole(msg.sender,ROLE_SUPERUSER);            _;       }              modifier onlyOwnerOrSuperuser(){            require(msg.sender == owner || isSuperuser(msg.sender));            _;       }              function isSuperuser(address _addr)            public            view            returns(bool){                return hasRole(_addr, ROLE_SUPERUSER);            }              function transferSuperuser(address _newSuperuser) public onlySuperuser{            require(_newSuperuser != address(0));            removeRole(msg.sender, ROLE_SUPERUSER);            addRole(msg.sender,ROLE_SUPERUSER);       }       //转移合约地址       function transferOwnership(address _newOwner) public onlySuperuser{             _transferOwnership(_newOwner);   }

超级用户可用直接修改合约归属权,即使他不是合约的Owner.

 

联系方式(Contactable.sol)

简单地给Owner合约添加字符串附加信息的基础合约

pragma solidity ^0.4.24;import "./Ownable.sol";contract contactable is Owner{    string public contactInformation;    function setcontactInformation(string info) onlyOwner public{           contactInformation = info;    } }


归属权转移请求(Claimable.sol)

Ownable的扩展,允许在做归属权转移时,由新的的合约拥有者“声明接受归属权”

pragma solidity ^0.4.24;import "./Ownable.sol";contract Claimable is Owner{    address public pendingOwner;        modifier onlypendingOwner(){        require(msg.sender == pendingOwner);        _;    }        function transferOwnership(address newOwner) onlyOwner public{        pendingOwner = newOner;    }        function claimOwnership() onlypengdingOwner public{        emit Ownershiptransferred(owner, pendingOwner);        owner = pendingOwner;        pendingOwner = address(0);    }}    


有时限的归属权转移请求(DelayedClaimable.sol)

当前合约是对Claimable.sol的扩展,由当前合约所有者指定了一个接受归属权转移的时间期限,新的owner只有在时间期限内调用claimOwnership函数才能获得合约的归属权。

这里的时间条件是区块号(block.number)的范围。原因:区块链系统基于分布式对等网络,各个节点(客户端)本地时间未必与UTC时间一致,所有使用区块号这个全网共识的时间标志作为判定条件。

pragma solidity ^0.4.24;import "./Claimable.sol";contract DelayedClaimable is Claimable{    uint256 public end;    uint256 public start;        function setLimits(uint256 _start, uint256 _end) onlyOwner public{        require(_start <= _end);        end = _end;        start = _start;    }        function claimOwnership() onlyPendingOwner public{        requier((block.number <= end) && (block.number >= start));        emit OwnershipTransferred(owner, pendingOwner);        owner = pendingOwner;        pendingOwner = address(0);        end = 0;    }}


归属权继承(Heritable.sol)

pragma solidity ^0.4.24;import "./Ownable.sol";contract Heritable is Ownable{    address private heir_;    uint256 private heartbeatTimeout_;    uint256 private timeOfDeath_;        event HeirChange(address indexed owner, addresss indexed newHeir);    event OwnerHeartbeated(address indexed owner);    event OwnerProclaimedDead(        address indexed owener,        address indexed heir,        uint256 timeOfDeath);    event HeirOwnershipClaimed(        address indexed previousOwner,        addresss indexed newOwner);        modifier onlyHeir(){        require(msg.sender == heir_);        _;    }        constructor(uint256 _heartbeatTimeout) public{        setHeartbeatTimeout(_heartbeatTimeout);    }        function setHeir(address newHeir) public onlyOwner{        require(newOwner != owner);        heartbeat();        emit HeirChanged(owner, newHeir);        heir_ = newHeir;    }    }

 

合约不归属合约(HasNocontracts.sol)

当某个继承Ownable合约的合约,其所有者地址被设置为一个合约地址的时候,可以使用HasNoConstracts合约定义的reclaimConstract方法将其所有者地址转移到当前合约的所有者。

pragma solidity ^0.4.24;import "./Ownable.sol";contact HaoNoContracts is Ownable{    function reclaimConstract(address constractAddr) external onlyOwner{        Ownable constractInst = Ownable(contractAddr);        constractInst.transferOwnership(owner);    }}


合约不持有以太币(HasNoEther.sol)

对Ownable合约的拓展,来确保合约中不持有以太币。

pragma solidity ^0.4.24;import "./Ownale.sol";contract HasNoEther is Ownable{    constructer() public payable{        require(msg.sender == 0);    }        function() external{   }   //将此合约余额转给合约的拥有者    function() reclaimEther() external onlyOwner{        owner.transfer(address(this).balance);    }}

 

合约可找回token(CanClaimToken.sol)

将合约所持有的ERC20 token取回到合约所有者的地址。

pragma solidity ^0.4.24;import "./Ownable.sol";import "../token/ERC20/ERC20Basic.sol";import "../token/ERC20/SafeERC20.sol";contract CanClaimToken is Ownable{    using SafeERC20 for ERC20Basic;       function reclaimToken(ERC20Basic token) external onlyOwner {       uint256 balance = token.balance(this);//此合约余额       token.safeTransfer(owner,balance);//合约拥有者转走余额   }   }


合约不持有token(HasNoToken.sol)

pragma solidity ^0.4.24;import "./CanClaimToken.sol";contract HasNoTokens is CanReclaimToken{    function tokenFallback(address _from, uint256 _value, bytes _data) external {        _from;        _value;        _data;       revert();//revert函数会导致EVM异常终止回退所有先前改变的状态    }}

 

tokenFallback函数就是ERC233标准中要求接受者合约实现的一个函数,实现这个函数的合约会被认定是可以持有ERC233token的合约。

 

合约什么都不持有(NoOwner.sol)

pragma solidity ^0.4.24;import "./HasNoEther.sol";import "./HasNoToken.sol";import "./HasNocontracts.sol";contract NoOwner is HasNoEther, HasNoToken, HasNocontracts{    }

 

签名保镖(SigmatureBouncer.sol)

pragma solidity ^0.4.24;import "../Ownership/Ownable.sol";import "../Ownership/rbac/RBAC.sol";import "../ERCRecovery.sol";contract SigmatureBouncer is Owner, RBAC {    using ERCRecovery for bytes32;        string public constant bytes32;    uint constant METHOD_ID_SIZE = 4;    //(签名数据长度)32字节 + (65 字节签名的整字长度)96字节    uint constant SIGNATURE_SIZE = 128;    //需要提供保镖的有效签名    modifier onlyValidSignture(bytes _sig)    {        require(isValidSignture(msg.sender, _sig));        _;    }    //需要保镖提供对某个特定函数的有效签名    modifier onlyValidSigntureAndMethod(bytes _sig)    {        require(isValidSigntureAndMethod(msg.sender, _sig));        _;    }    //需要保镖提供对某个特定参数表的函数的有效签名    modifier onlyValidSigntureAndData(bytes _sig)    {        require(isValidSigntureAndData(msg.sender, _sig));        _;    }    //允许合约所有者添加保镖    function addBouncer(address _bouncer)         onlyOwner         public     {         require(_bouncer != address(0));         addRole(_bouncer, ROLE_BOUNCER);     }         //允许合约所有者移除保镖     function removeBouncer(address _bouncer)         onlyOwner         public     {         require(_bouncer != address(0));         removeRole(_bouncer, ROLE_BOUNCER);     }         //判断保镖签名是否是"this+sender"的签名     function isValidSignature(address _address, bytes _sig)          internal          view          returns(bool)     {         return isValidDataHash(             keccak256(abi.encodePacked(address(this), _address)),             _sig         );     }     //判断保镖签名是否是"this+sender+methodId"的签名      function isValidSignatureAndMethod(address _address, bytes _sig)          internal          view          returns(bool)     {         bytes memory data = new bytes (METHOD_ID_SIZE);         for (uint i = 0; i < data.length; i++){             data[i] = msg.data[];         }         return isValidDataHash(             keccak256(abi.encodePacked(address(this), _address data)),             _sig         );     }                //判断保镖签名是否是"this+sender+methodId+params(s)"的签名         function isValidSignatureAndData(address _address, bytes _sig)          internal          view          returns(bool)     {         reqire(msg.data.length > SIGNATURE_SIZE);         bytes memory data = new bytes (msg.data.length - SIGNATURE_SIZE);         for (uint i = 0; i < data.length; i++){             data[i] = msg.data[];         }         return isValidDataHash(             keccak256(abi.encodePacked(address(this), _address data)),             _sig         );     }      //一个internal函数,将hash值转换成客户端签发的消息数据,而后恢复成签名公钥来验证签名是否来自一个具有保镖角色的地址。      function isValidDataHash(byte32 hash, bytes _sig)          internal          view          returns(bool)     {         address signer = hash             .toEthSignedMessageHash()             .recover(_sig);         return hasRole(signer, ROLE_BOUNCER);     }            }

这个合约继承了Owner和RBAC,它有一个所有者,且有一个保存了角色和相应地址的映射

 

白名单(Whitelist.sol)

pragma solidity ^0.4.24;import "../Ownership/Ownable.sol";import "../Ownership/rbac/RBAC.sol";contract Whitelist is Ownable, RBAC{    string public constant ROLE_WHITELISTED = "whitelist";    modifier onlyIfWhitelisted(address _operator){        checkRole(_operator, ROLE_WHITRLISTED);        _;    }    //向白名单中添加一个地址    function addAddressToWhitelist(address _operator)        onlyOwner        public{        addRole(_operator, ROLE_WHITELISTED);     }    //检查白名单中是否存在这个地址    function whitelist(address _operator)        onlyOwner        public        returns(bool){        return hasRole(_operator, ROLE_WHITELISTED);     }    //添加一组地址    function addAddressesToWhitelist(address[] _operator)        onlyOwner        public{        for (uint256 i = 0; i < _operator.length; i++){            addAddressToWhitelist(_operator[i]);        }    }             //从白名单中移除一个地址    function removeAddressFromWhitelist(address _operator)        onlyOwner        public{        removeRole(_operator, ROLE_WHITELISTED);     }     //从白名单中移除一组地址        function removeAddressesFromWhitelist(address[] _operator)        onlyOwner        public{        for (uint256 i = 0; i < _operator.length; i++){            removeAddressFromWhitelist(_operator[i]);        }    }              }

 

可自毁(Destructible.sol)

pragma solidity ^0.4.24;import "../Ownership/Ownable.sol";contract Destructible is Ownable{    constructor() public payable{}    //销毁合约将余额发个合约所有者    function destroy() onlyOwner public{        selfdestruct(owner);    }    //销毁合约将余额发个指定地址    function destoryAndSend(address _recipient) onlyOwner public{        selfdestruct(_recipient);    }}

 

可暂停运作(Pausable.sol)

pragma solidity ^0.4.24;import "../Ownership/Ownable.sol";contract Pausable is Ownable{    event Pause();    event Unpause();        bool public paused = false;    //在未暂停状态下使用    modifier whenNotPaused(){        require(!paused);        _;    }    //在暂停状态下使用    modifier whenPaused(){        require(paused);        _;    }    //合约所有者暂停合约    function pause() onlyOwner wenNotPaused public {        paused = true;        emit pause();    }    //合约所有者启动合约     function Unpause() onlyOwner wenPaused public {        paused = false;        emit Unpause();    }}

 

token可自毁(TokenDestuctible.sol)

pragma solidity ^0.4.24;import "../Ownership/Ownable.sol";import "../token/ERC20/ERC20Gasic.sol";contract TokenDestuctible is Ownable{    constructor() public payable{}        function destroy(address[] tokens) onlyOwner public{        for (uint256 i = 0; i < tokens.length; i++){            ERC20Gasic token = ERC20Gasic(tokens[i]);            uint256 balance = token.balanceOf(this);            token.transfer(owner,balance);        }        selfdestruct(owner);//自毁    }}

 

托管(Escrow.sol)

pragma solidity ^0.4.24;import "../Ownership/Ownable.sol";import "../math/SafeMath";contract Escrow is Ownable{    using SafeMath for uint256;        event Deposited(address indexed payee, uint256 weiAmount);   event withdrawn(address indexed payee, uint256 weiAmount);      mapping(address => uint256) private deposits;      function depositsOf(address _payee) public view returns (uint256){       renturn deposits[_payee];   }   //充值   function deposit(address _payee) public onlyOwner payable{       uint256 amount = msg.value;       deposits[_payee] = deposits[_payee].add(amount);              emit Deposited(_payee, amount);   }   //取回   function withdraw(address _payee) public onlyOwner {       uint256 payment = deposits[_payee];              assert(address(this).balance >= payment);              deposits[_payee] = 0;              _payee.transfer(payment);              emit Witndrawn(_payee, payment)   }}


条件托(ConditionalEscrow.sol)

super is 调用父类的回撤方法

pragma solidity ^0.4.24;import "./Escrow.sol";contract ConditionalEscrow is Escrow {    function withdrawalAllowed(address _payee) public view returns(bool);        function withdraw(address _payee) public{        reqire(withdrawalAllowed(_payee));       super.withdraw(_payee);     }}

 

退还托管(RefundEscrow.sol)

 

pragma solidity ^0.4.24;import "../Ownership/Ownable.sol";import "./ConditionalEscrow.sol";contract RefundEscrow is Ownable, ConditionalEscrow{   enum State {Active, Refund, Closec}       event Closed();   event RefundsEnable();            State public state;    address public beneficiary;    //_beneficiary受益人地址    constructor(address _beneficiary) public {        require(_beneficiary != address(0));        beneficiary = _beneficiary;        state = State.Active;//合约状态    }    //为可能退还的处理保存资金    function deposit(address _refundee) public paypable{        require(state == State.Active);        super.deposit(_refundee);    }    //允许受益人取回资金并拒绝其再次充值    function colse() public onlyOwner{        require(state == State.Active);        state = State.Closed;        emit Closed;    }    //允许款项退还拒绝其再次充值    function enableRefunds() public onlyOwner{        require(state == State.Active);        state = State.Refunding;        emit RefundsEnabled();    }    //将合约余额转给受益人    function beneficiaryWithdraw() public{        require(state == State.Closed);        beneficiary.transfer(address(this).balance);    }                                  //返回(是否正在进行退款处理)    function withdrawalAllowed(address _payee) public view returns (bool){        return state == State.Refunding;    }                                                                                                                                                                  }

 

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值