creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "SimulateTax (1).sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n\ninterface IWETH {\n    function deposit() external payable;\n    function transfer(address to, uint value) external returns (bool);\n    function withdraw(uint) external;\n}\n\ninterface IPancakePair {\n    event Approval(address indexed owner, address indexed spender, uint value);\n    event Transfer(address indexed from, address indexed to, uint value);\n\n    function name() external pure returns (string memory);\n    function symbol() external pure returns (string memory);\n    function decimals() external pure returns (uint8);\n    function totalSupply() external view returns (uint);\n    function balanceOf(address owner) external view returns (uint);\n    function allowance(address owner, address spender) external view returns (uint);\n\n    function approve(address spender, uint value) external returns (bool);\n    function transfer(address to, uint value) external returns (bool);\n    function transferFrom(address from, address to, uint value) external returns (bool);\n\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n    function PERMIT_TYPEHASH() external pure returns (bytes32);\n    function nonces(address owner) external view returns (uint);\n\n    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;\n\n    event Mint(address indexed sender, uint amount0, uint amount1);\n    event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);\n    event Swap(\n        address indexed sender,\n        uint amount0In,\n        uint amount1In,\n        uint amount0Out,\n        uint amount1Out,\n        address indexed to\n    );\n    event Sync(uint112 reserve0, uint112 reserve1);\n\n    function MINIMUM_LIQUIDITY() external pure returns (uint);\n    function factory() external view returns (address);\n    function token0() external view returns (address);\n    function token1() external view returns (address);\n    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);\n    function price0CumulativeLast() external view returns (uint);\n    function price1CumulativeLast() external view returns (uint);\n    function kLast() external view returns (uint);\n\n    function mint(address to) external returns (uint liquidity);\n    function burn(address to) external returns (uint amount0, uint amount1);\n    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;\n    function skim(address to) external;\n    function sync() external;\n\n    function initialize(address, address) external;\n}\n\ncontract SimulateTax {\n    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut, uint256 feeDeduct) internal pure returns (uint amountOut) {\n        require(amountIn > 0, 'PancakeLibrary: INSUFFICIENT_INPUT_AMOUNT');\n        require(reserveIn > 0 && reserveOut > 0, 'PancakeLibrary: INSUFFICIENT_LIQUIDITY');\n        uint amountInWithFee = amountIn * (10000 - feeDeduct);\n        uint numerator = amountInWithFee * reserveOut;\n        uint denominator = reserveIn * 10000 + amountInWithFee;\n        amountOut = numerator / denominator;\n    }\n\n    function pairSwap(address currentPair, address currentToken, address _to, uint256 feeDeduct) internal returns (uint256) {\n        IPancakePair pair = IPancakePair(currentPair);\n        uint amountInput;\n        uint amountOutput;\n        { // scope to avoid stack too deep errors\n            (uint reserve0, uint reserve1,) = pair.getReserves();\n            (uint reserveInput, uint reserveOutput) = pair.token0() == currentToken ? (reserve0, reserve1) : (reserve1, reserve0);\n            amountInput = IERC20(currentToken).balanceOf(address(pair)) - reserveInput;\n            amountOutput = getAmountOut(amountInput, reserveInput, reserveOutput, feeDeduct);\n        }\n        (uint amount0Out, uint amount1Out) = pair.token0() == currentToken ? (uint(0), amountOutput) : (amountOutput, uint(0));\n        pair.swap(amount0Out, amount1Out, _to, new bytes(0));\n\n        return amount0Out > 0? amount0Out: amount1Out;\n    }\n\n    function testTax(address token, address weth, address[] calldata pairChain, uint256 feeDeduct) external payable returns (\n        uint256 totalBuyAmount,\n        uint256 boughtAmount,\n        uint256 totalSellAmount,\n        uint256 soldAmount\n    ) {\n        IERC20 tokenContract = IERC20(token);\n        require(pairChain.length > 0, \"Null pair chain\");\n        require(IPancakePair(pairChain[0]).token0() == weth || IPancakePair(pairChain[0]).token1() == weth, \"WETH is not set\");\n\n        {\n            uint amountIn = msg.value;\n            IWETH(weth).deposit{value: amountIn}();\n            assert(IWETH(weth).transfer(pairChain[0], amountIn));\n        }\n\n        address[] memory tokenChain = new address[](pairChain.length + 1);\n        {\n            tokenChain[0] = weth;\n            uint256 i;\n            for (i = 1; i < tokenChain.length; i ++) {\n                if (IPancakePair(pairChain[i - 1]).token0() == tokenChain[i - 1]) tokenChain[i] = IPancakePair(pairChain[i - 1]).token1();\n                else if (IPancakePair(pairChain[i - 1]).token1() == tokenChain[i - 1]) tokenChain[i] = IPancakePair(pairChain[i - 1]).token0();\n                else revert(\"Not valid pair chain\");\n            }\n\n            require(token == tokenChain[tokenChain.length - 1], \"Token not set\");\n        }\n\n        {\n            // buy chain processing\n            address to = address(this);\n            uint256 oldBalance = tokenContract.balanceOf(to);\n\n            //_swapSupportingFeeOnTransferTokens(path, to)\n            for (uint256 i = 0; i < tokenChain.length - 1; i++) {\n                uint256 outAmount = pairSwap(pairChain[i], tokenChain[i], i < tokenChain.length - 2 ? pairChain[i + 1]: to, feeDeduct);\n\n                if (i >= tokenChain.length - 2) {\n                    totalBuyAmount = outAmount;\n                }\n            }\n\n            boughtAmount = tokenContract.balanceOf(to) - oldBalance;\n        }\n        {\n            // sell chain processing\n            // address to = address(this);\n            IPancakePair pair;\n            bool bFirstToken;\n            {\n                address tokenPair = pairChain[pairChain.length - 1];\n                pair = IPancakePair(tokenPair);\n                bFirstToken = pair.token0() == token;\n\n                // (uint oldReserve0, uint oldReserve1,) = pair.getReserves();\n                // (uint oldReserveInput, uint oldReserveOutput) = bFirstToken ? (oldReserve0, oldReserve1) : (oldReserve1, oldReserve0);\n\n                tokenContract.transfer(tokenPair, boughtAmount);\n                \n                (uint newReserve0, uint newReserve1,) = pair.getReserves();\n                (uint newReserveInput, ) = bFirstToken ? (newReserve0, newReserve1) : (newReserve1, newReserve0);\n\n                soldAmount = tokenContract.balanceOf(tokenPair) - newReserveInput;\n                // if (newReserveInput > oldReserveInput) { // contract sell\n                // } else if (newReserveInput < oldReserveInput) { // contract buy\n                // }\n            }\n\n            totalSellAmount = boughtAmount;\n            // uint256 outAmount = pairSwap(address(pair), token, to);\n        }\n    }\n\n    receive() external payable {\n    }\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      }
    }
  }}