Last active
September 1, 2023 22:00
Revisions
-
darkerego renamed this gist
Sep 1, 2023 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
darkerego revised this gist
Sep 1, 2023 . 1 changed file with 53 additions and 52 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,74 +1,75 @@ // 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); } } } -
darkerego created this gist
Sep 1, 2023 .There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,74 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "contracts/simulateCalls/ViewStorageAccessible.sol"; contract StaticCallCheck { uint256 public stateVariable = 0; uint256 public fakeTimestamp = 0; uint256 public lol = 100; uint public oldLol; bool public lastSuccess ; bytes4 constant CHANGE_LOL_SEL = bytes4(keccak256(bytes('changeLol()'))); function changeLol() external returns(uint256 _lol) { oldLol = lol; require(msg.sender == address(this) && tx.origin != address(0), "?origin"); lol += lol; require(lol > oldLol, "Change not updated!"); _lol = lol; } function bytesToUintAssembly(bytes memory input) public pure returns (uint256 result) { assembly { result := mload(add(input, 32)) } } function stateChangingFunx() external returns(bool success) { bytes memory currentLol; (success, currentLol) = address(this).call{value: 0}(abi.encodeWithSelector(CHANGE_LOL_SEL)); require(success, "The call failed!"); lastSuccess = success; lol += lol; uint _currentLol = bytesToUintAssembly(currentLol); if (lol == _currentLol) { revert("The state did not change!"); } else { success = true; } } function setStateVariable(uint256 newValue) public { uint256 initialGas = gasleft(); // Try to change state stateVariable = newValue * 2; uint256 finalGas = gasleft(); uint256 gasConsumed = initialGas - finalGas; // Mimic a timestamp change fakeTimestamp = block.timestamp; // Check if state changes were effective if (stateVariable != newValue * 2 || fakeTimestamp != block.timestamp) { revert("Possible staticcall detected via state changing variables"); } // Use gas consumption to further infer the type of call if (gasConsumed == 0) { revert("Possible staticcall detected via gas consumed"); } if (msg.sender == address(0) || tx.origin == address(0)) { revert("Possible staticcall detected via send/origin"); } stateVariable = newValue; require(this.stateChangingFunx(), "Static call!"); } }