Refs #53
File: contracts/test/CharonLiquidatorFork.t.sol, _mockVenusAndPcs(), ~line 88
Code:
vm.mockCall(
PCS_V3_ROUTER,
abi.encodeWithSelector(ISwapRouter.exactInputSingle.selector),
abi.encode(uint256(0)) // amountOut = 0
);
Problem:
The mock always returns amountOut=0 from exactInputSingle. The test then also calls:
deal(m.debtToken, address(liquidator), surplus);
This pre-seeds the liquidator with exactly the funds needed (repayment + premium + profit). The test passes not because executeOperation correctly used the swap output, but because deal() bypassed the entire swap path. The logic in executeOperation that checks 'did the swap produce enough tokens to repay Aave' is never exercised — deal() ensures the balance is always sufficient regardless of what the mock returns.
Impact:
A bug in how executeOperation computes repayment sufficiency from amountOut would be completely invisible to this test suite. The swap return path is the exact surface where fee tier mismatch (#122) and slippage configuration (#122) manifest.
Fix:
Mock the swap to return a plausible non-zero amountOut that matches the deal() seeding:
vm.mockCall(
PCS_V3_ROUTER,
abi.encodeWithSelector(ISwapRouter.exactInputSingle.selector),
abi.encode(m.seizedUnderlying) // realistic swap output matching the collateral deal
);
Then remove the redundant deal(m.debtToken, ...) that masks the result, so executeOperation must actually derive surplus from the mock swap return.
Refs #53
File: contracts/test/CharonLiquidatorFork.t.sol, _mockVenusAndPcs(), ~line 88
Code:
vm.mockCall(
PCS_V3_ROUTER,
abi.encodeWithSelector(ISwapRouter.exactInputSingle.selector),
abi.encode(uint256(0)) // amountOut = 0
);
Problem:
The mock always returns amountOut=0 from exactInputSingle. The test then also calls:
deal(m.debtToken, address(liquidator), surplus);
This pre-seeds the liquidator with exactly the funds needed (repayment + premium + profit). The test passes not because executeOperation correctly used the swap output, but because deal() bypassed the entire swap path. The logic in executeOperation that checks 'did the swap produce enough tokens to repay Aave' is never exercised — deal() ensures the balance is always sufficient regardless of what the mock returns.
Impact:
A bug in how executeOperation computes repayment sufficiency from amountOut would be completely invisible to this test suite. The swap return path is the exact surface where fee tier mismatch (#122) and slippage configuration (#122) manifest.
Fix:
Mock the swap to return a plausible non-zero amountOut that matches the deal() seeding:
vm.mockCall(
PCS_V3_ROUTER,
abi.encodeWithSelector(ISwapRouter.exactInputSingle.selector),
abi.encode(m.seizedUnderlying) // realistic swap output matching the collateral deal
);
Then remove the redundant deal(m.debtToken, ...) that masks the result, so executeOperation must actually derive surplus from the mock swap return.