From 5df15eaab39963962a8dbcaa3d7d069364fd1700 Mon Sep 17 00:00:00 2001 From: z80 Date: Mon, 28 Oct 2024 21:03:02 -0400 Subject: [PATCH] Add PuffDeployer for Foundry tests --- examples/add_two.huff | 4 +- src/Deployers.sol | 89 +++++++++++++++++++++++++++++++++++++++++++ test/Counter.t.sol | 11 +++--- 3 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 src/Deployers.sol diff --git a/examples/add_two.huff b/examples/add_two.huff index 8c2af80..23f9fcb 100644 --- a/examples/add_two.huff +++ b/examples/add_two.huff @@ -1,8 +1,8 @@ #include "./dummy.huff" #define macro MAIN() = takes(0) returns(0) { - 0x00 calldataload // [number1] // load first 32 bytes onto the stack - number 1 - 0x20 calldataload // [number2] // load second 32 bytes onto the stack - number 2 + 0x04 calldataload // [number1] // load first 32 bytes onto the stack - number 1 + 0x24 calldataload // [number2] // load second 32 bytes onto the stack - number 2 add // [number1+number2] // add number 1 and 2 and put the result onto the stack 0x00 mstore // place [number1 + number2] in memory diff --git a/src/Deployers.sol b/src/Deployers.sol new file mode 100644 index 0000000..417c687 --- /dev/null +++ b/src/Deployers.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity >=0.8.7 <0.9.0; + +///@notice This cheat codes interface is named _CheatCodes so you can use the CheatCodes interface in other testing files without errors +interface _CheatCodes { + function ffi(string[] calldata) external returns (bytes memory); +} + +contract PuffDeployer { + + address constant HEVM_ADDRESS = address(bytes20(uint160(uint256(keccak256("hevm cheat code"))))); + + /// @notice Initializes cheat codes in order to use ffi to compile Vyper contracts + _CheatCodes cheatCodes = _CheatCodes(HEVM_ADDRESS); + + ///@notice Compiles a Huff contract and returns the address that the contract was deployeod to + ///@notice If deployment fails, an error will be thrown + ///@param fileName - The file name of the Huff contract. + ///@return deployedAddress - The address that the contract was deployed to + + function deployContract(string memory fileName) public returns (address) { + ///@notice create a list of strings with the commands necessary to compile Vyper contracts + string[] memory cmds = new string[](3); + cmds[0] = "puffc"; + cmds[1] = "-b"; + cmds[2] = fileName; + + ///@notice compile the Huff contract and return the bytecode + bytes memory bytecode = cheatCodes.ffi(cmds); + + ///@notice deploy the bytecode with the create instruction + address deployedAddress; + assembly { + deployedAddress := create(0, add(bytecode, 0x20), mload(bytecode)) + } + + ///@notice check that the deployment was successful + require( + deployedAddress != address(0), + "PuffDeployer could not deploy contract" + ); + + ///@notice return the address that the contract was deployed to + return deployedAddress; + } + +} + + +contract HuffDeployer { + + address constant HEVM_ADDRESS = address(bytes20(uint160(uint256(keccak256("hevm cheat code"))))); + + /// @notice Initializes cheat codes in order to use ffi to compile Vyper contracts + _CheatCodes cheatCodes = _CheatCodes(HEVM_ADDRESS); + + ///@notice Compiles a Huff contract and returns the address that the contract was deployeod to + ///@notice If deployment fails, an error will be thrown + ///@param fileName - The file name of the Vyper contract. For example, the file name for "SimpleStore.vy" is "SimpleStore" + ///@return deployedAddress - The address that the contract was deployed to + + function deployContract(string memory fileName) public returns (address) { + ///@notice create a list of strings with the commands necessary to compile Vyper contracts + string[] memory cmds = new string[](3); + cmds[0] = "huffc"; + cmds[1] = "-b"; + cmds[2] = fileName; + + ///@notice compile the Vyper contract and return the bytecode + bytes memory bytecode = cheatCodes.ffi(cmds); + + ///@notice deploy the bytecode with the create instruction + address deployedAddress; + assembly { + deployedAddress := create(0, add(bytecode, 0x20), mload(bytecode)) + } + + ///@notice check that the deployment was successful + require( + deployedAddress != address(0), + "PuffDeployer could not deploy contract" + ); + + ///@notice return the address that the contract was deployed to + return deployedAddress; + } + +} diff --git a/test/Counter.t.sol b/test/Counter.t.sol index 41e9131..b515fd5 100644 --- a/test/Counter.t.sol +++ b/test/Counter.t.sol @@ -4,24 +4,25 @@ pragma solidity ^0.8.13; import {Test, console} from "forge-std/Test.sol"; import {Counter} from "../src/Counter.sol"; import {CreateX} from "../src/CreateX.sol"; +import {PuffDeployer, HuffDeployer} from "../src/Deployers.sol"; interface IAddsUints { function addUints(uint256, uint256) external returns (uint256); } contract CounterTest is Test { - Counter public counter; CreateX public createx; + PuffDeployer public puffDeployer; + HuffDeployer public huffDeployer; function setUp() public { - counter = new Counter(); - counter.setNumber(0); createx = new CreateX(); + puffDeployer = new PuffDeployer(); + huffDeployer = new HuffDeployer(); } function test_addNumbers() public { - bytes memory bytecode = hex"600c8060093d393df3600435602435015952595ff3"; - address newContract = createx.deployCreate(bytecode); + address newContract = puffDeployer.deployContract("examples/add_two.huff"); IAddsUints adder = IAddsUints(newContract); uint256 sum = adder.addUints(1, 2); assertEq(sum, 3);