// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.24; import {CurrencyLibrary, Currency} from "../types/Currency.sol"; import {IPoolManager} from "../interfaces/IPoolManager.sol"; import {BalanceDelta} from "../types/BalanceDelta.sol"; import {PoolKey} from "../types/PoolKey.sol"; import {SwapParams} from "../types/PoolOperation.sol"; import {IHooks} from "../interfaces/IHooks.sol"; import {Hooks} from "../libraries/Hooks.sol"; import {PoolTestBase} from "./PoolTestBase.sol"; import {CurrencySettler} from "../../test/utils/CurrencySettler.sol"; contract PoolSwapTest is PoolTestBase { using CurrencySettler for Currency; using Hooks for IHooks; constructor(IPoolManager _manager) PoolTestBase(_manager) {} error NoSwapOccurred(); struct CallbackData { address sender; TestSettings testSettings; PoolKey key; SwapParams params; bytes hookData; } struct TestSettings { bool takeClaims; bool settleUsingBurn; } function swap(PoolKey memory key, SwapParams memory params, TestSettings memory testSettings, bytes memory hookData) external payable returns (BalanceDelta delta) { delta = abi.decode( manager.unlock(abi.encode(CallbackData(msg.sender, testSettings, key, params, hookData))), (BalanceDelta) ); uint256 ethBalance = address(this).balance; if (ethBalance > 0) CurrencyLibrary.ADDRESS_ZERO.transfer(msg.sender, ethBalance); } function unlockCallback(bytes calldata rawData) external returns (bytes memory) { require(msg.sender == address(manager)); CallbackData memory data = abi.decode(rawData, (CallbackData)); (,, int256 deltaBefore0) = _fetchBalances(data.key.currency0, data.sender, address(this)); (,, int256 deltaBefore1) = _fetchBalances(data.key.currency1, data.sender, address(this)); require(deltaBefore0 == 0, "deltaBefore0 is not equal to 0"); require(deltaBefore1 == 0, "deltaBefore1 is not equal to 0"); BalanceDelta delta = manager.swap(data.key, data.params, data.hookData); (,, int256 deltaAfter0) = _fetchBalances(data.key.currency0, data.sender, address(this)); (,, int256 deltaAfter1) = _fetchBalances(data.key.currency1, data.sender, address(this)); if (data.params.zeroForOne) { if (data.params.amountSpecified < 0) { // exact input, 0 for 1 require( deltaAfter0 >= data.params.amountSpecified, "deltaAfter0 is not greater than or equal to data.params.amountSpecified" ); require(delta.amount0() == deltaAfter0, "delta.amount0() is not equal to deltaAfter0"); require(deltaAfter1 >= 0, "deltaAfter1 is not greater than or equal to 0"); } else { // exact output, 0 for 1 require(deltaAfter0 <= 0, "deltaAfter0 is not less than or equal to zero"); require(delta.amount1() == deltaAfter1, "delta.amount1() is not equal to deltaAfter1"); require( deltaAfter1 <= data.params.amountSpecified, "deltaAfter1 is not less than or equal to data.params.amountSpecified" ); } } else { if (data.params.amountSpecified < 0) { // exact input, 1 for 0 require( deltaAfter1 >= data.params.amountSpecified, "deltaAfter1 is not greater than or equal to data.params.amountSpecified" ); require(delta.amount1() == deltaAfter1, "delta.amount1() is not equal to deltaAfter1"); require(deltaAfter0 >= 0, "deltaAfter0 is not greater than or equal to 0"); } else { // exact output, 1 for 0 require(deltaAfter1 <= 0, "deltaAfter1 is not less than or equal to 0"); require(delta.amount0() == deltaAfter0, "delta.amount0() is not equal to deltaAfter0"); require( deltaAfter0 <= data.params.amountSpecified, "deltaAfter0 is not less than or equal to data.params.amountSpecified" ); } } if (deltaAfter0 < 0) { data.key.currency0.settle(manager, data.sender, uint256(-deltaAfter0), data.testSettings.settleUsingBurn); } if (deltaAfter1 < 0) { data.key.currency1.settle(manager, data.sender, uint256(-deltaAfter1), data.testSettings.settleUsingBurn); } if (deltaAfter0 > 0) { data.key.currency0.take(manager, data.sender, uint256(deltaAfter0), data.testSettings.takeClaims); } if (deltaAfter1 > 0) { data.key.currency1.take(manager, data.sender, uint256(deltaAfter1), data.testSettings.takeClaims); } return abi.encode(delta); } }