Skip to content

Instantly share code, notes, and snippets.

@darkerego
Last active September 1, 2023 22:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save darkerego/edce02f936b6441b93e3ca66ae817780 to your computer and use it in GitHub Desktop.
Save darkerego/edce02f936b6441b93e3ca66ae817780 to your computer and use it in GitHub Desktop.
Attempting to Revert Static Calls
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract TestStateChange {
uint public originalValue = 123;
uint public oldValue;
uint public incrementer = 0;
bytes4 public constant CHANGE_SEL = bytes4(keccak256(bytes('changeState(uint256)')));
bytes4 public constant WRAP_CHANGE_SEL = bytes4(keccak256(bytes('wrapChangeState(uint256)')));
error CallFailedError(string reason,address msgSender,address txOrigin);
event CallFailed(string indexed reason);
event CallSuccess(string indexed reason);
function _getRevertReason(bytes memory returnData) internal pure returns(string memory) {
// If the length is less than 68, then the transaction failed silently (without a revert message)
if (returnData.length < 68) return "Transaction reverted silently";
bytes memory revertData = new bytes(returnData.length - 68);
// The first 4 bytes of returnData are the function hash and the next 64 bytes are the
// length of the revert reason. The actual revert reason starts from the 68th byte.
assembly {
revertData := add(0x40, add(returnData, 0x24))
}
return abi.decode(revertData, (string));
}
function changeState(uint256 _value) external returns(bool success, string memory reason) {
require(_value != originalValue, "Choose any other number");
oldValue = originalValue;
originalValue = _value;
if (oldValue != originalValue) {
success = true;
reason = 'OK';
emit CallSuccess(reason);
} else {
reason = "The value did not change!";
//revert CallFailedError(reason, msg.sender, tx.origin);
emit CallFailed(reason);
}
}
function testFunc() public returns(bool success) {
require(msg.sender == tx.origin, "Function cannot be called with staticCall or web3.eth.call()");
incrementer += 1;
success = true;
}
function wrapChangeState(uint _value) public returns(bool success, bytes memory ret) {
// require(msg.sender == tx.origin, "Sender!Origin");
require(_value != originalValue, "Choose any other number");
uint currentValue = originalValue;
bytes memory data = abi.encodeWithSelector(CHANGE_SEL, _value);
(success, ret) = address(this).call{value: 0}(data);
require(success, "Call Failed!");
require(currentValue != originalValue, "State did not change!");
success = true;
}
function wrapChangeStateView(uint _value) public view returns(bool success) {
bytes memory returnData;
(success, returnData) = address(this).staticcall(abi.encodeWithSelector(WRAP_CHANGE_SEL, _value));
if (! success) {
string memory _reason = _getRevertReason(returnData);
revert CallFailedError(_reason, msg.sender, tx.origin);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment