diff --git a/README.md b/README.md index cb430a5787..60e81e7624 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ tokens utils ├─ Base58 — "Library for Base58 encoding and decoding" ├─ Base64 — "Library for Base64 encoding and decoding" +├─ BlockHashLib — "Library for accessing block hashes way beyond the 256-block limit" ├─ CallContextChecker — "Call context checker mixin" ├─ CREATE3 — "Deterministic deployments agnostic to the initialization code" ├─ DateTimeLib — "Library for date time operations" diff --git a/docs/utils/blockhashlib.md b/docs/utils/blockhashlib.md new file mode 100644 index 0000000000..8bae3100c6 --- /dev/null +++ b/docs/utils/blockhashlib.md @@ -0,0 +1,37 @@ +# BlockHashLib + +Library for accessing block hashes way beyond the 256-block limit. + + + + + + + + +## Constants + +### HISTORY_STORAGE_ADDRESS + +```solidity +address internal constant HISTORY_STORAGE_ADDRESS = + 0x0000F90827F1C53a10cb7A02335B175320002935 +``` + +Address of the EIP-2935 history storage contract. +See: https://eips.ethereum.org/EIPS/eip-2935 + +## Operations + +### blockHash(uint256) + +```solidity +function blockHash(uint256 blockNumber) + internal + view + returns (bytes32 result) +``` + +Retrieves the block hash for any historical block within the supported range. +The function gracefully handles future blocks and blocks beyond the history window by returning zero, +consistent with the EVM's native `BLOCKHASH` behavior. \ No newline at end of file diff --git a/docs/utils/libbit.md b/docs/utils/libbit.md index 078d433f66..944dbbb36c 100644 --- a/docs/utils/libbit.md +++ b/docs/utils/libbit.md @@ -140,6 +140,17 @@ function commonBytePrefix(uint256 x, uint256 y) Returns the common prefix of `x` and `y` at the byte level. +### toNibbles(bytes) + +```solidity +function toNibbles(bytes memory s) + internal + pure + returns (bytes memory result) +``` + +hex"ABCD" -> hex"0A0B0C0D". + ## Boolean Operations A Solidity bool on the stack or memory is represented as a 256-bit word. diff --git a/docs/utils/safetransferlib.md b/docs/utils/safetransferlib.md index 7e3f7dad8e..b63d5c2d26 100644 --- a/docs/utils/safetransferlib.md +++ b/docs/utils/safetransferlib.md @@ -132,6 +132,17 @@ The canonical Permit2 address. [Github](https://github.com/Uniswap/permit2) [Etherscan](https://etherscan.io/address/0x000000000022D473030F116dDEE9F6B43aC78BA3) +### ETH_MOVER + +```solidity +address internal constant ETH_MOVER = + 0x00000000000073c48c8055bD43D1A53799176f0D +``` + +The canonical address of the `SELFDESTRUCT` ETH mover. +See: https://gist.github.com/Vectorized/1cb8ad4cf393b1378e08f23f79bd99fa +[Etherscan](https://etherscan.io/address/0x00000000000073c48c8055bD43D1A53799176f0D) + ## ETH Operations If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants. @@ -222,6 +233,18 @@ function trySafeTransferAllETH(address to, uint256 gasStipend) Sends all the ETH in the current contract to `to`, with a `gasStipend`. +### safeMoveETH(address,uint256) + +```solidity +function safeMoveETH(address to, uint256 amount) + internal + returns (address vault) +``` + +Force transfers ETH to `to`, without triggering the fallback (if any). +This method attempts to use a separate contract to send via `SELFDESTRUCT`, +and upon failure, deploys a minimal vault to accrue the ETH. + ## ERC20 Operations ### safeTransferFrom(address,address,address,uint256) diff --git a/src/Milady.sol b/src/Milady.sol index 60da0907ac..1749970c38 100644 --- a/src/Milady.sol +++ b/src/Milady.sol @@ -25,6 +25,7 @@ import "./tokens/ERC721.sol"; import "./tokens/WETH.sol"; import "./utils/Base58.sol"; import "./utils/Base64.sol"; +import "./utils/BlockHashLib.sol"; import "./utils/CREATE3.sol"; import "./utils/CallContextChecker.sol"; import "./utils/DateTimeLib.sol"; diff --git a/src/utils/BlockHashLib.sol b/src/utils/BlockHashLib.sol index faa5d16853..c26fbabb25 100644 --- a/src/utils/BlockHashLib.sol +++ b/src/utils/BlockHashLib.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; -/// @notice Library for accessing block hashes way beyond the 256-block limit. ref: EIP-2935 +/// @notice Library for accessing block hashes way beyond the 256-block limit. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/BlockHashLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Blockhash.sol) library BlockHashLib { diff --git a/test/SafeTransferLib.t.sol b/test/SafeTransferLib.t.sol index 120e496f93..fec734311d 100644 --- a/test/SafeTransferLib.t.sol +++ b/test/SafeTransferLib.t.sol @@ -1277,35 +1277,4 @@ contract SafeTransferLibTest is SoladyTest { assertEq(mover.code, hex"3d35ff"); assertEq(mover, SafeTransferLib.ETH_MOVER); } - - function _deployOneTimeVault(address to, uint256 amount) internal returns (address vault) { - /// @solidity memory-safe-assembly - assembly { - to := shr(96, shl(96, to)) // Clean upper 96 bits. - for {} 1 {} { - let m := mload(0x40) - // If the mover is missing or bricked, deploy a minimal accrual contract - // that withdraws all ETH to `to` when being called only by `to`. - mstore( - add(m, 0x1f), 0x33146025575b600160005260206000f35b3d3d3d3d47335af1601a573d3dfd - ) - mstore(m, or(to, shl(160, 0x6034600b3d3960343df3fe73))) - // Compute and store the bytecode hash. - mstore8(0x00, 0xff) // Write the prefix. - mstore(0x35, keccak256(m, 0x3f)) - mstore(0x01, shl(96, address())) // Deployer. - mstore(0x15, 0) // Salt. - vault := keccak256(0x00, 0x55) - if iszero( - mul( - returndatasize(), - call(gas(), vault, amount, codesize(), 0x00, codesize(), 0x00) - ) - ) { if iszero(create2(0, m, 0x3f, 0)) { revert(codesize(), codesize()) } } // For gas estimation. - - mstore(0x40, m) - break - } - } - } }