Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Base Hook Middleware #140

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions contracts/BaseHook.sol
Original file line number Diff line number Diff line change
Expand Up @@ -72,22 +72,22 @@ abstract contract BaseHook is IHooks, SafeCallback {
revert HookNotImplemented();
}

function beforeRemoveLiquidity(
function afterAddLiquidity(
address,
PoolKey calldata,
IPoolManager.ModifyLiquidityParams calldata,
BalanceDelta,
bytes calldata
) external virtual returns (bytes4) {
) external virtual returns (bytes4, BalanceDelta) {
revert HookNotImplemented();
}

function afterAddLiquidity(
function beforeRemoveLiquidity(
address,
PoolKey calldata,
IPoolManager.ModifyLiquidityParams calldata,
BalanceDelta,
bytes calldata
) external virtual returns (bytes4, BalanceDelta) {
) external virtual returns (bytes4) {
revert HookNotImplemented();
}

Expand Down
9 changes: 9 additions & 0 deletions contracts/interfaces/IBaseHook.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol";
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";

interface IBaseHook is IHooks {
function getHookPermissions() external pure returns (Hooks.Permissions memory);
}
8 changes: 8 additions & 0 deletions contracts/interfaces/IBaseImplementation.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;

import {IBaseHook} from "./IBaseHook.sol";

interface IBaseImplementation is IBaseHook {
function initializeMiddleware(address _middleware) external;
}
17 changes: 17 additions & 0 deletions contracts/interfaces/IMiddlewareFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;

interface IMiddlewareFactory {
event MiddlewareCreated(address implementation, address middleware);

/// @notice Returns the implementation address for a given middleware
/// @param middleware The middleware address
/// @return implementation The implementation address
function getImplementation(address middleware) external view returns (address implementation);

/// @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, bytes32 salt) external returns (address middleware);
}
148 changes: 148 additions & 0 deletions contracts/middleware/BaseImplementation.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol";
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
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 {SafeCallback} from "./../base/SafeCallback.sol";
import {ImmutableState} from "./../base/ImmutableState.sol";

abstract contract BaseImplementation is IHooks, SafeCallback {
error NotSelf();
error InvalidPool();
error LockFailure();
error HookNotImplemented();
error NotMiddleware();
error NotMiddlewareFactory();

address public immutable middlewareFactory;
address public middleware;

constructor(IPoolManager _manager, address _middlewareFactory) ImmutableState(_manager) {
middlewareFactory = _middlewareFactory;
}

/// @dev Only this address may call this function
modifier selfOnly() {
if (msg.sender != address(this)) revert NotSelf();
_;
}

/// @dev Only pools with hooks set to this contract may call this function
modifier onlyValidPools(IHooks hooks) {
if (hooks != this) revert InvalidPool();
_;
}

modifier onlyByMiddleware() {
if (msg.sender != middleware) revert NotMiddleware();
_;
}

function initializeMiddleware(address _middleware) external {
if (msg.sender != middlewareFactory) revert NotMiddlewareFactory();
middleware = _middleware;
}

function updateDynamicFee(PoolKey calldata key, uint24 fee) external {
if (msg.sender != middlewareFactory) revert NotMiddlewareFactory();
manager.updateDynamicLPFee(key, fee);
}

function getHookPermissions() public pure virtual returns (Hooks.Permissions memory);

function _unlockCallback(bytes calldata data) internal virtual override returns (bytes memory) {
(bool success, bytes memory returnData) = address(this).call(data);
if (success) return returnData;
if (returnData.length == 0) revert LockFailure();
// if the call failed, bubble up the reason
/// @solidity memory-safe-assembly
assembly {
revert(add(returnData, 32), mload(returnData))
}
}

function beforeInitialize(address, PoolKey calldata, uint160, bytes calldata) external virtual returns (bytes4) {
revert HookNotImplemented();
}

function afterInitialize(address, PoolKey calldata, uint160, int24, bytes calldata)
external
virtual
returns (bytes4)
{
revert HookNotImplemented();
}

function beforeAddLiquidity(address, PoolKey calldata, IPoolManager.ModifyLiquidityParams calldata, bytes calldata)
external
virtual
returns (bytes4)
{
revert HookNotImplemented();
}

function beforeRemoveLiquidity(
address,
PoolKey calldata,
IPoolManager.ModifyLiquidityParams calldata,
bytes calldata
) external virtual returns (bytes4) {
revert HookNotImplemented();
}

function afterAddLiquidity(
address,
PoolKey calldata,
IPoolManager.ModifyLiquidityParams calldata,
BalanceDelta,
bytes calldata
) external virtual returns (bytes4, BalanceDelta) {
revert HookNotImplemented();
}

function afterRemoveLiquidity(
address,
PoolKey calldata,
IPoolManager.ModifyLiquidityParams calldata,
BalanceDelta,
bytes calldata
) external virtual returns (bytes4, BalanceDelta) {
revert HookNotImplemented();
}

function beforeSwap(address, PoolKey calldata, IPoolManager.SwapParams calldata, bytes calldata)
external
virtual
returns (bytes4, BeforeSwapDelta, uint24)
{
revert HookNotImplemented();
}

function afterSwap(address, PoolKey calldata, IPoolManager.SwapParams calldata, BalanceDelta, bytes calldata)
external
virtual
returns (bytes4, int128)
{
revert HookNotImplemented();
}

function beforeDonate(address, PoolKey calldata, uint256, uint256, bytes calldata)
external
virtual
returns (bytes4)
{
revert HookNotImplemented();
}

function afterDonate(address, PoolKey calldata, uint256, uint256, bytes calldata)
external
virtual
returns (bytes4)
{
revert HookNotImplemented();
}
}
153 changes: 153 additions & 0 deletions contracts/middleware/BaseMiddleware.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol";
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
import {IBaseHook} from "./../interfaces/IBaseHook.sol";
import {BaseHook} from "./../BaseHook.sol";
import {BalanceDelta, BalanceDeltaLibrary} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
import {BeforeSwapDelta, BeforeSwapDeltaLibrary} from "@uniswap/v4-core/src/types/BeforeSwapDelta.sol";

contract BaseMiddleware is IHooks {
using Hooks for BaseMiddleware;
using BeforeSwapDeltaLibrary for BeforeSwapDelta;

error NotManager();

IPoolManager public immutable manager;
IBaseHook public immutable implementation;

constructor(IPoolManager _manager, IBaseHook _implementation) {
manager = _manager;
implementation = _implementation;
}

modifier onlyByManager() {
if (msg.sender != address(manager)) revert NotManager();
_;
}

function getHookPermissions() public view returns (Hooks.Permissions memory) {
return implementation.getHookPermissions();
}

function beforeInitialize(address sender, PoolKey calldata key, uint160 sqrtPriceX96, bytes calldata hookData)
external
virtual
onlyByManager
returns (bytes4)
{
if (msg.sender == address(implementation)) return BaseHook.beforeInitialize.selector;
return implementation.beforeInitialize(sender, key, sqrtPriceX96, hookData);
}

function afterInitialize(
address sender,
PoolKey calldata key,
uint160 sqrtPriceX96,
int24 tick,
bytes calldata hookData
) external virtual onlyByManager returns (bytes4) {
if (msg.sender == address(implementation)) return BaseHook.afterInitialize.selector;
return implementation.afterInitialize(sender, key, sqrtPriceX96, tick, hookData);
}

function beforeAddLiquidity(
address sender,
PoolKey calldata key,
IPoolManager.ModifyLiquidityParams calldata params,
bytes calldata hookData
) external virtual onlyByManager returns (bytes4) {
if (msg.sender == address(implementation)) return BaseHook.beforeAddLiquidity.selector;
return implementation.beforeAddLiquidity(sender, key, params, hookData);
}

function afterAddLiquidity(
address sender,
PoolKey calldata key,
IPoolManager.ModifyLiquidityParams calldata params,
BalanceDelta delta,
bytes calldata hookData
) external virtual onlyByManager returns (bytes4, BalanceDelta) {
if (msg.sender == address(implementation)) {
return (BaseHook.afterAddLiquidity.selector, BalanceDeltaLibrary.ZERO_DELTA);
}
return implementation.afterAddLiquidity(sender, key, params, delta, hookData);
}

function beforeRemoveLiquidity(
address sender,
PoolKey calldata key,
IPoolManager.ModifyLiquidityParams calldata params,
bytes calldata hookData
) external virtual onlyByManager returns (bytes4) {
if (msg.sender == address(implementation)) return BaseHook.beforeRemoveLiquidity.selector;
return implementation.beforeRemoveLiquidity(sender, key, params, hookData);
}

function afterRemoveLiquidity(
address sender,
PoolKey calldata key,
IPoolManager.ModifyLiquidityParams calldata params,
BalanceDelta delta,
bytes calldata hookData
) external virtual onlyByManager returns (bytes4, BalanceDelta) {
if (msg.sender == address(implementation)) {
return (BaseHook.afterRemoveLiquidity.selector, BalanceDeltaLibrary.ZERO_DELTA);
}
return implementation.afterRemoveLiquidity(sender, key, params, delta, hookData);
}

function beforeSwap(
address sender,
PoolKey calldata key,
IPoolManager.SwapParams calldata params,
bytes calldata hookData
) external virtual onlyByManager returns (bytes4 selector, BeforeSwapDelta beforeSwapDelta, uint24 lpFeeOverride) {
if (msg.sender == address(implementation)) {
return (BaseHook.beforeSwap.selector, BeforeSwapDeltaLibrary.ZERO_DELTA, 0);
}
(selector, beforeSwapDelta, lpFeeOverride) = implementation.beforeSwap(sender, key, params, hookData);
if (this.hasPermission(Hooks.BEFORE_SWAP_RETURNS_DELTA_FLAG)) {
manager.take(key.currency0, sender, uint256(uint128(beforeSwapDelta.getSpecifiedDelta())));
manager.take(key.currency1, sender, uint256(uint128(beforeSwapDelta.getUnspecifiedDelta())));
}
}

function afterSwap(
address sender,
PoolKey calldata key,
IPoolManager.SwapParams calldata params,
BalanceDelta delta,
bytes calldata hookData
) external virtual onlyByManager returns (bytes4, int128) {
if (msg.sender == address(implementation)) {
return (BaseHook.afterSwap.selector, 0);
}
return implementation.afterSwap(sender, key, params, delta, hookData);
}

function beforeDonate(
address sender,
PoolKey calldata key,
uint256 amount0,
uint256 amount1,
bytes calldata hookData
) external virtual onlyByManager returns (bytes4) {
if (msg.sender == address(implementation)) return BaseHook.beforeDonate.selector;
return implementation.beforeDonate(sender, key, amount0, amount1, hookData);
}

function afterDonate(
address sender,
PoolKey calldata key,
uint256 amount0,
uint256 amount1,
bytes calldata hookData
) external virtual onlyByManager returns (bytes4) {
if (msg.sender == address(implementation)) return BaseHook.afterDonate.selector;
return implementation.afterDonate(sender, key, amount0, amount1, hookData);
}
}
Loading
Loading