Skip to content

Latest commit

 

History

History
109 lines (94 loc) · 4.32 KB

File metadata and controls

109 lines (94 loc) · 4.32 KB

第二十课 发送ETH

Solidity有三种方法向其他合约发送ETH,他们是:transfer(),send()和call(),其中call()是被鼓励的用法。

1. transfer

用法: 用法是接收方地址.transfer(发送ETH数额)。
transfer()的gas限制是2300,足够用于转账,但对方合约的fallback()或receive()函数不能实现太复杂的逻辑。
transfer()如果转账失败,会自动revert(回滚交易)。

    // 用transfer()发送ETH to地址是接受eth的地址,amount是转账的数量
    function transferETH(address payable _to, uint256 amount) external payable{
        _to.transfer(amount);
    }

2. send

用法是接收方地址.send(发送ETH数额)。
send()的gas限制是2300,足够用于转账,但对方合约的fallback()或receive()函数不能实现太复杂的逻辑。
send()如果转账失败,不会revert。
send()的返回值是bool,代表着转账成功或失败,需要额外代码处理一下。

    error SendFailed(); // 用send发送ETH失败error
    // send()发送ETH
    function sendETH(address payable _to, uint256 amount) external payable{
        // 处理下send的返回值,如果失败,revert交易并发送error
        bool success = _to.send(amount);
        if(!success){
            revert SendFailed();
        }
    }

3. call

用法是接收方地址.call{value: 发送ETH数额}("")。
call()没有gas限制,可以支持对方合约fallback()或receive()函数实现复杂逻辑。
call()如果转账失败,不会revert。
call()的返回值是(bool, bytes),其中bool代表着转账成功或失败,需要额外代码处理一下。

error CallFailed(); // 用call发送ETH失败error

// call()发送ETH
    function callETH(address payable _to, uint256 amount) external payable{
        // 处理下call的返回值,如果失败,revert交易并发送error
        (bool success,) = _to.call{value: amount}("");
        if(!success){
            revert CallFailed();
        }
    }

第二十一课 调用其他合约

一个合约可以调用另一个合约的函数,这在构建复杂的DApps时非常有用。 调用其他合约的方式


以标准的erc20的transfer方法为例:

  1. 在知道调用的函数方法名称和参数的情况下:

    1. 创建接口合约调用
        interface ITest {
            function transfer(address to, uint256 value) external returns (bool);
        }
        function functionCall(address erc20, address to, uint256 value) public {
            // 调用地址为erc20的合约的transfer方法,发送数量为value的token给到to地址。
            ITest(erc20).transfer(to, value);
        }
    
    1. 引用原合约调用
        import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
        function functionCall(address erc20, address to, uint256 value) public {
            // 调用地址为erc20的合约的transfer方法,发送数量为value的token给到to地址。
            IERC20(erc20).transfer(to, value);
        }
    
    1. 直接使用call方法调用,用abi.encodeWithSignature(string memory signature, ...) returns (bytes memory)进行abi编码获取调用数据。 signature是函数声明
    import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
        function functionCall(address erc20, address to, uint256 value) public {
            // 调用地址为erc20的合约的transfer方法,发送数量为value的token给到to地址。
            erc20.call(abi.encodeWithSignature(bytes4(keccak256(bytes("transfer(address, uint256)"))), to, value));
        } 
  2. 在不知道调用的函数方法名称的情况下

    1. 使用call方法调用,用abi.encodeWithSelector(bytes4 selector, ...) returns (bytes memory)进行编码获取调用数据。 selector是函数选择器,通过将函数声明进行hash,然后获取的前八个十六进制字符。
        function functionCall(address erc20, address to, uint256 value) public {
            // 调用地址为erc20的合约的transfer方法,发送数量为value的token给到to地址。
            erc20.call(abi.encodeWithSelector(hex"a9059cbb", to, value));
        }