User: // SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.0.0
pragma solidity ^0.8.26;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";

struct StructUserAccount {
    address user;
}

contract SwapRouter is
    Initializable,
    PausableUpgradeable,
    OwnableUpgradeable,
    UUPSUpgradeable
{
    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    function initialize(address initialOwner) public initializer {
        __Pausable_init();
        __Ownable_init(initialOwner);
        __UUPSUpgradeable_init();
    }

    function getAmountsOut() external view returns (uint256[] memory amounts) {}

    receive() external payable {}

    function pause() public onlyOwner {
        _pause();
    }

    function unpause() public onlyOwner {
        _unpause();
    }

    function _authorizeUpgrade(
        address newImplementation
    ) internal override onlyOwner {}
}


can you complete the code, what i want is, user is able to swap multiple tokens at the same time using uniswap v2 and v3, whenever he swap a token from liquidity current price should be added with the token address pair address and with router address, so that we can calculate the profit, i want user should be able to swap or more specific can buy and sell at a certain percentage movement of price change like on every 5% of price up and down
Assistant: Creating a smart contract that facilitates multiple token swaps using both Uniswap V2 and V3, and also tracks price changes for strategic trading, requires careful design. Below is a sample code that outlines how you might implement such functionality:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";

contract SwapRouter is Initializable, PausableUpgradeable, OwnableUpgradeable, UUPSUpgradeable {
    using SafeERC20 for IERC20;

    IUniswapV2Router02 public uniswapV2Router;
    ISwapRouter public uniswapV3Router;

    struct TokenConfig {
        address token;
        address pair;
        uint256 lastPrice;
    }

    mapping(address => TokenConfig) public tokenConfigs;
    
    event TokenSwapped(address indexed user, address indexed token, uint256 amountIn, uint256 amountOut, uint256 price);

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    function initialize(address initialOwner, address _uniswapV2Router, address _uniswapV3Router) public initializer {
        __Pausable_init();
        __Ownable_init(initialOwner);
        __UUPSUpgradeable_init();

        uniswapV2Router = IUniswapV2Router02(_uniswapV2Router);
        uniswapV3Router = ISwapRouter(_uniswapV3Router);
    }

    function configureToken(address token, address pair) external onlyOwner {
        require(token != address(0) && pair != address(0), "Invalid addresses");
        tokenConfigs[token] = TokenConfig(token, pair, 0);
    }

    function swapTokensV2(address tokenIn, uint256 amountIn, address tokenOut) external whenNotPaused {
        require(tokenConfigs[tokenIn].token != address(0), "Token not configured");
        
        IERC20(tokenIn).safeTransferFrom(msg.sender, address(this), amountIn);
        IERC20(tokenIn).safeApprove(address(uniswapV2Router), amountIn);

        address[] memory path = new address[](2);
        path[0] = tokenIn;
        path[1] = tokenOut;

        uint256[] memory amounts = uniswapV2Router.swapExactTokensForTokens(
            amountIn,
            0,
            path,
            msg.sender,
            block.timestamp + 60
        );

        uint256 newPrice = calculateCurrentPrice(tokenIn, amounts[0]);
        emit TokenSwapped(msg.sender, tokenIn, amountIn, amounts[1], newPrice);
    }

    function swapTokensV3(address tokenIn, uint256 amountIn, address tokenOut, uint24 fee) external whenNotPaused {
        require(tokenConfigs[tokenIn].token != address(0), "Token not configured");

        IERC20(tokenIn).safeTransferFrom(msg.sender, address(this), amountIn);
        IERC20(tokenIn).safeApprove(address(uniswapV3Router), amountIn);

        ISwapRouter.ExactInputSingleParams memory params =
            ISwapRouter.ExactInputSingleParams({
                tokenIn: tokenIn,
                tokenOut: tokenOut,
                fee: fee,
                recipient: msg.sender,
                deadline: block.timestamp + 60,
                amountIn: amountIn,
                amountOutMinimum: 0,
                sqrtPriceLimitX96: 0
            });

        uniswapV3Router.exactInputSingle(params);
        
        uint256 newPrice = calculateCurrentPrice(tokenIn, amountIn); // Simplified
        emit TokenSwapped(msg.sender, tokenIn, amountIn, amountIn, newPrice);
    }

    function calculateCurrentPrice(address token, uint256 amount) internal view returns (uint256) {
        // Placeholder function to integrate with an oracle or use Off-chain calculation
        return amount; // dummy return
    }

    receive() external payable {}

    function pause() public onlyOwner {
        _pause();
    }

    function unpause() public onlyOwner {
        _unpause();
    }

    function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
}

```

### Key Components:

1. **Token Management:** The `configureToken` function allows you to set up tokens alongside their pair address (liquidity pool) and last known price.

2. **Swapping Logic:**
   - **Uniswap V2:** Swaps are done through `swapTokensV2` which uses Uniswap V2's router for token exchange.
   - **Uniswap V3:** Similarly, `swapTokensV3` facilitates swaps on Uniswap V3 using `exactInputSingle`.

3. **Tracking Price Changes:** A structure to store token pricing and pairs has been set up. The `calculateCurrentPrice` function should be extended to actually fetch and calculate real-time prices, potentially using a price oracle.

4. **Event Emission:** Emitting events after a swap (`TokenSwapped`) captures the token, amounts, and price metrics for external indexing or off-chain use.

5. **Upgradability:** Utilizes OpenZeppelin's upgradeable framework which allows you to deploy upgrades through the UUPS pattern.

### Considerations:
- The above logic does not directly buy/sell at defined price movements yet; you'd need additional logic to store price thresholds and trigger swaps based on those conditions.
- Real-world scenarios must include robust mechanisms to handle slippage, prevent reentrancy, ensure gas limits, and handle error states effectively.
User: there is also a view function that will will the current price of the token
Assistant: