solidity代码功能模块

2022-05-20 09:15:52 浏览数 (1)

地址工具

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

代码语言:javascript复制
pragma solidity ^0.4.24
library 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 声明这个函数不会改变状态

限制子合约的余额

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

代码语言:javascript复制
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类型进行算术四则运算的库,也是最常用库,防止溢出。

代码语言:javascript复制
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)

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

代码语言:javascript复制
pragma solidity ^0.4.24;
interface ERC165{
    function supportsInterface(bytes64 _interfaceId)
    external  //外部函数
    view  //不会修改状态
    returns(bool);
}//gas 消耗控制在30000以内
_interfaceId函数选择器,是合约某个函数的标识(合约函数调用数据的前4个字节)

接口查找基础合约

代码语言:javascript复制
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)

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

代码语言:javascript复制
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)

代码语言:javascript复制
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)

代码语言:javascript复制
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)

代码语言:javascript复制
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合约添加字符串附加信息的基础合约

代码语言:javascript复制
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的扩展,允许在做归属权转移时,由新的的合约拥有者“声明接受归属权”

代码语言:javascript复制
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时间一致,所有使用区块号这个全网共识的时间标志作为判定条件。

代码语言:javascript复制
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)

代码语言:javascript复制
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方法将其所有者地址转移到当前合约的所有者。

代码语言:javascript复制
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合约的拓展,来确保合约中不持有以太币。

代码语言:javascript复制
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取回到合约所有者的地址。

代码语言:javascript复制
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)

代码语言:javascript复制
pragma solidity ^0.4.24;

import "./HasNoEther.sol";
import "./HasNoToken.sol";
import "./HasNocontracts.sol";

contract NoOwner is HasNoEther, HasNoToken, HasNocontracts{
    }

签名保镖(SigmatureBouncer.sol)

代码语言:javascript复制
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)

代码语言:javascript复制
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)

代码语言:javascript复制
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)

代码语言:javascript复制
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)

代码语言:javascript复制
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 调用父类的回撤方法

代码语言:javascript复制
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)

代码语言:javascript复制
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;
    }                                                                                                                                                                  
}

0 人点赞