IUniswapV3Adapter
Title: IUniswapV3Adapter
Authors: David Dada <daveproxy80@gmail.com> (https://github.com/dadadave80), Modified from Uniswap V3 (https://github.com/Uniswap/v3-periphery)
Uniswap-V3-specific config ABI. The adapter also implements IStrategy +
IProtocolAdapter. A CUSTOM adapter: a Uniswap V3 LP is a two-token, NFT-wrapped
concentrated-liquidity position, which does not map cleanly onto the single-asset
IStrategy surface. The adapter pins the position to full-range (min/max usable
ticks) so there is no active range management, and the adapter's asset is token0
(the vault-facing accounting token).
Valuation (the central risk). NAV is computed from the pool's TWAP
(pool.observe over twapWindow), NEVER from slot0 spot — the spot tick is
single-block manipulable, so reading it for share pricing would let an attacker mint/burn
vault shares at a flash-loan-skewed price. The TWAP tick is converted to a sqrt price and
the position's token0 leg is derived at that price.
NAV is token0 only. The vault can only ever receive token0, so NAV is idle token0 plus
the position's token0 leg. token1 is never counted, whether idle in the adapter or in the
position's token1 leg, so NAV never includes value a redeemer cannot receive. See
UniswapV3AdapterLib.totalAssetsManaged.
Swap-free. The adapter never swaps. The keeper supplies BOTH token0 and token1 to the
adapter before deploy; the adapter only adds/removes liquidity. The keeper's token1 never
enters NAV. Accrued fees (token0 + token1) are routed RAW to rewardRecipient on harvest;
idle balances never are.
Deploy bound. The pool prices a mint at spot while NAV counts the new token0 leg at the
TWAP, so a deploy steps NAV by about consumed0 × (√(P_spot / P_twap) − 1): flat only at
spot == TWAP. deploy runs inside the permissionless rebalance(), so it refuses a step larger
than slippageBps of the token0 consumed (UniswapV3AdapterDeployOffTwap). Within that bound
an attacker who moves spot can still choose the step.
Withdraw pays idle token0 only. IStrategy.withdraw(amount, to) is denominated in
token0 and sends only the adapter's idle token0; it never removes liquidity (a decrease pays
out at spot against the TWAP-counted leg, which the StrategyManager's value-loss check would
reject whenever spot sits above the TWAP). It is shortfall-honest: it returns the REAL
token0 delta and never over-reports; the StrategyManager accepts the partial recall.
Exit. rebalance() can allocate into the position but never recall from it, so capital
allocated here reaches redeemers only after the admin's emergencyWithdraw. At a target of 0
a rebalance recalls the idle token0, the token0 leg stays counted, and removeStrategy
refuses. The admin's emergencyWithdraw removes the position and sends both tokens to the
vault, and the strategy can then be removed. The token0 replaces the counted leg but is paid at
spot with no floor, so NAV steps by about leg0 × (√(P_twap / P_spot) − 1): exit while spot
sits near the TWAP. The token1 lands in the vault outside NAV; VaultCore has no sweep for a
non-asset token.
Functions
positionManager
Returns the Uniswap V3 NonfungiblePositionManager.
function positionManager() external view returns (address);Returns
| Name | Type | Description |
|---|---|---|
| <none> | address |
pool
Returns the Uniswap V3 pool the adapter LPs into.
function pool() external view returns (address);Returns
| Name | Type | Description |
|---|---|---|
| <none> | address |
token0
Returns the pool's token0 (== the adapter's asset, the vault-facing accounting token).
function token0() external view returns (address);Returns
| Name | Type | Description |
|---|---|---|
| <none> | address |
token1
Returns the pool's token1 (supplied by the keeper, never swapped by the adapter).
function token1() external view returns (address);Returns
| Name | Type | Description |
|---|---|---|
| <none> | address |
fee
Returns the pool fee tier (hundredths of a bip).
function fee() external view returns (uint24);Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint24 |
tokenId
Returns the current position NFT id (0 == no position minted yet).
function tokenId() external view returns (uint256);Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint256 |
vault
Returns the Lattice vault funds are returned to on emergency exit.
function vault() external view returns (address);Returns
| Name | Type | Description |
|---|---|---|
| <none> | address |
twapWindow
Returns the TWAP observation window (seconds) used for valuation.
function twapWindow() external view returns (uint32);Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint32 |
slippageBps
Returns the configured slippage tolerance in basis points.
function slippageBps() external view returns (uint256);Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint256 |
setTwapWindow
Sets the TWAP observation window in seconds (admin only). Must be non-zero.
function setTwapWindow(uint32 twapWindow) external;Parameters
| Name | Type | Description |
|---|---|---|
| twapWindow | uint32 |
setSlippageBps
Sets the slippage tolerance in basis points (admin only).
function setSlippageBps(uint256 slippageBps) external;Parameters
| Name | Type | Description |
|---|---|---|
| slippageBps | uint256 |
setRewardRecipient
Sets the reward recipient (admin only).
function setRewardRecipient(address recipient) external;Parameters
| Name | Type | Description |
|---|---|---|
| recipient | address |
Events
UniswapV3AdapterConfigured
Emitted once at init with the core wiring.
event UniswapV3AdapterConfigured(
address indexed positionManager, address indexed pool, address token0, address indexed token1, uint24 fee
);Parameters
| Name | Type | Description |
|---|---|---|
| positionManager | address | The Uniswap V3 NonfungiblePositionManager. |
| pool | address | The Uniswap V3 pool the position LPs into. |
| token0 | address | The pool's token0 (== the adapter's asset). |
| token1 | address | The pool's token1. |
| fee | uint24 | The pool fee tier. |
UniswapV3PositionMinted
Emitted when the full-range position NFT is first minted.
event UniswapV3PositionMinted(uint256 indexed tokenId, uint128 liquidity);Parameters
| Name | Type | Description |
|---|---|---|
| tokenId | uint256 | The minted position id. |
| liquidity | uint128 | The initial liquidity added. |
UniswapV3TwapWindowSet
Emitted when the TWAP observation window is changed.
event UniswapV3TwapWindowSet(uint32 twapWindow);Parameters
| Name | Type | Description |
|---|---|---|
| twapWindow | uint32 |
UniswapV3SlippageSet
Emitted when the slippage tolerance (bps) is changed.
event UniswapV3SlippageSet(uint256 slippageBps);Parameters
| Name | Type | Description |
|---|---|---|
| slippageBps | uint256 |
Errors
UniswapV3AdapterPoolMismatch
The reward recipient is announced via IProtocolAdapter.RewardRecipientSet (shared with
the generic adapter ABI) — not redeclared here to avoid an event-name collision when the
facet inherits both interfaces.
The pool's token0/token1/fee do not match the configured values.
error UniswapV3AdapterPoolMismatch();UniswapV3AdapterSlippageTooHigh
The supplied slippage tolerance exceeds the allowed maximum (bps).
error UniswapV3AdapterSlippageTooHigh(uint256 slippageBps, uint256 maxBps);Parameters
| Name | Type | Description |
|---|---|---|
| slippageBps | uint256 | |
| maxBps | uint256 |
UniswapV3AdapterTwapWindowZero
The supplied TWAP window is zero (an instantaneous "TWAP" is just spot — disallowed).
error UniswapV3AdapterTwapWindowZero();UniswapV3AdapterBadTickSpacing
The pool reported a non-positive tick spacing (cannot align a full-range position).
error UniswapV3AdapterBadTickSpacing(int24 tickSpacing);Parameters
| Name | Type | Description |
|---|---|---|
| tickSpacing | int24 |
UniswapV3AdapterPositionsCallFailed
The position manager's positions() call failed or returned short data.
error UniswapV3AdapterPositionsCallFailed(uint256 tokenId);Parameters
| Name | Type | Description |
|---|---|---|
| tokenId | uint256 | The adapter's position NFT id. |
UniswapV3AdapterDeployOffTwap
A deploy consumed consumed0 token0 at the pool's spot price, but the liquidity it added holds
counted0 token0 at the TWAP, and the gap exceeds slippageBps of consumed0. Spot is too far
from the TWAP: deploying would step the vault's NAV by that gap.
error UniswapV3AdapterDeployOffTwap(uint256 consumed0, uint256 counted0);Parameters
| Name | Type | Description |
|---|---|---|
| consumed0 | uint256 | The token0 the mint or increase took from the adapter. |
| counted0 | uint256 | The token0 the added liquidity holds at the TWAP price, as NAV counts it. |