为什么我无法使用 ‘send’ 或 ‘transfer’ 函数将以太币发送到其他合同?

huangapple go评论63阅读模式
英文:

Why am I unable to send ether to other contract with 'send' or 'transfer' function?

问题

为什么 `send()``transfer()` 不起作用?

我刚学会了Solidity,对发送以太币的方法很感兴趣。
我在Solidity中编写了两个智能合约,并在Remix IDE中部署了它们(环境为Remix VM(Merge))。我尝试以三种不同的方式从发送方合约向接收方合约发送1个以太币,分别是 `send()`、`transfer()` 和 `call()`
我能够通过 `call()` 方法发送以太币,但无法使用 `send()``transfer()` 函数发送。

以下是代码。

```solidity
pragma solidity ^0.8.0;

contract Receiver {
    // ...(代码省略)
}

contract Sender {
    // ...(代码省略)
}

发送方合约有三个函数,分别是 "sendWithSend"、"sendWithTransfer" 和 "sendWithCall"。

我尝试使用每个函数向接收方合约发送1个以太币,我期望它们都能成功,使接收方合约拥有3个以太币。但实际上只有1个以太币。

call() 方法起作用,但 send()transfer() 失败。

我尝试了很多次,但 send()transfer() 从未起作用。

以下是错误日志:

send() 错误:

send error log 1

send error log 2

transfer() 错误:

transfer error log 1

transfer error log 2

call() 方法成功日志:

call success log

我非常感谢您的帮助。


<details>
<summary>英文:</summary>

Why `send()` and `transfer()` doesn&#39;t work?

I just learned solidity and I&#39;m curious about the methods of sending ether.
I wrote two smart contract in solidity and deployed them with Remix IDE(Environment is Remix VM(Merge)). I tried to send 1 ether from Sender contract to Receiver contract in three different ways, `send()`, `transfer()`, `call()`.

I was able to send ether trough `call()`, but I was unable to send ether with `send()` and `transfer()` function.

Here is the code.



pragma solidity ^0.8.0;

contract Receiver {
address receiver;
uint public prize;
address public owner;

constructor() payable {
  receiver = msg.sender;
  owner = msg.sender;  
  prize = 0.001 ether;
}

receive() external payable {
  require(msg.value &gt;= prize || msg.sender == owner);
  payable(receiver).transfer(msg.value);
  receiver = msg.sender;
  prize = msg.value;
}

}

contract Sender {

constructor() payable{
}

function sendWithSend(address payable _to) public payable{
    //send ether with send
    //failed
    bool success = _to.send(msg.value);
    require(success, &quot;failed&quot;);
}
function sendWithTransfer(address payable _to) public payable{
    //send ether with transfer
    //failed
    _to.transfer(msg.value);      
}
function sendWithCall(address payable _to) public payable{
    //send ether with call
    //success
    (bool sent, ) = _to.call{value: msg.value}(&quot;&quot;);
    require(sent, &quot;Failled&quot; );
}

}


Sender contract has three functions, &quot;sendWithSend&quot;, &quot;sendWithTransfer&quot; and &quot;sendWithCall&quot;.

I tried to sent 1 ether to Receiver contract with each function and I expected all worked so Receiver contract would have 3 ether. But it got only 1 ether.

`call()` worked but `send()` and `transfer()` failed. 

I tried many times but `send()` and `transfer()` never works.


here is the error log

`send()` error

[send error log 1](https://i.stack.imgur.com/UVw9j.png)

[send error log 2](https://i.stack.imgur.com/umzAV.png)


`transfer()` error

[transfer error log 1](https://i.stack.imgur.com/kKM4c.png)

[transfer error log 2](https://i.stack.imgur.com/Leaw2.png)


and here is `call()` method success log

[call success log](https://i.stack.imgur.com/TqBho.png)


I would really appreciate your help.


</details>


# 答案1
**得分**: 0

send() 和 transfer() 的燃气限制为 21000,而 call() 没有默认的燃气限制。

对于 send() 和 transfer() 函数,当接收到资金时,receive() 函数将执行额外的代码,这将达到燃气限制。因此,交易将被回滚。

如果你创建一个空的 receive 函数,那么这应该可以工作,因为不会达到燃气限制。

这就是为什么最佳实践是始终使用 call() 函数,如果你可能要与智能合同交互的话。

<details>
<summary>英文:</summary>

send() and transfer() have a gas limit of 21000 while call() does not have default gas limit.

For the send() and transfer() function, when the funds are received, the receive() function will execute additional code which will reach the gas limit. Therefor the transaction will be reverted.

If you make an empty receive function, this should work as the gas limit will not be reached.

This is why the best practice is to always use the call() function if you may interact with a smart contract.

</details>



huangapple
  • 本文由 发表于 2023年3月31日 22:00:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/75899405.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定