7. Solidity:报错控制、事件

2023-09-26  本文已影响0人  泡泡龙吐泡泡

7.1 报错控制

Solidity中抛出异常的方法有:require、revert、assert。本章分别介绍三种方法的使用。

7.1.1 require

require命令是solidity 0.8版本之前抛出异常的常用方法,目前很多主流合约仍然还在使用它。require使用简单方便,唯一的缺点就是gas随着描述异常的字符串长度增加,比error命令(下一节介绍)要高。使用方法:require(检查条件,"异常的描述"),当检查条件不成立的时候,就会抛出异常。

示例代码:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

contract errorDemo {
    // 定义owner变量
    address public owner;

    // 在合约构造方法中设置owner
    constructor() {
        owner = msg.sender;
    }

    // 变更合约owner
    function transferOwner(address _oneOwner) external {
        require(msg.sender == owner, "No permissions!");
        owner = _oneOwner;
    }
}

7.1.2 revert

7.1.2.1 默认revert

revert使用方法相似,只是判断写在revert语句之外,且判断方向和require相反。revert中只包含报错信息。
示例代码:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

contract errorDemo {
    // 定义owner变量
    address public owner;

    // 在合约构造方法中设置owner
    constructor() {
        owner = msg.sender;
    }

    // 变更合约owner
    function transferOwnerRevert(address _oneOwner) external {
        if (msg.sender != owner) {
            revert("No permissions!");
        }
        owner = _oneOwner;
    }
}
7.1.2.2 revert自定义error

error是solidity 0.8.4版本新增加的内容,允许开发者自定义错误。error不仅能够携带操作失败的原因信息,还能够携带参数,方便开发者进行调试,提高合约调用的操作体验。error需要和revert配合使用。
示例代码:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

contract errorDemo {
    // 定义owner变量
    address public owner;

    // 在合约构造方法中设置owner
    constructor() {
        owner = msg.sender;
    }

    // 自定义错误
    error NoPermissions(address caller, address owner);
    // 变更合约owner
    function transferOwnerRevertError(address _owner) external {
        if (msg.sender != owner) {
            revert NoPermissions(msg.sender, owner);
        }
        owner = _owner;
    }

}

报错信息:

NoPermissions
Parameters:
{
 "caller": {
  "value": "0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2"
 },
 "owner": {
  "value": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"
 }
}

7.1.3 assert

assert命令一般用于程序员写程序debug,因为它不能解释抛出异常的原因(比require少个字符串)。它的用法很简单:assert(检查条件),当检查条件不成立的时候,就会抛出异常。
示例代码:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

contract errorDemo {
    // 定义owner变量
    address public owner;

    // 在合约构造方法中设置owner
    constructor() {
        owner = msg.sender;
    }

    // 变更合约owner
    function transferOwnerAssert(address _oneOwner) external {
        assert(msg.sender == owner);
        owner = _oneOwner;
    }

TODO:try catch

7.2 事件

7.2.1 智能合约中的事件

Solidity中的事件(event)是EVM上日志的抽象,它具有两个特点:

7.2.1.1 事件声明

事件的声明由event关键字开头,接着是事件名称,括号里面写好事件需要记录的变量类型和变量名。以ERC20代币合约的Transfer事件为例:

    event Transfer(address indexed from, address indexed to, uint value);

该事件包含from、to、value三个参数,其中,from和to参数使用indexed修饰。indexed关键字有以下特点:

7.2..1.2 释放事件

上述自定义事件的释放示例函数:

    function emitFunc(address _from, address _to, uint _value) external {
        emit Transfer(_from, _to, _value);
    }

remix中的log记录:

[
    {
        "from": "0x9D7f74d0C41E726EC95884E0e97Fa6129e3b5E99",
        "topic": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "event": "Transfer",
        "args": {
            "0": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4",
            "1": "0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2",
            "2": "123",
            "from": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4",
            "to": "0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2",
            "value": "123"
        }
    }
]

区块链浏览器中的log记录

transfer_log.png
上一篇 下一篇

猜你喜欢

热点阅读