Solidity 调用合约

Solidity 支持一个合约调用另一个合约。两个合约既可以位于同一sol文件,也可以位于不同的两个sol文件。

Solidity 还能调用已经上链的其它合约。

调用内部合约

内部合约是指位于同一sol文件中的合约,它们不需要额外的声明就可以直接调用。

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

contract Hello {
    function echo() external pure returns(string memory){
       return "Hello World!";
   }
}

contract SoldityTest {
   function callHello(address addr) external pure returns(string memory){
      // 调用外部合约 Hello 的方法 echo
      return Hello(addr).echo();
   }

   // 另外一种写法
   function callHelloOr(Hello hello) external pure returns(string memory){
       // 调用外部合约 Hello 的方法 echo
      return hello.echo();
   }
}

我们在部署上面两个合约的时候,首先要部署 Hello,得到它的地址,例如:0x78FD83768c7492aE537924c9658BE3D29D8ffFc1。

然后再部署合约 SoldityTest,调用 SoldityTest 的方法 callHello,传入参数 0x78FD83768c7492aE537924c9658BE3D29D8ffFc1 ,就会输出调用结果:"Hello World!"。

调用外部合约

外部合约是指位于不同文件的外部合约,以及上链的合约。

调用外部合约有两种方法:通过接口方式调用 和 通过签名方式调用。

通过接口方式调用

通过接口方式调用合约,需要在调用者所在的文件中声明被调用者的接口。

被调用者合约 hello.sol:

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

contract IHello {
    function echo() external pure returns(string memory){
       return "Hello World!";
   }
}

调用者合约 test.sol:

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

// 被调用者接口
interface IHello {
    // 被调用的方法
    function echo() external pure returns(string memory);
}

// 调用者合约
contract SoldityTest {
   function callHello(address addr) external pure returns(string memory){
      // 调用外部合约Hello的方法:echo
      return IHello(addr).echo();
   }
}

我们首先要部署 hello.sol 文件中的合约 Hello,得到它的地址,例如:0x78FD83768c7492aE537924c9658BE3D29D8ffFc1。

然后再部署合约 SoldityTest,调用 SoldityTest 的方法 callHello,传入参数 0x78FD83768c7492aE537924c9658BE3D29D8ffFc1 ,就会输出调用结果:"Hello World!"。

通过签名方式调用

通过签名方式调用合约,只需要传入被调用者的地址和调用方法声明。

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

// 调用者合约
contract SoldityTest {
   function callHello(address addr) external returns(string memory){
       // 调用合约
       (bool success,bytes memory data) = addr.call(abi.encodeWithSignature("echo()"));
       if(success){
           return abi.decode(data,(string));
        } else {
            return "error";
        }
   }
}

另一种写法:

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

// 调用者合约
contract SoldityTest {
   function callHello(address addr) external view returns(string memory){
       // 编码被调用者的方法签名
       bytes4 methodId = bytes4(keccak256("echo()"));
       
       // 调用合约
       (bool success,bytes memory data) = addr.staticcall(abi.encodeWithSelector(methodId));
       if(success){
           return abi.decode(data,(string));
        } else {
            return "error";
        }
   }
}

我们首先要部署 hello.sol 文件中的合约 Hello,得到它的地址,例如:0x78FD83768c7492aE537924c9658BE3D29D8ffFc1。

然后再部署合约 SoldityTest,调用 SoldityTest 的方法 callHello,传入参数 0x78FD83768c7492aE537924c9658BE3D29D8ffFc1 ,就会输出调用结果:"Hello World!"。

签名方式调用,发送Eth

通过签名方式调用合约,可以发送Eth。

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

// 调用者合约
contract SoldityTest {
   function callHello(address addr) external returns(string memory){
       // 调用合约
       (bool success,bytes memory data) = addr.call{value:1000}(abi.encodeWithSignature("echo()"));
       if(success){
           return abi.decode(data,(string));
        } else {
            return "error";
        }
   }
}

使用 payable 标记的 Solidity 函数可以用于发送和接收 Eth。payable 意味着在调用这个函数的消息中可以附带 Eth。使用 payable 标记的 Solidity 地址 ...