github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/src/libraries/SafeCall.sol (about) 1 // SPDX-License-Identifier: MIT 2 pragma solidity 0.8.15; 3 4 /// @title SafeCall 5 /// @notice Perform low level safe calls 6 library SafeCall { 7 /// @notice Performs a low level call without copying any returndata. 8 /// @dev Passes no calldata to the call context. 9 /// @param _target Address to call 10 /// @param _gas Amount of gas to pass to the call 11 /// @param _value Amount of value to pass to the call 12 function send(address _target, uint256 _gas, uint256 _value) internal returns (bool) { 13 bool _success; 14 assembly { 15 _success := 16 call( 17 _gas, // gas 18 _target, // recipient 19 _value, // ether value 20 0, // inloc 21 0, // inlen 22 0, // outloc 23 0 // outlen 24 ) 25 } 26 return _success; 27 } 28 29 /// @notice Perform a low level call without copying any returndata 30 /// @param _target Address to call 31 /// @param _gas Amount of gas to pass to the call 32 /// @param _value Amount of value to pass to the call 33 /// @param _calldata Calldata to pass to the call 34 function call(address _target, uint256 _gas, uint256 _value, bytes memory _calldata) internal returns (bool) { 35 bool _success; 36 assembly { 37 _success := 38 call( 39 _gas, // gas 40 _target, // recipient 41 _value, // ether value 42 add(_calldata, 32), // inloc 43 mload(_calldata), // inlen 44 0, // outloc 45 0 // outlen 46 ) 47 } 48 return _success; 49 } 50 51 /// @notice Helper function to determine if there is sufficient gas remaining within the context 52 /// to guarantee that the minimum gas requirement for a call will be met as well as 53 /// optionally reserving a specified amount of gas for after the call has concluded. 54 /// @param _minGas The minimum amount of gas that may be passed to the target context. 55 /// @param _reservedGas Optional amount of gas to reserve for the caller after the execution 56 /// of the target context. 57 /// @return `true` if there is enough gas remaining to safely supply `_minGas` to the target 58 /// context as well as reserve `_reservedGas` for the caller after the execution of 59 /// the target context. 60 /// @dev !!!!! FOOTGUN ALERT !!!!! 61 /// 1.) The 40_000 base buffer is to account for the worst case of the dynamic cost of the 62 /// `CALL` opcode's `address_access_cost`, `positive_value_cost`, and 63 /// `value_to_empty_account_cost` factors with an added buffer of 5,700 gas. It is 64 /// still possible to self-rekt by initiating a withdrawal with a minimum gas limit 65 /// that does not account for the `memory_expansion_cost` & `code_execution_cost` 66 /// factors of the dynamic cost of the `CALL` opcode. 67 /// 2.) This function should *directly* precede the external call if possible. There is an 68 /// added buffer to account for gas consumed between this check and the call, but it 69 /// is only 5,700 gas. 70 /// 3.) Because EIP-150 ensures that a maximum of 63/64ths of the remaining gas in the call 71 /// frame may be passed to a subcontext, we need to ensure that the gas will not be 72 /// truncated. 73 /// 4.) Use wisely. This function is not a silver bullet. 74 function hasMinGas(uint256 _minGas, uint256 _reservedGas) internal view returns (bool) { 75 bool _hasMinGas; 76 assembly { 77 // Equation: gas × 63 ≥ minGas × 64 + 63(40_000 + reservedGas) 78 _hasMinGas := iszero(lt(mul(gas(), 63), add(mul(_minGas, 64), mul(add(40000, _reservedGas), 63)))) 79 } 80 return _hasMinGas; 81 } 82 83 /// @notice Perform a low level call without copying any returndata. This function 84 /// will revert if the call cannot be performed with the specified minimum 85 /// gas. 86 /// @param _target Address to call 87 /// @param _minGas The minimum amount of gas that may be passed to the call 88 /// @param _value Amount of value to pass to the call 89 /// @param _calldata Calldata to pass to the call 90 function callWithMinGas( 91 address _target, 92 uint256 _minGas, 93 uint256 _value, 94 bytes memory _calldata 95 ) 96 internal 97 returns (bool) 98 { 99 bool _success; 100 bool _hasMinGas = hasMinGas(_minGas, 0); 101 assembly { 102 // Assertion: gasleft() >= (_minGas * 64) / 63 + 40_000 103 if iszero(_hasMinGas) { 104 // Store the "Error(string)" selector in scratch space. 105 mstore(0, 0x08c379a0) 106 // Store the pointer to the string length in scratch space. 107 mstore(32, 32) 108 // Store the string. 109 // 110 // SAFETY: 111 // - We pad the beginning of the string with two zero bytes as well as the 112 // length (24) to ensure that we override the free memory pointer at offset 113 // 0x40. This is necessary because the free memory pointer is likely to 114 // be greater than 1 byte when this function is called, but it is incredibly 115 // unlikely that it will be greater than 3 bytes. As for the data within 116 // 0x60, it is ensured that it is 0 due to 0x60 being the zero offset. 117 // - It's fine to clobber the free memory pointer, we're reverting. 118 mstore(88, 0x0000185361666543616c6c3a204e6f7420656e6f75676820676173) 119 120 // Revert with 'Error("SafeCall: Not enough gas")' 121 revert(28, 100) 122 } 123 124 // The call will be supplied at least ((_minGas * 64) / 63) gas due to the 125 // above assertion. This ensures that, in all circumstances (except for when the 126 // `_minGas` does not account for the `memory_expansion_cost` and `code_execution_cost` 127 // factors of the dynamic cost of the `CALL` opcode), the call will receive at least 128 // the minimum amount of gas specified. 129 _success := 130 call( 131 gas(), // gas 132 _target, // recipient 133 _value, // ether value 134 add(_calldata, 32), // inloc 135 mload(_calldata), // inlen 136 0x00, // outloc 137 0x00 // outlen 138 ) 139 } 140 return _success; 141 } 142 }