├── .github └── workflows │ └── test.yml ├── .gitignore ├── .gitmodules ├── README.md ├── foundry.toml ├── src ├── HasherKeccak256.sol ├── HasherSha256.sol ├── TextHasher.sol └── interfaces │ └── IHasher.sol └── test └── TextHasher.t.sol /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: workflow_dispatch 4 | 5 | env: 6 | FOUNDRY_PROFILE: ci 7 | 8 | jobs: 9 | check: 10 | strategy: 11 | fail-fast: true 12 | 13 | name: Foundry project 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v3 17 | with: 18 | submodules: recursive 19 | 20 | - name: Install Foundry 21 | uses: foundry-rs/foundry-toolchain@v1 22 | with: 23 | version: nightly 24 | 25 | - name: Run Forge build 26 | run: | 27 | forge --version 28 | forge build --sizes 29 | id: build 30 | 31 | - name: Run Forge tests 32 | run: | 33 | forge test -vvv 34 | id: test 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiler files 2 | cache/ 3 | out/ 4 | 5 | # Ignores development broadcast logs 6 | !/broadcast 7 | /broadcast/*/31337/ 8 | /broadcast/**/dry-run/ 9 | 10 | # Docs 11 | docs/ 12 | 13 | # Dotenv file 14 | .env 15 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/forge-std"] 2 | path = lib/forge-std 3 | url = https://github.com/foundry-rs/forge-std 4 | branch = v1.3.0 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cursed Functions 2 | 3 | > Note: This could actually be really cool internally in some modular protocol, this is just to 4 | > showcase how weird it can get. 5 | 6 | This allows external functions to be assigned to a state variable, which can be returned from the 7 | contract as a `bytes24`, but can also be used internally to make an external call. 8 | 9 | ## Contracts 10 | 11 | ### [TextHasher](./src/TextHasher.sol) 12 | 13 | This contract stores the external `hasher` function of other contracts. It also logs an event when 14 | the hasher changes. 15 | 16 | Using `TextHasher.hash(string)` will make an external call to the current `hasher` contract's 17 | function, which hashes and returns the digest. 18 | 19 | ### [HasherKeccak256](./src/HasherKeccak256.sol) 20 | 21 | This implements `IHasher`, therefore it may be assigned to the `TextHasher.hasher` value. 22 | 23 | This simply returns the `keccak256` hash digest to the `TextHasher` contract. 24 | 25 | ### [HasherSha256](./src/HasherSha256.sol) 26 | 27 | This implements `IHasher`, therefore it may be assigned to the `TextHasher.hasher` value. 28 | 29 | This simply returns the `sha256` hash digest to the `TextHasher` contract. 30 | 31 | ### [IHasher](./src/interfaces/IHasher.sol) 32 | 33 | This interface requires an inheriting contract implements `hasher(string):(bytes32)`. 34 | 35 | Any hashing algorithm may be implemented and used, so long as their external interface conforms to 36 | `IHasher`. 37 | -------------------------------------------------------------------------------- /foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = 'src' 3 | out = 'out' 4 | libs = ['lib'] 5 | 6 | # See more config options https://github.com/foundry-rs/foundry/tree/master/config -------------------------------------------------------------------------------- /src/HasherKeccak256.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.18; 3 | 4 | import "src/interfaces/IHasher.sol"; 5 | 6 | contract HasherKeccak256 is IHasher { 7 | function hasher(string memory text) external pure returns (bytes32) { 8 | return keccak256(bytes(text)); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/HasherSha256.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.18; 3 | 4 | import "src/interfaces/IHasher.sol"; 5 | 6 | contract HasherSha256 is IHasher { 7 | function hasher(string memory text) external pure returns (bytes32) { 8 | return sha256(bytes(text)); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/TextHasher.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.18; 3 | 4 | /// @title Text Hasher 5 | /// @author jtriley.eth 6 | /// @notice Hasher is interchangeable 7 | contract TextHasher { 8 | /// @notice Interchangeable Hasher Contract 9 | function(string memory) external view returns (bytes32) public hasher; 10 | 11 | /// @notice Logged when the Hasher changes 12 | /// @param setter Address that set the Hasher 13 | /// @param oldHasher Old Hasher 14 | /// @param newHasher New Hasher 15 | event HasherSet( 16 | address indexed setter, 17 | function(string memory) external view returns (bytes32) indexed oldHasher, 18 | function(string memory) external view returns (bytes32) indexed newHasher 19 | ); 20 | 21 | /// @notice Sets the Hasher 22 | /// @param newHasher New Hasher 23 | function setHasher( 24 | function(string memory) external view returns (bytes32) newHasher 25 | ) external { 26 | require(newHasher("test") != bytes32(0), "Invalid Hasher"); 27 | function(string memory) external view returns (bytes32) oldHasher = hasher; 28 | hasher = newHasher; 29 | emit HasherSet(msg.sender, oldHasher, newHasher); 30 | } 31 | 32 | /// @notice Hashes text with current Hasher 33 | /// @param text Text to hash 34 | /// @return hashedText Hashed text 35 | function hash(string memory text) external view returns (bytes32 hashedText) { 36 | hashedText = hasher(text); 37 | require(hashedText != bytes32(0), "Invalid Hasher"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/interfaces/IHasher.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.18; 3 | 4 | interface IHasher { 5 | function hasher(string memory) external pure returns (bytes32); 6 | } 7 | -------------------------------------------------------------------------------- /test/TextHasher.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.18; 3 | 4 | import "lib/forge-std/src/Test.sol"; 5 | import "src/TextHasher.sol"; 6 | import "src/HasherKeccak256.sol"; 7 | import "src/HasherSha256.sol"; 8 | 9 | contract TextHasherTest is Test { 10 | event HasherSet( 11 | address indexed setter, 12 | function(string memory) external view returns (bytes32) indexed oldHasher, 13 | function(string memory) external view returns (bytes32) indexed newHasher 14 | ); 15 | 16 | TextHasher textHasher; 17 | HasherKeccak256 hasherKeccak256; 18 | HasherSha256 hasherSha256; 19 | 20 | function setUp() external { 21 | textHasher = new TextHasher(); 22 | hasherKeccak256 = new HasherKeccak256(); 23 | hasherSha256 = new HasherSha256(); 24 | } 25 | 26 | function testSetHasher() external { 27 | function(string memory) external view returns (bytes32) empty; 28 | 29 | vm.expectEmit({ 30 | checkTopic1: false, 31 | checkTopic2: true, 32 | checkTopic3: true, 33 | checkData: true, 34 | emitter: address(textHasher) 35 | }); 36 | emit HasherSet(address(0), empty, hasherKeccak256.hasher); 37 | 38 | textHasher.setHasher(hasherKeccak256.hasher); 39 | } 40 | 41 | function testHasherKeccak256() external { 42 | string memory text = "asdf"; 43 | 44 | textHasher.setHasher(hasherKeccak256.hasher); 45 | 46 | assertEq(textHasher.hash(text), hasherKeccak256.hasher(text)); 47 | assertEq(textHasher.hash(text), keccak256(bytes(text))); 48 | } 49 | 50 | function testHasherSha256() external { 51 | string memory text = "asdf"; 52 | 53 | textHasher.setHasher(hasherSha256.hasher); 54 | 55 | assertEq(textHasher.hash(text), hasherSha256.hasher(text)); 56 | assertEq(textHasher.hash(text), sha256(bytes(text))); 57 | } 58 | } 59 | --------------------------------------------------------------------------------