当前位置:网站首页>Solidity - 合约继承子合约包含构造函数时报错 及 一个合约调用另一合约view函数收取gas费用

Solidity - 合约继承子合约包含构造函数时报错 及 一个合约调用另一合约view函数收取gas费用

2022-06-26 18:20:00 ling1998

合约继承子合约包含构造函数时报错

错误信息

在写了一个业务合约时,发现被继承合约含有构造函数时报错,去掉被继承合约中构造函数正常,有些奇怪,于是写一个简单例子进行复现,合约代码如下:

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

//基合约接囗
interface IcontractA {
    function getMsg() external view returns(string memory);
}

//基合约实现
contract contractA is IcontractA {
    string message;

    //构造函数
    constructor(string memory _message) {
        message = _message;
    }

    function _getMsg() internal view returns (string memory) {
        return message;
    }

    function getMsg() external override view returns(string memory) {
        return _getMsg();
    }
}

//子合约 - 继承基合约
contract contractB is contractA {
    address admin;

    //构造函数
    constructor(string memory _message) {
        admin = msg.sender;
    }

    //调用基合约函数
    function callA() external view returns(string memory) {
        return _getMsg();
    }
}

错误信息

TypeError: Contract "contractB" should be marked as abstract. --> Test/CallContract.sol:28:1: | 28 | contract contractB is contractA { | ^ (Relevant source part starts here and spans across multiple lines). Note: Missing implementation: --> Test/CallContract.sol:14:5: | 14 | constructor(string memory _message) { | ^ (Relevant source part starts here and spans across multiple lines).

Remix浏览器执行结果:

原因

当继承合约时,派生合约(子合约)需要提供基类构造函数需要的所有参数,参见 合约 — Solidity develop 文档

解决方案

在派生合约构造函数中添加基合约所需要的参数

32行调整如下:

constructor(string memory _message) contractA(_message) {

修正后合约代码如下:

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

//基合约接囗
interface IcontractA {
    function getMsg() external view returns(string memory);
}

//基合约实现
contract contractA is IcontractA {
    string message;

    //构造函数
    constructor(string memory _message) {
        message = _message;
    }

    function _getMsg() internal view returns (string memory) {
        return message;
    }

    function getMsg() external override view returns(string memory) {
        return _getMsg();
    }
}

//子合约 - 继承基合约
contract contractB is contractA {
    address admin;

    //构造函数
    constructor(string memory _message) contractA(_message) {
        admin = msg.sender;
    }

    //调用基合约函数
    function callA() external view returns(string memory) {
        return _getMsg();
    }
}

如果基合约构造函数无参数,在派生合约中也需要提供基合约构造函数,只是无参而已,微调上面代码,基合约构造函数设置无参

32行调整如下:

constructor(string memory _message) contractA() {

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

//基合约接囗
interface IcontractA {
    function getMsg() external view returns(string memory);
}

//基合约实现
contract contractA is IcontractA {
    string message;

    //构造函数
    constructor() {
        message = "_message";
    }

    function _getMsg() internal view returns (string memory) {
        return message;
    }

    function getMsg() external override view returns(string memory) {
        return _getMsg();
    }
}

//子合约 - 继承基合约
contract contractB is contractA {
    address admin;

    //构造函数
    constructor() contractA() {
        admin = msg.sender;
    }

    //调用基合约函数
    function callA() external view returns(string memory) {
        return _getMsg();
    }
}

合约B中创建另一个合约A,调用合约A中view函数时,不能使用view

当子合约中创建一个基合约,通过新创建的基合约调用自己的查询函数(使用view修饰符)时,子合约中的函数不能使用view修饰符,合约代码如下:

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

//基合约接囗
interface IcontractA {
    function getMsg() external view returns(string memory);
}

//基合约实现
contract contractA is IcontractA {
    string message;

    //构造函数
    constructor(string memory _message) {
        message = _message;
    }

    function _getMsg() internal view returns (string memory) {
        return message;
    }

    function getMsg() external override view returns (string memory) {
        return _getMsg();
    }
}

//子合约 - 继承基合约
contract contractB is contractA {
    address admin;

    //构造函数
    constructor(string memory _message) contractA(_message) {
        admin = msg.sender;
    }

    //调用基合约函数
    function callA() external view returns (string memory) {
        return _getMsg();
    }

    //创建基合约,调用函数
    function callANewContract() external view returns (string memory) {
        contractA contractAddr = new contractA("Hello, I am tracy");
        return contractA(contractAddr).getMsg();
    }
}

错误信息如下:

TypeError: Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. --> Test/CallContract.sol:43:34: | 43 | contractA contractAddr = new contractA("Hello, I am tracy"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

去除42行中的view修饰符,部署合约B,发现调用函数callANewContract()居然是收取gas费的函数(黄色背景标识为收取gas费函数),如下图所示:

 

原网站

版权声明
本文为[ling1998]所创,转载请带上原文链接,感谢
https://blog.csdn.net/ling1998/article/details/125465710