第16节:安全事故5-msgvalue持久化问题
小白入门:https://github.com/dukedaily/solidity-expert ,欢迎star转发,文末加V入群。
在如下代码中,存在msg.value被重复使用的问题:在delegatecall中,msg.value与当前batch函数中msg.value一致,这可能导致错误。
function batch(bytes[] calldata calls, bool revertOnFail) external payable returns(bool[] memory success, bytes[] memory results) {
successes = new bool[](calls.length);
results = new bytes[](calls.length);
for (uint256 i=0; i< calls.length; i++) {
(bool success, bytes memory result) = address(this).delegatecall(calls[i]);
require(success || !revertOnFail, _getReyerMsg(result));
successes[i] = success;
results[i] = result;
}
}
我们写一个测试案例:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
contract batch {
uint public num;
address public sender;
uint public value;
function mintBatch(uint _num) public payable {
// Proxy's storage is set, Implementation is not modified.
for (uint i = 0; i < _num; i++) {
(bool success, bytes memory data) = address(this).delegatecall(
abi.encodeWithSignature("mint(uint256)", _num)
);
}
}
function mint(uint _num) public payable {
require(msg.value == 1 ether, "error");
num = _num;
sender = msg.sender;
value += msg.value;
}
}
执行结果:
- 调用mintBatch时传入1ETH,内部会调用mint30次;
- 理论上一共应该话费30ETH,但是实际上每次delegatecall执行后这1ETH都会返回到当前的合约中,并在下次循环时被重复使用;
解决思路:
- 在使用delegatecall时如果涉及到了msg.value,不用与for循环配合使用。