-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
85 additions
and
81 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,90 @@ | ||
= Fee | ||
|
||
Fee-related base hooks are provided in the library to allow for flexible ways to adjust or override fees for different actions, like swaps and liquidity modifications. | ||
|
||
== Dynamic | ||
|
||
xref:api:fee.adoc#BaseDynamicFee[BaseDynamicFee] allows for dynamic setting and application of LP fees. Implementers must override the xref:api:fee.adoc#BaseDynamicFee-_getFee-struct-PoolKey-[`_getFee`] function to return a fee value expressed in hundredths of a bip, based on their chosen logic. The fee is automatically applied after initialization, and can be refreshed at any time by calling the permissionless xref:api:fee.adoc#BaseDynamicFee-poke-struct-PoolKey-[`poke`] function. This allows the fee to be dynamically updated based on external data or conditions. However, since xref:api:fee.adoc#BaseDynamicFee-poke-struct-PoolKey-[`poke`] can be called by anyone, implementers must carefully consider whether their xref:api:fee.adoc#BaseDynamicFee-_getFee-struct-PoolKey-[`_getFee`] implementation relies on external states that could be manipulated by adversaries. | ||
|
||
[source,solidity] | ||
---- | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.26; | ||
import {BaseDynamicFee, IPoolManager, PoolKey} from "src/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 { | ||
uint24 public fee; | ||
constructor(IPoolManager _poolManager) BaseDynamicFee(_poolManager) Ownable(msg.sender) {} | ||
/** | ||
* @inheritdoc BaseDynamicFee | ||
*/ | ||
function _getFee(PoolKey calldata) internal view override returns (uint24) { | ||
return fee; | ||
} | ||
/** | ||
* @notice Sets the LP fee, denominated in hundredths of a bip. | ||
*/ | ||
function setFee(uint24 _fee) external onlyOwner { | ||
fee = _fee; | ||
} | ||
} | ||
---- | ||
|
||
The constructor checks if the pool is configured with the dynamic fee flag and reverts if not. | ||
|
||
== Override | ||
|
||
== After Swap | ||
xref:api:fee.adoc#BaseOverrideFee[BaseOverrideFee] allows for dynamic setting and application of swap fees. Similar to xref:api:fee.adoc#BaseDynamicFee[BaseDynamicFee], implementers must override the xref:api:fee.adoc#BaseOverrideFee-_getFee-struct-PoolKey-[`_getFee`] function to return a fee value, which is masked with the override fee flag and passed to the `PoolManager` before a swap. | ||
|
||
This approach can be useful for time-based, volume-based, or volatility-based fees where the fee may fluctuate frequently. Because the hook runs before the swap is executed, an implementer can examine the current context (like liquidity levels or external price oracles) to decide the appropriate fee for each trade. It also doesn't require poking the hook to refresh the fee, as the fee is dynamically fetched before each swap. | ||
|
||
[source,solidity] | ||
---- | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.26; | ||
import {BaseOverrideFee, IPoolManager, PoolKey} from "src/fee/BaseOverrideFee.sol"; | ||
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; | ||
/** | ||
* @dev A hook that allows the owner to dynamically update the swap fee. | ||
*/ | ||
contract DynamicSwapFeeHook is BaseOverrideFee, Ownable { | ||
uint24 public fee; | ||
constructor(IPoolManager _poolManager) BaseOverrideFee(_poolManager) Ownable(msg.sender) {} | ||
/** | ||
* @inheritdoc BaseOverrideFee | ||
*/ | ||
function _getFee(address, PoolKey calldata, IPoolManager.SwapParams calldata, bytes calldata) | ||
internal | ||
view | ||
override | ||
returns (uint24) | ||
{ | ||
return fee; | ||
} | ||
/** | ||
* @notice Sets the swap fee, denominated in hundredths of a bip. | ||
*/ | ||
function setFee(uint24 _fee) external onlyOwner { | ||
fee = _fee; | ||
} | ||
} | ||
---- | ||
|
||
== After Swap | ||
|
||
xref:api:fee.adoc#BaseDynamicAfterFee[BaseDynamicAfterFee] applies adjustments to the tokens to be received by a user for exact-input swaps. This strategy relies on first capturing the swap context in the xref:api:base.adoc#BaseHook-_beforeSwap-address-struct-PoolKey-struct-IPoolManager-SwapParams-bytes-[`_beforeSwap`] phase and storing a target delta. Once the swap is processed by the `PoolManager`, the hook's xref:api:base.adoc#BaseHook-_afterSwap-address-struct-PoolKey-struct-IPoolManager-SwapParams-BalanceDelta-bytes-[`_afterSwap`] method checks for exact-input swaps and compares the actual user output with the stored target delta. Any positive difference becomes a fee donation to the pool, effectively implementing a dynamic fee that is only finalized once all of the swap's internal calculations are done. | ||
|
||
Implementers should carefully consider how to mitigate the risk of attackers exploiting "just-in-time" liquidity additions to gain an outsized share of these fees. As the contract notes, the target deltas are cleared after each swap, so it is recommended to define or reset them each time in xref:api:base.adoc#BaseHook-_beforeSwap-address-struct-PoolKey-struct-IPoolManager-SwapParams-bytes-[`_beforeSwap`] to ensure consistency. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.