UniswapV4SwapperAdapter
Inherits: ISwapper
Title: UniswapV4SwapperAdapter
Author: Golem Foundation
ISwapper adapter for Uniswap V4 exact-input swaps via the singleton PoolManager
Supports both single-hop and multi-hop (via intermediate base token) swaps,
mirroring the routing logic of UniswapV3SwapperAdapter.
Single-hop: tokenIn --(fee/tickSpacing/hooks)--> tokenOut
Multi-hop: tokenIn --(fee/tickSpacing/hooks)--> base --(feeOut/tickSpacingOut/hooksOut)--> tokenOut
The routing mode is determined by the base constructor parameter:
- base == address(0): always single-hop
- base != address(0): multi-hop unless tokenIn or tokenOut IS the base token, in which case it falls back to single-hop with the appropriate pool config Settlement uses V4's sync/transfer/settle pattern for input tokens and take() for output tokens. No ERC20 approvals are needed. Uniswap V4 PoolManager on Ethereum mainnet: 0x000000000004444c5dc75cB358380D2e3dE08A90 This contract is fully immutable and holds no tokens between calls.
Note: security-contact: [email protected]
Quick Start - What Matters Most
Uniswap V4 adapter for the ISwapper pull pattern. It uses PoolManager unlock flows and supports configured single-hop or multihop routes while returning unused balances.
State Variables
MIN_SQRT_PRICE_LIMIT
Minimum sqrt price limit for V4 swaps (TickMath.MIN_SQRT_PRICE + 1)
uint160 internal constant MIN_SQRT_PRICE_LIMIT = 4295128740
MAX_SQRT_PRICE_LIMIT
Maximum sqrt price limit for V4 swaps (TickMath.MAX_SQRT_PRICE - 1)
uint160 internal constant MAX_SQRT_PRICE_LIMIT = 1461446703485210103287273052203988822378723970341
poolManager
The Uniswap V4 PoolManager singleton address
address public immutable poolManager
fee
Fee tier for direct swaps or the first hop (tokenIn -> base)
uint24 public immutable fee
tickSpacing
Tick spacing for direct swaps or the first hop
int24 public immutable tickSpacing
hooks
Hooks address for direct swaps or the first hop (address(0) = no hooks)
address public immutable hooks
base
Optional intermediate token for multi-hop routing (address(0) = direct swap)
address public immutable base
feeOut
Fee tier for the second hop (base -> tokenOut), only used when base != address(0)
uint24 public immutable feeOut
tickSpacingOut
Tick spacing for the second hop, only used when base != address(0)
int24 public immutable tickSpacingOut
hooksOut
Hooks address for the second hop (address(0) = no hooks)
address public immutable hooksOut
Functions
constructor
Creates a UniswapV4SwapperAdapter with fixed routing configuration
constructor(
address _poolManager,
uint24 _fee,
int24 _tickSpacing,
address _hooks,
address _base,
uint24 _feeOut,
int24 _tickSpacingOut,
address _hooksOut
) ;
Parameters
| Name | Type | Description |
|---|---|---|
_poolManager | address | Address of the Uniswap V4 PoolManager singleton |
_fee | uint24 | Fee tier for direct swaps or first hop |
_tickSpacing | int24 | Tick spacing for direct swaps or first hop |
_hooks | address | Hooks address for direct swaps or first hop (address(0) = no hooks) |
_base | address | Optional base token for multi-hop routing (address(0) for direct swaps) |
_feeOut | uint24 | Fee tier for second hop when using multi-hop (ignored if _base is address(0)) |
_tickSpacingOut | int24 | Tick spacing for second hop (ignored if _base is address(0)) |
_hooksOut | address | Hooks address for second hop (ignored if _base is address(0)) |
swap
Execute a token swap and send output to receiver
The caller MUST have approved this contract for at least amountIn
of tokenIn before calling. The implementation pulls via
transferFrom(msg.sender, this, amountIn) and returns any unused
tokenIn to msg.sender before returning.
Reverts if output is less than minAmountOut.
function swap(address tokenIn, address tokenOut, uint256 amountIn, uint256 minAmountOut, address receiver)
external
override
returns (uint256 amountOut);
Parameters
| Name | Type | Description |
|---|---|---|
tokenIn | address | Address of the input token |
tokenOut | address | Address of the output token |
amountIn | uint256 | Maximum amount of tokenIn to pull from msg.sender |
minAmountOut | uint256 | Minimum acceptable output amount (reverts if not met) |
receiver | address | Address to receive the output tokens |
Returns
| Name | Type | Description |
|---|---|---|
amountOut | uint256 | Actual amount of tokenOut sent to receiver |
unlockCallback
Callback invoked by PoolManager during unlock(); executes swaps and settles
Only callable by the PoolManager. Reverts with UnauthorizedCallback otherwise.
function unlockCallback(bytes calldata data) external returns (bytes memory);
Parameters
| Name | Type | Description |
|---|---|---|
data | bytes | ABI-encoded (originalCaller, tokenIn, tokenOut, amountIn, minAmountOut, receiver) |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bytes | ABI-encoded amountOut |
_singleHop
Execute a single-hop exact-input swap
function _singleHop(address tokenIn, address tokenOut, uint256 amountIn)
internal
returns (uint256 amountOut, uint256 consumed);
Returns
| Name | Type | Description |
|---|---|---|
amountOut | uint256 | Amount of output token received |
consumed | uint256 | Amount of tokenIn actually consumed by the pool |
_multiHop
Execute a two-hop exact-input swap: tokenIn → base → tokenOut. Base token deltas net to zero when hop 2 consumes the full hop-1 output; otherwise the unused base is returned to the original caller.
function _multiHop(address tokenIn, address tokenOut, uint256 amountIn)
internal
returns (uint256 amountOut, uint256 consumed, uint256 unusedBase);
Returns
| Name | Type | Description |
|---|---|---|
amountOut | uint256 | Final output amount |
consumed | uint256 | tokenIn consumed by hop 1 (may be less than amountIn on a shallow pool) |
unusedBase | uint256 | base token produced by hop 1 but not consumed by hop 2 |
Errors
InvalidPoolManager
Thrown when the PoolManager address is zero
error InvalidPoolManager();
InvalidToken
Thrown when a token address is zero
error InvalidToken();
InvalidTickSpacing
Thrown when tickSpacing is zero (invalid V4 pool configuration)
error InvalidTickSpacing();
UnauthorizedCallback
Thrown when the callback caller is not the PoolManager
error UnauthorizedCallback();
InsufficientOutput
Thrown when the swap output is less than the minimum required
error InsufficientOutput(uint256 expected, uint256 actual);
Parameters
| Name | Type | Description |
|---|---|---|
expected | uint256 | Minimum amount expected |
actual | uint256 | Amount actually received |