├── .gitignore ├── .gitmodules ├── README.md ├── foundry.toml ├── remappings.txt ├── script └── Counter.s.sol ├── src ├── Counter.huff ├── Deployer.sol └── interfaces │ └── ICounter.sol └── test └── Counter.t.sol /.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | cache/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/forge-std"] 2 | path = lib/forge-std 3 | url = https://github.com/foundry-rs/forge-std 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hufflepuff 2 | 3 | Huff for fun 4 | 5 | 6 | ``` 7 | forge test --ffi --debug testCounter 8 | ``` -------------------------------------------------------------------------------- /foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = 'src' 3 | out = 'out' 4 | libs = ['lib'] 5 | compiler = '0.8.16' 6 | 7 | # See more config options https://github.com/foundry-rs/foundry/tree/master/config -------------------------------------------------------------------------------- /remappings.txt: -------------------------------------------------------------------------------- 1 | forge-std/=lib/forge-std/src/ -------------------------------------------------------------------------------- /script/Counter.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | import "forge-std/Script.sol"; 5 | 6 | contract CounterScript is Script { 7 | function setUp() public {} 8 | 9 | function run() public { 10 | vm.broadcast(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Counter.huff: -------------------------------------------------------------------------------- 1 | // Counter example 2 | // Bare minimum example of how to set and read data from huff 3 | 4 | // Interface 5 | #define function increment() nonpayable returns () 6 | #define function setValue(uint256) nonpayable returns () 7 | #define function getValue() view returns (uint256) 8 | 9 | // Storage definitions 10 | #define constant VALUE_SLOT = FREE_STORAGE_POINTER() 11 | 12 | // Functions 13 | #define macro INCREMENT() = takes (0) returns (0) { 14 | [VALUE_SLOT] sload // [var_value] 15 | 0x01 // [0x01, var_value] 16 | add // [var_value++] 17 | [VALUE_SLOT] sstore // []; stores updated value 18 | stop 19 | } 20 | 21 | #define macro SET_VALUE() = takes (0) returns (0) { 22 | 0x04 calldataload // [value] 23 | [VALUE_SLOT] // [value_slot, value] 24 | sstore 25 | stop 26 | } 27 | 28 | #define macro GET_VALUE() = takes (0) returns (0) { 29 | [VALUE_SLOT] sload // [var_value] 30 | 0x00 // [0x00, var_value] 31 | mstore // []; stores var_value into memory location 0x0 32 | 0x20 // [0x20] 33 | 0x00 // [0x00, 0x20] 34 | return 35 | } 36 | 37 | #define macro MAIN() = takes (0) returns (0) { 38 | // Load the function selector 39 | pc calldataload 0xE0 shr // [sig] 40 | 41 | dup1 __FUNC_SIG(increment) eq increment jumpi 42 | dup1 __FUNC_SIG(getValue) eq getValue jumpi 43 | dup1 __FUNC_SIG(setValue) eq setValue jumpi 44 | 45 | getValue: 46 | GET_VALUE() 47 | 48 | setValue: 49 | SET_VALUE() 50 | 51 | increment: 52 | INCREMENT() 53 | } -------------------------------------------------------------------------------- /src/Deployer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.16; 3 | 4 | import {Vm} from "forge-std/Vm.sol"; 5 | 6 | using { compile } for Vm; 7 | using { appendArg, create } for bytes; 8 | 9 | function compile(Vm vm, string memory path) returns (bytes memory) { 10 | string[] memory cmd = new string[](3); 11 | cmd[0] = "huffc"; 12 | cmd[1] = "-b"; 13 | cmd[2] = path; 14 | return vm.ffi(cmd); 15 | } 16 | 17 | error DeploymentFailure(bytes bytecode); 18 | 19 | function create(bytes memory bytecode, uint256 value) returns (address deployedAddress) { 20 | assembly { 21 | deployedAddress := create(value, add(bytecode, 0x20), mload(bytecode)) 22 | } 23 | 24 | if (deployedAddress == address(0)) revert DeploymentFailure(bytecode); 25 | } 26 | 27 | function create2( 28 | bytes memory bytecode, 29 | uint256 value, 30 | bytes32 salt 31 | ) returns (address deployedAddress) { 32 | assembly { 33 | deployedAddress := create2(value, add(bytecode, 0x20), mload(bytecode), salt) 34 | } 35 | 36 | if (deployedAddress == address(0)) revert DeploymentFailure(bytecode); 37 | } 38 | 39 | function appendArg(bytes memory bytecode, address arg) pure returns (bytes memory) { 40 | return bytes.concat(bytecode, abi.encode(arg)); 41 | } 42 | 43 | contract TryDeployer { 44 | address a; 45 | 46 | constructor(bytes memory bytecode, uint256 value) { 47 | a = create(bytecode, value); 48 | } 49 | 50 | function getDeployedBytecode() external view returns (bytes memory) { 51 | return address(a).code; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/interfaces/ICounter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.16; 3 | 4 | interface ICounter { 5 | function increment() external; 6 | function setValue(uint256) external; 7 | function getValue() external returns (uint256); 8 | } -------------------------------------------------------------------------------- /test/Counter.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "../src/interfaces/ICounter.sol"; 6 | import "../src/Deployer.sol"; 7 | 8 | using { compile } for Vm; 9 | using { create } for bytes; 10 | 11 | contract CounterTest is Test { 12 | ICounter counter; 13 | 14 | function setUp() public { 15 | counter = ICounter(vm.compile("src/Counter.huff").create(0)); 16 | } 17 | 18 | function testCode() public { 19 | emit log_bytes(address(counter).code); 20 | } 21 | 22 | function testCounter() public { 23 | assertEq(counter.getValue(), 0); 24 | counter.setValue(5); 25 | assertEq(counter.getValue(), 5); 26 | counter.setValue(3); 27 | assertEq(counter.getValue(), 3); 28 | counter.increment(); 29 | assertEq(counter.getValue(), 4); 30 | } 31 | } 32 | --------------------------------------------------------------------------------