diff --git a/src/base/BaseCustomAccounting.sol b/src/base/BaseCustomAccounting.sol index 7c65ba8..9da03ba 100644 --- a/src/base/BaseCustomAccounting.sol +++ b/src/base/BaseCustomAccounting.sol @@ -27,7 +27,7 @@ abstract contract BaseCustomAccounting is BaseHook { constructor(IPoolManager _poolManager) BaseHook(_poolManager) {} /** - * @dev Call the custom swap logic and create a return delta to be consumed by the {PoolManager}. + * @dev Call the custom swap logic and create a return delta to be consumed by the `PoolManager`. */ function _beforeSwap(address, PoolKey calldata key, IPoolManager.SwapParams calldata params, bytes calldata) internal @@ -72,7 +72,7 @@ abstract contract BaseCustomAccounting is BaseHook { returns (uint256 amount); /** - * @dev Set the hook permissions, specifically {beforeAddLiquidity}, {beforeSwap} and {beforeSwapReturnDelta}. + * @dev Set the hook permissions, specifically `beforeSwap` and `beforeSwapReturnDelta`. */ function getHookPermissions() public pure virtual override returns (Hooks.Permissions memory) { return Hooks.Permissions({ diff --git a/src/base/BaseCustomCurve.sol b/src/base/BaseCustomCurve.sol index 647818a..4f990ba 100644 --- a/src/base/BaseCustomCurve.sol +++ b/src/base/BaseCustomCurve.sol @@ -18,7 +18,7 @@ import {CurrencySettler} from "v4-core/test/utils/CurrencySettler.sol"; * v3-like concentrated liquidity implementation of Uniswap. By inheriting {BaseCustomAccounting}, the hook calls * the {_getAmountOutFromExactInput} or {_getAmountInForExactOutput} function to calculate the amount of tokens * to be taken or settled, and a return delta is created based on their outputs. This return delta is then - * consumed by the {PoolManager}. + * consumed by the `PoolManager`. * * IMPORTANT: This base contract acts similarly to {BaseNoOp}, which means that the hook must hold the liquidity * for swaps. @@ -83,7 +83,7 @@ abstract contract BaseCustomCurve is BaseCustomAccounting { returns (uint256 amountIn); /** - * @dev Set the hook permissions, specifically {beforeAddLiquidity}, {beforeSwap} and {beforeSwapReturnDelta}. + * @dev Set the hook permissions, specifically `beforeAddLiquidity`, `beforeSwap` and `beforeSwapReturnDelta`. */ function getHookPermissions() public pure virtual override returns (Hooks.Permissions memory) { return Hooks.Permissions({ diff --git a/src/base/BaseNoOp.sol b/src/base/BaseNoOp.sol index f83c9a5..be0d22d 100644 --- a/src/base/BaseNoOp.sol +++ b/src/base/BaseNoOp.sol @@ -14,7 +14,7 @@ import {SafeCast} from "v4-core/src/libraries/SafeCast.sol"; /** * @dev Base implementation for no-op hooks. * - * IMPORTANT: Given that this contract overrides default logic of the {PoolManager}, liquidity + * IMPORTANT: Given that this contract overrides default logic of the `PoolManager`, liquidity * must be provided by the hook itself (i.e. the hook must hold the liquidity/tokens). * * _Available since v0.1.0_ @@ -45,7 +45,7 @@ abstract contract BaseNoOp is BaseHook { } /** - * @dev Set the hook permissions, specifically {beforeSwap} and {beforeSwapReturnDelta}. + * @dev Set the hook permissions, specifically `beforeSwap` and `beforeSwapReturnDelta`. */ function getHookPermissions() public pure virtual override returns (Hooks.Permissions memory) { return Hooks.Permissions({ diff --git a/src/examples/AntiSandwichHook.sol b/src/general/AntiSandwichHook.sol similarity index 82% rename from src/examples/AntiSandwichHook.sol rename to src/general/AntiSandwichHook.sol index 09b5360..540cea6 100644 --- a/src/examples/AntiSandwichHook.sol +++ b/src/general/AntiSandwichHook.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Uniswap Hooks (last updated v0.1.0) (src/examples/AntiSandwichHook.sol) +// OpenZeppelin Uniswap Hooks (last updated v0.1.0) (src/general/AntiSandwichHook.sol) pragma solidity ^0.8.20; @@ -15,9 +15,23 @@ import {Slot0} from "v4-core/src/types/Slot0.sol"; import {StateLibrary} from "v4-core/src/libraries/StateLibrary.sol"; /** - * @dev Implementation of an anti-sandwich hook. + * @dev Sandwich-resistant hook, based on + * https://github.com/cairoeth/sandwich-resistant-hook/blob/master/src/srHook.sol[this] + * implementation. * - * Based on the https://github.com/cairoeth/sandwich-resistant-hook/blob/master/src/srHook.sol[implementation by cairoeth]. + * This hook implements the sandwich-resistant AMM design introduced + * https://www.umbraresearch.xyz/writings/sandwich-resistant-amm[here]. Specifically, + * this hook guarantees that no swaps get filled at a price better than the price at + * the beginning of the slot window (i.e. one block). + * + * Within a slot window, swaps impact the pool asymmetrically for buys and sells. + * When a buy order is executed, the offer on the pool increases in accordance with + * the xy=k curve. However, the bid price remains constant, instead increasing the + * amount of liquidity on the bid. Subsequent sells eat into this liquidity, while + * decreasing the offer price according to xy=k. + * + * NOTE: Swaps in the other direction do not get the positive price difference + * compared to the initial price before the first block swap. * * _Available since v0.1.0_ */ diff --git a/src/general/README.adoc b/src/general/README.adoc new file mode 100644 index 0000000..b42cef4 --- /dev/null +++ b/src/general/README.adoc @@ -0,0 +1,12 @@ += General + +[.readme-notice] +NOTE: This document is better viewed on the docs page. + +Ready-to-use hooks built on top of the base and fee abstract contracts + + * {AntiSandwichHook}: Hook resistant to atomic sandwich attacks + +== Hooks + +{{AntiSandwichHook}} diff --git a/test/examples/AntiSandwichHook.t.sol b/test/examples/AntiSandwichHook.t.sol index 72a04a1..c360c47 100644 --- a/test/examples/AntiSandwichHook.t.sol +++ b/test/examples/AntiSandwichHook.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.20; import {Test} from "forge-std/Test.sol"; import {Deployers} from "v4-core/test/utils/Deployers.sol"; -import {AntiSandwichHook} from "src/examples/AntiSandwichHook.sol"; +import {AntiSandwichHook} from "src/general/AntiSandwichHook.sol"; import {IHooks} from "v4-core/src/interfaces/IHooks.sol"; import {Hooks} from "v4-core/src/libraries/Hooks.sol"; import {PoolSwapTest} from "v4-core/src/test/PoolSwapTest.sol"; @@ -24,7 +24,7 @@ contract AntiSandwichHookTest is Test, Deployers { hook = AntiSandwichHook( address(uint160(Hooks.BEFORE_SWAP_FLAG | Hooks.AFTER_SWAP_FLAG | Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG)) ); - deployCodeTo("src/examples/AntiSandwichHook.sol:AntiSandwichHook", abi.encode(manager), address(hook)); + deployCodeTo("src/general/AntiSandwichHook.sol:AntiSandwichHook", abi.encode(manager), address(hook)); (key,) = initPoolAndAddLiquidity( currency0, currency1, IHooks(address(hook)), LPFeeLibrary.DYNAMIC_FEE_FLAG, SQRT_PRICE_1_1