creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "src/ButtonswapRouter.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport {IButtonswapRouter} from \"./interfaces/IButtonswapRouter/IButtonswapRouter.sol\";\nimport {IButtonswapFactory} from\n    \"buttonswap-periphery_buttonswap-core/interfaces/IButtonswapFactory/IButtonswapFactory.sol\";\nimport {IButtonswapPair} from \"buttonswap-periphery_buttonswap-core/interfaces/IButtonswapPair/IButtonswapPair.sol\";\nimport {TransferHelper} from \"./libraries/TransferHelper.sol\";\nimport {ButtonswapLibrary} from \"./libraries/ButtonswapLibrary.sol\";\nimport {IERC20} from \"./interfaces/IERC20.sol\";\nimport {IWETH} from \"./interfaces/IWETH.sol\";\nimport {ETHButtonswapRouter} from \"./ETHButtonswapRouter.sol\";\n\ncontract ButtonswapRouter is ETHButtonswapRouter, IButtonswapRouter {\n    constructor(address _factory, address _WETH) ETHButtonswapRouter(_factory, _WETH) {}\n\n    /**\n     * @inheritdoc IButtonswapRouter\n     */\n    function getPair(address tokenA, address tokenB) external view returns (address pair) {\n        return IButtonswapFactory(factory).getPair(tokenA, tokenB);\n    }\n\n    /**\n     * @inheritdoc IButtonswapRouter\n     */\n    function isCreationRestricted() external view returns (bool _isCreationRestricted) {\n        _isCreationRestricted = IButtonswapFactory(factory).isCreationRestricted();\n    }\n\n    // **** LIBRARY FUNCTIONS ****\n\n    /**\n     * @inheritdoc IButtonswapRouter\n     */\n    function quote(uint256 amountA, uint256 poolA, uint256 poolB)\n        external\n        pure\n        virtual\n        override\n        returns (uint256 amountB)\n    {\n        return ButtonswapLibrary.quote(amountA, poolA, poolB);\n    }\n\n    /**\n     * @inheritdoc IButtonswapRouter\n     */\n    function getAmountOut(uint256 amountIn, uint256 poolIn, uint256 poolOut)\n        external\n        pure\n        virtual\n        override\n        returns (uint256 amountOut)\n    {\n        return ButtonswapLibrary.getAmountOut(amountIn, poolIn, poolOut);\n    }\n\n    /**\n     * @inheritdoc IButtonswapRouter\n     */\n    function getAmountIn(uint256 amountOut, uint256 poolIn, uint256 poolOut)\n        external\n        pure\n        virtual\n        override\n        returns (uint256 amountIn)\n    {\n        return ButtonswapLibrary.getAmountIn(amountOut, poolIn, poolOut);\n    }\n\n    /**\n     * @inheritdoc IButtonswapRouter\n     */\n    function getAmountsOut(uint256 amountIn, address[] memory path)\n        external\n        view\n        virtual\n        override\n        returns (uint256[] memory amounts)\n    {\n        return ButtonswapLibrary.getAmountsOut(factory, amountIn, path);\n    }\n\n    /**\n     * @inheritdoc IButtonswapRouter\n     */\n    function getAmountsIn(uint256 amountOut, address[] memory path)\n        external\n        view\n        virtual\n        override\n        returns (uint256[] memory amounts)\n    {\n        return ButtonswapLibrary.getAmountsIn(factory, amountOut, path);\n    }\n\n    /**\n     * @inheritdoc IButtonswapRouter\n     */\n    function getMintSwappedAmounts(address tokenA, address tokenB, uint256 mintAmountA)\n        external\n        view\n        virtual\n        override\n        returns (uint256 tokenAToSwap, uint256 swappedReservoirAmountB)\n    {\n        return ButtonswapLibrary.getMintSwappedAmounts(factory, tokenA, tokenB, mintAmountA);\n    }\n\n    /**\n     * @inheritdoc IButtonswapRouter\n     */\n    function getBurnSwappedAmounts(address tokenA, address tokenB, uint256 liquidity)\n        external\n        view\n        virtual\n        override\n        returns (uint256 tokenOutA, uint256 swappedReservoirAmountA)\n    {\n        return ButtonswapLibrary.getBurnSwappedAmounts(factory, tokenA, tokenB, liquidity);\n    }\n}\n"
      },
      "src/interfaces/IButtonswapRouter/IButtonswapRouter.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport {IETHButtonswapRouter} from \"./IETHButtonswapRouter.sol\";\n\ninterface IButtonswapRouter is IETHButtonswapRouter {\n    /**\n     * @notice Returns the Pair contract for given tokens. Returns the zero address if no pair exists\n     * @param tokenA First token address\n     * @param tokenB Second token address\n     * @return pair The pair address\n     */\n    function getPair(address tokenA, address tokenB) external view returns (address pair);\n\n    /**\n     * @notice Returns the factory state of `isCreationRestricted`\n     * @return _isCreationRestricted The `isCreationRestricted` state of the factory.\n     */\n    function isCreationRestricted() external view returns (bool _isCreationRestricted);\n\n    /**\n     * @notice Given some amount of an asset and pair pools, returns an equivalent amount of the other asset\n     * @param amountA The amount of token A\n     * @param poolA The balance of token A in the pool\n     * @param poolB The balance of token B in the pool\n     * @return amountB The amount of token B\n     */\n    function quote(uint256 amountA, uint256 poolA, uint256 poolB) external pure returns (uint256 amountB);\n\n    /**\n     * @notice Given an input amount of an asset and pair pools, returns the maximum output amount of the other asset\n     * Factors in the fee on the input amount.\n     * @param amountIn The input amount of the asset\n     * @param poolIn The balance of the input asset in the pool\n     * @param poolOut The balance of the output asset in the pool\n     * @return amountOut The output amount of the other asset\n     */\n    function getAmountOut(uint256 amountIn, uint256 poolIn, uint256 poolOut)\n        external\n        pure\n        returns (uint256 amountOut);\n\n    /**\n     * @notice Given an output amount of an asset and pair pools, returns a required input amount of the other asset\n     * @param amountOut The output amount of the asset\n     * @param poolIn The balance of the input asset in the pool\n     * @param poolOut The balance of the output asset in the pool\n     * @return amountIn The required input amount of the other asset\n     */\n    function getAmountIn(uint256 amountOut, uint256 poolIn, uint256 poolOut) external pure returns (uint256 amountIn);\n\n    /**\n     * @notice Given an ordered array of tokens and an input amount of the first asset, performs chained getAmountOut calculations to calculate the output amount of the final asset\n     * @param amountIn The input amount of the first asset\n     * @param path An array of token addresses [tokenA, tokenB, tokenC, ...] representing the path the input token takes to get to the output token\n     * @return amounts The output amounts of each asset in the path\n     */\n    function getAmountsOut(uint256 amountIn, address[] calldata path)\n        external\n        view\n        returns (uint256[] memory amounts);\n\n    /**\n     * @notice Given an ordered array of tokens and an output amount of the final asset, performs chained getAmountIn calculations to calculate the input amount of the first asset\n     * @param amountOut The output amount of the final asset\n     * @param path An array of token addresses [tokenA, tokenB, tokenC, ...] representing the path the input token takes to get to the output token\n     * @return amounts The input amounts of each asset in the path\n     */\n    function getAmountsIn(uint256 amountOut, address[] calldata path)\n        external\n        view\n        returns (uint256[] memory amounts);\n\n    /**\n     * @notice Returns how much of the much of mintAmountA will be swapped for tokenB and for how much during a mintWithReservoir operation.\n     * @param tokenA First token address\n     * @param tokenB Second token address\n     * @param mintAmountA The amount of tokenA to be minted\n     * @return tokenAToSwap The amount of tokenA to be exchanged for tokenB from the reservoir\n     * @return swappedReservoirAmountB The amount of tokenB returned from the reservoir\n     */\n    function getMintSwappedAmounts(address tokenA, address tokenB, uint256 mintAmountA)\n        external\n        view\n        returns (uint256 tokenAToSwap, uint256 swappedReservoirAmountB);\n\n    /**\n     * @notice Returns how much of tokenA will be withdrawn from the pair and how much of it came from the reservoir during a burnFromReservoir operation.\n     * @param tokenA First token address\n     * @param tokenB Second token address\n     * @param liquidity The amount of liquidity to be burned\n     * @return tokenOutA The amount of tokenA to be withdrawn from the pair\n     * @return swappedReservoirAmountA The amount of tokenA returned from the reservoir\n     */\n    function getBurnSwappedAmounts(address tokenA, address tokenB, uint256 liquidity)\n        external\n        view\n        returns (uint256 tokenOutA, uint256 swappedReservoirAmountA);\n}\n"
      },
      "lib/buttonswap-core/src/interfaces/IButtonswapFactory/IButtonswapFactory.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.13;\n\nimport {IButtonswapFactoryErrors} from \"./IButtonswapFactoryErrors.sol\";\nimport {IButtonswapFactoryEvents} from \"./IButtonswapFactoryEvents.sol\";\n\ninterface IButtonswapFactory is IButtonswapFactoryErrors, IButtonswapFactoryEvents {\n    /**\n     * @notice Returns the current address for `feeTo`.\n     * The owner of this address receives the protocol fee as it is collected over time.\n     * @return _feeTo The `feeTo` address\n     */\n    function feeTo() external view returns (address _feeTo);\n\n    /**\n     * @notice Returns the current address for `feeToSetter`.\n     * The owner of this address has the power to update both `feeToSetter` and `feeTo`.\n     * @return _feeToSetter The `feeToSetter` address\n     */\n    function feeToSetter() external view returns (address _feeToSetter);\n\n    /**\n     * @notice The name of the ERC20 liquidity token.\n     * @return _tokenName The `tokenName`\n     */\n    function tokenName() external view returns (string memory _tokenName);\n\n    /**\n     * @notice The symbol of the ERC20 liquidity token.\n     * @return _tokenSymbol The `tokenSymbol`\n     */\n    function tokenSymbol() external view returns (string memory _tokenSymbol);\n\n    /**\n     * @notice Returns the current state of restricted creation.\n     * If true, then no new pairs, only feeToSetter can create new pairs\n     * @return _isCreationRestricted The `isCreationRestricted` state\n     */\n    function isCreationRestricted() external view returns (bool _isCreationRestricted);\n\n    /**\n     * @notice Returns the current address for `isCreationRestrictedSetter`.\n     * The owner of this address has the power to update both `isCreationRestrictedSetter` and `isCreationRestricted`.\n     * @return _isCreationRestrictedSetter The `isCreationRestrictedSetter` address\n     */\n    function isCreationRestrictedSetter() external view returns (address _isCreationRestrictedSetter);\n\n    /**\n     * @notice Get the (unique) Pair address created for the given combination of `tokenA` and `tokenB`.\n     * If the Pair does not exist then zero address is returned.\n     * @param tokenA The first unsorted token\n     * @param tokenB The second unsorted token\n     * @return pair The address of the Pair instance\n     */\n    function getPair(address tokenA, address tokenB) external view returns (address pair);\n\n    /**\n     * @notice Get the Pair address at the given `index`, ordered chronologically.\n     * @param index The index to query\n     * @return pair The address of the Pair created at the given `index`\n     */\n    function allPairs(uint256 index) external view returns (address pair);\n\n    /**\n     * @notice Get the current total number of Pairs created\n     * @return count The total number of Pairs created\n     */\n    function allPairsLength() external view returns (uint256 count);\n\n    /**\n     * @notice Creates a new {ButtonswapPair} instance for the given unsorted tokens `tokenA` and `tokenB`.\n     * @dev The tokens are sorted later, but can be provided to this method in either order.\n     * @param tokenA The first unsorted token address\n     * @param tokenB The second unsorted token address\n     * @return pair The address of the new {ButtonswapPair} instance\n     */\n    function createPair(address tokenA, address tokenB) external returns (address pair);\n\n    /**\n     * @notice Updates the address that receives the protocol fee.\n     * This can only be called by the `feeToSetter` address.\n     * @param _feeTo The new address\n     */\n    function setFeeTo(address _feeTo) external;\n\n    /**\n     * @notice Updates the address that has the power to set the `feeToSetter` and `feeTo` addresses.\n     * This can only be called by the `feeToSetter` address.\n     * @param _feeToSetter The new address\n     */\n    function setFeeToSetter(address _feeToSetter) external;\n\n    /**\n     * @notice Updates the state of restricted creation.\n     * This can only be called by the `feeToSetter` address.\n     * @param _isCreationRestricted The new state\n     */\n    function setIsCreationRestricted(bool _isCreationRestricted) external;\n\n    /**\n     * @notice Updates the address that has the power to set the `isCreationRestrictedSetter` and `isCreationRestricted`.\n     * This can only be called by the `isCreationRestrictedSetter` address.\n     * @param _isCreationRestrictedSetter The new address\n     */\n    function setIsCreationRestrictedSetter(address _isCreationRestrictedSetter) external;\n\n    /**\n     * @notice Returns the current address for `isPausedSetter`.\n     * The owner of this address has the power to update both `isPausedSetter` and call `setIsPaused`.\n     * @return _isPausedSetter The `isPausedSetter` address\n     */\n    function isPausedSetter() external view returns (address _isPausedSetter);\n\n    /**\n     * @notice Updates the address that has the power to set the `isPausedSetter` and call `setIsPaused`.\n     * This can only be called by the `isPausedSetter` address.\n     * @param _isPausedSetter The new address\n     */\n    function setIsPausedSetter(address _isPausedSetter) external;\n\n    /**\n     * @notice Updates the pause state of given Pairs.\n     * This can only be called by the `feeToSetter` address.\n     * @param pairs A list of addresses for the pairs that should be updated\n     * @param isPausedNew The new pause state\n     */\n    function setIsPaused(address[] calldata pairs, bool isPausedNew) external;\n\n    /**\n     * @notice Returns the current address for `paramSetter`.\n     * The owner of this address has the power to update `paramSetter`, default parameters, and current parameters on existing pairs\n     * @return _paramSetter The `paramSetter` address\n     */\n    function paramSetter() external view returns (address _paramSetter);\n\n    /**\n     * @notice Updates the address that has the power to set the `paramSetter` and update the default params.\n     * This can only be called by the `paramSetter` address.\n     * @param _paramSetter The new address\n     */\n    function setParamSetter(address _paramSetter) external;\n\n    /**\n     * @notice Returns the default value of `movingAverageWindow` used for new pairs.\n     * @return _defaultMovingAverageWindow The `defaultMovingAverageWindow` value\n     */\n    function defaultMovingAverageWindow() external view returns (uint32 _defaultMovingAverageWindow);\n\n    /**\n     * @notice Returns the default value of `maxVolatilityBps` used for new pairs.\n     * @return _defaultMaxVolatilityBps The `defaultMaxVolatilityBps` value\n     */\n    function defaultMaxVolatilityBps() external view returns (uint16 _defaultMaxVolatilityBps);\n\n    /**\n     * @notice Returns the default value of `minTimelockDuration` used for new pairs.\n     * @return _defaultMinTimelockDuration The `defaultMinTimelockDuration` value\n     */\n    function defaultMinTimelockDuration() external view returns (uint32 _defaultMinTimelockDuration);\n\n    /**\n     * @notice Returns the default value of `maxTimelockDuration` used for new pairs.\n     * @return _defaultMaxTimelockDuration The `defaultMaxTimelockDuration` value\n     */\n    function defaultMaxTimelockDuration() external view returns (uint32 _defaultMaxTimelockDuration);\n\n    /**\n     * @notice Returns the default value of `maxSwappableReservoirLimitBps` used for new pairs.\n     * @return _defaultMaxSwappableReservoirLimitBps The `defaultMaxSwappableReservoirLimitBps` value\n     */\n    function defaultMaxSwappableReservoirLimitBps()\n        external\n        view\n        returns (uint16 _defaultMaxSwappableReservoirLimitBps);\n\n    /**\n     * @notice Returns the default value of `swappableReservoirGrowthWindow` used for new pairs.\n     * @return _defaultSwappableReservoirGrowthWindow The `defaultSwappableReservoirGrowthWindow` value\n     */\n    function defaultSwappableReservoirGrowthWindow()\n        external\n        view\n        returns (uint32 _defaultSwappableReservoirGrowthWindow);\n\n    /**\n     * @notice Updates the default parameters used for new pairs.\n     * This can only be called by the `paramSetter` address.\n     * @param newDefaultMovingAverageWindow The new defaultMovingAverageWindow\n     * @param newDefaultMaxVolatilityBps The new defaultMaxVolatilityBps\n     * @param newDefaultMinTimelockDuration The new defaultMinTimelockDuration\n     * @param newDefaultMaxTimelockDuration The new defaultMaxTimelockDuration\n     * @param newDefaultMaxSwappableReservoirLimitBps The new defaultMaxSwappableReservoirLimitBps\n     * @param newDefaultSwappableReservoirGrowthWindow The new defaultSwappableReservoirGrowthWindow\n     */\n    function setDefaultParameters(\n        uint32 newDefaultMovingAverageWindow,\n        uint16 newDefaultMaxVolatilityBps,\n        uint32 newDefaultMinTimelockDuration,\n        uint32 newDefaultMaxTimelockDuration,\n        uint16 newDefaultMaxSwappableReservoirLimitBps,\n        uint32 newDefaultSwappableReservoirGrowthWindow\n    ) external;\n\n    /**\n     * @notice Updates the `movingAverageWindow` value of given Pairs.\n     * This can only be called by the `paramSetter` address.\n     * @param pairs A list of addresses for the pairs that should be updated\n     * @param newMovingAverageWindow The new `movingAverageWindow` value\n     */\n    function setMovingAverageWindow(address[] calldata pairs, uint32 newMovingAverageWindow) external;\n\n    /**\n     * @notice Updates the `maxVolatilityBps` value of given Pairs.\n     * This can only be called by the `paramSetter` address.\n     * @param pairs A list of addresses for the pairs that should be updated\n     * @param newMaxVolatilityBps The new `maxVolatilityBps` value\n     */\n    function setMaxVolatilityBps(address[] calldata pairs, uint16 newMaxVolatilityBps) external;\n\n    /**\n     * @notice Updates the `minTimelockDuration` value of given Pairs.\n     * This can only be called by the `paramSetter` address.\n     * @param pairs A list of addresses for the pairs that should be updated\n     * @param newMinTimelockDuration The new `minTimelockDuration` value\n     */\n    function setMinTimelockDuration(address[] calldata pairs, uint32 newMinTimelockDuration) external;\n\n    /**\n     * @notice Updates the `maxTimelockDuration` value of given Pairs.\n     * This can only be called by the `paramSetter` address.\n     * @param pairs A list of addresses for the pairs that should be updated\n     * @param newMaxTimelockDuration The new `maxTimelockDuration` value\n     */\n    function setMaxTimelockDuration(address[] calldata pairs, uint32 newMaxTimelockDuration) external;\n\n    /**\n     * @notice Updates the `maxSwappableReservoirLimitBps` value of given Pairs.\n     * This can only be called by the `paramSetter` address.\n     * @param pairs A list of addresses for the pairs that should be updated\n     * @param newMaxSwappableReservoirLimitBps The new `maxSwappableReservoirLimitBps` value\n     */\n    function setMaxSwappableReservoirLimitBps(address[] calldata pairs, uint16 newMaxSwappableReservoirLimitBps)\n        external;\n\n    /**\n     * @notice Updates the `swappableReservoirGrowthWindow` value of given Pairs.\n     * This can only be called by the `paramSetter` address.\n     * @param pairs A list of addresses for the pairs that should be updated\n     * @param newSwappableReservoirGrowthWindow The new `swappableReservoirGrowthWindow` value\n     */\n    function setSwappableReservoirGrowthWindow(address[] calldata pairs, uint32 newSwappableReservoirGrowthWindow)\n        external;\n\n    /**\n     * @notice Returns the last token pair created and the parameters used.\n     * @return token0 The first token address\n     * @return token1 The second token address\n     * @return movingAverageWindow The moving average window\n     * @return maxVolatilityBps The max volatility bps\n     * @return minTimelockDuration The minimum time lock duration\n     * @return maxTimelockDuration The maximum time lock duration\n     * @return maxSwappableReservoirLimitBps The max swappable reservoir limit bps\n     * @return swappableReservoirGrowthWindow The swappable reservoir growth window\n     */\n    function lastCreatedTokensAndParameters()\n        external\n        returns (\n            address token0,\n            address token1,\n            uint32 movingAverageWindow,\n            uint16 maxVolatilityBps,\n            uint32 minTimelockDuration,\n            uint32 maxTimelockDuration,\n            uint16 maxSwappableReservoirLimitBps,\n            uint32 swappableReservoirGrowthWindow\n        );\n}\n"
      },
      "lib/buttonswap-core/src/interfaces/IButtonswapPair/IButtonswapPair.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.13;\n\nimport {IButtonswapPairErrors} from \"./IButtonswapPairErrors.sol\";\nimport {IButtonswapPairEvents} from \"./IButtonswapPairEvents.sol\";\nimport {IButtonswapERC20} from \"../IButtonswapERC20/IButtonswapERC20.sol\";\n\ninterface IButtonswapPair is IButtonswapPairErrors, IButtonswapPairEvents, IButtonswapERC20 {\n    /**\n     * @notice The smallest value that {IButtonswapERC20-totalSupply} can be.\n     * @dev After the first mint the total liquidity (represented by the liquidity token total supply) can never drop below this value.\n     *\n     * This is to protect against an attack where the attacker mints a very small amount of liquidity, and then donates pool tokens to skew the ratio.\n     * This results in future minters receiving no liquidity tokens when they deposit.\n     * By enforcing a minimum liquidity value this attack becomes prohibitively expensive to execute.\n     * @return MINIMUM_LIQUIDITY The MINIMUM_LIQUIDITY value\n     */\n    function MINIMUM_LIQUIDITY() external pure returns (uint256 MINIMUM_LIQUIDITY);\n\n    /**\n     * @notice The duration for which the moving average is calculated for.\n     * @return _movingAverageWindow The value of movingAverageWindow\n     */\n    function movingAverageWindow() external view returns (uint32 _movingAverageWindow);\n\n    /**\n     * @notice Updates the movingAverageWindow parameter of the pair.\n     * This can only be called by the Factory address.\n     * Refer to [parameters.md](https://github.com/buttonwood-protocol/buttonswap-core/blob/main/notes/parameters.md#movingaveragewindow) for more detail.\n     * @param newMovingAverageWindow The new value for movingAverageWindow\n     */\n    function setMovingAverageWindow(uint32 newMovingAverageWindow) external;\n\n    /**\n     * @notice Numerator (over 10_000) of the threshold when price volatility triggers maximum single-sided timelock duration.\n     * @return _maxVolatilityBps The value of maxVolatilityBps\n     */\n    function maxVolatilityBps() external view returns (uint16 _maxVolatilityBps);\n\n    /**\n     * @notice Updates the maxVolatilityBps parameter of the pair.\n     * This can only be called by the Factory address.\n     * Refer to [parameters.md](https://github.com/buttonwood-protocol/buttonswap-core/blob/main/notes/parameters.md#maxvolatilitybps) for more detail.\n     * @param newMaxVolatilityBps The new value for maxVolatilityBps\n     */\n    function setMaxVolatilityBps(uint16 newMaxVolatilityBps) external;\n\n    /**\n     * @notice How long the minimum singled-sided timelock lasts for.\n     * @return _minTimelockDuration The value of minTimelockDuration\n     */\n    function minTimelockDuration() external view returns (uint32 _minTimelockDuration);\n\n    /**\n     * @notice Updates the minTimelockDuration parameter of the pair.\n     * This can only be called by the Factory address.\n     * Refer to [parameters.md](https://github.com/buttonwood-protocol/buttonswap-core/blob/main/notes/parameters.md#mintimelockduration) for more detail.\n     * @param newMinTimelockDuration The new value for minTimelockDuration\n     */\n    function setMinTimelockDuration(uint32 newMinTimelockDuration) external;\n\n    /**\n     * @notice How long the maximum singled-sided timelock lasts for.\n     * @return _maxTimelockDuration The value of maxTimelockDuration\n     */\n    function maxTimelockDuration() external view returns (uint32 _maxTimelockDuration);\n\n    /**\n     * @notice Updates the maxTimelockDuration parameter of the pair.\n     * This can only be called by the Factory address.\n     * Refer to [parameters.md](https://github.com/buttonwood-protocol/buttonswap-core/blob/main/notes/parameters.md#maxtimelockduration) for more detail.\n     * @param newMaxTimelockDuration The new value for maxTimelockDuration\n     */\n    function setMaxTimelockDuration(uint32 newMaxTimelockDuration) external;\n\n    /**\n     * @notice Numerator (over 10_000) of the fraction of the pool balance that acts as the maximum limit on how much of the reservoir\n     * can be swapped in a given timeframe.\n     * @return _maxSwappableReservoirLimitBps The value of maxSwappableReservoirLimitBps\n     */\n    function maxSwappableReservoirLimitBps() external view returns (uint16 _maxSwappableReservoirLimitBps);\n\n    /**\n     * @notice Updates the maxSwappableReservoirLimitBps parameter of the pair.\n     * This can only be called by the Factory address.\n     * Refer to [parameters.md](https://github.com/buttonwood-protocol/buttonswap-core/blob/main/notes/parameters.md#maxswappablereservoirlimitbps) for more detail.\n     * @param newMaxSwappableReservoirLimitBps The new value for maxSwappableReservoirLimitBps\n     */\n    function setMaxSwappableReservoirLimitBps(uint16 newMaxSwappableReservoirLimitBps) external;\n\n    /**\n     * @notice How much time it takes for the swappable reservoir value to grow from nothing to its maximum value.\n     * @return _swappableReservoirGrowthWindow The value of swappableReservoirGrowthWindow\n     */\n    function swappableReservoirGrowthWindow() external view returns (uint32 _swappableReservoirGrowthWindow);\n\n    /**\n     * @notice Updates the swappableReservoirGrowthWindow parameter of the pair.\n     * This can only be called by the Factory address.\n     * Refer to [parameters.md](https://github.com/buttonwood-protocol/buttonswap-core/blob/main/notes/parameters.md#swappablereservoirgrowthwindow) for more detail.\n     * @param newSwappableReservoirGrowthWindow The new value for swappableReservoirGrowthWindow\n     */\n    function setSwappableReservoirGrowthWindow(uint32 newSwappableReservoirGrowthWindow) external;\n\n    /**\n     * @notice The address of the {ButtonswapFactory} instance used to create this Pair.\n     * @dev Set to `msg.sender` in the Pair constructor.\n     * @return factory The factory address\n     */\n    function factory() external view returns (address factory);\n\n    /**\n     * @notice The address of the first sorted token.\n     * @return token0 The token address\n     */\n    function token0() external view returns (address token0);\n\n    /**\n     * @notice The address of the second sorted token.\n     * @return token1 The token address\n     */\n    function token1() external view returns (address token1);\n\n    /**\n     * @notice The time-weighted average price of the Pair.\n     * The price is of `token0` in terms of `token1`.\n     * @dev The price is represented as a [UQ112x112](https://en.wikipedia.org/wiki/Q_(number_format)) to maintain precision.\n     * Consequently this value must be divided by `2^112` to get the actual price.\n     *\n     * Because of the time weighting, `price0CumulativeLast` must also be divided by the total Pair lifetime to get the average price over that time period.\n     * @return price0CumulativeLast The current cumulative `token0` price\n     */\n    function price0CumulativeLast() external view returns (uint256 price0CumulativeLast);\n\n    /**\n     * @notice The time-weighted average price of the Pair.\n     * The price is of `token1` in terms of `token0`.\n     * @dev The price is represented as a [UQ112x112](https://en.wikipedia.org/wiki/Q_(number_format)) to maintain precision.\n     * Consequently this value must be divided by `2^112` to get the actual price.\n     *\n     * Because of the time weighting, `price1CumulativeLast` must also be divided by the total Pair lifetime to get the average price over that time period.\n     * @return price1CumulativeLast The current cumulative `token1` price\n     */\n    function price1CumulativeLast() external view returns (uint256 price1CumulativeLast);\n\n    /**\n     * @notice The timestamp for when the single-sided timelock concludes.\n     * The timelock is initiated based on price volatility of swaps over the last `movingAverageWindow`, and can be\n     *   extended by new swaps if they are sufficiently volatile.\n     * The timelock protects against attempts to manipulate the price that is used to valuate the reservoir tokens during\n     *   single-sided operations.\n     * It also guards against general legitimate volatility, as it is preferable to defer single-sided operations until\n     *   it is clearer what the market considers the price to be.\n     * @return singleSidedTimelockDeadline The current deadline timestamp\n     */\n    function singleSidedTimelockDeadline() external view returns (uint120 singleSidedTimelockDeadline);\n\n    /**\n     * @notice The timestamp by which the amount of reservoir tokens that can be exchanged during a single-sided operation\n     *   reaches its maximum value.\n     * This maximum value is not necessarily the entirety of the reservoir, instead being calculated as a fraction of the\n     *   corresponding token's active liquidity.\n     * @return swappableReservoirLimitReachesMaxDeadline The current deadline timestamp\n     */\n    function swappableReservoirLimitReachesMaxDeadline()\n        external\n        view\n        returns (uint120 swappableReservoirLimitReachesMaxDeadline);\n\n    /**\n     * @notice Returns the current limit on the number of reservoir tokens that can be exchanged during a single-sided mint/burn operation.\n     * @return swappableReservoirLimit The amount of reservoir token that can be exchanged\n     */\n    function getSwappableReservoirLimit() external view returns (uint256 swappableReservoirLimit);\n\n    /**\n     * @notice Whether the Pair is currently paused\n     * @return _isPaused The paused state\n     */\n    function getIsPaused() external view returns (bool _isPaused);\n\n    /**\n     * @notice Updates the pause state.\n     * This can only be called by the Factory address.\n     * @param isPausedNew The new value for isPaused\n     */\n    function setIsPaused(bool isPausedNew) external;\n\n    /**\n     * @notice Get the current liquidity values.\n     * @return _pool0 The active `token0` liquidity\n     * @return _pool1 The active `token1` liquidity\n     * @return _reservoir0 The inactive `token0` liquidity\n     * @return _reservoir1 The inactive `token1` liquidity\n     * @return _blockTimestampLast The timestamp of when the price was last updated\n     */\n    function getLiquidityBalances()\n        external\n        view\n        returns (uint112 _pool0, uint112 _pool1, uint112 _reservoir0, uint112 _reservoir1, uint32 _blockTimestampLast);\n\n    /**\n     * @notice The current `movingAveragePrice0` value, based on the current block timestamp.\n     * @dev This is the `token0` price, time weighted to prevent manipulation.\n     * Refer to [reservoir-valuation.md](https://github.com/buttonwood-protocol/buttonswap-core/blob/main/notes/reservoir-valuation.md#price-stability) for more detail.\n     *\n     * The price is represented as a [UQ112x112](https://en.wikipedia.org/wiki/Q_(number_format)) to maintain precision.\n     * It is used to valuate the reservoir tokens that are exchanged during single-sided operations.\n     * @return _movingAveragePrice0 The current `movingAveragePrice0` value\n     */\n    function movingAveragePrice0() external view returns (uint256 _movingAveragePrice0);\n\n    /**\n     * @notice Mints new liquidity tokens to `to` based on `amountIn0` of `token0` and `amountIn1  of`token1` deposited.\n     * Expects both tokens to be deposited in a ratio that matches the current Pair price.\n     * @dev The token deposits are deduced to be the delta between token balance before and after the transfers in order to account for unusual tokens.\n     * Refer to [mint-math.md](https://github.com/buttonwood-protocol/buttonswap-core/blob/main/notes/mint-math.md#dual-sided-mint) for more detail.\n     * @param amountIn0 The amount of `token0` that should be transferred in from the user\n     * @param amountIn1 The amount of `token1` that should be transferred in from the user\n     * @param to The account that receives the newly minted liquidity tokens\n     * @return liquidityOut THe amount of liquidity tokens minted\n     */\n    function mint(uint256 amountIn0, uint256 amountIn1, address to) external returns (uint256 liquidityOut);\n\n    /**\n     * @notice Mints new liquidity tokens to `to` based on how much `token0` or `token1` has been deposited.\n     * The token transferred is the one that the Pair does not have a non-zero inactive liquidity balance for.\n     * Expects only one token to be deposited, so that it can be paired with the other token's inactive liquidity.\n     * @dev The token deposits are deduced to be the delta between token balance before and after the transfers in order to account for unusual tokens.\n     * Refer to [mint-math.md](https://github.com/buttonwood-protocol/buttonswap-core/blob/main/notes/mint-math.md#single-sided-mint) for more detail.\n     * @param amountIn The amount of tokens that should be transferred in from the user\n     * @param to The account that receives the newly minted liquidity tokens\n     * @return liquidityOut THe amount of liquidity tokens minted\n     */\n    function mintWithReservoir(uint256 amountIn, address to) external returns (uint256 liquidityOut);\n\n    /**\n     * @notice Burns `liquidityIn` liquidity tokens to redeem to `to` the corresponding `amountOut0` of `token0` and `amountOut1` of `token1`.\n     * @dev Refer to [burn-math.md](https://github.com/buttonwood-protocol/buttonswap-core/blob/main/notes/burn-math.md#dual-sided-burn) for more detail.\n     * @param liquidityIn The amount of liquidity tokens to burn\n     * @param to The account that receives the redeemed tokens\n     * @return amountOut0 The amount of `token0` that the liquidity tokens are redeemed for\n     * @return amountOut1 The amount of `token1` that the liquidity tokens are redeemed for\n     */\n    function burn(uint256 liquidityIn, address to) external returns (uint256 amountOut0, uint256 amountOut1);\n\n    /**\n     * @notice Burns `liquidityIn` liquidity tokens to redeem to `to` the corresponding `amountOut0` of `token0` and `amountOut1` of `token1`.\n     * Only returns tokens from the non-zero inactive liquidity balance, meaning one of `amountOut0` and `amountOut1` will be zero.\n     * @dev Refer to [burn-math.md](https://github.com/buttonwood-protocol/buttonswap-core/blob/main/notes/burn-math.md#single-sided-burn) for more detail.\n     * @param liquidityIn The amount of liquidity tokens to burn\n     * @param to The account that receives the redeemed tokens\n     * @return amountOut0 The amount of `token0` that the liquidity tokens are redeemed for\n     * @return amountOut1 The amount of `token1` that the liquidity tokens are redeemed for\n     */\n    function burnFromReservoir(uint256 liquidityIn, address to)\n        external\n        returns (uint256 amountOut0, uint256 amountOut1);\n\n    /**\n     * @notice Swaps one token for the other, taking `amountIn0` of `token0` and `amountIn1` of `token1` from the sender and sending `amountOut0` of `token0` and `amountOut1` of `token1` to `to`.\n     * The price of the swap is determined by maintaining the \"K Invariant\".\n     * A 0.3% fee is collected to distribute between liquidity providers and the protocol.\n     * @dev The token deposits are deduced to be the delta between the current Pair contract token balances and the last stored balances.\n     * Optional calldata can be passed to `data`, which will be used to confirm the output token transfer with `to` if `to` is a contract that implements the {IButtonswapCallee} interface.\n     * Refer to [swap-math.md](https://github.com/buttonwood-protocol/buttonswap-core/blob/main/notes/swap-math.md) for more detail.\n     * @param amountIn0 The amount of `token0` that the sender sends\n     * @param amountIn1 The amount of `token1` that the sender sends\n     * @param amountOut0 The amount of `token0` that the recipient receives\n     * @param amountOut1 The amount of `token1` that the recipient receives\n     * @param to The account that receives the swap output\n     */\n    function swap(uint256 amountIn0, uint256 amountIn1, uint256 amountOut0, uint256 amountOut1, address to) external;\n}\n"
      },
      "src/libraries/TransferHelper.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// ToDo: Replace with solmate/SafeTransferLib\npragma solidity >=0.6.0;\n\n// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false\nlibrary TransferHelper {\n    function safeApprove(address token, address to, uint256 value) internal {\n        // bytes4(keccak256(bytes('approve(address,uint256)')));\n        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));\n        require(success && (data.length == 0 || abi.decode(data, (bool))), \"TransferHelper: APPROVE_FAILED\");\n    }\n\n    function safeTransfer(address token, address to, uint256 value) internal {\n        // bytes4(keccak256(bytes('transfer(address,uint256)')));\n        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));\n        require(success && (data.length == 0 || abi.decode(data, (bool))), \"TransferHelper: TRANSFER_FAILED\");\n    }\n\n    function safeTransferFrom(address token, address from, address to, uint256 value) internal {\n        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));\n        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));\n        require(success && (data.length == 0 || abi.decode(data, (bool))), \"TransferHelper: TRANSFER_FROM_FAILED\");\n    }\n\n    function safeTransferETH(address to, uint256 value) internal {\n        (bool success,) = to.call{value: value}(new bytes(0));\n        require(success, \"TransferHelper: ETH_TRANSFER_FAILED\");\n    }\n}\n"
      },
      "src/libraries/ButtonswapLibrary.sol": {
        "content": "pragma solidity ^0.8.13;\n\nimport {IButtonswapPair} from \"buttonswap-periphery_buttonswap-core/interfaces/IButtonswapPair/IButtonswapPair.sol\";\nimport {Math} from \"buttonswap-periphery_buttonswap-core/libraries/Math.sol\";\nimport {IERC20} from \"../interfaces/IERC20.sol\";\n\nlibrary ButtonswapLibrary {\n    /// @notice Identical addresses provided\n    error IdenticalAddresses();\n    /// @notice Zero address provided\n    error ZeroAddress();\n    /// @notice Insufficient amount provided\n    error InsufficientAmount();\n    /// @notice Insufficient liquidity provided\n    error InsufficientLiquidity();\n    /// @notice Insufficient input amount provided\n    error InsufficientInputAmount();\n    /// @notice Insufficient output amount provided\n    error InsufficientOutputAmount();\n    /// @notice Invalid path provided\n    error InvalidPath();\n\n    /**\n     * @dev Returns sorted token addresses, used to handle return values from pairs sorted in this order\n     * @param tokenA First token address\n     * @param tokenB Second token address\n     * @return token0 First sorted token address\n     * @return token1 Second sorted token address\n     */\n    function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {\n        if (tokenA == tokenB) {\n            revert IdenticalAddresses();\n        }\n        (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);\n        // If the tokens are different and sorted, only token0 can be the zero address\n        if (token0 == address(0)) {\n            revert ZeroAddress();\n        }\n    }\n\n    /**\n     * @dev Predicts the address that the Pair contract for given tokens would have been deployed to\n     * @dev Specifically, this calculates the CREATE2 address for a Pair contract.\n     * @dev It's done this way to avoid making any external calls, and thus saving on gas versus other approaches.\n     * @param factory The address of the ButtonswapFactory used to create the pair\n     * @param tokenA First token address\n     * @param tokenB Second token address\n     * @return pair The pair address\n     */\n    function pairFor(address factory, address tokenA, address tokenB) internal pure returns (address pair) {\n        (address token0, address token1) = sortTokens(tokenA, tokenB);\n        // Init Hash Code is generated by the following command:\n        //        bytes32 initHashCode = keccak256(abi.encodePacked(type(ButtonswapPair).creationCode));\n        pair = address(\n            uint160(\n                uint256(\n                    keccak256(\n                        abi.encodePacked(\n                            hex\"ff\",\n                            factory,\n                            keccak256(abi.encodePacked(token0, token1)),\n                            hex\"912fa011211d18178fef8f22392edc90ca8f101645ab8347e1359b5ce2f890df\" // init code hash\n                        )\n                    )\n                )\n            )\n        );\n    }\n\n    /**\n     * @dev Fetches and sorts the pools for a pair. Pools are the current token balances in the pair contract serving as liquidity.\n     * @param factory The address of the ButtonswapFactory\n     * @param tokenA First token address\n     * @param tokenB Second token address\n     * @return poolA Pool corresponding to tokenA\n     * @return poolB Pool corresponding to tokenB\n     */\n    function getPools(address factory, address tokenA, address tokenB)\n        internal\n        view\n        returns (uint256 poolA, uint256 poolB)\n    {\n        (address token0,) = sortTokens(tokenA, tokenB);\n        (uint256 pool0, uint256 pool1,,,) = IButtonswapPair(pairFor(factory, tokenA, tokenB)).getLiquidityBalances();\n        (poolA, poolB) = tokenA == token0 ? (pool0, pool1) : (pool1, pool0);\n    }\n\n    /**\n     * @dev Fetches and sorts the reservoirs for a pair. Reservoirs are the current token balances in the pair contract not actively serving as liquidity.\n     * @param factory The address of the ButtonswapFactory\n     * @param tokenA First token address\n     * @param tokenB Second token address\n     * @return reservoirA Reservoir corresponding to tokenA\n     * @return reservoirB Reservoir corresponding to tokenB\n     */\n    function getReservoirs(address factory, address tokenA, address tokenB)\n        internal\n        view\n        returns (uint256 reservoirA, uint256 reservoirB)\n    {\n        (address token0,) = sortTokens(tokenA, tokenB);\n        (,, uint256 reservoir0, uint256 reservoir1,) =\n            IButtonswapPair(pairFor(factory, tokenA, tokenB)).getLiquidityBalances();\n        (reservoirA, reservoirB) = tokenA == token0 ? (reservoir0, reservoir1) : (reservoir1, reservoir0);\n    }\n\n    /**\n     * @dev Fetches and sorts the pools and reservoirs for a pair.\n     *   - Pools are the current token balances in the pair contract serving as liquidity.\n     *   - Reservoirs are the current token balances in the pair contract not actively serving as liquidity.\n     * @param factory The address of the ButtonswapFactory\n     * @param tokenA First token address\n     * @param tokenB Second token address\n     * @return poolA Pool corresponding to tokenA\n     * @return poolB Pool corresponding to tokenB\n     * @return reservoirA Reservoir corresponding to tokenA\n     * @return reservoirB Reservoir corresponding to tokenB\n     */\n    function getLiquidityBalances(address factory, address tokenA, address tokenB)\n        internal\n        view\n        returns (uint256 poolA, uint256 poolB, uint256 reservoirA, uint256 reservoirB)\n    {\n        (address token0,) = sortTokens(tokenA, tokenB);\n        (uint256 pool0, uint256 pool1, uint256 reservoir0, uint256 reservoir1,) =\n            IButtonswapPair(pairFor(factory, tokenA, tokenB)).getLiquidityBalances();\n        (poolA, poolB, reservoirA, reservoirB) =\n            tokenA == token0 ? (pool0, pool1, reservoir0, reservoir1) : (pool1, pool0, reservoir1, reservoir0);\n    }\n\n    /**\n     * @dev Given some amount of an asset and pair pools, returns an equivalent amount of the other asset\n     * @param amountA The amount of token A\n     * @param poolA The balance of token A in the pool\n     * @param poolB The balance of token B in the pool\n     * @return amountB The amount of token B\n     */\n    function quote(uint256 amountA, uint256 poolA, uint256 poolB) internal pure returns (uint256 amountB) {\n        if (amountA == 0) {\n            revert InsufficientAmount();\n        }\n        if (poolA == 0 || poolB == 0) {\n            revert InsufficientLiquidity();\n        }\n        amountB = (amountA * poolB) / poolA;\n    }\n\n    /**\n     * @dev Given a factory, two tokens, and a mintAmount of the first, returns how much of the much of the mintAmount will be swapped for the other token and for how much during a mintWithReservoir operation.\n     * @dev The logic is a condensed version of PairMath.getSingleSidedMintLiquidityOutAmountA and PairMath.getSingleSidedMintLiquidityOutAmountB\n     * @param factory The address of the ButtonswapFactory that created the pairs\n     * @param tokenA First token address\n     * @param tokenB Second token address\n     * @param mintAmountA The amount of tokenA to be minted\n     * @return tokenAToSwap The amount of tokenA to be exchanged for tokenB from the reservoir\n     * @return swappedReservoirAmountB The amount of tokenB returned from the reservoir\n     */\n    function getMintSwappedAmounts(address factory, address tokenA, address tokenB, uint256 mintAmountA)\n        internal\n        view\n        returns (uint256 tokenAToSwap, uint256 swappedReservoirAmountB)\n    {\n        IButtonswapPair pair = IButtonswapPair(pairFor(factory, tokenA, tokenB));\n        uint256 totalA = IERC20(tokenA).balanceOf(address(pair));\n        uint256 totalB = IERC20(tokenB).balanceOf(address(pair));\n        uint256 movingAveragePrice0 = pair.movingAveragePrice0();\n\n        // tokenA == token0\n        if (tokenA < tokenB) {\n            tokenAToSwap =\n                (mintAmountA * totalB) / (Math.mulDiv(movingAveragePrice0, (totalA + mintAmountA), 2 ** 112) + totalB);\n            swappedReservoirAmountB = (tokenAToSwap * movingAveragePrice0) / 2 ** 112;\n        } else {\n            tokenAToSwap =\n                (mintAmountA * totalB) / (((2 ** 112 * (totalA + mintAmountA)) / movingAveragePrice0) + totalB);\n            // Inverse price so again we can use it without overflow risk\n            swappedReservoirAmountB = (tokenAToSwap * (2 ** 112)) / movingAveragePrice0;\n        }\n    }\n\n    /**\n     * @dev Given a factory, two tokens, and a liquidity amount, returns how much of the first token will be withdrawn from the pair and how much of it came from the reservoir during a burnFromReservoir operation.\n     * @dev The logic is a condensed version of PairMath.getSingleSidedBurnOutputAmountA and PairMath.getSingleSidedBurnOutputAmountB\n     * @param factory The address of the ButtonswapFactory that created the pairs\n     * @param tokenA First token address\n     * @param tokenB Second token address\n     * @param liquidity The amount of liquidity to be burned\n     * @return tokenOutA The amount of tokenA to be withdrawn from the pair\n     * @return swappedReservoirAmountA The amount of tokenA returned from the reservoir\n     */\n    function getBurnSwappedAmounts(address factory, address tokenA, address tokenB, uint256 liquidity)\n        internal\n        view\n        returns (uint256 tokenOutA, uint256 swappedReservoirAmountA)\n    {\n        IButtonswapPair pair = IButtonswapPair(pairFor(factory, tokenA, tokenB));\n        uint256 totalLiquidity = pair.totalSupply();\n        uint256 totalA = IERC20(tokenA).balanceOf(address(pair));\n        uint256 totalB = IERC20(tokenB).balanceOf(address(pair));\n        uint256 movingAveragePrice0 = pair.movingAveragePrice0();\n        uint256 tokenBToSwap = (totalB * liquidity) / totalLiquidity;\n        tokenOutA = (totalA * liquidity) / totalLiquidity;\n\n        // tokenA == token0\n        if (tokenA < tokenB) {\n            swappedReservoirAmountA = (tokenBToSwap * (2 ** 112)) / movingAveragePrice0;\n        } else {\n            swappedReservoirAmountA = (tokenBToSwap * movingAveragePrice0) / 2 ** 112;\n        }\n        tokenOutA += swappedReservoirAmountA;\n    }\n\n    /**\n     * @dev Given an input amount of an asset and pair pools, returns the maximum output amount of the other asset\n     * Factors in the fee on the input amount.\n     * @param amountIn The input amount of the asset\n     * @param poolIn The balance of the input asset in the pool\n     * @param poolOut The balance of the output asset in the pool\n     * @return amountOut The output amount of the other asset\n     */\n    function getAmountOut(uint256 amountIn, uint256 poolIn, uint256 poolOut)\n        internal\n        pure\n        returns (uint256 amountOut)\n    {\n        if (amountIn == 0) {\n            revert InsufficientInputAmount();\n        }\n        if (poolIn == 0 || poolOut == 0) {\n            revert InsufficientLiquidity();\n        }\n        uint256 amountInWithFee = amountIn * 997;\n        uint256 numerator = amountInWithFee * poolOut;\n        uint256 denominator = (poolIn * 1000) + amountInWithFee;\n        amountOut = numerator / denominator;\n    }\n\n    /**\n     * @dev Given an output amount of an asset and pair pools, returns a required input amount of the other asset\n     * @param amountOut The output amount of the asset\n     * @param poolIn The balance of the input asset in the pool\n     * @param poolOut The balance of the output asset in the pool\n     * @return amountIn The required input amount of the other asset\n     */\n    function getAmountIn(uint256 amountOut, uint256 poolIn, uint256 poolOut) internal pure returns (uint256 amountIn) {\n        if (amountOut == 0) {\n            revert InsufficientOutputAmount();\n        }\n        if (poolIn == 0 || poolOut == 0) {\n            revert InsufficientLiquidity();\n        }\n        uint256 numerator = poolIn * amountOut * 1000;\n        uint256 denominator = (poolOut - amountOut) * 997;\n        amountIn = ((numerator + denominator - 1) / denominator);\n    }\n\n    /**\n     * @dev Given an ordered array of tokens and an input amount of the first asset, performs chained getAmountOut calculations to calculate the output amount of the final asset\n     * @param factory The address of the ButtonswapFactory that created the pairs\n     * @param amountIn The input amount of the first asset\n     * @param path An array of token addresses [tokenA, tokenB, tokenC, ...] representing the path the input token takes to get to the output token\n     * @return amounts The output amounts of each asset in the path\n     */\n    function getAmountsOut(address factory, uint256 amountIn, address[] memory path)\n        internal\n        view\n        returns (uint256[] memory amounts)\n    {\n        if (path.length < 2) {\n            revert InvalidPath();\n        }\n        amounts = new uint256[](path.length);\n        amounts[0] = amountIn;\n        for (uint256 i; i < path.length - 1; i++) {\n            (uint256 poolIn, uint256 poolOut,,) = getLiquidityBalances(factory, path[i], path[i + 1]);\n            amounts[i + 1] = getAmountOut(amounts[i], poolIn, poolOut);\n        }\n    }\n\n    /**\n     * @dev Given an ordered array of tokens and an output amount of the final asset, performs chained getAmountIn calculations to calculate the input amount of the first asset\n     * @param factory The address of the ButtonswapFactory that created the pairs\n     * @param amountOut The output amount of the final asset\n     * @param path An array of token addresses [tokenA, tokenB, tokenC, ...] representing the path the input token takes to get to the output token\n     * @return amounts The input amounts of each asset in the path\n     */\n    function getAmountsIn(address factory, uint256 amountOut, address[] memory path)\n        internal\n        view\n        returns (uint256[] memory amounts)\n    {\n        if (path.length < 2) {\n            revert InvalidPath();\n        }\n        amounts = new uint256[](path.length);\n        amounts[amounts.length - 1] = amountOut;\n        for (uint256 i = path.length - 1; i > 0; i--) {\n            (uint256 poolIn, uint256 poolOut,,) = getLiquidityBalances(factory, path[i - 1], path[i]);\n            amounts[i - 1] = getAmountIn(amounts[i], poolIn, poolOut);\n        }\n    }\n}\n"
      },
      "src/interfaces/IERC20.sol": {
        "content": "pragma solidity >=0.5.0;\n\ninterface IERC20 {\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    function name() external view returns (string memory);\n\n    function symbol() external view returns (string memory);\n\n    function decimals() external view returns (uint8);\n\n    function totalSupply() external view returns (uint256);\n\n    function balanceOf(address owner) external view returns (uint256);\n\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    function approve(address spender, uint256 value) external returns (bool);\n\n    function transfer(address to, uint256 value) external returns (bool);\n\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"
      },
      "src/interfaces/IWETH.sol": {
        "content": "pragma solidity >=0.5.0;\n\ninterface IWETH {\n    function deposit() external payable;\n\n    function transfer(address to, uint256 value) external returns (bool);\n\n    function withdraw(uint256) external;\n\n    function approve(address guy, uint256 wad) external returns (bool);\n\n    function balanceOf(address owner) external view returns (uint256);\n}\n"
      },
      "src/ETHButtonswapRouter.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport {IButtonswapFactory} from\n    \"buttonswap-periphery_buttonswap-core/interfaces/IButtonswapFactory/IButtonswapFactory.sol\";\nimport {IButtonswapPair} from \"buttonswap-periphery_buttonswap-core/interfaces/IButtonswapPair/IButtonswapPair.sol\";\nimport {TransferHelper} from \"./libraries/TransferHelper.sol\";\nimport {IETHButtonswapRouter} from \"./interfaces/IButtonswapRouter/IETHButtonswapRouter.sol\";\nimport {ButtonswapLibrary} from \"./libraries/ButtonswapLibrary.sol\";\nimport {IERC20} from \"./interfaces/IERC20.sol\";\nimport {IWETH} from \"./interfaces/IWETH.sol\";\nimport {BasicButtonswapRouter} from \"./BasicButtonswapRouter.sol\";\n\ncontract ETHButtonswapRouter is BasicButtonswapRouter, IETHButtonswapRouter {\n    /**\n     * @inheritdoc IETHButtonswapRouter\n     */\n    address public immutable override WETH;\n\n    constructor(address _factory, address _WETH) BasicButtonswapRouter(_factory) {\n        WETH = _WETH;\n    }\n\n    /**\n     * @dev Only accepts ETH via fallback from the WETH contract\n     */\n    receive() external payable {\n        if (msg.sender != WETH) {\n            revert NonWETHSender();\n        }\n    }\n\n    /**\n     * @inheritdoc IETHButtonswapRouter\n     */\n    function addLiquidityETH(\n        address token,\n        uint256 amountTokenDesired,\n        uint256 amountTokenMin,\n        uint256 amountETHMin,\n        uint16 movingAveragePrice0ThresholdBps,\n        address to,\n        uint256 deadline\n    )\n        external\n        payable\n        virtual\n        override\n        ensure(deadline)\n        returns (uint256 amountToken, uint256 amountETH, uint256 liquidity)\n    {\n        (amountToken, amountETH) = _addLiquidity(\n            token, WETH, amountTokenDesired, msg.value, amountTokenMin, amountETHMin, movingAveragePrice0ThresholdBps\n        );\n        address pair = ButtonswapLibrary.pairFor(factory, token, WETH);\n        TransferHelper.safeTransferFrom(token, msg.sender, address(this), amountToken);\n        TransferHelper.safeApprove(token, pair, amountToken);\n        IWETH(WETH).deposit{value: amountETH}();\n        TransferHelper.safeApprove(WETH, pair, amountETH);\n\n        (address token0,) = ButtonswapLibrary.sortTokens(token, WETH);\n        liquidity = (token == token0)\n            ? IButtonswapPair(pair).mint(amountToken, amountETH, to)\n            : IButtonswapPair(pair).mint(amountETH, amountToken, to);\n\n        // refund dust eth, if any\n        if (msg.value > amountETH) {\n            TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH);\n        }\n    }\n\n    /**\n     * @inheritdoc IETHButtonswapRouter\n     */\n    function createAndAddLiquidityETH(address token, uint256 amountTokenDesired, address to, uint256 deadline)\n        external\n        payable\n        virtual\n        override\n        ensure(deadline)\n        returns (uint256 amountToken, uint256 amountETH, uint256 liquidity)\n    {\n        (amountToken, amountETH) = _createAndAddLiquidity(token, WETH, amountTokenDesired, msg.value);\n        address pair = ButtonswapLibrary.pairFor(factory, token, WETH);\n        TransferHelper.safeTransferFrom(token, msg.sender, address(this), amountToken);\n        TransferHelper.safeApprove(token, pair, amountToken);\n        IWETH(WETH).deposit{value: amountETH}();\n        TransferHelper.safeApprove(WETH, pair, amountETH);\n\n        (address token0,) = ButtonswapLibrary.sortTokens(token, WETH);\n        liquidity = (token == token0)\n            ? IButtonswapPair(pair).mint(amountToken, amountETH, to)\n            : IButtonswapPair(pair).mint(amountETH, amountToken, to);\n\n        // refund dust eth, if any\n        if (msg.value > amountETH) {\n            TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH);\n        }\n    }\n\n    /**\n     * @inheritdoc IETHButtonswapRouter\n     */\n    function addLiquidityETHWithReservoir(\n        address token,\n        uint256 amountTokenDesired,\n        uint256 amountTokenMin,\n        uint256 amountETHMin,\n        address to,\n        uint256 deadline\n    )\n        external\n        payable\n        virtual\n        override\n        ensure(deadline)\n        returns (uint256 amountToken, uint256 amountETH, uint256 liquidity)\n    {\n        (amountToken, amountETH) =\n            _addLiquidityWithReservoir(token, WETH, amountTokenDesired, msg.value, amountTokenMin, amountETHMin);\n        address pair = ButtonswapLibrary.pairFor(factory, token, WETH);\n        if (amountToken > 0) {\n            TransferHelper.safeTransferFrom(token, msg.sender, address(this), amountToken);\n            TransferHelper.safeApprove(token, pair, amountToken);\n            liquidity = IButtonswapPair(pair).mintWithReservoir(amountToken, to);\n        } else if (amountETH > 0) {\n            IWETH(WETH).deposit{value: amountETH}();\n            TransferHelper.safeApprove(WETH, pair, amountETH);\n            liquidity = IButtonswapPair(pair).mintWithReservoir(amountETH, to);\n        }\n        // refund dust eth, if any\n        if (msg.value > amountETH) {\n            TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH);\n        }\n    }\n\n    /**\n     * @inheritdoc IETHButtonswapRouter\n     */\n    function removeLiquidityETH(\n        address token,\n        uint256 liquidity,\n        uint256 amountTokenMin,\n        uint256 amountETHMin,\n        address to,\n        uint256 deadline\n    ) public virtual override ensure(deadline) returns (uint256 amountToken, uint256 amountETH) {\n        (amountToken, amountETH) =\n            removeLiquidity(token, WETH, liquidity, amountTokenMin, amountETHMin, address(this), deadline);\n        TransferHelper.safeTransfer(token, to, amountToken);\n        IWETH(WETH).withdraw(amountETH);\n        TransferHelper.safeTransferETH(to, amountETH);\n    }\n\n    /**\n     * @inheritdoc IETHButtonswapRouter\n     */\n    function removeLiquidityETHFromReservoir(\n        address token,\n        uint256 liquidity,\n        uint256 amountTokenMin,\n        uint256 amountETHMin,\n        address to,\n        uint256 deadline\n    ) public virtual override ensure(deadline) returns (uint256 amountToken, uint256 amountETH) {\n        (amountToken, amountETH) =\n            removeLiquidityFromReservoir(token, WETH, liquidity, amountTokenMin, amountETHMin, address(this), deadline);\n        if (amountToken > 0) {\n            TransferHelper.safeTransfer(token, to, amountToken);\n        } else if (amountETH > 0) {\n            IWETH(WETH).withdraw(amountETH);\n            TransferHelper.safeTransferETH(to, amountETH);\n        }\n    }\n\n    function removeLiquidityETHWithPermit(\n        address token,\n        uint256 liquidity,\n        uint256 amountTokenMin,\n        uint256 amountETHMin,\n        address to,\n        uint256 deadline,\n        bool approveMax,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external virtual override returns (uint256 amountToken, uint256 amountETH) {\n        address pair = ButtonswapLibrary.pairFor(factory, token, WETH);\n        uint256 value = approveMax ? type(uint256).max : liquidity;\n        IButtonswapPair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);\n        (amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline);\n    }\n\n    /**\n     * @inheritdoc IETHButtonswapRouter\n     */\n    function swapExactETHForTokens(uint256 amountOutMin, address[] calldata path, address to, uint256 deadline)\n        external\n        payable\n        virtual\n        override\n        ensure(deadline)\n        returns (uint256[] memory amounts)\n    {\n        if (path[0] != WETH) {\n            revert InvalidPath();\n        }\n        amounts = ButtonswapLibrary.getAmountsOut(factory, msg.value, path);\n        if (amounts[amounts.length - 1] < amountOutMin) {\n            revert InsufficientOutputAmount();\n        }\n\n        IWETH(WETH).deposit{value: amounts[0]}();\n        if (!IWETH(WETH).transfer(address(this), amounts[0])) {\n            revert FailedWETHTransfer();\n        }\n        _swap(amounts, path, to);\n    }\n\n    /**\n     * @inheritdoc IETHButtonswapRouter\n     */\n    function swapTokensForExactETH(\n        uint256 amountOut,\n        uint256 amountInMax,\n        address[] calldata path,\n        address to,\n        uint256 deadline\n    ) external virtual override ensure(deadline) returns (uint256[] memory amounts) {\n        if (path[path.length - 1] != WETH) {\n            revert InvalidPath();\n        }\n        amounts = ButtonswapLibrary.getAmountsIn(factory, amountOut, path);\n        if (amounts[0] > amountInMax) {\n            revert ExcessiveInputAmount();\n        }\n\n        TransferHelper.safeTransferFrom(path[0], msg.sender, address(this), amounts[0]);\n        _swap(amounts, path, address(this));\n\n        // Convert final token to ETH and send to `to`\n        IWETH(WETH).withdraw(amounts[amounts.length - 1]);\n        TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);\n    }\n\n    /**\n     * @inheritdoc IETHButtonswapRouter\n     */\n    function swapExactTokensForETH(\n        uint256 amountIn,\n        uint256 amountOutMin,\n        address[] calldata path,\n        address to,\n        uint256 deadline\n    ) external virtual override ensure(deadline) returns (uint256[] memory amounts) {\n        if (path[path.length - 1] != WETH) {\n            revert InvalidPath();\n        }\n        amounts = ButtonswapLibrary.getAmountsOut(factory, amountIn, path);\n        if (amounts[amounts.length - 1] < amountOutMin) {\n            revert InsufficientOutputAmount();\n        }\n\n        TransferHelper.safeTransferFrom(path[0], msg.sender, address(this), amounts[0]);\n        _swap(amounts, path, address(this));\n        IWETH(WETH).withdraw(amounts[amounts.length - 1]);\n        TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);\n    }\n\n    /**\n     * @inheritdoc IETHButtonswapRouter\n     */\n    function swapETHForExactTokens(uint256 amountOut, address[] calldata path, address to, uint256 deadline)\n        external\n        payable\n        virtual\n        override\n        ensure(deadline)\n        returns (uint256[] memory amounts)\n    {\n        if (path[0] != WETH) {\n            revert InvalidPath();\n        }\n        amounts = ButtonswapLibrary.getAmountsIn(factory, amountOut, path);\n        if (amounts[0] > msg.value) {\n            revert ExcessiveInputAmount();\n        }\n\n        IWETH(WETH).deposit{value: amounts[0]}();\n        if (!IWETH(WETH).transfer(address(this), amounts[0])) {\n            revert FailedWETHTransfer();\n        }\n\n        _swap(amounts, path, to);\n        // refund dust eth, if any\n        if (msg.value > amounts[0]) {\n            TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]);\n        }\n    }\n}\n"
      },
      "src/interfaces/IButtonswapRouter/IETHButtonswapRouter.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport {IBasicButtonswapRouter} from \"./IBasicButtonswapRouter.sol\";\nimport {IETHButtonswapRouterErrors} from \"./IETHButtonswapRouterErrors.sol\";\n\ninterface IETHButtonswapRouter is IBasicButtonswapRouter, IETHButtonswapRouterErrors {\n    /**\n     * @notice Returns the address of the WETH token\n     * @return WETH The address of the WETH token\n     */\n    function WETH() external view returns (address WETH);\n\n    /**\n     * @notice Similar to `addLiquidity` but one of the tokens is ETH wrapped into WETH.\n     * Adds liquidity to a pair, reverting if it doesn't exist yet, and transfers the liquidity tokens to the recipient.\n     * @dev If the pair is empty, amountTokenMin and amountETHMin are ignored.\n     * If the pair is nonempty, it deposits as much of token and WETH as possible while maintaining 3 conditions:\n     * 1. The ratio of token to WETH in the pair remains approximately the same\n     * 2. The amount of token in the pair is at least amountTokenMin but less than or equal to amountTokenDesired\n     * 3. The amount of WETH in the pair is at least amountETHMin but less than or equal to ETH sent\n     * @param token The address of the non-WETH token in the pair.\n     * @param amountTokenDesired The maximum amount of the non-ETH token to add to the pair.\n     * @param amountTokenMin The minimum amount of the non-ETH token to add to the pair.\n     * @param amountETHMin The minimum amount of ETH/WETH to add to the pair.\n     * @param movingAveragePrice0ThresholdBps The percentage threshold that movingAveragePrice0 can deviate from the current price.\n     * @param to The address to send the liquidity tokens to.\n     * @param deadline The time after which this transaction can no longer be executed.\n     * @return amountToken The amount of token actually added to the pair.\n     * @return amountETH The amount of ETH/WETH actually added to the pair.\n     * @return liquidity The amount of liquidity tokens minted.\n     */\n    function addLiquidityETH(\n        address token,\n        uint256 amountTokenDesired,\n        uint256 amountTokenMin,\n        uint256 amountETHMin,\n        uint16 movingAveragePrice0ThresholdBps,\n        address to,\n        uint256 deadline\n    ) external payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);\n\n    /**\n     * @notice Similar to `creataeAndAddLiquidity` but one of the tokens is ETH wrapped into WETH.\n     * Adds liquidity to a pair, creating it if it doesn't exist yet, and transfers the liquidity tokens to the recipient.\n     * @dev If the pair is empty, amountTokenMin and amountETHMin are ignored.\n     * If the pair is nonempty, it deposits as much of token and WETH as possible while maintaining 3 conditions:\n     * 1. The ratio of token to WETH in the pair remains approximately the same\n     * 2. The amount of token in the pair is at least amountTokenMin but less than or equal to amountTokenDesired\n     * 3. The amount of WETH in the pair is at least amountETHMin but less than or equal to ETH sent\n     * @param token The address of the non-WETH token in the pair.\n     * @param amountTokenDesired The maximum amount of the non-ETH token to add to the pair.\n     * @param deadline The time after which this transaction can no longer be executed.\n     * @return amountToken The amount of token actually added to the pair.\n     * @return amountETH The amount of ETH/WETH actually added to the pair.\n     * @return liquidity The amount of liquidity tokens minted.\n     */\n    function createAndAddLiquidityETH(address token, uint256 amountTokenDesired, address to, uint256 deadline)\n        external\n        payable\n        returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);\n\n    /**\n     * @notice Similar to `addLiquidityWithReservoir` but one of the tokens is ETH wrapped into WETH.\n     *     Adds liquidity to a pair, opposite to the existing reservoir, and transfers the liquidity tokens to the recipient\n     * @dev Since there at most one reservoir at a given time, some conditions are checked:\n     * 1. If there is no reservoir, it rejects\n     * 2. If the non-WETH token has the reservoir, amountTokenDesired parameter ignored.\n     * 3. The token/WETH with the reservoir has its amount deducted from the reservoir (checked against corresponding amountMin parameter)\n     * @param token The address of the non-WETH token in the pair.\n     * @param amountTokenDesired The maximum amount of the non-WETH token to add to the pair.\n     * @param amountTokenMin The minimum amount of the non-WETH token to add to the pair.\n     * @param amountETHMin The minimum amount of WETH to add to the pair.\n     * @param to The address to send the liquidity tokens to.\n     * @param deadline The time after which this transaction can no longer be executed.\n     * @return amountToken The amount of the non-ETH token actually added to the pair.\n     * @return amountETH The amount of WETH actually added to the pair.\n     * @return liquidity The amount of liquidity tokens minted.\n     */\n    function addLiquidityETHWithReservoir(\n        address token,\n        uint256 amountTokenDesired,\n        uint256 amountTokenMin,\n        uint256 amountETHMin,\n        address to,\n        uint256 deadline\n    ) external payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);\n\n    /**\n     * @notice Similar to `removeLiquidity()` but one of the tokens is ETH wrapped into WETH.\n     * Removes liquidity from a pair, and transfers the tokens to the recipient.\n     * @param token The address of the non-WETH token in the pair.\n     * @param liquidity The amount of liquidity tokens to burn.\n     * @param amountTokenMin The minimum amount of the non-WETH token to withdraw from the pair.\n     * @param amountETHMin The minimum amount of ETH/WETH to withdraw from the pair.\n     * @param to The address to send the tokens to.\n     * @param deadline The time after which this transaction can no longer be executed.\n     * @return amountToken The amount of the non-WETH token actually withdrawn from the pair.\n     * @return amountETH The amount of ETH/WETH actually withdrawn from the pair.\n     */\n    function removeLiquidityETH(\n        address token,\n        uint256 liquidity,\n        uint256 amountTokenMin,\n        uint256 amountETHMin,\n        address to,\n        uint256 deadline\n    ) external returns (uint256 amountToken, uint256 amountETH);\n\n    /**\n     * @notice Similar to `removeLiquidityFromReservoir()` but one of the tokens is ETH wrapped into WETH.\n     * Removes liquidity from the reservoir of a pair and transfers the tokens to the recipient.\n     * @param token The address of the non-WETH token in the pair.\n     * @param liquidity The amount of liquidity tokens to burn.\n     * @param amountTokenMin The minimum amount of the non-WETH token to withdraw from the pair.\n     * @param amountETHMin The minimum amount of ETH/WETH to withdraw from the pair.\n     * @param to The address to send the tokens to.\n     * @param deadline The time after which this transaction can no longer be executed.\n     * @return amountToken The amount of the non-WETH token actually withdrawn from the pair.\n     * @return amountETH The amount of ETH/WETH actually withdrawn from the pair.\n     */\n    function removeLiquidityETHFromReservoir(\n        address token,\n        uint256 liquidity,\n        uint256 amountTokenMin,\n        uint256 amountETHMin,\n        address to,\n        uint256 deadline\n    ) external returns (uint256 amountToken, uint256 amountETH);\n\n    /**\n     * @notice Similar to `removeLiquidityWETH()` but utilizes the Permit signatures to reduce gas consumption.\n     * Removes liquidity from a pair where one of the tokens is ETH wrapped into WETH, and transfers the tokens to the recipient.\n     * @param token The address of the non-WETH token in the pair.\n     * @param liquidity The amount of liquidity tokens to burn.\n     * @param amountTokenMin The minimum amount of the non-WETH token to withdraw from the pair.\n     * @param amountETHMin The minimum amount of ETH/WETH to withdraw from the pair.\n     * @param to The address to send the tokens to.\n     * @param deadline The time after which this transaction can no longer be executed.\n     * @param approveMax Whether the signature is for the max uint256 or liquidity value\n     * @param v Part of the signature\n     * @param r Part of the signature\n     * @param s Part of the signature\n     * @return amountToken The amount of the non-WETH token actually withdrawn from the pair.\n     * @return amountETH The amount of ETH/WETH actually withdrawn from the pair.\n     */\n    function removeLiquidityETHWithPermit(\n        address token,\n        uint256 liquidity,\n        uint256 amountTokenMin,\n        uint256 amountETHMin,\n        address to,\n        uint256 deadline,\n        bool approveMax,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external returns (uint256 amountToken, uint256 amountETH);\n\n    /**\n     * @notice Similar to `swapExactTokensForTokens()` the first token is ETH wrapped into WETH.\n     * Given an ordered array of tokens, performs consecutive swaps from a specific amount of the first token to the last token in the array.\n     * @param amountOutMin The minimum amount of the last token to receive from the swap.\n     * @param path An array of token addresses [tokenA, tokenB, tokenC, ...] representing the path the input token takes to get to the output token\n     * @param to The address to send the output token to.\n     * @param deadline The time after which this transaction can no longer be executed.\n     */\n    function swapExactETHForTokens(uint256 amountOutMin, address[] calldata path, address to, uint256 deadline)\n        external\n        payable\n        returns (uint256[] memory amounts);\n\n    /**\n     * @notice Similar to `swapTokensForExactTokens()` the last token is ETH wrapped into WETH.\n     * Given an ordered array of tokens, performs consecutive swaps from the first token to a specific amount of the last token in the array.\n     * @param amountOut The amount of ETH to receive from the swap.\n     * @param amountInMax The maximum amount of the first token to swap.\n     * @param path An array of token addresses [tokenA, tokenB, tokenC, ...] representing the path the input token takes to get to the output token\n     * @param to The address to send the output token to.\n     * @param deadline The time after which this transaction can no longer be executed.\n     */\n    function swapTokensForExactETH(\n        uint256 amountOut,\n        uint256 amountInMax,\n        address[] calldata path,\n        address to,\n        uint256 deadline\n    ) external returns (uint256[] memory amounts);\n\n    /**\n     * @notice Similar to `swapExactTokensForTokens()` but the last token is ETH wrapped into WETH.\n     * Given an ordered array of tokens, performs consecutive swaps from a specific amount of the first token to the last token in the array.\n     * @param amountIn The amount of the first token to swap.\n     * @param amountOutMin The minimum amount of the last token to receive from the swap.\n     * @param path An array of token addresses [tokenA, tokenB, tokenC, ...] representing the path the input token takes to get to the output token\n     * @param to The address to send the output token to.\n     * @param deadline The time after which this transaction can no longer be executed.\n     */\n    function swapExactTokensForETH(\n        uint256 amountIn,\n        uint256 amountOutMin,\n        address[] calldata path,\n        address to,\n        uint256 deadline\n    ) external returns (uint256[] memory amounts);\n\n    /**\n     * @notice Similar to `swapTokensForExactTokens()` but the first token is ETH wrapped into WETH.\n     * Given an ordered array of tokens, performs consecutive swaps from the first token to a specific amount of the last token in the array.\n     * @param amountOut The amount of the last token to receive from the swap.\n     * @param path An array of token addresses [tokenA, tokenB, tokenC, ...] representing the path the input token takes to get to the output token\n     * @param to The address to send the output token to.\n     * @param deadline The time after which this transaction can no longer be executed.\n     */\n    function swapETHForExactTokens(uint256 amountOut, address[] calldata path, address to, uint256 deadline)\n        external\n        payable\n        returns (uint256[] memory amounts);\n}\n"
      },
      "lib/buttonswap-core/src/interfaces/IButtonswapFactory/IButtonswapFactoryErrors.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.13;\n\ninterface IButtonswapFactoryErrors {\n    /**\n     * @notice The given token addresses are the same\n     */\n    error TokenIdenticalAddress();\n\n    /**\n     * @notice The given token address is the zero address\n     */\n    error TokenZeroAddress();\n\n    /**\n     * @notice The given tokens already have a {ButtonswapPair} instance\n     */\n    error PairExists();\n\n    /**\n     * @notice User does not have permission for the attempted operation\n     */\n    error Forbidden();\n\n    /**\n     * @notice There was an attempt to update a parameter to an invalid value\n     */\n    error InvalidParameter();\n}\n"
      },
      "lib/buttonswap-core/src/interfaces/IButtonswapFactory/IButtonswapFactoryEvents.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.13;\n\ninterface IButtonswapFactoryEvents {\n    /**\n     * @notice Emitted when a new Pair is created.\n     * @param token0 The first sorted token\n     * @param token1 The second sorted token\n     * @param pair The address of the new {ButtonswapPair} contract\n     * @param count The new total number of Pairs created\n     */\n    event PairCreated(address indexed token0, address indexed token1, address pair, uint256 count);\n\n    /**\n     * @notice Emitted when the default parameters for a new pair have been updated.\n     * @param paramSetter The address that changed the parameters\n     * @param newDefaultMovingAverageWindow The new movingAverageWindow default value\n     * @param newDefaultMaxVolatilityBps The new maxVolatilityBps default value\n     * @param newDefaultMinTimelockDuration The new minTimelockDuration default value\n     * @param newDefaultMaxTimelockDuration The new maxTimelockDuration default value\n     * @param newDefaultMaxSwappableReservoirLimitBps The new maxSwappableReservoirLimitBps default value\n     * @param newDefaultSwappableReservoirGrowthWindow The new swappableReservoirGrowthWindow default value\n     */\n    event DefaultParametersUpdated(\n        address indexed paramSetter,\n        uint32 newDefaultMovingAverageWindow,\n        uint16 newDefaultMaxVolatilityBps,\n        uint32 newDefaultMinTimelockDuration,\n        uint32 newDefaultMaxTimelockDuration,\n        uint16 newDefaultMaxSwappableReservoirLimitBps,\n        uint32 newDefaultSwappableReservoirGrowthWindow\n    );\n}\n"
      },
      "lib/buttonswap-core/src/interfaces/IButtonswapPair/IButtonswapPairErrors.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.13;\n\nimport {IButtonswapERC20Errors} from \"../IButtonswapERC20/IButtonswapERC20Errors.sol\";\n\ninterface IButtonswapPairErrors is IButtonswapERC20Errors {\n    /**\n     * @notice Re-entrancy guard prevented method call\n     */\n    error Locked();\n\n    /**\n     * @notice User does not have permission for the attempted operation\n     */\n    error Forbidden();\n\n    /**\n     * @notice Integer maximums exceeded\n     */\n    error Overflow();\n\n    /**\n     * @notice Initial deposit not yet made\n     */\n    error Uninitialized();\n\n    /**\n     * @notice There was not enough liquidity in the reservoir\n     */\n    error InsufficientReservoir();\n\n    /**\n     * @notice Not enough liquidity was created during mint\n     */\n    error InsufficientLiquidityMinted();\n\n    /**\n     * @notice Not enough funds added to mint new liquidity\n     */\n    error InsufficientLiquidityAdded();\n\n    /**\n     * @notice More liquidity must be burned to be redeemed for non-zero amounts\n     */\n    error InsufficientLiquidityBurned();\n\n    /**\n     * @notice Swap was attempted with zero input\n     */\n    error InsufficientInputAmount();\n\n    /**\n     * @notice Swap was attempted with zero output\n     */\n    error InsufficientOutputAmount();\n\n    /**\n     * @notice Pool doesn't have the liquidity to service the swap\n     */\n    error InsufficientLiquidity();\n\n    /**\n     * @notice The specified \"to\" address is invalid\n     */\n    error InvalidRecipient();\n\n    /**\n     * @notice The product of pool balances must not change during a swap (save for accounting for fees)\n     */\n    error KInvariant();\n\n    /**\n     * @notice The new price ratio after a swap is invalid (one or more of the price terms are zero)\n     */\n    error InvalidFinalPrice();\n\n    /**\n     * @notice Single sided operations are not executable at this point in time\n     */\n    error SingleSidedTimelock();\n\n    /**\n     * @notice The attempted operation would have swapped reservoir tokens above the current limit\n     */\n    error SwappableReservoirExceeded();\n\n    /**\n     * @notice All operations on the pair other than dual-sided burning are currently paused\n     */\n    error Paused();\n}\n"
      },
      "lib/buttonswap-core/src/interfaces/IButtonswapPair/IButtonswapPairEvents.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.13;\n\nimport {IButtonswapERC20Events} from \"../IButtonswapERC20/IButtonswapERC20Events.sol\";\n\ninterface IButtonswapPairEvents is IButtonswapERC20Events {\n    /**\n     * @notice Emitted when a {IButtonswapPair-mint} is performed.\n     * Some `token0` and `token1` are deposited in exchange for liquidity tokens representing a claim on them.\n     * @param from The account that supplied the tokens for the mint\n     * @param amount0 The amount of `token0` that was deposited\n     * @param amount1 The amount of `token1` that was deposited\n     * @param amountOut The amount of liquidity tokens that were minted\n     * @param to The account that received the tokens from the mint\n     */\n    event Mint(address indexed from, uint256 amount0, uint256 amount1, uint256 amountOut, address indexed to);\n\n    /**\n     * @notice Emitted when a {IButtonswapPair-burn} is performed.\n     * Liquidity tokens are redeemed for underlying `token0` and `token1`.\n     * @param from The account that supplied the tokens for the burn\n     * @param amountIn The amount of liquidity tokens that were burned\n     * @param amount0 The amount of `token0` that was received\n     * @param amount1 The amount of `token1` that was received\n     * @param to The account that received the tokens from the burn\n     */\n    event Burn(address indexed from, uint256 amountIn, uint256 amount0, uint256 amount1, address indexed to);\n\n    /**\n     * @notice Emitted when a {IButtonswapPair-swap} is performed.\n     * @param from The account that supplied the tokens for the swap\n     * @param amount0In The amount of `token0` that went into the swap\n     * @param amount1In The amount of `token1` that went into the swap\n     * @param amount0Out The amount of `token0` that came out of the swap\n     * @param amount1Out The amount of `token1` that came out of the swap\n     * @param to The account that received the tokens from the swap\n     */\n    event Swap(\n        address indexed from,\n        uint256 amount0In,\n        uint256 amount1In,\n        uint256 amount0Out,\n        uint256 amount1Out,\n        address indexed to\n    );\n\n    /**\n     * @notice Emitted when the movingAverageWindow parameter for the pair has been updated.\n     * @param newMovingAverageWindow The new movingAverageWindow value\n     */\n    event MovingAverageWindowUpdated(uint32 newMovingAverageWindow);\n\n    /**\n     * @notice Emitted when the maxVolatilityBps parameter for the pair has been updated.\n     * @param newMaxVolatilityBps The new maxVolatilityBps value\n     */\n    event MaxVolatilityBpsUpdated(uint16 newMaxVolatilityBps);\n\n    /**\n     * @notice Emitted when the minTimelockDuration parameter for the pair has been updated.\n     * @param newMinTimelockDuration The new minTimelockDuration value\n     */\n    event MinTimelockDurationUpdated(uint32 newMinTimelockDuration);\n\n    /**\n     * @notice Emitted when the maxTimelockDuration parameter for the pair has been updated.\n     * @param newMaxTimelockDuration The new maxTimelockDuration value\n     */\n    event MaxTimelockDurationUpdated(uint32 newMaxTimelockDuration);\n\n    /**\n     * @notice Emitted when the maxSwappableReservoirLimitBps parameter for the pair has been updated.\n     * @param newMaxSwappableReservoirLimitBps The new maxSwappableReservoirLimitBps value\n     */\n    event MaxSwappableReservoirLimitBpsUpdated(uint16 newMaxSwappableReservoirLimitBps);\n\n    /**\n     * @notice Emitted when the swappableReservoirGrowthWindow parameter for the pair has been updated.\n     * @param newSwappableReservoirGrowthWindow The new swappableReservoirGrowthWindow value\n     */\n    event SwappableReservoirGrowthWindowUpdated(uint32 newSwappableReservoirGrowthWindow);\n}\n"
      },
      "lib/buttonswap-core/src/interfaces/IButtonswapERC20/IButtonswapERC20.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.13;\n\nimport {IButtonswapERC20Errors} from \"./IButtonswapERC20Errors.sol\";\nimport {IButtonswapERC20Events} from \"./IButtonswapERC20Events.sol\";\n\ninterface IButtonswapERC20 is IButtonswapERC20Errors, IButtonswapERC20Events {\n    /**\n     * @notice Returns the name of the token.\n     * @return _name The token name\n     */\n    function name() external view returns (string memory _name);\n\n    /**\n     * @notice Returns the symbol of the token, usually a shorter version of the name.\n     * @return _symbol The token symbol\n     */\n    function symbol() external view returns (string memory _symbol);\n\n    /**\n     * @notice Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     * @dev This information is only used for _display_ purposes: it in no way affects any of the arithmetic of the contract.\n     * @return decimals The number of decimals\n     */\n    function decimals() external pure returns (uint8 decimals);\n\n    /**\n     * @notice Returns the amount of tokens in existence.\n     * @return totalSupply The amount of tokens in existence\n     */\n    function totalSupply() external view returns (uint256 totalSupply);\n\n    /**\n     * @notice Returns the amount of tokens owned by `account`.\n     * @param owner The account the balance is being checked for\n     * @return balance The amount of tokens owned by `owner`\n     */\n    function balanceOf(address owner) external view returns (uint256 balance);\n\n    /**\n     * @notice Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}.\n     * This is zero by default.\n     * This value changes when {approve} or {transferFrom} are called.\n     * @param owner The account that owns the tokens\n     * @param spender The account that can spend the tokens\n     * @return allowance The amount of tokens owned by `owner` that the `spender` can transfer\n     */\n    function allowance(address owner, address spender) external view returns (uint256 allowance);\n\n    /**\n     * @notice Sets `value` as the allowance of `spender` over the caller's tokens.\n     * @dev 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 {IButtonswapERC20Events-Approval} event.\n     * @param spender The account that is granted permission to spend the tokens\n     * @param value The amount of tokens that can be spent\n     * @return success Whether the operation succeeded\n     */\n    function approve(address spender, uint256 value) external returns (bool success);\n\n    /**\n     * @notice Moves `value` tokens from the caller's account to `to`.\n     * @dev Emits a {IButtonswapERC20Events-Transfer} event.\n     * @param to The account that is receiving the tokens\n     * @param value The amount of tokens being sent\n     * @return success Whether the operation succeeded\n     */\n    function transfer(address to, uint256 value) external returns (bool success);\n\n    /**\n     * @notice Moves `value` tokens from `from` to `to` using the allowance mechanism.\n     * `value` is then deducted from the caller's allowance.\n     * @dev Emits a {IButtonswapERC20Events-Transfer} event.\n     * @param from The account that is sending the tokens\n     * @param to The account that is receiving the tokens\n     * @param value The amount of tokens being sent\n     * @return success Whether the operation succeeded\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n\n    /**\n     * @notice Returns the domain separator used in the encoding of the signature for {permit}, as defined by [EIP712](https://eips.ethereum.org/EIPS/eip-712).\n     * @return DOMAIN_SEPARATOR The `DOMAIN_SEPARATOR` value\n     */\n    function DOMAIN_SEPARATOR() external view returns (bytes32 DOMAIN_SEPARATOR);\n\n    /**\n     * @notice Returns the typehash used in the encoding of the signature for {permit}, as defined by [EIP712](https://eips.ethereum.org/EIPS/eip-712).\n     * @return PERMIT_TYPEHASH The `PERMIT_TYPEHASH` value\n     */\n    function PERMIT_TYPEHASH() external pure returns (bytes32 PERMIT_TYPEHASH);\n\n    /**\n     * @notice Returns the current nonce for `owner`.\n     * This value must be included whenever a signature is generated for {permit}.\n     * @dev Every successful call to {permit} increases `owner`'s nonce by one.\n     * This prevents a signature from being used multiple times.\n     * @param owner The account to get the nonce for\n     * @return nonce The current nonce for the given `owner`\n     */\n    function nonces(address owner) external view returns (uint256 nonce);\n\n    /**\n     * @notice Sets `value` as the allowance of `spender` over `owner`'s tokens, given `owner`'s signed approval.\n     * @dev IMPORTANT: The same issues {approve} has related to transaction ordering also apply here.\n     *\n     * Emits an {IButtonswapERC20Events-Approval} event.\n     *\n     * Requirements:\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments.\n     * - the signature must use `owner`'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the [relevant EIP section](https://eips.ethereum.org/EIPS/eip-2612#specification).\n     * @param owner The account that owns the tokens\n     * @param spender The account that can spend the tokens\n     * @param value The amount of `owner`'s tokens that `spender` can transfer\n     * @param deadline The future time after which the permit is no longer valid\n     * @param v Part of the signature\n     * @param r Part of the signature\n     * @param s Part of the signature\n     */\n    function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n        external;\n}\n"
      },
      "lib/buttonswap-core/src/libraries/Math.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.13;\n\n// a library for performing various math operations\n\nlibrary Math {\n    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        z = x < y ? x : y;\n    }\n\n    function max(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        z = x > y ? x : y;\n    }\n\n    // Borrowed implementation from solmate\n    // https://github.com/transmissions11/solmate/blob/2001af43aedb46fdc2335d2a7714fb2dae7cfcd1/src/utils/FixedPointMathLib.sol#L164\n    function sqrt(uint256 x) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let y := x // We start y at x, which will help us make our initial estimate.\n\n            z := 181 // The \"correct\" value is 1, but this saves a multiplication later.\n\n            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad\n            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.\n\n            // We check y >= 2^(k + 8) but shift right by k bits\n            // each branch to ensure that if x >= 256, then y >= 256.\n            if iszero(lt(y, 0x10000000000000000000000000000000000)) {\n                y := shr(128, y)\n                z := shl(64, z)\n            }\n            if iszero(lt(y, 0x1000000000000000000)) {\n                y := shr(64, y)\n                z := shl(32, z)\n            }\n            if iszero(lt(y, 0x10000000000)) {\n                y := shr(32, y)\n                z := shl(16, z)\n            }\n            if iszero(lt(y, 0x1000000)) {\n                y := shr(16, y)\n                z := shl(8, z)\n            }\n\n            // Goal was to get z*z*y within a small factor of x. More iterations could\n            // get y in a tighter range. Currently, we will have y in [256, 256*2^16).\n            // We ensured y >= 256 so that the relative difference between y and y+1 is small.\n            // That's not possible if x < 256 but we can just verify those cases exhaustively.\n\n            // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.\n            // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.\n            // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.\n\n            // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range\n            // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.\n\n            // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate\n            // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.\n\n            // There is no overflow risk here since y < 2^136 after the first branch above.\n            z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.\n\n            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n\n            // If x+1 is a perfect square, the Babylonian method cycles between\n            // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.\n            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division\n            // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.\n            // If you don't care whether the floor or ceil square root is returned, you can remove this statement.\n            z := sub(z, lt(div(x, z), z))\n        }\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n     * with further edits by Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod0 := mul(x, y)\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1);\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n            // in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n}\n"
      },
      "src/BasicButtonswapRouter.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport {IButtonswapFactory} from\n    \"buttonswap-periphery_buttonswap-core/interfaces/IButtonswapFactory/IButtonswapFactory.sol\";\nimport {IButtonswapPair} from \"buttonswap-periphery_buttonswap-core/interfaces/IButtonswapPair/IButtonswapPair.sol\";\nimport {TransferHelper} from \"./libraries/TransferHelper.sol\";\nimport {IBasicButtonswapRouter} from \"./interfaces/IButtonswapRouter/IBasicButtonswapRouter.sol\";\nimport {ButtonswapLibrary} from \"./libraries/ButtonswapLibrary.sol\";\nimport {IERC20} from \"./interfaces/IERC20.sol\";\nimport {IWETH} from \"./interfaces/IWETH.sol\";\nimport {RootButtonswapRouter} from \"./RootButtonswapRouter.sol\";\n\ncontract BasicButtonswapRouter is RootButtonswapRouter, IBasicButtonswapRouter {\n    modifier ensure(uint256 deadline) {\n        if (block.timestamp > deadline) {\n            revert Expired();\n        }\n        _;\n    }\n\n    constructor(address _factory) RootButtonswapRouter(_factory) {}\n\n    /**\n     * @inheritdoc IBasicButtonswapRouter\n     */\n    function addLiquidity(\n        address tokenA,\n        address tokenB,\n        uint256 amountADesired,\n        uint256 amountBDesired,\n        uint256 amountAMin,\n        uint256 amountBMin,\n        uint16 movingAveragePrice0ThresholdBps,\n        address to,\n        uint256 deadline\n    ) external virtual override ensure(deadline) returns (uint256 amountA, uint256 amountB, uint256 liquidity) {\n        (amountA, amountB) = _addLiquidity(\n            tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin, movingAveragePrice0ThresholdBps\n        );\n        address pair = ButtonswapLibrary.pairFor(factory, tokenA, tokenB);\n        TransferHelper.safeTransferFrom(tokenA, msg.sender, address(this), amountA);\n        TransferHelper.safeApprove(tokenA, pair, amountA);\n        TransferHelper.safeTransferFrom(tokenB, msg.sender, address(this), amountB);\n        TransferHelper.safeApprove(tokenB, pair, amountB);\n\n        if (tokenA < tokenB) {\n            liquidity = IButtonswapPair(pair).mint(amountA, amountB, to);\n        } else {\n            liquidity = IButtonswapPair(pair).mint(amountB, amountA, to);\n        }\n    }\n\n    /**\n     * @inheritdoc IBasicButtonswapRouter\n     */\n    function createAndAddLiquidity(\n        address tokenA,\n        address tokenB,\n        uint256 amountADesired,\n        uint256 amountBDesired,\n        address to,\n        uint256 deadline\n    ) external virtual override ensure(deadline) returns (uint256 amountA, uint256 amountB, uint256 liquidity) {\n        (amountA, amountB) = _createAndAddLiquidity(tokenA, tokenB, amountADesired, amountBDesired);\n        address pair = ButtonswapLibrary.pairFor(factory, tokenA, tokenB);\n        TransferHelper.safeTransferFrom(tokenA, msg.sender, address(this), amountA);\n        TransferHelper.safeApprove(tokenA, pair, amountA);\n        TransferHelper.safeTransferFrom(tokenB, msg.sender, address(this), amountB);\n        TransferHelper.safeApprove(tokenB, pair, amountB);\n\n        if (tokenA < tokenB) {\n            liquidity = IButtonswapPair(pair).mint(amountA, amountB, to);\n        } else {\n            liquidity = IButtonswapPair(pair).mint(amountB, amountA, to);\n        }\n    }\n\n    /**\n     * @inheritdoc IBasicButtonswapRouter\n     */\n    function addLiquidityWithReservoir(\n        address tokenA,\n        address tokenB,\n        uint256 amountADesired,\n        uint256 amountBDesired,\n        uint256 amountAMin,\n        uint256 amountBMin,\n        address to,\n        uint256 deadline\n    ) external virtual override ensure(deadline) returns (uint256 amountA, uint256 amountB, uint256 liquidity) {\n        (amountA, amountB) =\n            _addLiquidityWithReservoir(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);\n        address pair = ButtonswapLibrary.pairFor(factory, tokenA, tokenB);\n\n        if (amountA > 0) {\n            TransferHelper.safeTransferFrom(tokenA, msg.sender, address(this), amountA);\n            TransferHelper.safeApprove(tokenA, pair, amountA);\n            liquidity = IButtonswapPair(pair).mintWithReservoir(amountA, to);\n        } else if (amountB > 0) {\n            TransferHelper.safeTransferFrom(tokenB, msg.sender, address(this), amountB);\n            TransferHelper.safeApprove(tokenB, pair, amountB);\n            liquidity = IButtonswapPair(pair).mintWithReservoir(amountB, to);\n        }\n    }\n\n    // **** REMOVE LIQUIDITY ****\n    /**\n     * @inheritdoc IBasicButtonswapRouter\n     */\n    function removeLiquidity(\n        address tokenA,\n        address tokenB,\n        uint256 liquidity,\n        uint256 amountAMin,\n        uint256 amountBMin,\n        address to,\n        uint256 deadline\n    ) public virtual override ensure(deadline) returns (uint256 amountA, uint256 amountB) {\n        address pair = ButtonswapLibrary.pairFor(factory, tokenA, tokenB);\n        IButtonswapPair(pair).transferFrom(msg.sender, address(this), liquidity); // send liquidity to router\n        (uint256 amount0, uint256 amount1) = IButtonswapPair(pair).burn(liquidity, to);\n        (address token0,) = ButtonswapLibrary.sortTokens(tokenA, tokenB);\n        (amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);\n        if (amountA < amountAMin) {\n            revert InsufficientAAmount();\n        }\n        if (amountB < amountBMin) {\n            revert InsufficientBAmount();\n        }\n    }\n\n    /**\n     * @inheritdoc IBasicButtonswapRouter\n     */\n    function removeLiquidityFromReservoir(\n        address tokenA,\n        address tokenB,\n        uint256 liquidity,\n        uint256 amountAMin,\n        uint256 amountBMin,\n        address to,\n        uint256 deadline\n    ) public virtual override ensure(deadline) returns (uint256 amountA, uint256 amountB) {\n        address pair = ButtonswapLibrary.pairFor(factory, tokenA, tokenB);\n        IButtonswapPair(pair).transferFrom(msg.sender, address(this), liquidity); // send liquidity to router\n        (uint256 amount0, uint256 amount1) = IButtonswapPair(pair).burnFromReservoir(liquidity, to);\n        (address token0,) = ButtonswapLibrary.sortTokens(tokenA, tokenB);\n        (amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);\n        if (amountA < amountAMin) {\n            revert InsufficientAAmount();\n        }\n        if (amountB < amountBMin) {\n            revert InsufficientBAmount();\n        }\n    }\n\n    /**\n     * @inheritdoc IBasicButtonswapRouter\n     */\n    function removeLiquidityWithPermit(\n        address tokenA,\n        address tokenB,\n        uint256 liquidity,\n        uint256 amountAMin,\n        uint256 amountBMin,\n        address to,\n        uint256 deadline,\n        bool approveMax,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external virtual override returns (uint256 amountA, uint256 amountB) {\n        address pair = ButtonswapLibrary.pairFor(factory, tokenA, tokenB);\n        uint256 value = approveMax ? type(uint256).max : liquidity;\n        IButtonswapPair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);\n        (amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);\n    }\n\n    // **** SWAP ****\n    /**\n     * @inheritdoc IBasicButtonswapRouter\n     */\n    function swapExactTokensForTokens(\n        uint256 amountIn,\n        uint256 amountOutMin,\n        address[] calldata path,\n        address to,\n        uint256 deadline\n    ) external virtual override ensure(deadline) returns (uint256[] memory amounts) {\n        amounts = ButtonswapLibrary.getAmountsOut(factory, amountIn, path);\n        if (amounts[amounts.length - 1] < amountOutMin) {\n            revert InsufficientOutputAmount();\n        }\n        IButtonswapPair(ButtonswapLibrary.pairFor(factory, path[0], path[1]));\n\n        TransferHelper.safeTransferFrom(path[0], msg.sender, address(this), amounts[0]);\n        _swap(amounts, path, to);\n    }\n\n    /**\n     * @inheritdoc IBasicButtonswapRouter\n     */\n    function swapTokensForExactTokens(\n        uint256 amountOut,\n        uint256 amountInMax,\n        address[] calldata path,\n        address to,\n        uint256 deadline\n    ) external virtual override ensure(deadline) returns (uint256[] memory amounts) {\n        amounts = ButtonswapLibrary.getAmountsIn(factory, amountOut, path);\n        if (amounts[0] > amountInMax) {\n            revert ExcessiveInputAmount();\n        }\n        //        IButtonswapPair pair = IButtonswapPair(ButtonswapLibrary.pairFor(factory, path[0], path[1]));\n        TransferHelper.safeTransferFrom(path[0], msg.sender, address(this), amounts[0]);\n        _swap(amounts, path, to);\n    }\n}\n"
      },
      "src/interfaces/IButtonswapRouter/IBasicButtonswapRouter.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport {IRootButtonswapRouter} from \"./IRootButtonswapRouter.sol\";\n\ninterface IBasicButtonswapRouter is IRootButtonswapRouter {\n    /**\n     * @notice Adds liquidity to a pair, reverting if it doesn't exist yet, and transfers the liquidity tokens to the recipient.\n     * @dev If the pair is empty, amountAMin and amountBMin are ignored.\n     * If the pair is nonempty, it deposits as much of tokenA and tokenB as possible while maintaining 3 conditions:\n     * 1. The ratio of tokenA to tokenB in the pair remains approximately the same\n     * 2. The amount of tokenA in the pair is at least amountAMin but less than or equal to amountADesired\n     * 3. The amount of tokenB in the pair is at least amountBMin but less than or equal to amountBDesired\n     * @param tokenA The address of the first token in the pair.\n     * @param tokenB The address of the second token in the pair.\n     * @param amountADesired The maximum amount of the first token to add to the pair.\n     * @param amountBDesired The maximum amount of the second token to add to the pair.\n     * @param amountAMin The minimum amount of the first token to add to the pair.\n     * @param amountBMin The minimum amount of the second token to add to the pair.\n     * @param movingAveragePrice0ThresholdBps The percentage threshold that movingAveragePrice0 can deviate from the current price.\n     * @param to The address to send the liquidity tokens to.\n     * @param deadline The time after which this transaction can no longer be executed.\n     * @return amountA The amount of tokenA actually added to the pair.\n     * @return amountB The amount of tokenB actually added to the pair.\n     * @return liquidity The amount of liquidity tokens minted.\n     */\n    function addLiquidity(\n        address tokenA,\n        address tokenB,\n        uint256 amountADesired,\n        uint256 amountBDesired,\n        uint256 amountAMin,\n        uint256 amountBMin,\n        uint16 movingAveragePrice0ThresholdBps,\n        address to,\n        uint256 deadline\n    ) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);\n\n    /**\n     * @notice Adds liquidity to a pair, creating it if it doesn't exist yet, and transfers the liquidity tokens to the recipient.\n     * @dev If the pair is empty, amountAMin and amountBMin are ignored.\n     * If the pair is nonempty, it deposits as much of tokenA and tokenB as possible while maintaining 3 conditions:\n     * 1. The ratio of tokenA to tokenB in the pair remains approximately the same\n     * 2. The amount of tokenA in the pair is at least amountAMin but less than or equal to amountADesired\n     * 3. The amount of tokenB in the pair is at least amountBMin but less than or equal to amountBDesired\n     * @param tokenA The address of the first token in the pair.\n     * @param tokenB The address of the second token in the pair.\n     * @param amountADesired The maximum amount of the first token to add to the pair.\n     * @param amountBDesired The maximum amount of the second token to add to the pair.\n     * @param to The address to send the liquidity tokens to.\n     * @param deadline The time after which this transaction can no longer be executed.\n     * @return amountA The amount of tokenA actually added to the pair.\n     * @return amountB The amount of tokenB actually added to the pair.\n     * @return liquidity The amount of liquidity tokens minted.\n     */\n    function createAndAddLiquidity(\n        address tokenA,\n        address tokenB,\n        uint256 amountADesired,\n        uint256 amountBDesired,\n        address to,\n        uint256 deadline\n    ) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);\n\n    /**\n     * @notice Adds liquidity to a pair, opposite to the existing reservoir, and transfers the liquidity tokens to the recipient\n     * @dev Since there at most one reservoir at a given time, some conditions are checked:\n     * 1. If there is no reservoir, it rejects\n     * 2. The token with the reservoir has its amountDesired parameter ignored\n     * 3. The token with the reservoir has its amount deducted from the reservoir (checked against corresponding amountMin parameter)\n     * @param tokenA The address of the first token in the pair.\n     * @param tokenB The address of the second token in the pair.\n     * @param amountADesired The maximum amount of the first token to add to the pair.\n     * @param amountBDesired The maximum amount of the second token to add to the pair.\n     * @param amountAMin The minimum amount of the first token to add to the pair.\n     * @param amountBMin The minimum amount of the second token to add to the pair.\n     * @param to The address to send the liquidity tokens to.\n     * @param deadline The time after which this transaction can no longer be executed.\n     * @return amountA The amount of tokenA actually added to the pair.\n     * @return amountB The amount of tokenB actually added to the pair.\n     * @return liquidity The amount of liquidity tokens minted.\n     */\n    function addLiquidityWithReservoir(\n        address tokenA,\n        address tokenB,\n        uint256 amountADesired,\n        uint256 amountBDesired,\n        uint256 amountAMin,\n        uint256 amountBMin,\n        address to,\n        uint256 deadline\n    ) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);\n\n    /**\n     * @notice Removes liquidity from a pair, and transfers the tokens to the recipient.\n     * @param tokenA The address of the first token in the pair.\n     * @param tokenB The address of the second token in the pair.\n     * @param liquidity The amount of liquidity tokens to burn.\n     * @param amountAMin The minimum amount of the first token to withdraw from the pair.\n     * @param amountBMin The minimum amount of the second token to withdraw from the pair.\n     * @param to The address to send the tokens to.\n     * @param deadline The time after which this transaction can no longer be executed.\n     * @return amountA The amount of tokenA actually withdrawn from the pair.\n     * @return amountB The amount of tokenB actually withdrawn from the pair.\n     */\n    function removeLiquidity(\n        address tokenA,\n        address tokenB,\n        uint256 liquidity,\n        uint256 amountAMin,\n        uint256 amountBMin,\n        address to,\n        uint256 deadline\n    ) external returns (uint256 amountA, uint256 amountB);\n\n    /**\n     * @notice Removes liquidity from the reservoir of a pair and transfers the tokens to the recipient.\n     * @param tokenA The address of the first token in the pair.\n     * @param tokenB The address of the second token in the pair.\n     * @param liquidity The amount of liquidity tokens to burn.\n     * @param amountAMin The minimum amount of the first token to withdraw from the pair.\n     * @param amountBMin The minimum amount of the second token to withdraw from the pair.\n     * @param to The address to send the tokens to.\n     * @param deadline The time after which this transaction can no longer be executed.\n     * @return amountA The amount of tokenA actually withdrawn from the pair.\n     * @return amountB The amount of tokenB actually withdrawn from the pair.\n     */\n    function removeLiquidityFromReservoir(\n        address tokenA,\n        address tokenB,\n        uint256 liquidity,\n        uint256 amountAMin,\n        uint256 amountBMin,\n        address to,\n        uint256 deadline\n    ) external returns (uint256 amountA, uint256 amountB);\n\n    /**\n     * @notice Similar to `removeLiquidity()` but utilizes the Permit signatures to reduce gas consumption.\n     * Removes liquidity from a pair, and transfers the tokens to the recipient.\n     * @param tokenA The address of the first token in the pair.\n     * @param tokenB The address of the second token in the pair.\n     * @param liquidity The amount of liquidity tokens to burn.\n     * @param amountAMin The minimum amount of the first token to withdraw from the pair.\n     * @param amountBMin The minimum amount of the second token to withdraw from the pair.\n     * @param to The address to send the tokens to.\n     * @param deadline The time after which this transaction can no longer be executed.\n     * @param approveMax Whether the signature is for the max uint256 or liquidity value\n     * @param v Part of the signature\n     * @param r Part of the signature\n     * @param s Part of the signature\n     * @return amountA The amount of tokenA actually withdrawn from the pair.\n     * @return amountB The amount of tokenB actually withdrawn from the pair.\n     */\n    function removeLiquidityWithPermit(\n        address tokenA,\n        address tokenB,\n        uint256 liquidity,\n        uint256 amountAMin,\n        uint256 amountBMin,\n        address to,\n        uint256 deadline,\n        bool approveMax,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external returns (uint256 amountA, uint256 amountB);\n\n    /**\n     * @notice Given an ordered array of tokens, performs consecutive swaps from a specific amount of the first token to the last token in the array.\n     * @param amountIn The amount of the first token to swap.\n     * @param amountOutMin The minimum amount of the last token to receive from the swap.\n     * @param path An array of token addresses [tokenA, tokenB, tokenC, ...] representing the path the input token takes to get to the output token\n     * @param to The address to send the output token to.\n     * @param deadline The time after which this transaction can no longer be executed.\n     */\n    function swapExactTokensForTokens(\n        uint256 amountIn,\n        uint256 amountOutMin,\n        address[] calldata path,\n        address to,\n        uint256 deadline\n    ) external returns (uint256[] memory amounts);\n\n    /**\n     * @notice Given an ordered array of tokens, performs consecutive swaps from the first token to a specific amount of the last token in the array.\n     * @param amountOut The amount of the last token to receive from the swap.\n     * @param amountInMax The maximum amount of the first token to swap.\n     * @param path An array of token addresses [tokenA, tokenB, tokenC, ...] representing the path the input token takes to get to the output token\n     * @param to The address to send the output token to.\n     * @param deadline The time after which this transaction can no longer be executed.\n     */\n    function swapTokensForExactTokens(\n        uint256 amountOut,\n        uint256 amountInMax,\n        address[] calldata path,\n        address to,\n        uint256 deadline\n    ) external returns (uint256[] memory amounts);\n}\n"
      },
      "src/interfaces/IButtonswapRouter/IETHButtonswapRouterErrors.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\ninterface IETHButtonswapRouterErrors {\n    /// @notice Only WETH contract can send ETH to contract\n    error NonWETHSender();\n    /// @notice WETH transfer failed\n    error FailedWETHTransfer();\n}\n"
      },
      "lib/buttonswap-core/src/interfaces/IButtonswapERC20/IButtonswapERC20Errors.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.13;\n\ninterface IButtonswapERC20Errors {\n    /**\n     * @notice Permit deadline was exceeded\n     */\n    error PermitExpired();\n\n    /**\n     * @notice Permit signature invalid\n     */\n    error PermitInvalidSignature();\n}\n"
      },
      "lib/buttonswap-core/src/interfaces/IButtonswapERC20/IButtonswapERC20Events.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.13;\n\ninterface IButtonswapERC20Events {\n    /**\n     * @notice Emitted when the allowance of a `spender` for an `owner` is set by a call to {IButtonswapERC20-approve}.\n     * `value` is the new allowance.\n     * @param owner The account that has granted approval\n     * @param spender The account that has been given approval\n     * @param value The amount the spender can transfer\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @notice Emitted when `value` tokens are moved from one account (`from`) to another (`to`).\n     * @param from The account that sent the tokens\n     * @param to The account that received the tokens\n     * @param value The amount of tokens transferred\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n}\n"
      },
      "src/RootButtonswapRouter.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport {IButtonswapFactory} from\n    \"buttonswap-periphery_buttonswap-core/interfaces/IButtonswapFactory/IButtonswapFactory.sol\";\nimport {IButtonswapPair} from \"buttonswap-periphery_buttonswap-core/interfaces/IButtonswapPair/IButtonswapPair.sol\";\nimport {TransferHelper} from \"./libraries/TransferHelper.sol\";\nimport {IRootButtonswapRouter} from \"./interfaces/IButtonswapRouter/IRootButtonswapRouter.sol\";\nimport {ButtonswapLibrary} from \"./libraries/ButtonswapLibrary.sol\";\nimport {Math} from \"./libraries/Math.sol\";\nimport {IERC20} from \"./interfaces/IERC20.sol\";\n\ncontract RootButtonswapRouter is IRootButtonswapRouter {\n    uint256 private constant BPS = 10_000;\n\n    /**\n     * @inheritdoc IRootButtonswapRouter\n     */\n    address public immutable override factory;\n\n    constructor(address _factory) {\n        factory = _factory;\n    }\n\n    // **** ADD LIQUIDITY ****\n    // @dev Refer to [movingAveragePriceThreshold.md](https://github.com/buttonwood-protocol/buttonswap-periphery/blob/main/notes/movingAveragePriceThreshold.md) for more detail.\n\n    function _createAndAddLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired)\n        internal\n        virtual\n        returns (uint256 amountA, uint256 amountB)\n    {\n        // create the pair\n        IButtonswapFactory(factory).createPair(tokenA, tokenB);\n\n        (amountA, amountB) = (amountADesired, amountBDesired);\n    }\n\n    function _addLiquidity(\n        address tokenA,\n        address tokenB,\n        uint256 amountADesired,\n        uint256 amountBDesired,\n        uint256 amountAMin,\n        uint256 amountBMin,\n        uint16 movingAveragePrice0ThresholdBps\n    ) internal virtual returns (uint256 amountA, uint256 amountB) {\n        // create the pair if it doesn't exist yet\n        // Downstream logic will revert if pair does not exist\n        address pair = IButtonswapFactory(factory).getPair(tokenA, tokenB);\n\n        (uint256 poolA, uint256 poolB, uint256 reservoirA, uint256 reservoirB) =\n            ButtonswapLibrary.getLiquidityBalances(factory, tokenA, tokenB);\n\n        if ((poolA + reservoirA) == 0 && (poolB + reservoirB) == 0) {\n            (amountA, amountB) = (amountADesired, amountBDesired);\n        } else {\n            // Calculate optimal amountB and check if it fits\n            uint256 amountOptimal = ButtonswapLibrary.quote(amountADesired, poolA + reservoirA, poolB + reservoirB);\n            if (amountOptimal <= amountBDesired) {\n                if (amountOptimal < amountBMin) {\n                    revert InsufficientBAmount();\n                }\n                (amountA, amountB) = (amountADesired, amountOptimal);\n            } else {\n                // Calculate optimal amountA (repurposing variable to save gas) and check if it fits\n                amountOptimal = ButtonswapLibrary.quote(amountBDesired, poolB + reservoirB, poolA + reservoirA);\n                assert(amountOptimal <= amountADesired);\n                if (amountOptimal < amountAMin) {\n                    revert InsufficientAAmount();\n                }\n                (amountA, amountB) = (amountOptimal, amountBDesired);\n            }\n        }\n\n        // Validate that the moving average price is within the threshold for pairs that exist\n        _validateMovingAveragePrice0Threshold(pair, tokenA, tokenB, poolA, poolB, movingAveragePrice0ThresholdBps);\n    }\n\n    function _validateMovingAveragePrice0Threshold(\n        address pair,\n        address tokenA,\n        address tokenB,\n        uint256 poolA,\n        uint256 poolB,\n        uint16 movingAveragePrice0ThresholdBps\n    ) internal virtual {\n        if (poolA > 0 && poolB > 0) {\n            uint256 movingAveragePrice0 = IButtonswapPair(pair).movingAveragePrice0();\n            if (tokenA < tokenB) {\n                // tokenA is token0\n                uint256 cachedTerm = Math.mulDiv(movingAveragePrice0, poolA * BPS, 2 ** 112);\n                if (\n                    poolB * (BPS - movingAveragePrice0ThresholdBps) > cachedTerm\n                        || poolB * (BPS + movingAveragePrice0ThresholdBps) < cachedTerm\n                ) {\n                    revert MovingAveragePriceOutOfBounds();\n                }\n            } else {\n                // tokenB is token0\n                uint256 cachedTerm = Math.mulDiv(movingAveragePrice0, poolB * BPS, 2 ** 112);\n                if (\n                    poolA * (BPS - movingAveragePrice0ThresholdBps) > cachedTerm\n                        || poolA * (BPS + movingAveragePrice0ThresholdBps) < cachedTerm\n                ) {\n                    revert MovingAveragePriceOutOfBounds();\n                }\n            }\n        }\n    }\n\n    function _addLiquidityWithReservoir(\n        address tokenA,\n        address tokenB,\n        uint256 amountADesired,\n        uint256 amountBDesired,\n        uint256 amountAMin,\n        uint256 amountBMin\n    ) internal virtual returns (uint256 amountA, uint256 amountB) {\n        // If the pair doesn't exist yet, there isn't any reservoir\n        if (IButtonswapFactory(factory).getPair(tokenA, tokenB) == address(0)) {\n            revert NoReservoir();\n        }\n        (uint256 poolA, uint256 poolB, uint256 reservoirA, uint256 reservoirB) =\n            ButtonswapLibrary.getLiquidityBalances(factory, tokenA, tokenB);\n        // the first liquidity addition should happen through _addLiquidity\n        // can't initialize by matching with a reservoir\n        if (poolA == 0 || poolB == 0) {\n            revert NotInitialized();\n        }\n        if (reservoirA == 0 && reservoirB == 0) {\n            revert NoReservoir();\n        }\n\n        if (reservoirA > 0) {\n            // we take from reservoirA and the user-provided amountBDesired\n            // But modify so that you don't do liquidityOut logic since you don't need it\n            (, uint256 amountAOptimal) =\n                ButtonswapLibrary.getMintSwappedAmounts(factory, tokenB, tokenA, amountBDesired);\n            // User wants to drain to the res by amountAMin or more\n            // Slippage-check\n            if (amountAOptimal < amountAMin) {\n                revert InsufficientAAmount();\n            }\n            (amountA, amountB) = (0, amountBDesired);\n        } else {\n            // we take from reservoirB and the user-provided amountADesired\n            (, uint256 amountBOptimal) =\n                ButtonswapLibrary.getMintSwappedAmounts(factory, tokenA, tokenB, amountADesired);\n            if (amountBOptimal < amountBMin) {\n                revert InsufficientBAmount();\n            }\n            (amountA, amountB) = (amountADesired, 0);\n        }\n    }\n\n    // **** SWAP ****\n\n    function _swap(uint256[] memory amounts, address[] memory path, address _to) internal virtual {\n        for (uint256 i; i < path.length - 1; i++) {\n            (address input, address output) = (path[i], path[i + 1]);\n            (address token0,) = ButtonswapLibrary.sortTokens(input, output);\n            uint256 amountIn = amounts[i];\n            uint256 amountOut = amounts[i + 1];\n            (uint256 amount0In, uint256 amount1In) = input == token0 ? (amountIn, uint256(0)) : (uint256(0), amountIn);\n            (uint256 amount0Out, uint256 amount1Out) =\n                input == token0 ? (uint256(0), amountOut) : (amountOut, uint256(0));\n\n            address to = i < path.length - 2 ? address(this) : _to;\n            IButtonswapPair pair = IButtonswapPair(ButtonswapLibrary.pairFor(factory, input, output));\n            TransferHelper.safeApprove(input, address(pair), amountIn);\n            pair.swap(amount0In, amount1In, amount0Out, amount1Out, to);\n        }\n    }\n}\n"
      },
      "src/interfaces/IButtonswapRouter/IRootButtonswapRouter.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport {IButtonswapRouterErrors} from \"./IButtonswapRouterErrors.sol\";\n\ninterface IRootButtonswapRouter is IButtonswapRouterErrors {\n    /**\n     * @notice Returns the address of the Buttonswap Factory\n     * @return factory The address of the Buttonswap Factory\n     */\n    function factory() external view returns (address factory);\n}\n"
      },
      "src/libraries/Math.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\n// a library for performing various math operations\n\nlibrary Math {\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n     * with further edits by Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod0 := mul(x, y)\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1);\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n            // in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n}\n"
      },
      "src/interfaces/IButtonswapRouter/IButtonswapRouterErrors.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\ninterface IButtonswapRouterErrors {\n    /// @notice Deadline was exceeded\n    error Expired();\n    /// @notice Insufficient amount of token A available\n    error InsufficientAAmount();\n    /// @notice Insufficient amount of token B available\n    error InsufficientBAmount();\n    /// @notice Neither token in the pool has the required reservoir\n    error NoReservoir();\n    /// @notice Pools are not initialized\n    error NotInitialized();\n    /// @notice Insufficient amount of token A in the reservoir\n    error InsufficientAReservoir();\n    /// @notice Insufficient amount of token B in the reservoir\n    error InsufficientBReservoir();\n    /// @notice Insufficient tokens returned from operation\n    error InsufficientOutputAmount();\n    /// @notice Required input amount exceeds specified maximum\n    error ExcessiveInputAmount();\n    /// @notice Invalid path provided\n    error InvalidPath();\n    /// @notice movingAveragePrice0 is out of specified bounds\n    error MovingAveragePriceOutOfBounds();\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "forge-std/=null/",
        "openzeppelin-contracts/=null/",
        "@openzeppelin-contracts/=null/",
        "openzeppelin/=null/",
        "mock-contracts/=null/",
        "buttonswap-core/=null/",
        "buttonswap-periphery_forge-std/=lib/forge-std/src/",
        "buttonswap-periphery_mock-contracts/=lib/mock-contracts/src/",
        "buttonswap-periphery_buttonswap-core/=lib/buttonswap-core/src/",
        "buttonswap-core_@openzeppelin-contracts/=lib/buttonswap-core/lib/openzeppelin-contracts/contracts/",
        "buttonswap-core_forge-std/=lib/buttonswap-core/lib/forge-std/src/",
        "buttonswap-core_mock-contracts/=lib/buttonswap-core/lib/mock-contracts/src/",
        "ds-test/=lib/forge-std/lib/ds-test/src/",
        "erc4626-tests/=lib/buttonswap-core/lib/openzeppelin-contracts/lib/erc4626-tests/",
        "mock-contracts_@openzeppelin-contracts/=lib/mock-contracts/lib/openzeppelin-contracts/contracts/",
        "mock-contracts_forge-std/=lib/mock-contracts/lib/forge-std/src/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "none",
        "appendCBOR": false
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "paris",
      "viaIR": false,
      "libraries": {}
    }
  }}