Solidity中含Fallback函数的钱包合约触发VM revert错误,原因何在?
为什么我的带Fallback函数的钱包合约触发revert错误?
你遇到的这个VM error: revert加上提示“Note: The constructor should be payable if you send value.”,问题出在合约部署阶段的转账处理,和你写的fallback函数没关系,我给你拆解清楚:
核心原因
在Solidity 0.4.x版本中,如果你没有显式定义构造函数,编译器会自动生成一个默认的无参构造函数,而这个默认构造函数是non-payable的。当你部署合约的时候,如果给合约发送了ETH,这笔转账会被交给构造函数处理,但因为构造函数不接受转账(non-payable),就会直接触发revert错误。
你写的payable fallback函数,是用来处理合约部署完成后的两种情况:
- 调用合约中不存在的函数时
- 直接给合约地址转账时(不是部署阶段的转账)
所以部署时的转账根本轮不到fallback函数处理,这就是为什么你写了fallback还是报错。
解决方案
根据你的需求分两种情况处理:
情况1:部署合约时不需要转ETH
最简单的解决办法就是部署合约的时候,不要设置转账金额,直接部署即可,这样默认构造函数就能正常执行,不会触发revert。
情况2:部署时确实需要给合约转ETH
这时候你需要显式定义一个payable的构造函数,注意Solidity 0.4.x的版本差异:
- 如果你用的是0.4.22及以上版本,可以用
constructor关键字:
pragma solidity ^0.4.22; contract MyWallet { struct account { uint balance; uint dailyLimit; } mapping (address =>account) _accounts; // 显式定义payable构造函数,处理部署时的转账 constructor() payable public { // 把部署时转入的ETH存入部署者的账户 _accounts[msg.sender].balance += msg.value; } // fallback函数处理部署后的转账 function () payable { _accounts[msg.sender].balance += msg.value; } function getBalance() returns (uint){ return _accounts[msg.sender].balance; } }
- 如果是0.4.22之前的版本,需要用和合约同名的函数作为构造函数:
pragma solidity ^0.4.0; contract MyWallet { struct account { uint balance; uint dailyLimit; } mapping (address =>account) _accounts; // 和合约同名的payable构造函数 function MyWallet() payable public { _accounts[msg.sender].balance += msg.value; } function () payable { _accounts[msg.sender].balance += msg.value; } function getBalance() returns (uint){ return _accounts[msg.sender].balance; } }
这样修改后,部署时的转账就能被构造函数正常接收,不会再触发revert错误了。
内容的提问来源于stack exchange,提问作者Kaushik
相关产品推荐
相关产品推荐

