Solidity - 智能合约标准ERC-165

目录

1、如何获取接囗标识符 

2、合约如何实现接囗

3、如何检测合约实现了ERC-165接囗 

4、如何检测合约实现了指定的接囗

测试


ERC-165 Standard Interface Detection ,即检测合约是否实现接囗规范,使用函数标识(.selecor)进行检测。参考:EIP-165: Standard Interface Detection

1、如何获取接囗标识符 

pragma solidity ^0.4.20;

interface Solidity101 {
    function hello() external pure;
    function world(int) external pure;
}

contract Selector {
    function calculateSelector() public pure returns (bytes4) {
        Solidity101 i;
        return i.hello.selector ^ i.world.selector;
    }
}

通过两种方法可获取函数接囗标识符

(1)i.hello.selector

(2)bytes4(keccak256("hello()"))

增加测试函数进行验证以上(1)与(2)是等价的,代码如下:

pragma solidity ^0.6.0;

interface Solidity101 {
    function hello() external pure;
    function world(int) external pure;
}

contract Selector {
    function calculateSelector() public pure returns (bytes4) {
        Solidity101 i;
        return i.hello.selector ^ i.world.selector;
    }

    function testSelector() public pure returns (bytes32,bytes4,bytes4) {
        Solidity101 i;
        return (keccak256("hello()"), bytes4(keccak256("hello()")), i.hello.selector);
    }
}

 验证结果如下图所示:

2、合约如何实现接囗

pragma solidity ^0.4.20;

interface ERC165 {
    /// @notice Query if a contract implements an interface
    /// @param interfaceID The interface identifier, as specified in ERC-165
    /// @dev Interface identification is specified in ERC-165. This function
    ///  uses less than 30,000 gas.
    /// @return `true` if the contract implements `interfaceID` and
    ///  `interfaceID` is not 0xffffffff, `false` otherwise
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
}
  • interfaceID = 0x01ffc9a7(EIP165接囗),返回true
  • bytes4(keccak256("supportsInterface(bytes4)")); //0x01ffc9a7
  • interfaceID = 0xffffffff 返回false
  • 合约中实现接囗的interfaceID ,返回true
  • 合约中未实现接囗的interfaceID,返回false

3、如何检测合约实现了ERC-165接囗 

1、在合约地址上使用附加数据(input data)0x01ffc9a701ffc9a700000000000000000000000000000000000000000000000000000000 和 gas 30,000 进行STATICCALL调用,相当于contract.supportsInterface(0x01ffc9a7) ;
2、如果调用失败或返回false , 说明合约不兼容ERC-165标准;
3、如果返回true,则使用输入数据0x01ffc9a7ffffffff000000000000000000000000000000000000000000000000000000000000进行第二次调用;
4、如果第二次调用失败或返回true,则目标合约没有实现ERC-165;
5、否则它实现了ERC-165。

4、如何检测合约实现了指定的接囗

1、如果不确定合约是否实现ERC-165,请使用上面的方法进行确认;
2、如果没有实现ERC-165,那么不得不看看它采用哪种老式方法;
3、如果实现了ERC-165,那么只需调用 supportsInterface(interfaceID) 来确定它是否实现了对应的接口。 

测试

pragma solidity ^0.6.0;

interface IERC165 {
    /// @notice Query if a contract implements an interface
    /// @param interfaceID The interface identifier, as specified in ERC-165
    /// @dev Interface identification is specified in ERC-165. This function
    ///  uses less than 30,000 gas.
    /// @return `true` if the contract implements `interfaceID` and
    ///  `interfaceID` is not 0xffffffff, `false` otherwise
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
}

contract ERC165Test is IERC165 {
    //定义一个常量,记录ERC165接囗ID
     bytes4 private constant INTERFACE_ID_ERC165 = 0x01ffc9a7;

    // //记录接囗注册
     mapping(bytes4=>bool) private _supportInterface;

    //构造函数,初始化接囗注册
    constructor() public {
        registerInterface(INTERFACE_ID_ERC165);
    }

    // //实现接囗方法
    function supportsInterface(bytes4 interfaceID) external view override returns (bool) {
        return _supportInterface[interfaceID];
    }

    //注册接囗
    function registerInterface(bytes4 interfaceID) public {
        require(interfaceID != 0xffffffff, "无效的接囗ID");
        _supportInterface[interfaceID] = true;
    }
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Solidity中,可以通过使用智能合约来实现ERC20代币的锁仓与释放。以下是一个简单的锁仓合约示例: ``` pragma solidity ^0.8.0; import "./IERC20.sol"; import "./SafeMath.sol"; contract TokenVesting { using SafeMath for uint256; address public beneficiary; uint256 public cliff; uint256 public start; uint256 public duration; uint256 public released; IERC20 public token; constructor( address _beneficiary, uint256 _cliff, uint256 _duration, address _token ) public { require(_beneficiary != address(0)); require(_cliff <= _duration); beneficiary = _beneficiary; cliff = _cliff; duration = _duration; start = block.timestamp; token = IERC20(_token); } function release() public { uint256 unreleased = releasableAmount(); require(unreleased > 0); released = released.add(unreleased); token.transfer(beneficiary, unreleased); } function releasableAmount() public view returns (uint256) { return vestedAmount().sub(released); } function vestedAmount() public view returns (uint256) { uint256 currentBalance = token.balanceOf(address(this)); uint256 totalBalance = currentBalance.add(released); if (block.timestamp < start.add(cliff)) { return 0; } else if (block.timestamp >= start.add(duration)) { return totalBalance; } else { return totalBalance.mul(block.timestamp.sub(start)).div(duration); } } } ``` 在这个合约中,当创建合约时,需要传入受益人地址、锁仓期、释放期、代币地址等信息。锁仓期结束后,受益人可以通过调用 `release()` 函数来释放锁仓代币。如果释放函数被调用,但是当前时间还没有到达释放期,则会抛出异常。 为了保证代币不能被提前释放,合约还实现了 cliff 的概念,即在锁仓期结束之前,代币不能被释放。当 cliff 结束之后,代币将按照线性方式释放,直到释放期结束。 需要注意的是,以上示例只是一个简单的锁仓合约示例,实际生产环境中需要更加严格地考虑各种情况和安全性问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值