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


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

    错误信息

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

    1. // SPDX-License-Identifier: MIT
    2. pragma solidity ^0.8.7;
    3. //基合约接囗
    4. interface IcontractA {
    5. function getMsg() external view returns(string memory);
    6. }
    7. //基合约实现
    8. contract contractA is IcontractA {
    9. string message;
    10. //构造函数
    11. constructor(string memory _message) {
    12. message = _message;
    13. }
    14. function _getMsg() internal view returns (string memory) {
    15. return message;
    16. }
    17. function getMsg() external override view returns(string memory) {
    18. return _getMsg();
    19. }
    20. }
    21. //子合约 - 继承基合约
    22. contract contractB is contractA {
    23. address admin;
    24. //构造函数
    25. constructor(string memory _message) {
    26. admin = msg.sender;
    27. }
    28. //调用基合约函数
    29. function callA() external view returns(string memory) {
    30. return _getMsg();
    31. }
    32. }

    错误信息

    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) {

    修正后合约代码如下:

    1. // SPDX-License-Identifier: MIT
    2. pragma solidity ^0.8.7;
    3. //基合约接囗
    4. interface IcontractA {
    5. function getMsg() external view returns(string memory);
    6. }
    7. //基合约实现
    8. contract contractA is IcontractA {
    9. string message;
    10. //构造函数
    11. constructor(string memory _message) {
    12. message = _message;
    13. }
    14. function _getMsg() internal view returns (string memory) {
    15. return message;
    16. }
    17. function getMsg() external override view returns(string memory) {
    18. return _getMsg();
    19. }
    20. }
    21. //子合约 - 继承基合约
    22. contract contractB is contractA {
    23. address admin;
    24. //构造函数
    25. constructor(string memory _message) contractA(_message) {
    26. admin = msg.sender;
    27. }
    28. //调用基合约函数
    29. function callA() external view returns(string memory) {
    30. return _getMsg();
    31. }
    32. }

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

    32行调整如下:

    constructor(string memory _message) contractA() {

    1. // SPDX-License-Identifier: MIT
    2. pragma solidity ^0.8.7;
    3. //基合约接囗
    4. interface IcontractA {
    5. function getMsg() external view returns(string memory);
    6. }
    7. //基合约实现
    8. contract contractA is IcontractA {
    9. string message;
    10. //构造函数
    11. constructor() {
    12. message = "_message";
    13. }
    14. function _getMsg() internal view returns (string memory) {
    15. return message;
    16. }
    17. function getMsg() external override view returns(string memory) {
    18. return _getMsg();
    19. }
    20. }
    21. //子合约 - 继承基合约
    22. contract contractB is contractA {
    23. address admin;
    24. //构造函数
    25. constructor() contractA() {
    26. admin = msg.sender;
    27. }
    28. //调用基合约函数
    29. function callA() external view returns(string memory) {
    30. return _getMsg();
    31. }
    32. }

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

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

    1. // SPDX-License-Identifier: MIT
    2. pragma solidity ^0.8.7;
    3. //基合约接囗
    4. interface IcontractA {
    5. function getMsg() external view returns(string memory);
    6. }
    7. //基合约实现
    8. contract contractA is IcontractA {
    9. string message;
    10. //构造函数
    11. constructor(string memory _message) {
    12. message = _message;
    13. }
    14. function _getMsg() internal view returns (string memory) {
    15. return message;
    16. }
    17. function getMsg() external override view returns (string memory) {
    18. return _getMsg();
    19. }
    20. }
    21. //子合约 - 继承基合约
    22. contract contractB is contractA {
    23. address admin;
    24. //构造函数
    25. constructor(string memory _message) contractA(_message) {
    26. admin = msg.sender;
    27. }
    28. //调用基合约函数
    29. function callA() external view returns (string memory) {
    30. return _getMsg();
    31. }
    32. //创建基合约,调用函数
    33. function callANewContract() external view returns (string memory) {
    34. contractA contractAddr = new contractA("Hello, I am tracy");
    35. return contractA(contractAddr).getMsg();
    36. }
    37. }

    错误信息如下:

    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费函数),如下图所示:

     

  • 相关阅读:
    [资料] GM8284DD:LVDS转TTL/RGB视频转换IC
    Hive的概念与基本架构
    浔川身份证号码查询——浔川python科技社
    Linux基础指令笔记大全
    常规动态网页爬取
    利用 SonarScanner 静态扫描 Rainbond 上的 Maven 项目
    Python使用openpyxl和pandas处理Excel文件实现数据脱敏案例一则
    LENOVO联想ThinkBook 16p G4 IRH(21J8)笔记本电脑原装出厂Windows11系统镜像
    写Python爬虫又被屏蔽了,你现在需要一个稳定的代理IP
    Linux多线程【生产者消费者模型】
  • 原文地址:https://blog.csdn.net/ling1998/article/details/125465710