前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >solidity代码功能模块

solidity代码功能模块

作者头像
rectinajh
发布2022-05-20 09:15:52
5820
发布2022-05-20 09:15:52
举报
文章被收录于专栏:华仔的技术笔记

地址工具

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

代码语言: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;
    }                                                                                                                                                                  
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档