// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.15; import 'forge-std/Test.sol'; import {Permit2} from 'permit2/src/Permit2.sol'; import {ERC20} from 'solmate/src/tokens/ERC20.sol'; import {IAstraFactory} from '@airdao/astra-contracts/contracts/core/interfaces/IAstraFactory.sol'; import {IAstraPair} from '@airdao/astra-contracts/contracts/core/interfaces/IAstraPair.sol'; import {UniversalRouter} from '../../contracts/UniversalRouter.sol'; import {Payments} from '../../contracts/modules/Payments.sol'; import {Constants} from '../../contracts/libraries/Constants.sol'; import {Commands} from '../../contracts/libraries/Commands.sol'; import {RouterParameters} from '../../contracts/base/RouterImmutables.sol'; import '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol'; import '@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol'; abstract contract AstraClassicTest is Test { address constant RECIPIENT = address(10); uint256 constant AMOUNT = 1 ether; uint256 constant BALANCE = 100000 ether; IAstraFactory constant FACTORY = IAstraFactory(0x7bf4227eDfAA6823aD577dc198DbCadECccbEb07); ERC20 constant SAMB = ERC20(0x2Cf845b49e1c4E5D657fbBF36E97B7B5B7B7b74b); Permit2 constant PERMIT2 = Permit2(0x2B75bF9B8ec5966832c123bc24Db3a283E3C1be4); address constant FROM = address(1234); UniversalRouter router; function setUp() public virtual { vm.createSelectFork(vm.envString('FORK_URL'), 2810478); setUpTokens(); RouterParameters memory params = RouterParameters({ permit2: address(PERMIT2), samb: address(SAMB), seaportV1_5: address(0), seaportV1_4: address(0), openseaConduit: address(0), nftxZap: address(0), x2y2: address(0), foundation: address(0), sudoswap: address(0), elementMarket: address(0), nft20Zap: address(0), cryptopunks: address(0), looksRareV2: address(0), routerRewardsDistributor: address(0), looksRareRewardsDistributor: address(0), looksRareToken: address(0), classicFactory: address(FACTORY), clFactory: address(0), pairInitCodeHash: bytes32(0x890f57556fe54f67a74a243b39a055a4ad13602f405bfc7607a203a81592f64e), poolInitCodeHash: bytes32(0) }); router = new UniversalRouter(params); // pair doesn't exist, make a mock one if (FACTORY.getPair(token0(), token1()) == address(0)) { address pair = FACTORY.createPair(token0(), token1()); deal(token0(), pair, 100 ether); deal(token1(), pair, 100 ether); IAstraPair(pair).sync(); } vm.startPrank(FROM); deal(FROM, BALANCE); deal(token0(), FROM, BALANCE); deal(token1(), FROM, BALANCE); ERC20(token0()).approve(address(PERMIT2), type(uint256).max); ERC20(token1()).approve(address(PERMIT2), type(uint256).max); PERMIT2.approve(token0(), address(router), type(uint160).max, type(uint48).max); PERMIT2.approve(token1(), address(router), type(uint160).max, type(uint48).max); } function testExactInput0For1() public { bytes memory commands = abi.encodePacked(bytes1(uint8(Commands.CLASSIC_SWAP_EXACT_IN))); address[] memory path = new address[](2); path[0] = token0(); path[1] = token1(); bytes[] memory inputs = new bytes[](1); inputs[0] = abi.encode(Constants.MSG_SENDER, AMOUNT, 0, path, true); router.execute(commands, inputs); assertEq(ERC20(token0()).balanceOf(FROM), BALANCE - AMOUNT); assertGt(ERC20(token1()).balanceOf(FROM), BALANCE); } function testExactInput1For0() public { bytes memory commands = abi.encodePacked(bytes1(uint8(Commands.CLASSIC_SWAP_EXACT_IN))); address[] memory path = new address[](2); path[0] = token1(); path[1] = token0(); bytes[] memory inputs = new bytes[](1); inputs[0] = abi.encode(Constants.MSG_SENDER, AMOUNT, 0, path, true); router.execute(commands, inputs); assertEq(ERC20(token1()).balanceOf(FROM), BALANCE - AMOUNT); assertGt(ERC20(token0()).balanceOf(FROM), BALANCE); } function testExactInput0For1FromRouter() public { bytes memory commands = abi.encodePacked(bytes1(uint8(Commands.CLASSIC_SWAP_EXACT_IN))); deal(token0(), address(router), AMOUNT); address[] memory path = new address[](2); path[0] = token0(); path[1] = token1(); bytes[] memory inputs = new bytes[](1); inputs[0] = abi.encode(Constants.MSG_SENDER, AMOUNT, 0, path, false); router.execute(commands, inputs); assertGt(ERC20(token1()).balanceOf(FROM), BALANCE); } function testExactInput1For0FromRouter() public { bytes memory commands = abi.encodePacked(bytes1(uint8(Commands.CLASSIC_SWAP_EXACT_IN))); deal(token1(), address(router), AMOUNT); address[] memory path = new address[](2); path[0] = token1(); path[1] = token0(); bytes[] memory inputs = new bytes[](1); inputs[0] = abi.encode(Constants.MSG_SENDER, AMOUNT, 0, path, false); router.execute(commands, inputs); assertGt(ERC20(token0()).balanceOf(FROM), BALANCE); } function testExactOutput0For1() public { bytes memory commands = abi.encodePacked(bytes1(uint8(Commands.CLASSIC_SWAP_EXACT_OUT))); address[] memory path = new address[](2); path[0] = token0(); path[1] = token1(); bytes[] memory inputs = new bytes[](1); inputs[0] = abi.encode(Constants.MSG_SENDER, AMOUNT, type(uint256).max, path, true); router.execute(commands, inputs); assertLt(ERC20(token0()).balanceOf(FROM), BALANCE); assertGe(ERC20(token1()).balanceOf(FROM), BALANCE + AMOUNT); } function testExactOutput1For0() public { bytes memory commands = abi.encodePacked(bytes1(uint8(Commands.CLASSIC_SWAP_EXACT_OUT))); address[] memory path = new address[](2); path[0] = token1(); path[1] = token0(); bytes[] memory inputs = new bytes[](1); inputs[0] = abi.encode(Constants.MSG_SENDER, AMOUNT, type(uint256).max, path, true); router.execute(commands, inputs); assertLt(ERC20(token1()).balanceOf(FROM), BALANCE); assertGe(ERC20(token0()).balanceOf(FROM), BALANCE + AMOUNT); } function testExactOutput0For1FromRouter() public { bytes memory commands = abi.encodePacked(bytes1(uint8(Commands.CLASSIC_SWAP_EXACT_OUT))); deal(token0(), address(router), BALANCE); address[] memory path = new address[](2); path[0] = token0(); path[1] = token1(); bytes[] memory inputs = new bytes[](1); inputs[0] = abi.encode(Constants.MSG_SENDER, AMOUNT, type(uint256).max, path, false); router.execute(commands, inputs); assertGe(ERC20(token1()).balanceOf(FROM), BALANCE + AMOUNT); } function testExactOutput1For0FromRouter() public { bytes memory commands = abi.encodePacked(bytes1(uint8(Commands.CLASSIC_SWAP_EXACT_OUT))); deal(token1(), address(router), BALANCE); address[] memory path = new address[](2); path[0] = token1(); path[1] = token0(); bytes[] memory inputs = new bytes[](1); inputs[0] = abi.encode(Constants.MSG_SENDER, AMOUNT, type(uint256).max, path, false); router.execute(commands, inputs); assertGe(ERC20(token0()).balanceOf(FROM), BALANCE + AMOUNT); } function token0() internal virtual returns (address); function token1() internal virtual returns (address); function setUpTokens() internal virtual {} }