This proves the hook never enforces or collects the sell fee via on-chain balance changes.
function test_SellReFi_NoHookFeeCollected2() public {
(, uint24 sellFee) = rebateHook.getFeeConfig();
console.log("Configured sellFee (bps):", sellFee);
assertEq(sellFee, 3000, "Sell fee should be 3000");
uint256 hookReFiStart = reFiToken.balanceOf(address(rebateHook));
console.log("Hook initial ReFi balance:", hookReFiStart);
assertEq(hookReFiStart, 0, "Hook should start with 0 ReFi");
uint256 reFiAmount = 0.01 ether;
console.log("ReFi amount to sell:", reFiAmount);
vm.startPrank(user1);
reFiToken.approve(address(swapRouter), type(uint256).max);
uint256 userReFiBefore = reFiToken.balanceOf(user1);
uint256 userEthBefore = user1.balance;
uint256 hookReFiBefore = reFiToken.balanceOf(address(rebateHook));
uint256 hookEthBefore = address(rebateHook).balance;
console.log("== BEFORE SWAP ==");
console.log("user1 ReFi:", userReFiBefore);
console.log("user1 ETH:", userEthBefore);
console.log("hook ReFi:", hookReFiBefore);
console.log("hook ETH:", hookEthBefore);
SwapParams memory params = SwapParams({
zeroForOne: false,
amountSpecified: -int256(reFiAmount),
sqrtPriceLimitX96: TickMath.MAX_SQRT_PRICE - 1
});
PoolSwapTest.TestSettings memory testSettings = PoolSwapTest.TestSettings({
takeClaims: false,
settleUsingBurn: false
});
console.log("Calling swap for user1: selling ReFi for ETH...");
swapRouter.swap(key, params, testSettings, ZERO_BYTES);
vm.stopPrank();
uint256 userReFiAfter = reFiToken.balanceOf(user1);
uint256 userEthAfter = user1.balance;
uint256 hookReFiAfter = reFiToken.balanceOf(address(rebateHook));
uint256 hookEthAfter = address(rebateHook).balance;
console.log("== AFTER SWAP ==");
console.log("user1 ReFi:", userReFiAfter);
console.log("user1 ETH:", userEthAfter);
console.log("hook ReFi:", hookReFiAfter);
console.log("hook ETH:", hookEthAfter);
console.log("== DELTAS ==");
console.log("user1 ReFi delta (before - after):", userReFiBefore - userReFiAfter);
console.log("user1 ETH delta (after - before):", userEthAfter - userEthBefore);
console.log("hook ReFi delta (after - before):", hookReFiAfter - hookReFiBefore);
console.log("hook ETH delta (after - before):", hookEthAfter - hookEthBefore);
assertEq(
userReFiBefore - userReFiAfter,
reFiAmount,
"User should only lose the specified ReFi amount (no extra hook fee)"
);
assertEq(
hookReFiAfter,
hookReFiBefore,
"Hook should not receive any ReFi from the sell (ZERO_DELTA)"
);
assertEq(
hookEthAfter,
hookEthBefore,
"Hook should not receive any ETH from the sell (ZERO_DELTA)"
);
assertGt(
userEthAfter,
userEthBefore,
"User should receive ETH from selling ReFi"
);
}
PASS] test_SellReFi_NoHookFeeCollected2() (gas: 230671)
Logs:
Configured sellFee (bps): 3000
Hook initial ReFi balance: 0
ReFi amount to sell: 10000000000000000
== BEFORE SWAP ==
user1 ReFi: 1000000000000000000000
user1 ETH: 0
hook ReFi: 0
hook ETH: 0
Calling swap for user1: selling ReFi for ETH...
== AFTER SWAP ==
user1 ReFi: 999990000000000000000
user1 ETH: 9997005541990553
hook ReFi: 0
hook ETH: 0
== DELTAS ==
user1 ReFi delta (before - after): 10000000000000000
user1 ETH delta (after - before): 9997005541990553
hook ReFi delta (after - before): 0
hook ETH delta (after - before): 0
Traces:
[230671] TestReFiSwapRebateHook::test_SellReFi_NoHookFeeCollected2()
├─ [2894] ReFiSwapRebateHook::getFeeConfig() [staticcall]
│ └─ ← [Return] 0, 3000
├─ [0] console::log("Configured sellFee (bps):", 3000) [staticcall]
│ └─ ← [Stop]
├─ [2825] MockERC20::balanceOf(ReFiSwapRebateHook: [0x5Ea76dced871d32C594E967FA4D07df7832AF080]) [staticcall]
│ └─ ← [Return] 0
├─ [0] console::log("Hook initial ReFi balance:", 0) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("ReFi amount to sell:", 10000000000000000 [1e16]) [staticcall]
│ └─ ← [Stop]
├─ [0] VM::startPrank(ECRecover: [0x0000000000000000000000000000000000000001])
│ └─ ← [Return]
├─ [25102] MockERC20::approve(PoolSwapTest: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], 115792089237316195423570985008687907853269984665640564039457584007913129639935 [1.157e77])
│ ├─ emit Approval(owner: ECRecover: [0x0000000000000000000000000000000000000001], spender: PoolSwapTest: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], value: 115792089237316195423570985008687907853269984665640564039457584007913129639935 [1.157e77])
│ └─ ← [Return] true
├─ [2825] MockERC20::balanceOf(ECRecover: [0x0000000000000000000000000000000000000001]) [staticcall]
│ └─ ← [Return] 1000000000000000000000 [1e21]
├─ [825] MockERC20::balanceOf(ReFiSwapRebateHook: [0x5Ea76dced871d32C594E967FA4D07df7832AF080]) [staticcall]
│ └─ ← [Return] 0
├─ [0] console::log("== BEFORE SWAP ==") [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("user1 ReFi:", 1000000000000000000000 [1e21]) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("user1 ETH:", 0) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("hook ReFi:", 0) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("hook ETH:", 0) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("Calling swap for user1: selling ReFi for ETH...") [staticcall]
│ └─ ← [Stop]
├─ [135305] PoolSwapTest::swap(PoolKey({ currency0: 0x0000000000000000000000000000000000000000, currency1: 0x2a07706473244BC757E10F2a9E86fB532828afe3, fee: 8388608 [8.388e6], tickSpacing: 60, hooks: 0x5Ea76dced871d32C594E967FA4D07df7832AF080 }), SwapParams({ zeroForOne: false, amountSpecified: -10000000000000000 [-1e16], sqrtPriceLimitX96: 1461446703485210103287273052203988822378723970341 [1.461e48] }), TestSettings({ takeClaims: false, settleUsingBurn: false }), 0x)
│ ├─ [124066] PoolManager::unlock(0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a07706473244bc757e10f2a9e86fb532828afe30000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000005ea76dced871d32c594e967fa4d07df7832af0800000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffdc790d903f0000000000000000000000000000fffd8963efd1fc6a506488495d951d5263988d2500000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000000)
│ │ ├─ [121083] PoolSwapTest::unlockCallback(0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a07706473244bc757e10f2a9e86fb532828afe30000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000005ea76dced871d32c594e967fa4d07df7832af0800000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffdc790d903f0000000000000000000000000000fffd8963efd1fc6a506488495d951d5263988d2500000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000000)
│ │ │ ├─ [549] PoolManager::exttload(0xc6bd81b73d1fd76b6ab7b2a3e675f602f162633118b2ec0b74d6456669dd8579) [staticcall]
│ │ │ │ └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000000
│ │ │ ├─ [825] MockERC20::balanceOf(ECRecover: [0x0000000000000000000000000000000000000001]) [staticcall]
│ │ │ │ └─ ← [Return] 1000000000000000000000 [1e21]
│ │ │ ├─ [2825] MockERC20::balanceOf(PoolManager: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f]) [staticcall]
│ │ │ │ └─ ← [Return] 100000000000000000 [1e17]
│ │ │ ├─ [549] PoolManager::exttload(0x10e143d4e19b26f18146d695ea98e08249192e595a44ce1e4b46eb27ca3a2c40) [staticcall]
│ │ │ │ └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000000
│ │ │ ├─ [39751] PoolManager::swap(PoolKey({ currency0: 0x0000000000000000000000000000000000000000, currency1: 0x2a07706473244BC757E10F2a9E86fB532828afe3, fee: 8388608 [8.388e6], tickSpacing: 60, hooks: 0x5Ea76dced871d32C594E967FA4D07df7832AF080 }), SwapParams({ zeroForOne: false, amountSpecified: -10000000000000000 [-1e16], sqrtPriceLimitX96: 1461446703485210103287273052203988822378723970341 [1.461e48] }), 0x)
│ │ │ │ ├─ [4251] ReFiSwapRebateHook::beforeSwap(PoolSwapTest: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], PoolKey({ currency0: 0x0000000000000000000000000000000000000000, currency1: 0x2a07706473244BC757E10F2a9E86fB532828afe3, fee: 8388608 [8.388e6], tickSpacing: 60, hooks: 0x5Ea76dced871d32C594E967FA4D07df7832AF080 }), SwapParams({ zeroForOne: false, amountSpecified: -10000000000000000 [-1e16], sqrtPriceLimitX96: 1461446703485210103287273052203988822378723970341 [1.461e48] }), 0x)
│ │ │ │ │ ├─ emit ReFiBought(buyer: PoolSwapTest: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], amount: 10000000000000000 [1e16])
│ │ │ │ │ └─ ← [Return] 0x575e24b4, 0, 4194304 [4.194e6]
│ │ │ │ ├─ emit Swap(id: 0xc14102b82a2458dd50349db85930df8ba510fe545d122ef7b9779a0055e4c8e6, sender: PoolSwapTest: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], amount0: 9997005541990553 [9.997e15], amount1: -10000000000000000 [-1e16], sqrtPriceX96: 79251894161187818237737846152 [7.925e28], liquidity: 33385024970969944913 [3.338e19], tick: 5, fee: 0)
│ │ │ │ └─ ← [Return] 3401804707950284987846385279791586160233259406626586624 [3.401e54]
│ │ │ ├─ [549] PoolManager::exttload(0xc6bd81b73d1fd76b6ab7b2a3e675f602f162633118b2ec0b74d6456669dd8579) [staticcall]
│ │ │ │ └─ ← [Return] 0x000000000000000000000000000000000000000000000000002384393c25e099
│ │ │ ├─ [825] MockERC20::balanceOf(ECRecover: [0x0000000000000000000000000000000000000001]) [staticcall]
│ │ │ │ └─ ← [Return] 1000000000000000000000 [1e21]
│ │ │ ├─ [825] MockERC20::balanceOf(PoolManager: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f]) [staticcall]
│ │ │ │ └─ ← [Return] 100000000000000000 [1e17]
│ │ │ ├─ [549] PoolManager::exttload(0x10e143d4e19b26f18146d695ea98e08249192e595a44ce1e4b46eb27ca3a2c40) [staticcall]
│ │ │ │ └─ ← [Return] 0xffffffffffffffffffffffffffffffffffffffffffffffffffdc790d903f0000
│ │ │ ├─ [2497] PoolManager::sync(MockERC20: [0x2a07706473244BC757E10F2a9E86fB532828afe3])
│ │ │ │ ├─ [825] MockERC20::balanceOf(PoolManager: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f]) [staticcall]
│ │ │ │ │ └─ ← [Return] 100000000000000000 [1e17]
│ │ │ │ └─ ← [Stop]
│ │ │ ├─ [9736] MockERC20::transferFrom(ECRecover: [0x0000000000000000000000000000000000000001], PoolManager: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], 10000000000000000 [1e16])
│ │ │ │ ├─ emit Transfer(from: ECRecover: [0x0000000000000000000000000000000000000001], to: PoolManager: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], value: 10000000000000000 [1e16])
│ │ │ │ └─ ← [Return] true
│ │ │ ├─ [4024] PoolManager::settle()
│ │ │ │ ├─ [825] MockERC20::balanceOf(PoolManager: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f]) [staticcall]
│ │ │ │ │ └─ ← [Return] 110000000000000000 [1.1e17]
│ │ │ │ └─ ← [Return] 10000000000000000 [1e16]
│ │ │ ├─ [37209] PoolManager::take(0x0000000000000000000000000000000000000000, ECRecover: [0x0000000000000000000000000000000000000001], 9997005541990553 [9.997e15])
│ │ │ │ ├─ [3000] PRECOMPILES::ecrecover{value: 9997005541990553}(0x)
│ │ │ │ │ └─ ← [Return] 0x
│ │ │ │ └─ ← [Stop]
│ │ │ └─ ← [Return] 0x0000000000000000002384393c25e099ffffffffffffffffffdc790d903f0000
│ │ └─ ← [Return] 0x0000000000000000002384393c25e099ffffffffffffffffffdc790d903f0000
│ └─ ← [Return] 3401804707950284987846385279791586160233259406626586624 [3.401e54]
├─ [0] VM::stopPrank()
│ └─ ← [Return]
├─ [825] MockERC20::balanceOf(ECRecover: [0x0000000000000000000000000000000000000001]) [staticcall]
│ └─ ← [Return] 999990000000000000000 [9.999e20]
├─ [825] MockERC20::balanceOf(ReFiSwapRebateHook: [0x5Ea76dced871d32C594E967FA4D07df7832AF080]) [staticcall]
│ └─ ← [Return] 0
├─ [0] console::log("== AFTER SWAP ==") [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("user1 ReFi:", 999990000000000000000 [9.999e20]) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("user1 ETH:", 9997005541990553 [9.997e15]) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("hook ReFi:", 0) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("hook ETH:", 0) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("== DELTAS ==") [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("user1 ReFi delta (before - after):", 10000000000000000 [1e16]) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("user1 ETH delta (after - before):", 9997005541990553 [9.997e15]) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("hook ReFi delta (after - before):", 0) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("hook ETH delta (after - before):", 0) [staticcall]
│ └─ ← [Stop]
└─ ← [Stop]