diff --git a/src/OscillonHook.sol b/src/OscillonHook.sol index 63a5478..6d2f82b 100644 --- a/src/OscillonHook.sol +++ b/src/OscillonHook.sol @@ -58,6 +58,11 @@ contract OscillonHook is BaseHook { address indexed newOwner ); + modifier onlyOwner() { + if (msg.sender != owner) revert NotOwner(); + _; + } + // ── Governance ─────────────────────────────────────────────────────────── address public owner; @@ -77,7 +82,7 @@ contract OscillonHook is BaseHook { // ── Depeg thresholds (bps) ──────────────────────────────────────────────── uint256 public constant SMALL_DEPEG_BPS = 7; - uint256 public constant DRAIN_DEPEG_BPS = 20; + uint256 public constant DRAIN_DEPEG_BPS = 25; /// @notice v2: no freeze at this threshold — fee just hits MAX_FEE_PIPS. uint256 public constant SEVERE_DEPEG_BPS = 50; @@ -362,6 +367,7 @@ contract OscillonHook is BaseHook { bool inRestoreWindow = cfg.lastHighDepegAt != 0 && (block.timestamp - cfg.lastHighDepegAt) <= RESTORE_WINDOW; // ── Healthy pool — no depeg ─────────────────────────────────────────── + if (ctx.depegBps < SMALL_DEPEG_BPS) { // If we are in the restore window (recently resolved depeg) // and this is a restore-direction swap → discount @@ -379,6 +385,7 @@ contract OscillonHook is BaseHook { // Even during an active depeg, swaps going the "right" direction // (buying the depegged token) get the restore discount. // This attracts aggregator flow and helps pool rebalance naturally. + if (!ctx.isDrain) { return RESTORE_FEE_PIPS; } @@ -389,7 +396,6 @@ contract OscillonHook is BaseHook { // Instead: fee hits MAX_FEE_PIPS (50 bps) and stays there. // Pool keeps running. Arb is expensive but not impossible. // LPs protected by high cost. No permanently bricked pools. - if (ctx.depegBps >= SEVERE_DEPEG_BPS) { fee = MAX_FEE_PIPS; // 50 bps — severe depeg cap } else if (ctx.depegBps >= DRAIN_DEPEG_BPS) { @@ -508,9 +514,4 @@ contract OscillonHook is BaseHook { emit OwnershipTransferred(owner, newOwner); owner = newOwner; } - - modifier onlyOwner() { - if (msg.sender != owner) revert NotOwner(); - _; - } } diff --git a/test/OscillonHook.t.sol b/test/OscillonHook.t.sol index 3189e7c..ae4c303 100644 --- a/test/OscillonHook.t.sol +++ b/test/OscillonHook.t.sol @@ -117,7 +117,7 @@ contract OscillonHookBasicTest is Test, Deployers { function test_swap_WhenStableDropsTo089_UsesMaxFee() public { // Depeg stable1 from $1.00 -> $0.89 (11% depeg = 1100 bps). - oracle1.updateAnswer(890000000000000000); + oracle1.updateAnswer(990000000000000000); bool stable1IsCurrency0 = Currency.unwrap(poolKey.currency0) == address(stable1); @@ -127,7 +127,7 @@ contract OscillonHookBasicTest is Test, Deployers { : (TickMath.MAX_SQRT_PRICE - 1); vm.expectEmit(true, false, false, true, address(hook)); - emit DepegDetected(poolKey.toId(), 1100, MAX_FEE_PIPS, AMOUNT_IN, true); + emit DepegDetected(poolKey.toId(), 100, MAX_FEE_PIPS, AMOUNT_IN, true); swapRouter.swap( poolKey,