```solidity
-import "uniswap-hooks/src/base/BaseAsyncSwap.sol";
+import "@openzeppelin/src/base/BaseAsyncSwap.sol";
```
Base implementation for async swaps, which skip the v3-like swap implementation of the `PoolManager`
@@ -51,7 +51,6 @@ _Available since v0.1.0_
-
-Restrict the function to only be called for a valid pool.
-
-
-
-
@@ -1152,7 +1052,7 @@ Restrict the function to only be called for a valid pool.
-Set the pool manager and check that the hook address matches the expected permissions and flags.
+Check that the hook address matches the expected permissions and flags.
@@ -1538,40 +1438,6 @@ flag must be set to true in the `getHookPermissions` function.
```solidity
-import "uniswap-hooks/src/fee/BaseDynamicAfterFee.sol";
+import "@openzeppelin/src/fee/BaseDynamicAfterFee.sol";
```
Base implementation for dynamic target hook fees applied after swaps.
Enables to enforce a dynamic target determined by [`BaseDynamicAfterFee._getTargetUnspecified`](#BaseDynamicAfterFee-_getTargetUnspecified-address-struct-PoolKey-struct-SwapParams-bytes-) for the unspecified currency of the swap
-during [`BaseAsyncSwap._beforeSwap`](/uniswap-hooks/api/base#BaseAsyncSwap-_beforeSwap-address-struct-PoolKey-struct-SwapParams-bytes-), where if the swap outcome results better than the target, any positive difference is taken
+during [`BaseAsyncSwap._beforeSwap`](base#BaseAsyncSwap-_beforeSwap-address-struct-PoolKey-struct-SwapParams-bytes-), where if the swap outcome results better than the target, any positive difference is taken
as a hook fee, being posteriorily handled or distributed by the hook via [`BaseDynamicAfterFee._afterSwapHandler`](#BaseDynamicAfterFee-_afterSwapHandler-struct-PoolKey-struct-SwapParams-BalanceDelta-uint256-uint256-).
@@ -45,7 +45,6 @@ _Available since v0.1.0_
- [_transientApplyTarget()](#BaseDynamicAfterFee-_transientApplyTarget--)
- [_setTransientTargetUnspecifiedAmount(value)](#BaseDynamicAfterFee-_setTransientTargetUnspecifiedAmount-uint256-)
- [_setTransientApplyTarget(value)](#BaseDynamicAfterFee-_setTransientApplyTarget-bool-)
-- [constructor(_poolManager)](#BaseDynamicAfterFee-constructor-contract-IPoolManager-)
- [_beforeSwap(sender, key, params, hookData)](#BaseDynamicAfterFee-_beforeSwap-address-struct-PoolKey-struct-SwapParams-bytes-)
- [_afterSwap(sender, key, params, delta, )](#BaseDynamicAfterFee-_afterSwap-address-struct-PoolKey-struct-SwapParams-BalanceDelta-bytes-)
- [_getTargetUnspecified(sender, key, params, hookData)](#BaseDynamicAfterFee-_getTargetUnspecified-address-struct-PoolKey-struct-SwapParams-bytes-)
@@ -95,8 +94,6 @@ _Available since v0.1.0_
#### IHookEvents [!toc]
#### BaseHook [!toc]
-- [NotSelf()](#BaseHook-NotSelf--)
-- [InvalidPool()](#BaseHook-InvalidPool--)
- [HookNotImplemented()](#BaseHook-HookNotImplemented--)
- [NotPoolManager()](#BaseHook-NotPoolManager--)
#### IHooks [!toc]
@@ -171,23 +168,6 @@ Set the apply flag to be used in the `afterSwap` hook.
@@ -283,7 +263,7 @@ Customizable handler called after `_afterSwap` to handle or distribute the fees.
-Set the hook permissions, specifically [`BaseHook.beforeSwap`](/uniswap-hooks/api/base#BaseHook-beforeSwap-address-struct-PoolKey-struct-SwapParams-bytes-), [`BaseHook.afterSwap`](/uniswap-hooks/api/base#BaseHook-afterSwap-address-struct-PoolKey-struct-SwapParams-BalanceDelta-bytes-) and `afterSwapReturnDelta`.
+Set the hook permissions, specifically [`BaseHook.beforeSwap`](base#BaseHook-beforeSwap-address-struct-PoolKey-struct-SwapParams-bytes-), [`BaseHook.afterSwap`](base#BaseHook-afterSwap-address-struct-PoolKey-struct-SwapParams-BalanceDelta-bytes-) and `afterSwapReturnDelta`.
@@ -292,16 +272,16 @@ Set the hook permissions, specifically [`BaseHook.beforeSwap`](/uniswap-hooks/ap
```solidity
-import "uniswap-hooks/src/fee/BaseDynamicFee.sol";
+import "@openzeppelin/src/fee/BaseDynamicFee.sol";
```
Base implementation to apply a dynamic fee via the `PoolManager`'s `updateDynamicLPFee` function.
@@ -317,10 +297,9 @@ _Available since v0.1.0_
-Updates the dynamic LP fee for the given pool, which must have a key
-that contains this hook's address.
+Updates the dynamic LP fee for the given pool
-
-This function can be called by anyone at any time. If `_getFee` implementation
-depends on external conditions (e.g., oracle prices, other pool states, token balances),
-it may be vulnerable to manipulation. An attacker could potentially:
-1. Manipulate the external conditions that `_getFee` depends on
-2. Call `poke()` to update the fee to a more favorable rate
-3. Execute trades at the manipulated fee rate
+
+It can be called internally at any point in the pool's lifecycle to update the fee
+given the current market conditions. Alternatively, it can be wrapped and exposed publicly
+to be externally called by an authorized party. If exposed, it must be properly protected
+and access control is recommended.
-Inheriting contracts should consider implementing access controls on this function,
-make the logic in `_getFee` resistant to short-term manipulation, or accept the risk
-of fee manipulation.
-
@@ -477,45 +430,52 @@ The hook was attempted to be initialized with a non-dynamic fee.
-
+
```solidity
-import "uniswap-hooks/src/fee/BaseOverrideFee.sol";
+import "@openzeppelin/src/fee/BaseHookFee.sol";
```
-Base implementation for automatic dynamic fees applied before swaps.
+Base implementation for applying hook fees to the unspecified currency of the swap.
+These fees are independent of the pool's LP fee and are charged as a percentage of the output
+amount after the swap completes.
+
+
+It is left to the implementing contract to handle the accumulated hook fees, such as distributing
+or withdrawing them via ERC-6909 claims.
+
This is experimental software and is provided on an "as is" and "as available" basis. We do
-not give any warranties and will not be liable for any losses incurred through any use of this code
-base.
+not give any warranties and will not be liable for any losses incurred through any use of this code base.
-_Available since v0.1.0_
+_Available since v1.2.0_
+
+Get the fee to be applied after the swap. Takes the `address` `sender`, a `PoolKey` `key`,
+the `SwapParams` `params`, `BalanceDelta` `delta` and `hookData` as arguments and returns the `fee`
+to be applied in hundredths of a bip. i.e. 1000000 = 100%
+
+
+
+Hooks into the `afterSwap` hook to apply the hook fee to the unspecified currency.
+
+
+The fee is calculated as a percentage of the output amount and taken as ERC-6909 claims.
+
+
+
+
+```solidity
+import "@openzeppelin/src/fee/BaseOverrideFee.sol";
+```
+
+Base implementation for automatic dynamic fees applied before swaps.
+
+
+This is experimental software and is provided on an "as is" and "as available" basis. We do
+not give any warranties and will not be liable for any losses incurred through any use of this code
+base.
+
+
+_Available since v0.1.0_
+
+
@@ -650,3 +763,4 @@ The hook was attempted to be initialized with a non-dynamic fee.
+
diff --git a/content/uniswap-hooks/api/general.mdx b/content/uniswap-hooks/api/general.mdx
index 703fadb1..91ce2635 100644
--- a/content/uniswap-hooks/api/general.mdx
+++ b/content/uniswap-hooks/api/general.mdx
@@ -7,16 +7,16 @@ description: "Smart contract general utilities and implementations"
@@ -158,7 +140,7 @@ Handles the before swap hook.
For the first swap in a block, it saves the current pool state as a checkpoint.
For subsequent swaps in the same block, it calculates a target output based on the beginning-of-block state,
-and sets the inherited `_targetOutput` and `_applyTargetOutput` variables to enforce price limits in [`BaseHook._afterSwap`](/uniswap-hooks/api/base#BaseHook-_afterSwap-address-struct-PoolKey-struct-SwapParams-BalanceDelta-bytes-).
+and sets the inherited `_targetOutput` and `_applyTargetOutput` variables to enforce price limits in [`BaseHook._afterSwap`](base#BaseHook-_afterSwap-address-struct-PoolKey-struct-SwapParams-BalanceDelta-bytes-).
@@ -228,16 +210,16 @@ Set the hook permissions, specifically `beforeSwap`, `afterSwap`, and `afterSwap
```solidity
-import "uniswap-hooks/src/general/LimitOrderHook.sol";
+import "@openzeppelin/src/general/LimitOrderHook.sol";
```
The order id library.
@@ -289,16 +271,16 @@ Increment the order id `a`. Might overflow.
@@ -471,7 +433,7 @@ Hooks into the `afterSwap` hook to get the ticks crossed by the swap and fill th
Places a limit order by adding liquidity out of range at a specific tick. The order will be filled when the
pool price crosses the specified `tick`. Takes a `PoolKey` `key`, target `tick`, direction `zeroForOne` indicating
whether to buy currency0 or currency1, and amount of `liquidity` to place. The interaction with the `poolManager` is done
-via the `unlock` function, which will trigger the [`BaseCustomAccounting.unlockCallback`](/uniswap-hooks/api/base#BaseCustomAccounting-unlockCallback-bytes-) function.
+via the `unlock` function, which will trigger the `[`BaseCustomAccounting.unlockCallback`](base#BaseCustomAccounting-unlockCallback-bytes-)` function.
@@ -492,7 +454,7 @@ Cancels a limit order by removing liquidity from the pool. Takes a `PoolKey` `ke
direction `zeroForOne` indicating whether it was buying currency0 or currency1, and recipient address `to` for the
removed liquidity. Note that partial cancellation is not supported - the entire liquidity added by the msg.sender will be removed.
Note also that cancelling an order will cancel the order placed by the msg.sender, not orders placed by other users in the same tick range.
-The interaction with the `poolManager` is done via the `unlock` function, which will trigger the [`BaseCustomAccounting.unlockCallback`](/uniswap-hooks/api/base#BaseCustomAccounting-unlockCallback-bytes-) function.
+The interaction with the `poolManager` is done via the `unlock` function, which will trigger the `[`BaseCustomAccounting.unlockCallback`](base#BaseCustomAccounting-unlockCallback-bytes-)` function.
@@ -512,7 +474,7 @@ The interaction with the `poolManager` is done via the `unlock` function, which
Withdraws liquidity from a filled order, sending it to address `to`. Takes an `OrderId` `orderId` of the filled
order to withdraw from. Returns the withdrawn amounts as `(amount0, amount1)`. Can only be called after the order is
filled - use `cancelOrder` to remove liquidity from unfilled orders. The interaction with the `poolManager` is done via the
-`unlock` function, which will trigger the [`BaseCustomAccounting.unlockCallback`](/uniswap-hooks/api/base#BaseCustomAccounting-unlockCallback-bytes-) function.
+`unlock` function, which will trigger the `[`BaseCustomAccounting.unlockCallback`](base#BaseCustomAccounting-unlockCallback-bytes-)` function.
@@ -920,22 +882,22 @@ Limit order is not filled.
```solidity
-import "uniswap-hooks/src/general/LiquidityPenaltyHook.sol";
+import "@openzeppelin/src/general/LiquidityPenaltyHook.sol";
```
Just-in-Time (JIT) liquidity provisioning resistant hook.
-This hook disincentivizes JIT attacks by penalizing LP fee collection during [`BaseHook._afterRemoveLiquidity`](/uniswap-hooks/api/base#BaseHook-_afterRemoveLiquidity-address-struct-PoolKey-struct-ModifyLiquidityParams-BalanceDelta-BalanceDelta-bytes-),
-and disabling it during [`BaseHook._afterAddLiquidity`](/uniswap-hooks/api/base#BaseHook-_afterAddLiquidity-address-struct-PoolKey-struct-ModifyLiquidityParams-BalanceDelta-BalanceDelta-bytes-) if liquidity was recently added to the position.
+This hook disincentivizes JIT attacks by penalizing LP fee collection during [`BaseHook._afterRemoveLiquidity`](base#BaseHook-_afterRemoveLiquidity-address-struct-PoolKey-struct-ModifyLiquidityParams-BalanceDelta-BalanceDelta-bytes-),
+and disabling it during [`BaseHook._afterAddLiquidity`](base#BaseHook-_afterAddLiquidity-address-struct-PoolKey-struct-ModifyLiquidityParams-BalanceDelta-BalanceDelta-bytes-) if liquidity was recently added to the position.
The penalty is donated to the pool's liquidity providers in range at the time of removal.
See [`LiquidityPenaltyHook._calculateLiquidityPenalty`](#LiquidityPenaltyHook-_calculateLiquidityPenalty-BalanceDelta-uint48-) for penalty calculation.
@@ -970,7 +932,7 @@ _Available since v0.1.1_
-Sets the `PoolManager` address and the `getBlockNumberOffset`.
+Sets the `getBlockNumberOffset` and the [`BaseHook.poolManager`](base#BaseHook-poolManager-contract-IPoolManager) address.
@@ -1054,7 +1014,7 @@ Sets the `PoolManager` address and the `getBlockNumberOffset`.
Tracks `lastAddedLiquidityBlock` and withholds `feeDelta` if liquidity was recently added within
the `blockNumberOffset` period.
-See [`BaseHook._afterRemoveLiquidity`](/uniswap-hooks/api/base#BaseHook-_afterRemoveLiquidity-address-struct-PoolKey-struct-ModifyLiquidityParams-BalanceDelta-BalanceDelta-bytes-) for claiming the withheld fees back.
+See [`BaseHook._afterRemoveLiquidity`](base#BaseHook-_afterRemoveLiquidity-address-struct-PoolKey-struct-ModifyLiquidityParams-BalanceDelta-BalanceDelta-bytes-) for claiming the withheld fees back.
@@ -1221,7 +1181,7 @@ Returns the `withheldFees` for a liquidity position.
`withheldFees` are UniswapV4's `feesAccrued` retained by this hook during liquidity addition if liquidity
has been recently added within the `blockNumberOffset` block time window, with the purpose of disabling fee
-collection during JIT liquidity provisioning attacks. See [`BaseHook._afterRemoveLiquidity`](/uniswap-hooks/api/base#BaseHook-_afterRemoveLiquidity-address-struct-PoolKey-struct-ModifyLiquidityParams-BalanceDelta-BalanceDelta-bytes-) for claiming the fees back.
+collection during JIT liquidity provisioning attacks. See [`BaseHook._afterRemoveLiquidity`](base#BaseHook-_afterRemoveLiquidity-address-struct-PoolKey-struct-ModifyLiquidityParams-BalanceDelta-BalanceDelta-bytes-) for claiming the fees back.
@@ -1312,3 +1272,770 @@ A penalty was attempted to be applied and donated to LP's in range, but there ar
+
+
+
+
+
+```solidity
+import "@openzeppelin/src/general/ReHypothecationHook.sol";
+```
+
+A Uniswap V4 hook that enables rehypothecation of liquidity positions.
+
+This hook allows users to deposit assets into yield-generating sources (e.g., ERC-4626 vaults)
+while providing liquidity to Uniswap pools Just-in-Time (JIT) during swaps. Assets earn yield
+when idle and are temporarily injected as pool liquidity only when needed for swap execution,
+then immediately withdrawn back to yield sources.
+
+Conceptually, the hook acts as an intermediary that manages:
+- the user-facing ERC20 share token (representing rehypothecated positions), and
+- the underlying relationship between yield sources and pool liquidity.
+
+Key features:
+- Users can deposit assets into yield sources via the hook and receive ERC20 shares
+ that represent their rehypothecated liquidity position.
+- The hook dynamically manages pool liquidity based on available yield source assets,
+ performing JIT provisioning during swaps.
+- After swaps, assets are deposited back into yield sources to continue earning yield.
+- Supports both ERC20 tokens and native ETH by default.
+
+
+By default, the hook liquidity position is placed in the entire curve range. Override
+the `getTickLower` and `getTickUpper` functions to customize the position.
+
+
+
+By default, both canonical and rehypothecated liquidity modifications are allowed. Override
+ `beforeAddLiquidity` and `beforeRemoveLiquidity` to disable canonical liquidity modifications if desired.
+
+
+
+This hook relies on the PoolManager singleton token reserves for flash accounting during swaps.
+During `afterSwap`, the hook takes tokens from the PoolManager to settle deltas before users transfer
+their swap tokens. The PoolManager may lack sufficient reserves for illiquid tokens, preventing
+swaps until the PoolManager accumulates enough tokens for these small flash loans. This can be mitigated by
+maintaining some permanent pool liquidity alongside rehypothecated liquidity.
+
+
+
+This is experimental software and is provided on an "as is" and "as available" basis.
+We do not give any warranties and will not be liable for any losses incurred through any use of
+this code base.
+_Available since v1.2.0_
+
+
+
+
+Initialize the hook's `poolKey`. The stored key by the hook is unique and
+should not be modified so that it can safely be used across the hook's lifecycle.
+
+
+Native ETH is supported by default, which can be disabled by overriding `_beforeInitialize` with:
+```solidity
+function _beforeInitialize(address, PoolKey calldata key, uint160) internal override returns (bytes4) {
+ if (key.currency0.isAddressZero()) revert UnsupportedCurrency();
+ return super._beforeInitialize(key);
+}
+```
+
+
+
+
+Adds rehypothecated liquidity to yield sources and mints shares to the caller.
+
+Liquidity is added in the ratio determined by the hook's existing balances in yield sources.
+Assets are deposited into yield sources where they earn returns when idle and can be
+dynamically used as pool liquidity during swaps.
+
+Returns a balance `delta` representing the assets deposited into the hook.
+
+Requirements:
+- Pool must be initialized
+- Sender must have sufficient token balances
+- Sender must have approved the hook to spend the required tokens
+
+
+
+Removes rehypothecated liquidity from yield sources and burns caller's shares.
+
+Liquidity is withdrawn in the ratio determined by the hook's existing balances in yield sources.
+Assets are withdrawn from yield sources where they were generating yield, allowing users to
+exit their rehypothecated position and reclaim their underlying tokens.
+
+Returns a balance `delta` representing the assets withdrawn from the hook.
+
+Requirements:
+- Pool must be initialized
+- Sender must have sufficient shares for the desired liquidity withdrawal
+
+
+
+Hook executed before a swap operation to provide liquidity from rehypothecated assets.
+
+Gets the amount of liquidity to be provided from yield sources and temporarily adds it to the pool,
+in a Just-in-Time provision of liquidity.
+
+Note that at this point there are no actual transfers of tokens happening to the pool, instead,
+thanks to the Flash Accounting model, this addition creates a currencyDelta to the hook, which
+must be settled during the `_afterSwap` function before locking the poolManager again.
+
+
+
+Hook executed after a swap operation to remove temporary liquidity and rebalance assets.
+
+Removes the liquidity that was temporarily added in `_beforeSwap`, and resolves the hook's
+deltas in each currency in order to neutralize any pending debits or credits.
+
+
+
+Takes or settles any pending `currencyDelta` amount with the poolManager,
+neutralizing the Flash Accounting deltas before locking the poolManager again.
+
+
+
+Calculates the amounts of currency0 and currency1 required for adding a specific amount of shares.
+
+If the hook has not emitted shares yet, the initial deposit ratio is determined by the current pool price.
+Otherwise, it is determined by ratio of the hook balances in the yield sources.
+
+
+
+Returns the `liquidity` to be provided just-in-time for incoming swaps.
+
+By default, returns the maximum liquidity that can be provided with the current
+balances of the hook in the yield sources.
+
+
+Since liquidity is provided and withdrawn transiently during flash accounting, it
+can be virtually inflated for performing "leveraged liquidity" strategies, which would
+give better pricing to swappers at the cost of the profitability of LP's and increased risks.
+
+
+
+
+Retrieves the current `liquidity` of the hook owned liquidity position in the `_poolKey` pool.
+
+
+Given that just-in-time liquidity provisioning is performed, this function will only return values
+larger than zero between `beforeSwap` and `afterSwap`, where the liquidity is actually inside the pool.
+It will return zero in any other point in the hook lifecycle. For determining the hook balances in any other point,
+use `_getAmountInYieldSource`.
+
+
+
+
+Returns the `yieldSource` address for a given `currency`.
+
+Note: Must be implemented and adapted for the desired type of yield sources, such as
+ ERC-4626 Vaults, or any custom DeFi protocol interface, optionally handling native currency.
+
+
+
+Deposits a specified `amount` of `currency` into its corresponding yield source.
+
+Note: Must be implemented and adapted for the desired type of yield sources, such as
+ ERC-4626 Vaults, or any custom DeFi protocol interface, optionally handling native currency.
+
+
+
+Withdraws a specified `amount` of `currency` from its corresponding yield source.
+
+Note: Must be implemented and adapted for the desired type of yield sources, such as
+ ERC-4626 Vaults, or any custom DeFi protocol interface, optionally handling native currency.
+
+
+
+Gets the `amount` of `currency` deposited in its corresponding yield source.
+
+Note: Must be implemented and adapted for the desired type of yield sources, such as
+ ERC-4626 Vaults, or any custom DeFi protocol interface, optionally handling native currency.
+
+
+
+Emitted when a `sender` adds rehypothecated `shares` to the `poolKey` pool,
+ transferring `amount0` of `currency0` and `amount1` of `currency1` to the hook.
+
+
+
+Emitted when a `sender` removes rehypothecated `liquidity` from the `poolKey` pool,
+ receiving `amount0` of `currency0` and `amount1` of `currency1` from the hook.
+
+
+
+```solidity
+import "@openzeppelin/src/oracles/panoptic/BaseOracleHook.sol";
+```
+
+A hook that enables a Uniswap V4 pool to record price observations and expose an oracle interface
+
+
+
+Get the hook permissions to signal which hook functions are to be implemented.
+
+Used at deployment to validate the address correctly represents the expected permissions.
+
+
+
+The hook called before a swap.
+
+
+Note that this hook does not return either a `BeforeSwapDelta` or lp fee override — this call is used exclusively for recording price observations.
+
+
+
+
+Returns the cumulative tick as of each timestamp `secondsAgo` from the current block timestamp on `underlyingPoolId`.
+
+
+To get a time weighted average tick, you must call this with two values, one representing
+the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick,
+you must call it with secondsAgos = [3600, 0].
+
+
+
+The time weighted average tick represents the geometric time weighted average price of the pool, in
+log base sqrt(1.0001) of currency1 / currency0. The TickMath library can be used to go from a tick value to a ratio.
+
+
+
+
+Emitted by the hook for increases to the number of observations that can be stored.
+
+
+`observationCardinalityNext` is not the observation cardinality until an observation is written at the index
+just before a mint/swap/burn.
+
+
+
+
+```solidity
+import "@openzeppelin/src/oracles/panoptic/OracleHookWithV3Adapters.sol";
+```
+
+A hook that enables a Uniswap V4 pool to record price observations and expose an oracle interface with Uniswap V3-compatible adapters
+
+
+
+```solidity
+import "@openzeppelin/src/oracles/panoptic/libraries/Oracle.sol";
+```
+
+Instances of stored oracle data, "observations", are collected in the oracle array
+Every pool is initialized with an oracle array length of 1. Anyone can pay the SSTOREs to increase the
+maximum length of the oracle array. New slots will be added when the array is fully populated.
+Observations are overwritten when the full length of the oracle array is populated.
+The most recent observation is available, independent of the length of the oracle array, by passing 0 to observe()
+
+
+
Functions
+
+- [transform(last, blockTimestamp, tick, maxAbsTickDelta)](#Oracle-transform-struct-Oracle-Observation-uint32-int24-int24-)
+- [initialize(self, time, tick)](#Oracle-initialize-struct-Oracle-Observation-65535--uint32-int24-)
+- [write(self, index, blockTimestamp, tick, cardinality, cardinalityNext, maxAbsTickDelta)](#Oracle-write-struct-Oracle-Observation-65535--uint16-uint32-int24-uint16-uint16-int24-)
+- [grow(self, current, next)](#Oracle-grow-struct-Oracle-Observation-65535--uint16-uint16-)
+- [lte(time, a, b)](#Oracle-lte-uint32-uint32-uint32-)
+- [binarySearch(self, time, target, index, cardinality)](#Oracle-binarySearch-struct-Oracle-Observation-65535--uint32-uint32-uint16-uint16-)
+- [getSurroundingObservations(self, time, target, tick, index, cardinality, maxAbsTickDelta)](#Oracle-getSurroundingObservations-struct-Oracle-Observation-65535--uint32-uint32-int24-uint16-uint16-int24-)
+- [observeSingle(self, time, secondsAgo, tick, index, cardinality, maxAbsTickDelta)](#Oracle-observeSingle-struct-Oracle-Observation-65535--uint32-uint32-int24-uint16-uint16-int24-)
+- [observe(self, time, secondsAgos, tick, index, cardinality, maxAbsTickDelta)](#Oracle-observe-struct-Oracle-Observation-65535--uint32-uint32---int24-uint16-uint16-int24-)
+
+
+Writable at most once per block. Index represents the most recently written element. cardinality and index must be tracked externally.
+If the index is at the end of the allowable array length (according to cardinality), and the next cardinality
+is greater than the current one, cardinality may be increased. This restriction is created to preserve ordering.
+
+
+
+The answer must be contained in the array, used when the target is located within the stored observation
+boundaries: older than the most recent observation and younger, or the same age as, the oldest observation.
+
+
+
+Assumes there is at least 1 initialized observation.
+Used by observeSingle() to compute the counterfactual accumulator values as of a given block timestamp.
+
+
+
+Reverts if an observation at or before the desired observation timestamp does not exist.
+0 may be passed as `secondsAgo' to return the current cumulative values.
+If called with a timestamp falling between two observations, returns the counterfactual accumulator values
+at exactly the timestamp between the two observations.
+
+
```solidity
-import "uniswap-hooks/src/utils/CurrencySettler.sol";
+import "@openzeppelin/src/utils/CurrencySettler.sol";
```
Library used to interact with the `PoolManager` to settle any open deltas.
@@ -66,3 +66,4 @@ Deltas are synced before any ERC-20 transfers in [`CurrencySettler.settle`](#Cur
+
diff --git a/content/uniswap-hooks/changelog.mdx b/content/uniswap-hooks/changelog.mdx
index 3c2c3ff1..f4740497 100644
--- a/content/uniswap-hooks/changelog.mdx
+++ b/content/uniswap-hooks/changelog.mdx
@@ -1,12 +1,82 @@
---
title: Changelog
---
+
+
+# [v1.2.1](https://github.com/OpenZeppelin/uniswap-hooks/releases/tag/v1.2.1) - 2025-11-27
+
+## Hardhat support
+* Add npm dependencies for hardhat support
+
+[Changes][v1.2.1]
+
+
+
+# [v1.2.0](https://github.com/OpenZeppelin/uniswap-hooks/releases/tag/v1.2.0) - 2025-11-27
+
+## Base
+
+**BaseHook**: Deprecate `onlySelf` and `onlyValidPools` modifiers to improve extensibility and simplify hook implementation patterns. ([#105](https://github.com/OpenZeppelin/uniswap-hooks/issues/105))
+
+## Fee
+
+**BaseFeeHook**: Add fee hook implementation to enable custom fee logic in derived contracts. ([#65](https://github.com/OpenZeppelin/uniswap-hooks/issues/65))
+
+**BaseDynamicFee**: Refactor dynamic fee calculation to support more flexible fee structures and improve gas efficiency. ([#105](https://github.com/OpenZeppelin/uniswap-hooks/issues/105))
+
+## General
+
+**RehypothecationHook**: Implementation of a rehypothecation mechanism allowing collateral reuse within liquidity pools. Hook enables efficient capital utilization while maintaining proper accounting. ([#84](https://github.com/OpenZeppelin/uniswap-hooks/issues/84))
+
+## Oracles
+
+**PanopticOracle**: Add Panoptic-style oracle implementations for improved price data aggregation and manipulation resistance in hook contexts. ([#99](https://github.com/OpenZeppelin/uniswap-hooks/issues/99))
+
+## Development
+- Add balance delta assertions to improve test coverage and validation of state changes during hook execution. ([#100](https://github.com/OpenZeppelin/uniswap-hooks/issues/100))
+- Refactor magic values across test suite for better maintainability and readability. ([#106](https://github.com/OpenZeppelin/uniswap-hooks/issues/106))
+- Add Solhint linting with pre-commit hooks for code quality enforcement. ([#69](https://github.com/OpenZeppelin/uniswap-hooks/issues/69))
+- Apply Solhint rule fixes across codebase. ([#95](https://github.com/OpenZeppelin/uniswap-hooks/issues/95))
+- Update Solhint configuration and disable no-unused-vars for function parameters. ([#102](https://github.com/OpenZeppelin/uniswap-hooks/issues/102))
+- Update CI/CD workflows and dependency versions. ([#94](https://github.com/OpenZeppelin/uniswap-hooks/issues/94))
+- Update remappings and bump Solidity pragma to 0.8.26. ([#98](https://github.com/OpenZeppelin/uniswap-hooks/issues/98))
+- Address Slither static analysis detections. ([#103](https://github.com/OpenZeppelin/uniswap-hooks/issues/103))
+- Update vulnerable dependencies (cookie, tmp). ([#107](https://github.com/OpenZeppelin/uniswap-hooks/issues/107))
+- Fix documentation publishing workflow to avoid errors with no changes. ([#108](https://github.com/OpenZeppelin/uniswap-hooks/issues/108))
+- Update git submodules to latest versions. ([#109](https://github.com/OpenZeppelin/uniswap-hooks/issues/109))
+- Bump library version to 1.2.0. ([#104](https://github.com/OpenZeppelin/uniswap-hooks/issues/104))
+
+[Changes][v1.2.0]
+
+
+
+# [v1.1.1](https://github.com/OpenZeppelin/uniswap-hooks/releases/tag/v1.1.1) - 2025-11-27
+
+## Hardhat support
+* Add npm dependencies for hardhat support
+
+[Changes][v1.1.1]
+
+
+
+# [v1.2.0-rc.1](https://github.com/OpenZeppelin/uniswap-hooks/releases/tag/v1.2.0-rc.1) - 2025-10-27
+
+
+
+[Changes][v1.2.0-rc.1]
+
+
+
+# [v1.2.0-rc.0](https://github.com/OpenZeppelin/uniswap-hooks/releases/tag/v1.2.0-rc.0) - 2025-10-23
+
+
+
+[Changes][v1.2.0-rc.0]
+
# [v1.1.0](https://github.com/OpenZeppelin/uniswap-hooks/releases/tag/v1.1.0) - 2025-07-11
-### Changes by Category
-
## Base
* `BaseAsyncSwap`: Add interface `IHookEvents` to the contract in order to standardize event emissions in hooks. Add `_calculateSwapFee` function to calculate the swap fee amount in an asynchronous swap. ([#47](https://github.com/OpenZeppelin/uniswap-hooks/issues/47))
@@ -35,6 +105,30 @@ title: Changelog
[Changes][v1.1.0]
+
+# [v1.1.0-rc.2](https://github.com/OpenZeppelin/uniswap-hooks/releases/tag/v1.1.0-rc.2) - 2025-06-17
+
+
+
+[Changes][v1.1.0-rc.2]
+
+
+
+# [v1.1.0-rc.1](https://github.com/OpenZeppelin/uniswap-hooks/releases/tag/v1.1.0-rc.1) - 2025-05-13
+
+
+
+[Changes][v1.1.0-rc.1]
+
+
+
+# [v1.1.0-rc.0](https://github.com/OpenZeppelin/uniswap-hooks/releases/tag/v1.1.0-rc.0) - 2025-04-28
+
+
+
+[Changes][v1.1.0-rc.0]
+
+
# [v1.0.0](https://github.com/OpenZeppelin/uniswap-hooks/releases/tag/v1.0.0) - 2025-02-24
@@ -64,5 +158,22 @@ Libraries and general purpose utilities to help develop hooks.
[Changes][v1.0.0]
-[v1.1.0]: https://github.com/OpenZeppelin/uniswap-hooks/compare/v1.0.0...v1.1.0
-[v1.0.0]: https://github.com/OpenZeppelin/uniswap-hooks/tree/v1.0.0
+
+# [v1.0.0-rc.0](https://github.com/OpenZeppelin/uniswap-hooks/releases/tag/v1.0.0-rc.0) - 2025-01-06
+
+
+
+[Changes][v1.0.0-rc.0]
+
+
+[v1.2.1]: https://github.com/OpenZeppelin/uniswap-hooks/compare/v1.2.0...v1.2.1
+[v1.2.0]: https://github.com/OpenZeppelin/uniswap-hooks/compare/v1.1.1...v1.2.0
+[v1.1.1]: https://github.com/OpenZeppelin/uniswap-hooks/compare/v1.2.0-rc.1...v1.1.1
+[v1.2.0-rc.1]: https://github.com/OpenZeppelin/uniswap-hooks/compare/v1.2.0-rc.0...v1.2.0-rc.1
+[v1.2.0-rc.0]: https://github.com/OpenZeppelin/uniswap-hooks/compare/v1.1.0...v1.2.0-rc.0
+[v1.1.0]: https://github.com/OpenZeppelin/uniswap-hooks/compare/v1.1.0-rc.2...v1.1.0
+[v1.1.0-rc.2]: https://github.com/OpenZeppelin/uniswap-hooks/compare/v1.1.0-rc.1...v1.1.0-rc.2
+[v1.1.0-rc.1]: https://github.com/OpenZeppelin/uniswap-hooks/compare/v1.1.0-rc.0...v1.1.0-rc.1
+[v1.1.0-rc.0]: https://github.com/OpenZeppelin/uniswap-hooks/compare/v1.0.0...v1.1.0-rc.0
+[v1.0.0]: https://github.com/OpenZeppelin/uniswap-hooks/compare/v1.0.0-rc.0...v1.0.0
+[v1.0.0-rc.0]: https://github.com/OpenZeppelin/uniswap-hooks/tree/v1.0.0-rc.0
diff --git a/content/uniswap-hooks/index.mdx b/content/uniswap-hooks/index.mdx
index 1aeab87f..4fa3a03b 100644
--- a/content/uniswap-hooks/index.mdx
+++ b/content/uniswap-hooks/index.mdx
@@ -4,19 +4,31 @@ title: Uniswap Hooks
A [Solidity library](https://github.com/OpenZeppelin/uniswap-hooks) for secure and modular hooks for [Uniswap v4](https://docs.uniswap.org/contracts/v4/overview). This library includes:
-* Base implementations for custom accounting, asynchronous swaps, and custom curves
-* Fee-related implementations for management and enforcement
-* Ready-to-use hooks for general use cases, like sandwich protection
-* Utilities and libraries for hook development
+* Utilities and libraries for advanced hooks development
+* Primitives for implementing features such as custom accounting, asynchronous swaps, and custom curves.
+* Different fee-related implementations, such as dynamic fees, target-or-penalty fees, and hook fees.
+* Ready-to-use hooks for general use cases, like sandwich protection, just in time liquidity protection, limit orders, and rehypothecated liquidity.
## Overview
### Installation
-The library can only be installed with Foundry using gitmodules for now. Support for Hardhat is coming soon.
+#### Hardhat (npm)
+
+```console
+$ npm install OpenZeppelin/uniswap-hooks
+```
#### Foundry (git)
+
+When installing via git, it is a common error to use the `master` branch. This is a development branch that should be avoided in favor of tagged releases. The release process involves security measures that the `master` branch does not guarantee.
+
+
+
+Foundry installs the latest version initially, but subsequent `forge update` commands will use the `master` branch.
+
+
```console
$ forge install OpenZeppelin/uniswap-hooks
```
@@ -25,6 +37,7 @@ $ forge install OpenZeppelin/uniswap-hooks
Make sure to add `@openzeppelin/uniswap-hooks/=lib/uniswap-hooks/src/` in `remappings.txt`.
+
### Usage
Once installed, you can use the contracts in the library by importing them:
@@ -33,13 +46,13 @@ Once installed, you can use the contracts in the library by importing them:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
-import {BaseDynamicFee, IPoolManager, PoolKey} from "src/fee/BaseDynamicFee.sol";
+import {BaseDynamicFee, IPoolManager, PoolKey} from "@openzeppelin/uniswap-hooks/fee/BaseDynamicFee.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
/**
* @dev A hook that allows the owner to dynamically update the LP fee.
*/
-contract DynamicLPFeeHook is BaseDynamicFee, Ownable {
+contract DynamicOwnedLPFeeHook is BaseDynamicFee, Ownable {
uint24 public fee;
constructor(IPoolManager _poolManager) BaseDynamicFee(_poolManager) Ownable(msg.sender) {
@@ -61,12 +74,25 @@ contract DynamicLPFeeHook is BaseDynamicFee, Ownable {
}
```
-To keep your system secure, you should ***always*** use the installed code as-is, and neither copy-paste it from online sources, nor modify it yourself. The library is designed so that only the contracts and functions you use are deployed, so you don’t need to worry about it needlessly increasing gas costs.
+
+If you’re new to uniswap v4 hooks development, head to [Uniswap Hooks Quickstart](https://docs.uniswap.org/contracts/v4/quickstart/hooks/setup) to learn to configure your environment for creating and compililing your first hook.
+
+
+
+To keep your system secure, you should ***always*** use the installed code as-is, and neither copy-paste it from online sources, nor modify it yourself. The library is designed so that only the contracts and functions you use are included, so you don’t need to worry about it needlessly increasing gas costs.
+
+## API Reference
+
+The [full API](/uniswap-hooks/api/) is also thoroughly documented, and serves as a great reference when developing your smart contract application. You can also ask for help or follow Contracts' development in the [community forum](https://forum.openzeppelin.com) or [telegram channel](https://t.me/openzeppelin_tg).
+
+## Hooks Wizard 🪄
+
+Head to the [Hooks Wizard](https://wizard.openzeppelin.com/uniswap-hooks) to construct feature-rich hooks by selecting the options that fit your needs, generating the code automatically for you.
-### Videos
+## Videos
In order to facilitate understanding of Uniswap Hooks and help start building with them, we’ve released this playlist of guidelines on our YouTube channel.
-
+
## Security
diff --git a/package.json b/package.json
index 12514344..0ee48c4f 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "docs",
"version": "0.0.0",
"private": true,
- "type": "module",
+ "type": "module",
"scripts": {
"build": "next build --turbo",
"dev": "next dev --turbo",
@@ -43,6 +43,7 @@
"next": "^15.5.7",
"next-themes": "^0.4.6",
"next-validate-link": "^1.6.3",
+ "prettier": "^3.7.4",
"react": "^19.2.1",
"react-dom": "^19.2.1",
"rehype-katex": "^7.0.1",
@@ -69,5 +70,5 @@
"tw-animate-css": "^1.3.8",
"typescript": "^5.9.2"
},
- "packageManager": "pnpm@10.17.1"
+ "packageManager": "pnpm@10.24.0"
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 90575e4f..4672ed97 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -83,6 +83,9 @@ importers:
next-validate-link:
specifier: ^1.6.3
version: 1.6.3
+ prettier:
+ specifier: ^3.7.4
+ version: 3.7.4
react:
specifier: ^19.2.1
version: 19.2.1
@@ -2608,8 +2611,8 @@ packages:
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
engines: {node: ^10 || ^12 || >=14}
- prettier@3.6.2:
- resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==}
+ prettier@3.7.4:
+ resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==}
engines: {node: '>=14'}
hasBin: true
@@ -3325,7 +3328,7 @@ snapshots:
dependencies:
'@apidevtools/json-schema-ref-parser': 11.9.3
js-yaml: 4.1.1
- prettier: 3.6.2
+ prettier: 3.7.4
'@iconify/types@2.0.0': {}
@@ -5904,7 +5907,7 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
- prettier@3.6.2: {}
+ prettier@3.7.4: {}
property-information@7.1.0: {}
diff --git a/scripts/generate-changelog.js b/scripts/generate-changelog.js
index 8f232575..091da850 100755
--- a/scripts/generate-changelog.js
+++ b/scripts/generate-changelog.js
@@ -1,18 +1,20 @@
#!/usr/bin/env node
-const fs = require("node:fs").promises;
-const path = require("node:path");
-const { execSync } = require("node:child_process");
+import { promises as fs } from "node:fs";
+import path from "node:path";
+import { execSync } from "node:child_process";
-// Check if two arguments are provided
-if (process.argv.length !== 4) {
- console.error("Usage: node generate-changelog.js ");
+// Check if at least two arguments are provided
+if (process.argv.length < 4) {
+ console.error("Usage: node generate-changelog.js [-p]");
+ console.error(" -p: Include pre-releases");
process.exit(1);
}
// Assign arguments to variables
const url = process.argv[2];
const filePath = process.argv[3];
+const includePrereleases = process.argv.includes("-p");
// Check if changelog-from-release is installed
function checkChangelogFromRelease() {
@@ -34,14 +36,18 @@ async function generateChangelog() {
const frontmatter = `---
title: Changelog
---
-
+
`;
// Run changelog-from-release and get output
- const changelogOutput = execSync(`changelog-from-release -r "${url}"`, {
- encoding: "utf8",
- stdio: "pipe",
- });
+ const flags = includePrereleases ? " -p" : "";
+ const changelogOutput = execSync(
+ `changelog-from-release -r "${url}"${flags}`,
+ {
+ encoding: "utf8",
+ stdio: "pipe",
+ },
+ );
// Remove the generated tag at the end
const cleanOutput = changelogOutput