diff --git a/contracts/interfaces/IMiddlewareFactory.sol b/contracts/interfaces/IMiddlewareFactory.sol index afc10a68..4af554fe 100644 --- a/contracts/interfaces/IMiddlewareFactory.sol +++ b/contracts/interfaces/IMiddlewareFactory.sol @@ -11,6 +11,7 @@ interface IMiddlewareFactory { /// @notice Creates a middleware for the given implementation /// @param implementation The implementation address + /// @param salt The salt to use to deploy the middleware /// @return middleware The address of the newly created middleware - function createMiddleware(address implementation) external returns (address middleware); + function createMiddleware(address implementation, bytes32 salt) external returns (address middleware); } diff --git a/contracts/hooks/middleware/BaseMiddleware.sol b/contracts/middleware/BaseMiddleware.sol similarity index 94% rename from contracts/hooks/middleware/BaseMiddleware.sol rename to contracts/middleware/BaseMiddleware.sol index f5fc500c..c9f6334d 100644 --- a/contracts/hooks/middleware/BaseMiddleware.sol +++ b/contracts/middleware/BaseMiddleware.sol @@ -8,7 +8,7 @@ import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol"; import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; import {BeforeSwapDelta} from "@uniswap/v4-core/src/types/BeforeSwapDelta.sol"; import {Proxy} from "@openzeppelin/contracts/proxy/Proxy.sol"; -import {console} from "../../../lib/forge-std/src/console.sol"; +import {console} from "../../lib/forge-std/src/console.sol"; contract BaseMiddleware is Proxy { /// @notice The address of the pool manager diff --git a/contracts/hooks/middleware/BaseMiddlewareDefault.txt b/contracts/middleware/BaseMiddlewareDefault.txt similarity index 100% rename from contracts/hooks/middleware/BaseMiddlewareDefault.txt rename to contracts/middleware/BaseMiddlewareDefault.txt diff --git a/contracts/hooks/middleware/MiddlewareProtect.sol b/contracts/middleware/MiddlewareProtect.sol similarity index 96% rename from contracts/hooks/middleware/MiddlewareProtect.sol rename to contracts/middleware/MiddlewareProtect.sol index 688fe536..faeb21ae 100644 --- a/contracts/hooks/middleware/MiddlewareProtect.sol +++ b/contracts/middleware/MiddlewareProtect.sol @@ -6,8 +6,8 @@ import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; import {BaseMiddleware} from "./BaseMiddleware.sol"; import {BalanceDelta, BalanceDeltaLibrary} from "@uniswap/v4-core/src/types/BalanceDelta.sol"; import {BeforeSwapDelta} from "@uniswap/v4-core/src/types/BeforeSwapDelta.sol"; -import {console} from "../../../lib/forge-std/src/console.sol"; -import {BaseHook} from "./../../BaseHook.sol"; +import {console} from "../../lib/forge-std/src/console.sol"; +import {BaseHook} from "./../BaseHook.sol"; contract MiddlewareProtect is BaseMiddleware { bool private swapBlocked; diff --git a/contracts/hooks/middleware/MiddlewareRemove.sol b/contracts/middleware/MiddlewareRemove.sol similarity index 94% rename from contracts/hooks/middleware/MiddlewareRemove.sol rename to contracts/middleware/MiddlewareRemove.sol index 2a90f89a..1cb08e90 100644 --- a/contracts/hooks/middleware/MiddlewareRemove.sol +++ b/contracts/middleware/MiddlewareRemove.sol @@ -9,8 +9,8 @@ import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; import {BeforeSwapDelta} from "@uniswap/v4-core/src/types/BeforeSwapDelta.sol"; import {Proxy} from "@openzeppelin/contracts/proxy/Proxy.sol"; import {BaseMiddleware} from "./BaseMiddleware.sol"; -import {BaseHook} from "../../BaseHook.sol"; -import {console} from "../../../lib/forge-std/src/console.sol"; +import {BaseHook} from "../BaseHook.sol"; +import {console} from "../../lib/forge-std/src/console.sol"; import {BalanceDeltaLibrary} from "@uniswap/v4-core/src/types/BalanceDelta.sol"; contract MiddlewareRemove is BaseMiddleware { diff --git a/contracts/middleware/MiddlewareRemoveFactory.sol b/contracts/middleware/MiddlewareRemoveFactory.sol new file mode 100644 index 00000000..72f4368a --- /dev/null +++ b/contracts/middleware/MiddlewareRemoveFactory.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.19; + +import {IMiddlewareFactory} from "../interfaces/IMiddlewareFactory.sol"; +import {MiddlewareRemove} from "./MiddlewareRemove.sol"; +import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; + +contract MiddlewareRemoveFactory is IMiddlewareFactory { + mapping(address => address) private _implementations; + + IPoolManager public immutable poolManager; + + constructor(IPoolManager _poolManager) { + poolManager = _poolManager; + } + + function getImplementation(address middleware) external view override returns (address implementation) { + return _implementations[middleware]; + } + + function createMiddleware(address implementation, bytes32 salt) external override returns (address middleware) { + middleware = address(new MiddlewareRemove{salt: salt}(poolManager, implementation)); + _implementations[middleware] = implementation; + emit MiddlewareCreated(implementation, middleware); + } +} diff --git a/contracts/hooks/middleware/test/FeeTakingLite.sol b/contracts/middleware/test/FeeTakingLite.sol similarity index 97% rename from contracts/hooks/middleware/test/FeeTakingLite.sol rename to contracts/middleware/test/FeeTakingLite.sol index d926b1a5..e4195ff2 100644 --- a/contracts/hooks/middleware/test/FeeTakingLite.sol +++ b/contracts/middleware/test/FeeTakingLite.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; -import {BaseHook} from "../../../BaseHook.sol"; +import {BaseHook} from "../../BaseHook.sol"; import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol"; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; @@ -11,7 +11,7 @@ import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol"; import {Owned} from "solmate/auth/Owned.sol"; import {IUnlockCallback} from "@uniswap/v4-core/src/interfaces/callback/IUnlockCallback.sol"; -import {console} from "../../../../lib/forge-std/src/console.sol"; +import {console} from "../../../lib/forge-std/src/console.sol"; contract FeeTakingLite is IUnlockCallback { using SafeCast for uint256; diff --git a/contracts/hooks/middleware/test/HooksOutOfGas.sol b/contracts/middleware/test/HooksOutOfGas.sol similarity index 97% rename from contracts/hooks/middleware/test/HooksOutOfGas.sol rename to contracts/middleware/test/HooksOutOfGas.sol index 6550032f..db441bfe 100644 --- a/contracts/hooks/middleware/test/HooksOutOfGas.sol +++ b/contracts/middleware/test/HooksOutOfGas.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; -import {BaseHook} from "../../../BaseHook.sol"; +import {BaseHook} from "../../BaseHook.sol"; import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol"; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; @@ -11,7 +11,7 @@ import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol"; import {Owned} from "solmate/auth/Owned.sol"; import {IUnlockCallback} from "@uniswap/v4-core/src/interfaces/callback/IUnlockCallback.sol"; -import {console} from "../../../../lib/forge-std/src/console.sol"; +import {console} from "../../../lib/forge-std/src/console.sol"; contract HooksOutOfGas { IPoolManager public immutable poolManager; diff --git a/contracts/hooks/middleware/test/HooksRevert.sol b/contracts/middleware/test/HooksRevert.sol similarity index 97% rename from contracts/hooks/middleware/test/HooksRevert.sol rename to contracts/middleware/test/HooksRevert.sol index 98efdf5a..bb125d3a 100644 --- a/contracts/hooks/middleware/test/HooksRevert.sol +++ b/contracts/middleware/test/HooksRevert.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; -import {BaseHook} from "../../../BaseHook.sol"; +import {BaseHook} from "../../BaseHook.sol"; import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol"; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; @@ -11,7 +11,7 @@ import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol"; import {Owned} from "solmate/auth/Owned.sol"; import {IUnlockCallback} from "@uniswap/v4-core/src/interfaces/callback/IUnlockCallback.sol"; -import {console} from "../../../../lib/forge-std/src/console.sol"; +import {console} from "../../../lib/forge-std/src/console.sol"; contract HooksRevert { error HookNotImplemented(); diff --git a/test/BaseMiddleware.t.sol b/test/BaseMiddleware.t.sol index 58863bfd..56093d31 100644 --- a/test/BaseMiddleware.t.sol +++ b/test/BaseMiddleware.t.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; import {Test} from "forge-std/Test.sol"; import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol"; -import {FeeTakingLite} from "../contracts/hooks/middleware/test/FeeTakingLite.sol"; -import {BaseMiddleware} from "../contracts/hooks/middleware/BaseMiddleware.sol"; +import {FeeTakingLite} from "../contracts/middleware/test/FeeTakingLite.sol"; +import {BaseMiddleware} from "../contracts/middleware/BaseMiddleware.sol"; import {BaseMiddlewareImplementation} from "./shared/implementation/BaseMiddlewareImplementation.sol"; import {PoolManager} from "@uniswap/v4-core/src/PoolManager.sol"; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; diff --git a/test/MiddlewareRemove.t.sol b/test/MiddlewareRemove.t.sol index 2dde78e8..fb198463 100644 --- a/test/MiddlewareRemove.t.sol +++ b/test/MiddlewareRemove.t.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; import {Test} from "forge-std/Test.sol"; import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol"; -import {FeeTakingLite} from "../contracts/hooks/middleware/test/FeeTakingLite.sol"; -import {MiddlewareRemove} from "../contracts/hooks/middleware/MiddlewareRemove.sol"; +import {FeeTakingLite} from "../contracts/middleware/test/FeeTakingLite.sol"; +import {MiddlewareRemove} from "../contracts/middleware/MiddlewareRemove.sol"; import {MiddlewareRemoveImplementation} from "./shared/implementation/MiddlewareRemoveImplementation.sol"; import {PoolManager} from "@uniswap/v4-core/src/PoolManager.sol"; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; @@ -18,8 +18,8 @@ import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol"; import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol"; import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol"; import {console} from "../../../lib/forge-std/src/console.sol"; -import {HooksRevert} from "../contracts/hooks/middleware/test/HooksRevert.sol"; -import {HooksOutOfGas} from "../contracts/hooks/middleware/test/HooksOutOfGas.sol"; +import {HooksRevert} from "../contracts/middleware/test/HooksRevert.sol"; +import {HooksOutOfGas} from "../contracts/middleware/test/HooksOutOfGas.sol"; contract MiddlewareRemoveTest is Test, Deployers { using PoolIdLibrary for PoolKey; @@ -66,8 +66,8 @@ contract MiddlewareRemoveTest is Test, Deployers { } // creates a middleware on an implementation - function testOn(address implementation, uint160 hooks) internal { - MiddlewareRemove middlewareRemove = MiddlewareRemove(payable(address(nonce << 20 | hooks))); + function testOn(address implementation, uint160 flags) internal { + MiddlewareRemove middlewareRemove = MiddlewareRemove(payable(address(nonce << 20 | flags))); nonce++; vm.record(); MiddlewareRemoveImplementation impl = diff --git a/test/MiddlewareRemoveFactory.t.sol b/test/MiddlewareRemoveFactory.t.sol new file mode 100644 index 00000000..29e40d83 --- /dev/null +++ b/test/MiddlewareRemoveFactory.t.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.19; + +import {Test} from "forge-std/Test.sol"; +import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol"; +import {FeeTakingLite} from "../contracts/middleware/test/FeeTakingLite.sol"; +import {MiddlewareRemove} from "../contracts/middleware/MiddlewareRemove.sol"; +import {MiddlewareRemoveImplementation} from "./shared/implementation/MiddlewareRemoveImplementation.sol"; +import {PoolManager} from "@uniswap/v4-core/src/PoolManager.sol"; +import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; +import {Deployers} from "@uniswap/v4-core/test/utils/Deployers.sol"; +import {TestERC20} from "@uniswap/v4-core/src/test/TestERC20.sol"; +import {CurrencyLibrary, Currency} from "@uniswap/v4-core/src/types/Currency.sol"; +import {PoolId, PoolIdLibrary} from "@uniswap/v4-core/src/types/PoolId.sol"; +import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; +import {HookEnabledSwapRouter} from "./utils/HookEnabledSwapRouter.sol"; +import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol"; +import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol"; +import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol"; +import {console} from "../../../lib/forge-std/src/console.sol"; +import {HooksRevert} from "../contracts/middleware/test/HooksRevert.sol"; +import {HooksOutOfGas} from "../contracts/middleware/test/HooksOutOfGas.sol"; +import {MiddlewareRemoveFactory} from "./../contracts/middleware/MiddlewareRemoveFactory.sol"; +import {HookMiner} from "./utils/HookMiner.sol"; + +contract MiddlewareRemoveFactoryTest is Test, Deployers { + using PoolIdLibrary for PoolKey; + using StateLibrary for IPoolManager; + + uint160 constant SQRT_RATIO_10_1 = 250541448375047931186413801569; + + address constant TREASURY = address(0x1234567890123456789012345678901234567890); + uint128 private constant TOTAL_BIPS = 10000; + + HookEnabledSwapRouter router; + TestERC20 token0; + TestERC20 token1; + PoolId id; + + MiddlewareRemoveFactory factory; + + function setUp() public { + deployFreshManagerAndRouters(); + (currency0, currency1) = deployMintAndApprove2Currencies(); + + router = new HookEnabledSwapRouter(manager); + token0 = TestERC20(Currency.unwrap(currency0)); + token1 = TestERC20(Currency.unwrap(currency1)); + + token0.approve(address(router), type(uint256).max); + token1.approve(address(router), type(uint256).max); + + factory = new MiddlewareRemoveFactory(manager); + } + + function testVariousE() public { + FeeTakingLite feeTakingLite = new FeeTakingLite(manager); + uint160 flags = + uint160(Hooks.AFTER_SWAP_FLAG | Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG | Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG); + (address hookAddress, bytes32 salt) = HookMiner.find( + address(factory), + flags, + type(MiddlewareRemove).creationCode, + abi.encode(address(manager), address(feeTakingLite)) + ); + testOn(address(feeTakingLite), salt); + HooksRevert hooksRevert = new HooksRevert(manager); + flags = uint160(Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG | Hooks.AFTER_REMOVE_LIQUIDITY_FLAG); + (hookAddress, salt) = HookMiner.find( + address(factory), + flags, + type(MiddlewareRemove).creationCode, + abi.encode(address(manager), address(hooksRevert)) + ); + testOn(address(hooksRevert), salt); + HooksOutOfGas hooksOutOfGas = new HooksOutOfGas(manager); + flags = uint160(Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG | Hooks.AFTER_REMOVE_LIQUIDITY_FLAG); + (hookAddress, salt) = HookMiner.find( + address(factory), + flags, + type(MiddlewareRemove).creationCode, + abi.encode(address(manager), address(hooksOutOfGas)) + ); + testOn(address(hooksOutOfGas), salt); + } + + // creates a middleware on an implementation + function testOn(address implementation, bytes32 salt) internal { + address hookAddress = factory.createMiddleware(implementation, salt); + MiddlewareRemove middlewareRemove = MiddlewareRemove(payable(hookAddress)); + + (key, id) = initPoolAndAddLiquidity( + currency0, currency1, IHooks(address(middlewareRemove)), 3000, SQRT_PRICE_1_1, ZERO_BYTES + ); + + removeLiquidity(currency0, currency1, IHooks(address(middlewareRemove)), 3000, SQRT_PRICE_1_1, ZERO_BYTES); + } +} diff --git a/test/RemoveMiddleware.txt b/test/RemoveMiddleware.txt index bfaaf25f..eb5db684 100644 --- a/test/RemoveMiddleware.txt +++ b/test/RemoveMiddleware.txt @@ -3,9 +3,9 @@ pragma solidity ^0.8.19; import {Test} from "forge-std/Test.sol"; import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol"; -import {FeeTakingLite} from "../contracts/hooks/middleware/test/FeeTakingLite.sol"; -import {HooksRevert} from "../contracts/hooks/middleware/test/HooksRevert.sol"; -import {MiddlewareRemove} from "../contracts/hooks/middleware/MiddlewareRemove.sol"; +import {FeeTakingLite} from "../contracts/middleware/test/FeeTakingLite.sol"; +import {HooksRevert} from "../contracts/middleware/test/HooksRevert.sol"; +import {MiddlewareRemove} from "../contracts/middleware/MiddlewareRemove.sol"; import {MiddlewareRemoveImplementation} from "./shared/implementation/MiddlewareRemoveImplementation.sol"; import {PoolManager} from "@uniswap/v4-core/src/PoolManager.sol"; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; diff --git a/test/shared/implementation/BaseMiddlewareImplementation.sol b/test/shared/implementation/BaseMiddlewareImplementation.sol index 9e598630..db954fc6 100644 --- a/test/shared/implementation/BaseMiddlewareImplementation.sol +++ b/test/shared/implementation/BaseMiddlewareImplementation.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; import {BaseHook} from "../../../contracts/BaseHook.sol"; -import {BaseMiddleware} from "../../../contracts/hooks/middleware/BaseMiddleware.sol"; +import {BaseMiddleware} from "../../../contracts/middleware/BaseMiddleware.sol"; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol"; import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol"; diff --git a/test/shared/implementation/FeeTakingLiteImplementation.sol b/test/shared/implementation/FeeTakingLiteImplementation.sol index 39742eb5..51d2cd0f 100644 --- a/test/shared/implementation/FeeTakingLiteImplementation.sol +++ b/test/shared/implementation/FeeTakingLiteImplementation.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; import {BaseHook} from "../../../contracts/BaseHook.sol"; -import {FeeTakingLite} from "../../../contracts/hooks/middleware/test/FeeTakingLite.sol"; +import {FeeTakingLite} from "../../../contracts/middleware/test/FeeTakingLite.sol"; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol"; diff --git a/test/shared/implementation/MiddlewareRemoveImplementation.sol b/test/shared/implementation/MiddlewareRemoveImplementation.sol index 38ab6dcf..33a190ac 100644 --- a/test/shared/implementation/MiddlewareRemoveImplementation.sol +++ b/test/shared/implementation/MiddlewareRemoveImplementation.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; import {BaseHook} from "../../../contracts/BaseHook.sol"; -import {MiddlewareRemove} from "../../../contracts/hooks/middleware/MiddlewareRemove.sol"; +import {MiddlewareRemove} from "../../../contracts/middleware/MiddlewareRemove.sol"; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol"; import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol"; diff --git a/test/utils/HookMiner.sol b/test/utils/HookMiner.sol new file mode 100644 index 00000000..d6b30c40 --- /dev/null +++ b/test/utils/HookMiner.sol @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.21; + +/// @title HookMiner - a library for mining hook addresses +/// @dev This library is intended for `forge test` environments. There may be gotchas when using salts in `forge script` or `forge create` +library HookMiner { + // mask to slice out the bottom 14 bit of the address + uint160 constant FLAG_MASK = 0x3FFF; + + // Maximum number of iterations to find a salt, avoid infinite loops + uint256 constant MAX_LOOP = 100_000; + + /// @notice Find a salt that produces a hook address with the desired `flags` + /// @param deployer The address that will deploy the hook. In `forge test`, this will be the test contract `address(this)` or the pranking address + /// In `forge script`, this should be `0x4e59b44847b379578588920cA78FbF26c0B4956C` (CREATE2 Deployer Proxy) + /// @param flags The desired flags for the hook address + /// @param creationCode The creation code of a hook contract. Example: `type(Counter).creationCode` + /// @param constructorArgs The encoded constructor arguments of a hook contract. Example: `abi.encode(address(manager))` + /// @return hookAddress salt and corresponding address that was found. The salt can be used in `new Hook{salt: salt}()` + function find(address deployer, uint160 flags, bytes memory creationCode, bytes memory constructorArgs) + internal + view + returns (address, bytes32) + { + address hookAddress; + bytes memory creationCodeWithArgs = abi.encodePacked(creationCode, constructorArgs); + + uint256 salt; + for (salt; salt < MAX_LOOP; salt++) { + hookAddress = computeAddress(deployer, salt, creationCodeWithArgs); + if (uint160(hookAddress) & FLAG_MASK == flags && hookAddress.code.length == 0) { + return (hookAddress, bytes32(salt)); + } + } + revert("HookMiner: could not find salt"); + } + + /// @notice Precompute a contract address deployed via CREATE2 + /// @param deployer The address that will deploy the hook. In `forge test`, this will be the test contract `address(this)` or the pranking address + /// In `forge script`, this should be `0x4e59b44847b379578588920cA78FbF26c0B4956C` (CREATE2 Deployer Proxy) + /// @param salt The salt used to deploy the hook + /// @param creationCode The creation code of a hook contract + function computeAddress(address deployer, uint256 salt, bytes memory creationCode) + internal + pure + returns (address hookAddress) + { + return address( + uint160(uint256(keccak256(abi.encodePacked(bytes1(0xFF), deployer, salt, keccak256(creationCode))))) + ); + } +}