# Solidity极简入门: 20. 发送ETH transfer,send和call

By [0xAA](https://paragraph.com/@wtfacademy) · 2022-05-03

---

我最近在重新学solidity，巩固一下细节，也写一个“Solidity极简入门”，供小白们使用（编程大佬可以另找教程），每周更新1-3讲。

欢迎关注我的推特：[@0xAA\_Science](https://twitter.com/0xAA_Science)

WTF技术社群discord，内有加微信群方法：[链接](https://discord.gg/5akcruXrsk)

所有代码和教程开源在github（1024个star发课程认证，2048个star发社群NFT）: [github.com/AmazingAng/WTFSolidity](https://github.com/AmazingAng/WTFSolidity)

* * *

`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;
        }
    }
    

部署好合约后，运行`getBalance()`函数，可以看到当前合约的`ETH`余额为`0`.

发送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);
        }
    

### send

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

代码样例：

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

### call

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

代码样例：

        // 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`。

总结
--

这一讲，我们介绍`solidity`三种发送`ETH`的方法：`transfer`，`send`和`call`。

*   `call`没有`gas`限制，最为灵活，是最提倡的方法；
    
*   `transfer`有`2300 gas`限制，但是发送失败会自动`revert`交易，是次优选择；
    
*   `send`有`2300 gas`限制，而且发送失败不会自动`revert`交易，几乎没有人用它。

---

*Originally published on [0xAA](https://paragraph.com/@wtfacademy/solidity-20-eth-transfer-send-call)*
