Solidity 102

1. 函数重载
2. 库合约
3. Import
4. 接收ETH
5. 发送ETH
6. 调用其他合约
7. Call
8. Delegatecall
9. 在合约中创建新合约
10. Create2
11. 删除合约
12. ABI编码解码
13. Hash
14. 选择器
15. Try Catch
.
发送ETH

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

接收ETH合约

我们先部署一个接收ETH合约ReceiveETH。ReceiveETH合约里有一个事件Log,记录收到的ETH数量和gas剩余。还有两个函数,一个是receive()函数,收到ETH被触发,并发送Log事件;另一个是查询合约ETH余额的getBalance()函数。

contract ReceiveETH {
    // 收到eth事件,记录amount和gas
    event Log(uint amount, uint gas);
    
    // receive方法,接收eth时被触发
    receive() external payable{
        emit Log(msg.value, gasleft());
    }
    
    // 返回合约ETH余额
    function getBalance() view public returns(uint) {
        return address(this).balance;
    }
}

部署ReceiveETH合约后,运行getBalance()函数,可以看到当前合约的ETH余额为0。

20-1

发送ETH合约

我们将实现三种方法向ReceiveETH合约发送ETH。首先,先在发送ETH合约SendETH中实现payable的构造函数和receive(),让我们能够在部署时和部署后向合约转账。

contract SendETH {
    // 构造函数,payable使得部署的时候可以转eth进去
    constructor() payable{}
    // receive方法,接收eth时被触发
    receive() external payable{}
}

transfer

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

代码样例,注意里面的_to填ReceiveETH合约的地址,amount是ETH转账金额:

// 用transfer()发送ETH
function transferETH(address payable _to, uint256 amount) external payable{
    _to.transfer(amount);
}

部署SendETH合约后,对ReceiveETH合约发送ETH,此时amount为10,value为0,amount>value,转账失败,发生revert。

20-2

此时amount为10,value为10,amount<=value,转账成功。

20-3

在ReceiveETH合约中,运行getBalance()函数,可以看到当前合约的ETH余额为10。

20-4

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();
    }
}

对ReceiveETH合约发送ETH,此时amount为10,value为0,amount>value,转账失败,因为经过处理,所以发生revert。

20-5

此时amount为10,value为11,amount<=value,转账成功。

20-6

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();
    }
}

对ReceiveETH合约发送ETH,此时amount为10,value为0,amount>value,转账失败,因为经过处理,所以发生revert。

20-7

此时amount为10,value为11,amount<=value,转账成功。

20-8

运行三种方法,可以看到,他们都可以成功地向ReceiveETH合约发送ETH。

总结

这一讲,我们介绍Solidity三种发送ETH的方法:transfer,send和call。

  • call没有gas限制,最为灵活,是最提倡的方法;
  • transfer有2300 gas限制,但是发送失败会自动revert交易,是次优选择;
  • send有2300 gas限制,而且发送失败不会自动revert交易,几乎没有人用它。
上一章下一章