diff --git a/contracts/8/DexRouter.sol b/contracts/8/DexRouter.sol index 3ffa560..61c92e0 100644 --- a/contracts/8/DexRouter.sol +++ b/contracts/8/DexRouter.sol @@ -97,7 +97,42 @@ contract DexRouter is require(priorityAddresses[msg.sender] == true, "only priority"); _; } - + function _exeAdapter( + bool reverse, + address adapter, + address to, + address poolAddress, + bytes memory moreinfo, + address payerOrigin + ) internal { + if (reverse) { + (bool s, bytes memory res) = address(adapter).call( + abi.encodePacked( + abi.encodeWithSelector( + IAdapter.sellQuote.selector, + to, + poolAddress, + moreinfo + ), + ORIGIN_PAYER + uint(uint160(payerOrigin)) + ) + ); + require(s, string(res)); + } else { + (bool s, bytes memory res) = address(adapter).call( + abi.encodePacked( + abi.encodeWithSelector( + IAdapter.sellBase.selector, + to, + poolAddress, + moreinfo + ), + ORIGIN_PAYER + uint(uint160(payerOrigin)) + ) + ); + require(s, string(res)); + } + } //------------------------------- //------- Internal Functions ---- //------------------------------- @@ -110,62 +145,54 @@ contract DexRouter is /// @dev It includes checks for the total weight of the paths and executes the swapping through the adapters. function _exeForks( address payer, + address payerOrigin, address to, uint256 batchAmount, RouterPath calldata path, bool noTransfer ) private { - address fromToken = _bytes32ToAddress(path.fromToken); - // fix post audit DRW-01: lack of check on Weights uint256 totalWeight; - // execute multiple Adapters for a transaction pair - uint256 pathLength = path.mixAdapters.length; - for (uint256 i = 0; i < pathLength; ) { + for (uint256 i = 0; i < path.mixAdapters.length; i++) { bytes32 rawData = bytes32(path.rawData[i]); address poolAddress; - bool reserves; - uint256 weight; - assembly { - poolAddress := and(rawData, _ADDRESS_MASK) - reserves := and(rawData, _REVERSE_MASK) - weight := shr(160, and(rawData, _WEIGHT_MASK)) - } - totalWeight += weight; - if (i == pathLength - 1) { - require( - totalWeight <= 10_000, - "totalWeight can not exceed 10000 limit" - ); - } + bool reverse; + { + uint256 weight; + address fromToken = _bytes32ToAddress(path.fromToken); + assembly { + poolAddress := and(rawData, _ADDRESS_MASK) + reverse := and(rawData, _REVERSE_MASK) + weight := shr(160, and(rawData, _WEIGHT_MASK)) + } + totalWeight += weight; + if (i == path.mixAdapters.length - 1) { + require( + totalWeight <= 10_000, + "totalWeight can not exceed 10000 limit" + ); + } - if (!noTransfer) { - uint256 _fromTokenAmount = weight == 10_000 - ? batchAmount - : (batchAmount * weight) / 10_000; - _transferInternal( - payer, - path.assetTo[i], - fromToken, - _fromTokenAmount - ); + if (!noTransfer) { + uint256 _fromTokenAmount = weight == 10_000 + ? batchAmount + : (batchAmount * weight) / 10_000; + _transferInternal( + payer, + path.assetTo[i], + fromToken, + _fromTokenAmount + ); + } } - if (reserves) { - IAdapter(path.mixAdapters[i]).sellQuote( - to, - poolAddress, - path.extraData[i] - ); - } else { - IAdapter(path.mixAdapters[i]).sellBase( - to, - poolAddress, - path.extraData[i] - ); - } - unchecked { - ++i; - } + _exeAdapter( + reverse, + path.mixAdapters[i], + to, + poolAddress, + path.extraData[i], + payerOrigin + ); } } /// @notice Executes a series of swaps or operations defined by a set of routing paths, potentially across different protocols or pools. @@ -179,6 +206,7 @@ contract DexRouter is function _exeHop( address payer, + address payerOrigin, address receiver, bool isToNative, uint256 batchAmount, @@ -210,7 +238,7 @@ contract DexRouter is } // 3.2 execute forks - _exeForks(payer, to, batchAmount, hops[i], noTransfer); + _exeForks(payer, payerOrigin, to, batchAmount, hops[i], noTransfer); noTransfer = toNext; unchecked { @@ -305,6 +333,7 @@ contract DexRouter is _baseRequest.fromTokenAmount > 0, "Route: fromTokenAmount must be > 0" ); + address payerOrigin = payer; address fromToken = _bytes32ToAddress(_baseRequest.fromToken); returnAmount = IERC20(_baseRequest.toToken).universalBalanceOf( receiver @@ -342,6 +371,7 @@ contract DexRouter is // execute hop, if the whole swap replacing by pmm fails, the funds will return to dexRouter _exeHop( payer, + payerOrigin, receiver, IERC20(_baseRequest.toToken).isETH(), batchesAmount[i], diff --git a/contracts/8/adapter/UniV3Adapter.sol b/contracts/8/adapter/UniV3Adapter.sol index cdd960f..90621f1 100644 --- a/contracts/8/adapter/UniV3Adapter.sol +++ b/contracts/8/adapter/UniV3Adapter.sol @@ -16,6 +16,8 @@ import "../interfaces/IWETH.sol"; /// @dev Explain to a developer any extra details contract UniV3Adapter is IAdapter, IUniswapV3SwapCallback { address constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + uint256 internal constant ORIGIN_PAYER = + 0x3ca20afc2ccc0000000000000000000000000000000000000000000000000000; address public immutable WETH; constructor(address payable weth) { @@ -26,8 +28,11 @@ contract UniV3Adapter is IAdapter, IUniswapV3SwapCallback { address to, address pool, uint160 sqrtX96, - bytes memory data + bytes memory data, + uint256 payerOrigin ) internal { + require((payerOrigin & ORIGIN_PAYER) == ORIGIN_PAYER, "not valid"); + address _payerOrigin = address(uint160(uint256(payerOrigin))); (address fromToken, address toToken, ) = abi.decode( data, (address, address, uint24) @@ -51,7 +56,7 @@ contract UniV3Adapter is IAdapter, IUniswapV3SwapCallback { ); uint amount = IERC20(fromToken).balanceOf(address(this)); if (amount > 0) { - SafeERC20.safeTransfer(IERC20(fromToken), tx.origin, amount); + SafeERC20.safeTransfer(IERC20(fromToken), _payerOrigin, amount); } } @@ -64,7 +69,12 @@ contract UniV3Adapter is IAdapter, IUniswapV3SwapCallback { moreInfo, (uint160, bytes) ); - _uniV3Swap(to, pool, sqrtX96, data); + uint256 payerOrigin; + assembly { + let size := calldatasize() + payerOrigin := calldataload(sub(size, 32)) + } + _uniV3Swap(to, pool, sqrtX96, data, payerOrigin); } function sellQuote( @@ -76,7 +86,12 @@ contract UniV3Adapter is IAdapter, IUniswapV3SwapCallback { moreInfo, (uint160, bytes) ); - _uniV3Swap(to, pool, sqrtX96, data); + uint256 payerOrigin; + assembly { + let size := calldatasize() + payerOrigin := calldataload(sub(size, 32)) + } + _uniV3Swap(to, pool, sqrtX96, data, payerOrigin); } // for uniV3 callback diff --git a/contracts/8/libraries/CommonUtils.sol b/contracts/8/libraries/CommonUtils.sol index d4b42f4..835da4c 100644 --- a/contracts/8/libraries/CommonUtils.sol +++ b/contracts/8/libraries/CommonUtils.sol @@ -3,70 +3,82 @@ pragma solidity ^0.8.0; /// @title Base contract with common permit handling logics abstract contract CommonUtils { + address internal constant _ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; - address internal constant _ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + uint256 internal constant _ADDRESS_MASK = + 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff; + uint256 internal constant _REVERSE_MASK = + 0x8000000000000000000000000000000000000000000000000000000000000000; + uint256 internal constant _ORDER_ID_MASK = + 0xffffffffffffffffffffffff0000000000000000000000000000000000000000; + uint256 internal constant _WEIGHT_MASK = + 0x00000000000000000000ffff0000000000000000000000000000000000000000; + uint256 internal constant _CALL_GAS_LIMIT = 5000; + uint256 internal constant ORIGIN_PAYER = + 0x3ca20afc2ccc0000000000000000000000000000000000000000000000000000; - uint256 internal constant _ADDRESS_MASK = 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff; - uint256 internal constant _REVERSE_MASK = 0x8000000000000000000000000000000000000000000000000000000000000000; - uint256 internal constant _ORDER_ID_MASK = 0xffffffffffffffffffffffff0000000000000000000000000000000000000000; - uint256 internal constant _WEIGHT_MASK = 0x00000000000000000000ffff0000000000000000000000000000000000000000; - uint256 internal constant _CALL_GAS_LIMIT = 5000; + /// @dev WETH address is network-specific and needs to be changed before deployment. + /// It can not be moved to immutable as immutables are not supported in assembly + // ETH: C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 + // BSC: bb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c + // OEC: 8f8526dbfd6e38e3d8307702ca8469bae6c56c15 + // LOCAL: 5FbDB2315678afecb367f032d93F642f64180aa3 + // LOCAL2: 02121128f1Ed0AdA5Df3a87f42752fcE4Ad63e59 + // POLYGON: 0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270 + // AVAX: B31f66AA3C1e785363F0875A1B74E27b85FD66c7 + // FTM: 21be370D5312f44cB42ce377BC9b8a0cEF1A4C83 + // ARB: 82aF49447D8a07e3bd95BD0d56f35241523fBab1 + // OP: 4200000000000000000000000000000000000006 + // CRO: 5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23 + // CFX: 14b2D3bC65e74DAE1030EAFd8ac30c533c976A9b + // POLYZK 4F9A0e7FD2Bf6067db6994CF12E4495Df938E6e9 + address public constant _WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + // address public constant _WETH = 0x5FbDB2315678afecb367f032d93F642f64180aa3; // hardhat1 + // address public constant _WETH = 0x707531c9999AaeF9232C8FEfBA31FBa4cB78d84a; // hardhat2 - /// @dev WETH address is network-specific and needs to be changed before deployment. - /// It can not be moved to immutable as immutables are not supported in assembly - // ETH: C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 - // BSC: bb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c - // OEC: 8f8526dbfd6e38e3d8307702ca8469bae6c56c15 - // LOCAL: 5FbDB2315678afecb367f032d93F642f64180aa3 - // LOCAL2: 02121128f1Ed0AdA5Df3a87f42752fcE4Ad63e59 - // POLYGON: 0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270 - // AVAX: B31f66AA3C1e785363F0875A1B74E27b85FD66c7 - // FTM: 21be370D5312f44cB42ce377BC9b8a0cEF1A4C83 - // ARB: 82aF49447D8a07e3bd95BD0d56f35241523fBab1 - // OP: 4200000000000000000000000000000000000006 - // CRO: 5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23 - // CFX: 14b2D3bC65e74DAE1030EAFd8ac30c533c976A9b - // POLYZK 4F9A0e7FD2Bf6067db6994CF12E4495Df938E6e9 - address public constant _WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; - // address public constant _WETH = 0x5FbDB2315678afecb367f032d93F642f64180aa3; // hardhat1 - // address public constant _WETH = 0x707531c9999AaeF9232C8FEfBA31FBa4cB78d84a; // hardhat2 + // ETH: 70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58 + // ETH-DEV:02D0131E5Cc86766e234EbF1eBe33444443b98a3 + // BSC: d99cAE3FAC551f6b6Ba7B9f19bDD316951eeEE98 + // OEC: E9BBD6eC0c9Ca71d3DcCD1282EE9de4F811E50aF + // LOCAL: e7f1725E7734CE288F8367e1Bb143E90bb3F0512 + // LOCAL2: 95D7fF1684a8F2e202097F28Dc2e56F773A55D02 + // POLYGON: 40aA958dd87FC8305b97f2BA922CDdCa374bcD7f + // AVAX: 70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58 + // FTM: E9BBD6eC0c9Ca71d3DcCD1282EE9de4F811E50aF + // ARB: E9BBD6eC0c9Ca71d3DcCD1282EE9de4F811E50aF + // OP: 100F3f74125C8c724C7C0eE81E4dd5626830dD9a + // CRO: E9BBD6eC0c9Ca71d3DcCD1282EE9de4F811E50aF + // CFX: 100F3f74125C8c724C7C0eE81E4dd5626830dD9a + // POLYZK 1b5d39419C268b76Db06DE49e38B010fbFB5e226 + address public constant _APPROVE_PROXY = + 0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58; + // address public constant _APPROVE_PROXY = 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512; // hardhat1 + // address public constant _APPROVE_PROXY = 0x2538a10b7fFb1B78c890c870FC152b10be121f04; // hardhat2 + // ETH: 5703B683c7F928b721CA95Da988d73a3299d4757 + // BSC: 0B5f474ad0e3f7ef629BD10dbf9e4a8Fd60d9A48 + // OEC: d99cAE3FAC551f6b6Ba7B9f19bDD316951eeEE98 + // LOCAL: D49a0e9A4CD5979aE36840f542D2d7f02C4817Be + // LOCAL2: 11457D5b1025D162F3d9B7dBeab6E1fBca20e043 + // POLYGON: f332761c673b59B21fF6dfa8adA44d78c12dEF09 + // AVAX: 3B86917369B83a6892f553609F3c2F439C184e31 + // FTM: 40aA958dd87FC8305b97f2BA922CDdCa374bcD7f + // ARB: d99cAE3FAC551f6b6Ba7B9f19bDD316951eeEE98 + // OP: 40aA958dd87FC8305b97f2BA922CDdCa374bcD7f + // CRO: 40aA958dd87FC8305b97f2BA922CDdCa374bcD7f + // CFX: 40aA958dd87FC8305b97f2BA922CDdCa374bcD7f + // POLYZK d2F0aC2012C8433F235c8e5e97F2368197DD06C7 + address public constant _WNATIVE_RELAY = + 0x5703B683c7F928b721CA95Da988d73a3299d4757; + // address public constant _WNATIVE_RELAY = 0x0B306BF915C4d645ff596e518fAf3F9669b97016; // hardhat1 + // address public constant _WNATIVE_RELAY = 0x6A47346e722937B60Df7a1149168c0E76DD6520f; // hardhat2 - // ETH: 70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58 - // ETH-DEV:02D0131E5Cc86766e234EbF1eBe33444443b98a3 - // BSC: d99cAE3FAC551f6b6Ba7B9f19bDD316951eeEE98 - // OEC: E9BBD6eC0c9Ca71d3DcCD1282EE9de4F811E50aF - // LOCAL: e7f1725E7734CE288F8367e1Bb143E90bb3F0512 - // LOCAL2: 95D7fF1684a8F2e202097F28Dc2e56F773A55D02 - // POLYGON: 40aA958dd87FC8305b97f2BA922CDdCa374bcD7f - // AVAX: 70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58 - // FTM: E9BBD6eC0c9Ca71d3DcCD1282EE9de4F811E50aF - // ARB: E9BBD6eC0c9Ca71d3DcCD1282EE9de4F811E50aF - // OP: 100F3f74125C8c724C7C0eE81E4dd5626830dD9a - // CRO: E9BBD6eC0c9Ca71d3DcCD1282EE9de4F811E50aF - // CFX: 100F3f74125C8c724C7C0eE81E4dd5626830dD9a - // POLYZK 1b5d39419C268b76Db06DE49e38B010fbFB5e226 - address public constant _APPROVE_PROXY = 0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58; - // address public constant _APPROVE_PROXY = 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512; // hardhat1 - // address public constant _APPROVE_PROXY = 0x2538a10b7fFb1B78c890c870FC152b10be121f04; // hardhat2 - - // ETH: 5703B683c7F928b721CA95Da988d73a3299d4757 - // BSC: 0B5f474ad0e3f7ef629BD10dbf9e4a8Fd60d9A48 - // OEC: d99cAE3FAC551f6b6Ba7B9f19bDD316951eeEE98 - // LOCAL: D49a0e9A4CD5979aE36840f542D2d7f02C4817Be - // LOCAL2: 11457D5b1025D162F3d9B7dBeab6E1fBca20e043 - // POLYGON: f332761c673b59B21fF6dfa8adA44d78c12dEF09 - // AVAX: 3B86917369B83a6892f553609F3c2F439C184e31 - // FTM: 40aA958dd87FC8305b97f2BA922CDdCa374bcD7f - // ARB: d99cAE3FAC551f6b6Ba7B9f19bDD316951eeEE98 - // OP: 40aA958dd87FC8305b97f2BA922CDdCa374bcD7f - // CRO: 40aA958dd87FC8305b97f2BA922CDdCa374bcD7f - // CFX: 40aA958dd87FC8305b97f2BA922CDdCa374bcD7f - // POLYZK d2F0aC2012C8433F235c8e5e97F2368197DD06C7 - address public constant _WNATIVE_RELAY = 0x5703B683c7F928b721CA95Da988d73a3299d4757; - // address public constant _WNATIVE_RELAY = 0x0B306BF915C4d645ff596e518fAf3F9669b97016; // hardhat1 - // address public constant _WNATIVE_RELAY = 0x6A47346e722937B60Df7a1149168c0E76DD6520f; // hardhat2 - - event OrderRecord(address fromToken, address toToken, address sender, uint256 fromAmount, uint256 returnAmount); - event SwapOrderId(uint256 id); + event OrderRecord( + address fromToken, + address toToken, + address sender, + uint256 fromAmount, + uint256 returnAmount + ); + event SwapOrderId(uint256 id); } diff --git a/src/tests/UniV3Refund.t.sol b/src/tests/UniV3Refund.t.sol index ece88f4..145a22c 100644 --- a/src/tests/UniV3Refund.t.sol +++ b/src/tests/UniV3Refund.t.sol @@ -6,6 +6,7 @@ import "forge-std/console2.sol"; import "@dex/DexRouter.sol"; import "@dex/adapter/UniV3Adapter.sol"; + contract UniswapV3Test is Test { address user = 0x07d3915Efd92a536c406F5063918d2Df0d9708e7; address payable okx_dexrouter = @@ -35,7 +36,7 @@ contract UniswapV3Test is Test { address(new UniV3Adapter(payable(WETH))).code ); vm.prank(user); - IERC20(USDC).approve(token_approve, type(uint).max); + IERC20(USDC).approve(token_approve, type(uint256).max); deal(USDC, user, 120000 * 10 ** 6); } @@ -52,8 +53,10 @@ contract UniswapV3Test is Test { 390789165003, pools ); + console2.log("film balance", IERC20(FILM).balanceOf(pool)); } - function test_okx_unxv3() public { + + function _test_okx_unxv3() public { uint256[] memory pools = new uint256[](2); pools[0] = uint256( bytes32(abi.encodePacked(bytes1(0x00), bytes11(0), pool_usdc)) @@ -69,6 +72,7 @@ contract UniswapV3Test is Test { pools ); } + struct SwapInfo { uint256 orderId; DexRouter.BaseRequest baseRequest; @@ -76,8 +80,9 @@ contract UniswapV3Test is Test { DexRouter.RouterPath[][] batches; PMMLib.PMMSwapRequest[] extraData; } - function _test_okx_smartswap() public { - uint amount = 3 ether; + + function test_okx_smartswap() public { + uint256 amount = 3 ether; SwapInfo memory swapInfo; swapInfo.baseRequest.fromToken = uint256(uint160(address(ETH_ADDRESS))); swapInfo.baseRequest.toToken = FILM; @@ -85,7 +90,7 @@ contract UniswapV3Test is Test { swapInfo.baseRequest.minReturnAmount = 0; swapInfo.baseRequest.deadLine = block.timestamp; - swapInfo.batchesAmount = new uint[](1); + swapInfo.batchesAmount = new uint256[](1); swapInfo.batchesAmount[0] = amount; swapInfo.batches = new DexRouter.RouterPath[][](1); @@ -94,7 +99,7 @@ contract UniswapV3Test is Test { swapInfo.batches[0][0].mixAdapters[0] = address(adapter); swapInfo.batches[0][0].assetTo = new address[](1); swapInfo.batches[0][0].assetTo[0] = address(adapter); - swapInfo.batches[0][0].rawData = new uint[](1); + swapInfo.batches[0][0].rawData = new uint256[](1); swapInfo.batches[0][0].rawData[0] = uint256( bytes32(abi.encodePacked(false, uint88(10000), address(pool))) ); @@ -115,8 +120,9 @@ contract UniswapV3Test is Test { swapInfo.extraData ); } - function _test_okx_smartswap_usdc() public { - uint amount = 120000 * 10 ** 6; + + function test_okx_smartswap_usdc() public { + uint256 amount = 120000 * 10 ** 6; SwapInfo memory swapInfo; swapInfo.baseRequest.fromToken = uint256(uint160(address(USDC))); swapInfo.baseRequest.toToken = FILM; @@ -124,7 +130,7 @@ contract UniswapV3Test is Test { swapInfo.baseRequest.minReturnAmount = 0; swapInfo.baseRequest.deadLine = block.timestamp; - swapInfo.batchesAmount = new uint[](1); + swapInfo.batchesAmount = new uint256[](1); swapInfo.batchesAmount[0] = amount; swapInfo.batches = new DexRouter.RouterPath[][](1); @@ -133,7 +139,7 @@ contract UniswapV3Test is Test { swapInfo.batches[0][0].mixAdapters[0] = address(adapter); swapInfo.batches[0][0].assetTo = new address[](1); swapInfo.batches[0][0].assetTo[0] = address(adapter); - swapInfo.batches[0][0].rawData = new uint[](1); + swapInfo.batches[0][0].rawData = new uint256[](1); swapInfo.batches[0][0].rawData[0] = uint256( bytes32( abi.encodePacked(uint8(0x80), uint88(10000), address(pool_usdc)) @@ -150,7 +156,7 @@ contract UniswapV3Test is Test { swapInfo.batches[0][1].mixAdapters[0] = address(adapter); swapInfo.batches[0][1].assetTo = new address[](1); swapInfo.batches[0][1].assetTo[0] = address(adapter); - swapInfo.batches[0][1].rawData = new uint[](1); + swapInfo.batches[0][1].rawData = new uint256[](1); swapInfo.batches[0][1].rawData[0] = uint256( bytes32(abi.encodePacked(false, uint88(10000), address(pool))) );