solidity->函数

122 阅读3分钟

可见行(visibility)

函数的可见行有四种:

Private(私有):限制性最强,函数只能在所定义的智能合约内部调用。

Internal(内部):可以在所定义智能合约内部调用该函数,也可以从继承合约中调用该函数。

External(外部):只能从智能合约外部调用。(如果要从智能合约中调用,必须使用this)

Public(公开):可以从任何地方调用。(最宽松)

状态可变形(mutability)

view: 用view声明的函数只能读取状态,而不能修改状态。

pure: 用pure声明的函数既不能读取也不能修改状态。

payable:用payable声明的函数可以接受发送给合约的以太币,如果未指定,该函数将自动拒绝所有发送给它的以太币。


用view和pure关键字定义的函数不会改变以太坊区块链的状态,这意味着当你调用这些函数时,你不会向区块链发送任何交易。因为交易被定义为从一个状态到另一个状态的状态栏变换。其仅仅是,你连接的节点通过检查自己的区块链版本在本地执行函数代码,并将结果返回,而无需将任何交易广播到以太网络。

接收以太币函数

合约最多具有一个receive函数。这个函数不能有参数,不能返回任何参数,并且必须具有receive可见性和payable状态可边性。

当向合约发送ether且未指定调用任何函数(calldata 为空)时执行,这是在普通的以太坊转账上执行的函数(通过send和transfer转帐)

Fallback函数

合约最多可以具有一个fallback函数(回退函数)。这个函数不能有参数,不能返回任何参数,并且必须具有external可见性。如果其他函数都不匹配给定的函数签名,或者根本没有提供任何数据并且没有receive函数,则在调用合约时执行该函数

如果对一个没有实现receive函数或payable回退函数的合约转账,则合约将抛出异常,以太币会退回。

函数修饰器

当你要执行函数之前检查某系条件时,可以使用修饰器。eg:如果你要检查发件人是否是合约的所有者,则可以编写以下内容

function selectWinner() external { 
    require(msg.sender == owner ," this function is restricted to the owner");
    ... 
}

如果使用修饰器,我们可以分离代码,以便我们可以将其与其他函数复用,我们只需要声明修饰器。

modifier onlyOwner() { 
    require(msg.sender == owner," this function is restricted to the owner");
    _;
}

然和将修饰器名称添加到函数中:

function selectWinner() external onlyOwner { 
    .... 
}

通过用空格分割的多个修饰器,可以将它们应用到一个函数,并按给出的顺序对其进行应用。

多签钱包

多签钱包是其中需要多个密钥才能授权交易的钱包。

例子:

// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity ^0.8.17;

contract Wallet {
    address[] public approvers; // 审批人
    uint8 public quorum; // 法定人数

    struct Transfer {
        uint id;
        uint amount;
        address payable to;
        uint approvers; // 审批人
        bool sent; // 发送
    }

    Transfer[] public transfers; // 转移

    mapping(address => mapping(uint => bool)) public approvals; // 批准

    constructor(address[] memory _approvers, uint8 _quorum) {
        approvers = _approvers;
        quorum = _quorum;
    }

    // 获取审批人信息
    function getApprovers() external view returns (address[] memory) {
        return approvers;
    }

    function createTransfer(uint amount, address payable to)
        external
        onlyApprover
    {
        transfers.push(Transfer(transfers.length, amount, to, 0, false));
    }

    function getTransfers() external view returns (Transfer[] memory) {
        return transfers;
    }

    function approveTransfer(uint id) external onlyApprover {
        require(transfers[id].sent == false, "transfer has already been sent");
        require(
            approvals[msg.sender][id] == false,
            "cannot approve transfer twice"
        );
        approvals[msg.sender][id] = true;
        transfers[id].approvers++;
        // 审批人数大于法定人数才能转帐
        if (transfers[id].approvers >= quorum) {
            transfers[id].sent = true;
            address payable to = transfers[id].to;
            uint amount = transfers[id].amount;
            to.transfer(amount);
        }
    }

    receive() external payable {}

    // 批准人的修饰器
    modifier onlyApprover() {
        bool isApprover = false;
        for (uint i = 0; i < approvers.length; i++) {
            if (approvers[i] == msg.sender) {
                isApprover = true;
                break;
            }
        }
        require(isApprover, "access restricted only to an approver");
        _;
    }
}