creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "src/AugustusV6.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Vendor\nimport { Diamond } from \"./vendor/Diamond.sol\";\n\n// Routers\nimport { Routers } from \"./routers/Routers.sol\";\n\n//                  ______                                   __                     __  __    ____\n//                 /\\  _  \\                                 /\\ \\__                 /\\ \\/\\ \\  /'___\\\n//                 \\ \\ \\L\\ \\  __  __     __   __  __    ____\\ \\ ,_\\  __  __    ____\\ \\ \\ \\ \\/\\ \\__/\n//                  \\ \\  __ \\/\\ \\/\\ \\  /'_ `\\/\\ \\/\\ \\  /',__\\\\ \\ \\/ /\\ \\/\\ \\  /',__\\\\ \\ \\ \\ \\ \\  _``\\\n//                   \\ \\ \\/\\ \\ \\ \\_\\ \\/\\ \\L\\ \\ \\ \\_\\ \\/\\__, `\\\\ \\ \\_\\ \\ \\_\\ \\/\\__, `\\\\ \\ \\_/ \\ \\ \\L\\ \\\n//                    \\ \\_\\ \\_\\ \\____/\\ \\____ \\ \\____/\\/\\____/ \\ \\__\\\\ \\____/\\/\\____/ \\ `\\___/\\ \\____/\n//                     \\/_/\\/_/\\/___/  \\/___L\\ \\/___/  \\/___/   \\/__/ \\/___/  \\/___/   `\\/__/  \\/___/\n//                                       /\\____/\n//                                       \\_/__/\n\n/// @title AugustusV6\n/// @notice The V6 implementation of the ParaSwap onchain aggregation protocol\ncontract AugustusV6 is Diamond, Routers {\n    /*//////////////////////////////////////////////////////////////\n                              CONSTRUCTOR\n    //////////////////////////////////////////////////////////////*/\n\n    constructor(\n        /// @dev Diamond\n        address _owner,\n        address _diamondCutFacet,\n        /// @dev Direct Routers\n        address _weth,\n        address payable _balancerVault,\n        uint256 _uniV3FactoryAndFF,\n        uint256 _uniswapV3PoolInitCodeHash,\n        uint256 _uniswapV2FactoryAndFF,\n        uint256 _uniswapV2PoolInitCodeHash,\n        address _rfq,\n        /// @dev Fees\n        address payable _feeVault,\n        /// @dev Permit2\n        address _permit2\n    )\n        Diamond(_owner, _diamondCutFacet)\n        Routers(\n            _weth,\n            _uniV3FactoryAndFF,\n            _uniswapV3PoolInitCodeHash,\n            _uniswapV2FactoryAndFF,\n            _uniswapV2PoolInitCodeHash,\n            _balancerVault,\n            _permit2,\n            _rfq,\n            _feeVault\n        )\n    { }\n\n    /*//////////////////////////////////////////////////////////////\n                                EXTERNAL\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Reverts if the caller is one of the following:\n    //         - an externally-owned account\n    //         - a contract in construction\n    //         - an address where a contract will be created\n    //         - an address where a contract lived, but was destroyed\n    receive() external payable override(Diamond) {\n        address addr = msg.sender;\n        // solhint-disable-next-line no-inline-assembly\n        assembly (\"memory-safe\") {\n            if iszero(extcodesize(addr)) { revert(0, 0) }\n        }\n    }\n}\n"
      },
      "src/vendor/Diamond.sol": {
        "content": "// SPDX-License-Identifier: MIT\n/**\n * Vendored on October 12, 2023 from:\n * https://github.com/mudgen/diamond-3-hardhat/blob/main/contracts/Diamond.sol\n */\npragma solidity ^0.8.0;\n\n/**\n * \\\n * Author: Nick Mudge <nick@perfectabstractions.com> (https://twitter.com/mudgen)\n * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535\n *\n * Implementation of a diamond.\n * /*****************************************************************************\n */\nimport { LibDiamond } from \"./libraries/LibDiamond.sol\";\nimport { IDiamondCut } from \"./interfaces/IDiamondCut.sol\";\n\ncontract Diamond {\n    error DiamondFunctionDoesNotExist();\n\n    constructor(address _contractOwner, address _diamondCutFacet) payable {\n        LibDiamond.setContractOwner(_contractOwner);\n\n        // Add the diamondCut external function from the diamondCutFacet\n        IDiamondCut.FacetCut[] memory cut = new IDiamondCut.FacetCut[](1);\n        bytes4[] memory functionSelectors = new bytes4[](1);\n        functionSelectors[0] = IDiamondCut.diamondCut.selector;\n        cut[0] = IDiamondCut.FacetCut({\n            facetAddress: _diamondCutFacet,\n            action: IDiamondCut.FacetCutAction.Add,\n            functionSelectors: functionSelectors\n        });\n        LibDiamond.diamondCut(cut, address(0), \"\");\n    }\n\n    // Find facet for function that is called and execute the\n    // function if a facet is found and return any value.\n    fallback() external payable {\n        LibDiamond.DiamondStorage storage ds;\n        bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION;\n        // get diamond storage\n        assembly {\n            ds.slot := position\n        }\n        // get facet from function selector\n        address facet = ds.selectorToFacetAndPosition[msg.sig].facetAddress;\n        // revert if function does not exist\n        if (facet == address(0)) {\n            revert DiamondFunctionDoesNotExist();\n        }\n        // Execute external function from facet using delegatecall and return any value.\n        assembly {\n            // copy function selector and any arguments\n            calldatacopy(0, 0, calldatasize())\n            // execute function call using the facet\n            let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)\n            // get any return value\n            returndatacopy(0, 0, returndatasize())\n            // return any return value or error back to the caller\n            switch result\n            case 0 { revert(0, returndatasize()) }\n            default { return(0, returndatasize()) }\n        }\n    }\n\n    receive() external payable virtual { }\n}\n"
      },
      "src/routers/Routers.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// DirectSwapExactAmountIn\nimport { BalancerV2SwapExactAmountIn } from \"./swapExactAmountIn/direct/BalancerV2SwapExactAmountIn.sol\";\nimport { CurveV1SwapExactAmountIn } from \"./swapExactAmountIn/direct/CurveV1SwapExactAmountIn.sol\";\nimport { CurveV2SwapExactAmountIn } from \"./swapExactAmountIn/direct/CurveV2SwapExactAmountIn.sol\";\nimport { UniswapV2SwapExactAmountIn } from \"./swapExactAmountIn/direct/UniswapV2SwapExactAmountIn.sol\";\nimport { UniswapV3SwapExactAmountIn } from \"./swapExactAmountIn/direct/UniswapV3SwapExactAmountIn.sol\";\n\n// DirectSwapExactAmountOut\nimport { BalancerV2SwapExactAmountOut } from \"./swapExactAmountOut/direct/BalancerV2SwapExactAmountOut.sol\";\nimport { UniswapV2SwapExactAmountOut } from \"./swapExactAmountOut/direct/UniswapV2SwapExactAmountOut.sol\";\nimport { UniswapV3SwapExactAmountOut } from \"./swapExactAmountOut/direct/UniswapV3SwapExactAmountOut.sol\";\n\n// Fees\nimport { AugustusFees } from \"../fees/AugustusFees.sol\";\n\n// GenericSwapExactAmountIn\nimport { GenericSwapExactAmountIn } from \"./swapExactAmountIn/GenericSwapExactAmountIn.sol\";\n\n// GenericSwapExactAmountOut\nimport { GenericSwapExactAmountOut } from \"./swapExactAmountOut/GenericSwapExactAmountOut.sol\";\n\n// General\nimport { AugustusRFQRouter } from \"./general/AugustusRFQRouter.sol\";\n\n// Utils\nimport { AugustusRFQUtils } from \"../util/AugustusRFQUtils.sol\";\nimport { BalancerV2Utils } from \"../util/BalancerV2Utils.sol\";\nimport { UniswapV2Utils } from \"../util/UniswapV2Utils.sol\";\nimport { UniswapV3Utils } from \"../util/UniswapV3Utils.sol\";\nimport { WETHUtils } from \"../util/WETHUtils.sol\";\nimport { Permit2Utils } from \"../util/Permit2Utils.sol\";\n\n/// @title Routers\n/// @notice A wrapper for all router contracts\ncontract Routers is\n    AugustusFees,\n    AugustusRFQRouter,\n    BalancerV2SwapExactAmountOut,\n    BalancerV2SwapExactAmountIn,\n    CurveV1SwapExactAmountIn,\n    CurveV2SwapExactAmountIn,\n    GenericSwapExactAmountOut,\n    GenericSwapExactAmountIn,\n    UniswapV2SwapExactAmountOut,\n    UniswapV2SwapExactAmountIn,\n    UniswapV3SwapExactAmountOut,\n    UniswapV3SwapExactAmountIn\n{\n    /*//////////////////////////////////////////////////////////////\n                               CONSTRUCTOR\n    //////////////////////////////////////////////////////////////*/\n\n    constructor(\n        address _weth,\n        uint256 _uniswapV3FactoryAndFF,\n        uint256 _uniswapV3PoolInitCodeHash,\n        uint256 _uniswapV2FactoryAndFF,\n        uint256 _uniswapV2PoolInitCodeHash,\n        address payable _balancerVault,\n        address _permit2,\n        address _rfq,\n        address payable _feeVault\n    )\n        AugustusFees(_feeVault)\n        AugustusRFQUtils(_rfq)\n        BalancerV2Utils(_balancerVault)\n        Permit2Utils(_permit2)\n        UniswapV2Utils(_uniswapV2FactoryAndFF, _uniswapV2PoolInitCodeHash)\n        UniswapV3Utils(_uniswapV3FactoryAndFF, _uniswapV3PoolInitCodeHash)\n        WETHUtils(_weth)\n    { }\n}\n"
      },
      "src/vendor/libraries/LibDiamond.sol": {
        "content": "// SPDX-License-Identifier: MIT\n/**\n * Vendored on October 12, 2023 from:\n * https://github.com/mudgen/diamond-3-hardhat/blob/main/contracts/libraries/LibDiamond.sol\n */\npragma solidity ^0.8.0;\n\n/**\n * \\\n * Author: Nick Mudge <nick@perfectabstractions.com> (https://twitter.com/mudgen)\n * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535\n * /*****************************************************************************\n */\nimport { IDiamondCut } from \"../interfaces/IDiamondCut.sol\";\n\n// Remember to add the loupe functions from DiamondLoupeFacet to the diamond.\n// The loupe functions are required by the EIP2535 Diamonds standard\n\nerror InitializationFunctionReverted(address _initializationContractAddress, bytes _calldata);\n\nlibrary LibDiamond {\n    bytes32 constant DIAMOND_STORAGE_POSITION = keccak256(\"diamond.standard.diamond.storage\");\n\n    struct FacetAddressAndPosition {\n        address facetAddress;\n        uint96 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array\n    }\n\n    struct FacetFunctionSelectors {\n        bytes4[] functionSelectors;\n        uint256 facetAddressPosition; // position of facetAddress in facetAddresses array\n    }\n\n    struct DiamondStorage {\n        // maps function selector to the facet address and\n        // the position of the selector in the facetFunctionSelectors.selectors array\n        mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition;\n        // maps facet addresses to function selectors\n        mapping(address => FacetFunctionSelectors) facetFunctionSelectors;\n        // facet addresses\n        address[] facetAddresses;\n        // Used to query if a contract implements an interface.\n        // Used to implement ERC-165.\n        mapping(bytes4 => bool) supportedInterfaces;\n        // owner of the contract\n        address contractOwner;\n    }\n\n    function diamondStorage() internal pure returns (DiamondStorage storage ds) {\n        bytes32 position = DIAMOND_STORAGE_POSITION;\n        assembly {\n            ds.slot := position\n        }\n    }\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    function setContractOwner(address _newOwner) internal {\n        DiamondStorage storage ds = diamondStorage();\n        address previousOwner = ds.contractOwner;\n        ds.contractOwner = _newOwner;\n        emit OwnershipTransferred(previousOwner, _newOwner);\n    }\n\n    function contractOwner() internal view returns (address contractOwner_) {\n        contractOwner_ = diamondStorage().contractOwner;\n    }\n\n    function enforceIsContractOwner() internal view {\n        require(msg.sender == diamondStorage().contractOwner, \"LibDiamond: Must be contract owner\");\n    }\n\n    event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);\n\n    // Internal function version of diamondCut\n    function diamondCut(IDiamondCut.FacetCut[] memory _diamondCut, address _init, bytes memory _calldata) internal {\n        for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {\n            IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;\n            if (action == IDiamondCut.FacetCutAction.Add) {\n                addFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);\n            } else if (action == IDiamondCut.FacetCutAction.Replace) {\n                replaceFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);\n            } else if (action == IDiamondCut.FacetCutAction.Remove) {\n                removeFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);\n            } else {\n                revert(\"LibDiamondCut: Incorrect FacetCutAction\");\n            }\n        }\n        emit DiamondCut(_diamondCut, _init, _calldata);\n        initializeDiamondCut(_init, _calldata);\n    }\n\n    function addFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {\n        require(_functionSelectors.length > 0, \"LibDiamondCut: No selectors in facet to cut\");\n        DiamondStorage storage ds = diamondStorage();\n        require(_facetAddress != address(0), \"LibDiamondCut: Add facet can't be address(0)\");\n        uint96 selectorPosition = uint96(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);\n        // add new facet address if it does not exist\n        if (selectorPosition == 0) {\n            addFacet(ds, _facetAddress);\n        }\n        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {\n            bytes4 selector = _functionSelectors[selectorIndex];\n            address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;\n            require(oldFacetAddress == address(0), \"LibDiamondCut: Can't add function that already exists\");\n            addFunction(ds, selector, selectorPosition, _facetAddress);\n            selectorPosition++;\n        }\n    }\n\n    function replaceFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {\n        require(_functionSelectors.length > 0, \"LibDiamondCut: No selectors in facet to cut\");\n        DiamondStorage storage ds = diamondStorage();\n        require(_facetAddress != address(0), \"LibDiamondCut: Add facet can't be address(0)\");\n        uint96 selectorPosition = uint96(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);\n        // add new facet address if it does not exist\n        if (selectorPosition == 0) {\n            addFacet(ds, _facetAddress);\n        }\n        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {\n            bytes4 selector = _functionSelectors[selectorIndex];\n            address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;\n            require(oldFacetAddress != _facetAddress, \"LibDiamondCut: Can't replace function with same function\");\n            removeFunction(ds, oldFacetAddress, selector);\n            addFunction(ds, selector, selectorPosition, _facetAddress);\n            selectorPosition++;\n        }\n    }\n\n    function removeFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {\n        require(_functionSelectors.length > 0, \"LibDiamondCut: No selectors in facet to cut\");\n        DiamondStorage storage ds = diamondStorage();\n        // if function does not exist then do nothing and return\n        require(_facetAddress == address(0), \"LibDiamondCut: Remove facet address must be address(0)\");\n        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {\n            bytes4 selector = _functionSelectors[selectorIndex];\n            address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;\n            removeFunction(ds, oldFacetAddress, selector);\n        }\n    }\n\n    function addFacet(DiamondStorage storage ds, address _facetAddress) internal {\n        enforceHasContractCode(_facetAddress, \"LibDiamondCut: New facet has no code\");\n        ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = ds.facetAddresses.length;\n        ds.facetAddresses.push(_facetAddress);\n    }\n\n    function addFunction(\n        DiamondStorage storage ds,\n        bytes4 _selector,\n        uint96 _selectorPosition,\n        address _facetAddress\n    )\n        internal\n    {\n        ds.selectorToFacetAndPosition[_selector].functionSelectorPosition = _selectorPosition;\n        ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(_selector);\n        ds.selectorToFacetAndPosition[_selector].facetAddress = _facetAddress;\n    }\n\n    function removeFunction(DiamondStorage storage ds, address _facetAddress, bytes4 _selector) internal {\n        require(_facetAddress != address(0), \"LibDiamondCut: Can't remove function that doesn't exist\");\n        // an immutable function is a function defined directly in a diamond\n        require(_facetAddress != address(this), \"LibDiamondCut: Can't remove immutable function\");\n        // replace selector with last selector, then delete last selector\n        uint256 selectorPosition = ds.selectorToFacetAndPosition[_selector].functionSelectorPosition;\n        uint256 lastSelectorPosition = ds.facetFunctionSelectors[_facetAddress].functionSelectors.length - 1;\n        // if not the same then replace _selector with lastSelector\n        if (selectorPosition != lastSelectorPosition) {\n            bytes4 lastSelector = ds.facetFunctionSelectors[_facetAddress].functionSelectors[lastSelectorPosition];\n            ds.facetFunctionSelectors[_facetAddress].functionSelectors[selectorPosition] = lastSelector;\n            ds.selectorToFacetAndPosition[lastSelector].functionSelectorPosition = uint96(selectorPosition);\n        }\n        // delete the last selector\n        ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop();\n        delete ds.selectorToFacetAndPosition[_selector];\n\n        // if no more selectors for facet address then delete the facet address\n        if (lastSelectorPosition == 0) {\n            // replace facet address with last facet address and delete last facet address\n            uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1;\n            uint256 facetAddressPosition = ds.facetFunctionSelectors[_facetAddress].facetAddressPosition;\n            if (facetAddressPosition != lastFacetAddressPosition) {\n                address lastFacetAddress = ds.facetAddresses[lastFacetAddressPosition];\n                ds.facetAddresses[facetAddressPosition] = lastFacetAddress;\n                ds.facetFunctionSelectors[lastFacetAddress].facetAddressPosition = facetAddressPosition;\n            }\n            ds.facetAddresses.pop();\n            delete ds.facetFunctionSelectors[_facetAddress].facetAddressPosition;\n        }\n    }\n\n    function initializeDiamondCut(address _init, bytes memory _calldata) internal {\n        if (_init == address(0)) {\n            return;\n        }\n        enforceHasContractCode(_init, \"LibDiamondCut: _init address has no code\");\n        (bool success, bytes memory error) = _init.delegatecall(_calldata);\n        if (!success) {\n            if (error.length > 0) {\n                // bubble up error\n                /// @solidity memory-safe-assembly\n                assembly {\n                    let returndata_size := mload(error)\n                    revert(add(32, error), returndata_size)\n                }\n            } else {\n                revert InitializationFunctionReverted(_init, _calldata);\n            }\n        }\n    }\n\n    function enforceHasContractCode(address _contract, string memory _errorMessage) internal view {\n        uint256 contractSize;\n        assembly {\n            contractSize := extcodesize(_contract)\n        }\n        require(contractSize > 0, _errorMessage);\n    }\n}\n"
      },
      "src/vendor/interfaces/IDiamondCut.sol": {
        "content": "// SPDX-License-Identifier: MIT\n/**\n * Vendored on October 12, 2023 from:\n * https://github.com/mudgen/diamond-3-hardhat/blob/main/contracts/interfaces/IDiamondCut.sol\n */\npragma solidity ^0.8.0;\n\n/**\n * \\\n * Author: Nick Mudge (https://twitter.com/mudgen)\n * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535\n * /*****************************************************************************\n */\ninterface IDiamondCut {\n    enum FacetCutAction {\n        Add,\n        Replace,\n        Remove\n    }\n    // Add=0, Replace=1, Remove=2\n\n    struct FacetCut {\n        address facetAddress;\n        FacetCutAction action;\n        bytes4[] functionSelectors;\n    }\n\n    /// @notice Add/replace/remove any number of functions and optionally execute\n    ///         a function with delegatecall\n    /// @param _diamondCut Contains the facet addresses and function selectors\n    /// @param _init The address of the contract or facet to execute _calldata\n    /// @param _calldata A function call, including function selector and arguments\n    ///                  _calldata is executed with delegatecall on _init\n    function diamondCut(FacetCut[] calldata _diamondCut, address _init, bytes calldata _calldata) external;\n\n    event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);\n}\n"
      },
      "src/routers/swapExactAmountIn/direct/BalancerV2SwapExactAmountIn.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IERC20 } from \"@openzeppelin/token/ERC20/IERC20.sol\";\nimport { IBalancerV2SwapExactAmountIn } from \"../../../interfaces/IBalancerV2SwapExactAmountIn.sol\";\n\n// Libraries\nimport { ERC20Utils } from \"../../../libraries/ERC20Utils.sol\";\n\n// Types\nimport { BalancerV2Data } from \"../../../AugustusV6Types.sol\";\n\n// Utils\nimport { BalancerV2Utils } from \"../../../util/BalancerV2Utils.sol\";\n\n/// @title BalancerV2SwapExactAmountIn\n/// @notice A contract for executing direct swapExactAmountIn on Balancer V2\nabstract contract BalancerV2SwapExactAmountIn is IBalancerV2SwapExactAmountIn, BalancerV2Utils {\n    /*//////////////////////////////////////////////////////////////\n                               LIBRARIES\n    //////////////////////////////////////////////////////////////*/\n\n    using ERC20Utils for IERC20;\n\n    /*//////////////////////////////////////////////////////////////\n                          SWAP EXACT AMOUNT IN\n    //////////////////////////////////////////////////////////////*/\n\n    /// @inheritdoc IBalancerV2SwapExactAmountIn\n    function swapExactAmountInOnBalancerV2(\n        BalancerV2Data calldata balancerData,\n        uint256 partnerAndFee,\n        bytes calldata permit,\n        bytes calldata data\n    )\n        external\n        payable\n        whenNotPaused\n        returns (uint256 receivedAmount, uint256 paraswapShare, uint256 partnerShare)\n    {\n        // Dereference balancerData\n        uint256 quotedAmountOut = balancerData.quotedAmount;\n        uint256 beneficiaryAndApproveFlag = balancerData.beneficiaryAndApproveFlag;\n        uint256 amountIn = balancerData.fromAmount;\n        uint256 minAmountOut = balancerData.toAmount;\n\n        // Decode params\n        (IERC20 srcToken, IERC20 destToken, address payable beneficiary, bool approve) =\n            _decodeBalancerV2Params(beneficiaryAndApproveFlag, data);\n\n        // Check if toAmount is valid\n        if (minAmountOut == 0) {\n            revert InvalidToAmount();\n        }\n\n        // Check if beneficiary is valid\n        if (beneficiary == address(0)) {\n            beneficiary = payable(msg.sender);\n        }\n\n        // Check if srcToken is ETH\n        if (srcToken.isETH(amountIn) == 0) {\n            // Check the length of the permit field,\n            // if < 257 and > 0 we should execute regular permit\n            // and if it is >= 257 we execute permit2\n            if (permit.length < 257) {\n                // Permit if needed\n                if (permit.length > 0) {\n                    srcToken.permit(permit);\n                }\n                srcToken.safeTransferFrom(msg.sender, address(this), amountIn);\n            } else {\n                // Otherwise Permit2.permitTransferFrom\n                permit2TransferFrom(permit, address(this), amountIn);\n            }\n            // Check if approve is needed\n            if (approve) {\n                // Approve BALANCER_VAULT to spend srcToken\n                srcToken.approve(BALANCER_VAULT);\n            }\n        }\n\n        // Execute swap\n        _callBalancerV2(data);\n\n        // Check balance after swap\n        receivedAmount = destToken.getBalance(address(this));\n\n        // Check if swap succeeded\n        if (receivedAmount < minAmountOut) {\n            revert InsufficientReturnAmount();\n        }\n\n        // Process fees and transfer destToken to beneficiary\n        return processSwapExactAmountInFeesAndTransfer(\n            beneficiary, destToken, partnerAndFee, receivedAmount, quotedAmountOut\n        );\n    }\n}\n"
      },
      "src/routers/swapExactAmountIn/direct/CurveV1SwapExactAmountIn.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IERC20 } from \"@openzeppelin/token/ERC20/IERC20.sol\";\nimport { ICurveV1SwapExactAmountIn } from \"../../../interfaces/ICurveV1SwapExactAmountIn.sol\";\n\n// Libraries\nimport { ERC20Utils } from \"../../../libraries/ERC20Utils.sol\";\n\n// Types\nimport { CurveV1Data } from \"../../../AugustusV6Types.sol\";\n\n// Utils\nimport { AugustusFees } from \"../../../fees/AugustusFees.sol\";\nimport { WETHUtils } from \"../../../util/WETHUtils.sol\";\nimport { Permit2Utils } from \"../../../util/Permit2Utils.sol\";\nimport { PauseUtils } from \"../../../util/PauseUtils.sol\";\n\n/// @title CurveV1SwapExactAmountIn\n/// @notice A contract for executing direct CurveV1 swaps\nabstract contract CurveV1SwapExactAmountIn is\n    ICurveV1SwapExactAmountIn,\n    AugustusFees,\n    WETHUtils,\n    Permit2Utils,\n    PauseUtils\n{\n    /*//////////////////////////////////////////////////////////////\n                               LIBRARIES\n    //////////////////////////////////////////////////////////////*/\n\n    using ERC20Utils for IERC20;\n\n    /*//////////////////////////////////////////////////////////////\n                          SWAP EXACT AMOUNT IN\n    //////////////////////////////////////////////////////////////*/\n\n    /// @inheritdoc ICurveV1SwapExactAmountIn\n    function swapExactAmountInOnCurveV1(\n        CurveV1Data calldata curveV1Data,\n        uint256 partnerAndFee,\n        bytes calldata permit\n    )\n        external\n        payable\n        whenNotPaused\n        returns (uint256 receivedAmount, uint256 paraswapShare, uint256 partnerShare)\n    {\n        // Dereference curveV1Data\n        IERC20 srcToken = curveV1Data.srcToken;\n        IERC20 destToken = curveV1Data.destToken;\n        uint256 amountIn = curveV1Data.fromAmount;\n        uint256 minAmountOut = curveV1Data.toAmount;\n        uint256 quotedAmountOut = curveV1Data.quotedAmount;\n        address payable beneficiary = curveV1Data.beneficiary;\n        uint256 curveAssets = curveV1Data.curveAssets;\n        uint256 curveData = curveV1Data.curveData;\n\n        // Check if toAmount is valid\n        if (minAmountOut == 0) {\n            revert InvalidToAmount();\n        }\n\n        // Check if beneficiary is valid\n        if (beneficiary == address(0)) {\n            beneficiary = payable(msg.sender);\n        }\n\n        // Decode curveData\n        // 160 bits for curve exchange address\n        // 1 bit for approve flag\n        // 2 bits for wrap flag\n        // 2 bits for swap type flag\n\n        address exchange;\n        bool approveFlag;\n        uint256 wrapFlag;\n        uint256 swapType;\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly (\"memory-safe\") {\n            exchange := and(curveData, 0xffffffffffffffffffffffffffffffffffffffff)\n            approveFlag := and(shr(160, curveData), 1)\n            wrapFlag := and(shr(161, curveData), 3)\n            swapType := and(shr(163, curveData), 3)\n        }\n\n        // Check if srcToken is ETH\n        // Transfer srcToken to augustus if not ETH\n        if (srcToken.isETH(amountIn) == 0) {\n            // Check the length of the permit field,\n            // if < 257 and > 0 we should execute regular permit\n            // and if it is >= 257 we execute permit2\n            if (permit.length < 257) {\n                // Permit if needed\n                if (permit.length > 0) {\n                    srcToken.permit(permit);\n                }\n                srcToken.safeTransferFrom(msg.sender, address(this), amountIn);\n            } else {\n                // Otherwise Permit2.permitTransferFrom\n                permit2TransferFrom(permit, address(this), amountIn);\n            }\n            // Check if approve flag is set\n            if (approveFlag) {\n                // Approve exchange\n                srcToken.approve(exchange);\n            }\n        } else {\n            // Check if approve flag is set\n            if (approveFlag) {\n                // Approve exchange\n                IERC20(WETH).approve(exchange);\n            }\n        }\n\n        // Execute swap\n        _executeSwapOnCurveV1(exchange, wrapFlag, swapType, curveAssets, amountIn);\n\n        // Check balance after swap and unwrap if needed\n        if (wrapFlag == 2) {\n            // Received amount is WETH balance\n            receivedAmount = IERC20(WETH).getBalance(address(this));\n            // Unwrap WETH\n            WETH.withdraw(receivedAmount - 1);\n            // Set receivedAmount to this contract's balance\n            receivedAmount = address(this).balance;\n        } else {\n            // Received amount is destToken balance\n            receivedAmount = destToken.getBalance(address(this));\n        }\n\n        // Check if swap succeeded\n        if (receivedAmount < minAmountOut) {\n            revert InsufficientReturnAmount();\n        }\n\n        // Process fees and transfer destToken to beneficiary\n        return processSwapExactAmountInFeesAndTransfer(\n            beneficiary, destToken, partnerAndFee, receivedAmount, quotedAmountOut\n        );\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                                PRIVATE\n    //////////////////////////////////////////////////////////////*/\n\n    function _executeSwapOnCurveV1(\n        address exchange,\n        uint256 wrapFlag,\n        uint256 swapType,\n        uint256 curveAssets,\n        uint256 fromAmount\n    )\n        private\n    {\n        // Load WETH address\n        address weth = address(WETH);\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            // Load free memory pointer\n            let ptr := mload(64)\n\n            //-----------------------------------------------------------------------------------\n            // Wrap ETH if needed\n            //-----------------------------------------------------------------------------------\n\n            // Check if wrap src flag is set\n            if eq(wrapFlag, 1) {\n                // Prepare call data for WETH.deposit()\n\n                // Store function selector and\n                mstore(ptr, 0xd0e30db000000000000000000000000000000000000000000000000000000000) // deposit()\n\n                // Perform the external call with the prepared calldata\n                // Check the outcome of the call and handle failure\n                if iszero(call(gas(), weth, callvalue(), ptr, 4, 0, 0)) {\n                    // The call failed; we retrieve the exact error message and revert with it\n                    returndatacopy(0, 0, returndatasize()) // Copy the error message to the start of memory\n                    revert(0, returndatasize()) // Revert with the error message\n                }\n            }\n\n            //-----------------------------------------------------------------------------------\n            // Execute swap\n            //-----------------------------------------------------------------------------------\n\n            // Prepare call data for external call\n\n            // Check swap type\n            switch swapType\n            // 0x01 for EXCHANGE_UNDERLYING\n            case 0x01 {\n                // Store function selector for function exchange_underlying(int128,int128,uint256,uint256)\n                mstore(ptr, 0xa6417ed600000000000000000000000000000000000000000000000000000000) // store selector\n                mstore(add(ptr, 4), shr(128, curveAssets)) // store index i\n                mstore(add(ptr, 36), and(curveAssets, 0xffffffffffffffffffffffffffffffff)) // store index j\n                mstore(add(ptr, 68), fromAmount) // store fromAmount\n                mstore(add(ptr, 100), 1) // store 1\n                // Perform the external call with the prepared calldata\n                // Check the outcome of the call and handle failure\n                if iszero(call(gas(), exchange, 0, ptr, 132, 0, 0)) {\n                    // The call failed; we retrieve the exact error message and revert with it\n                    returndatacopy(0, 0, returndatasize()) // Copy the error message to the start of memory\n                    revert(0, returndatasize()) // Revert with the error message\n                }\n            }\n            // 0x00(default) for EXCHANGE\n            default {\n                // check send eth wrap flag\n                switch eq(wrapFlag, 0x03)\n                // if it is not set, store selector for function exchange(int128,int128,uint256,uint256)\n                case 1 {\n                    mstore(ptr, 0x3df0212400000000000000000000000000000000000000000000000000000000) // store selector\n                    mstore(add(ptr, 4), shr(128, curveAssets)) // store index i\n                    mstore(add(ptr, 36), and(curveAssets, 0xffffffffffffffffffffffffffffffff)) // store index j\n                    mstore(add(ptr, 68), fromAmount) // store fromAmount\n                    mstore(add(ptr, 100), 1) // store 1\n                    // Perform the external call with the prepared calldata\n                    // Check the outcome of the call and handle failure\n                    if iszero(call(gas(), exchange, callvalue(), ptr, 132, 0, 0)) {\n                        // The call failed; we retrieve the exact error message and revert with it\n                        returndatacopy(0, 0, returndatasize()) // Copy the error message to the start of memory\n                        revert(0, returndatasize()) // Revert with the error message\n                    }\n                }\n                // if it is set, store selector for function exchange(int128,int128,uint256,uint256)\n                default {\n                    mstore(ptr, 0x3df0212400000000000000000000000000000000000000000000000000000000) // store selector\n                    mstore(add(ptr, 4), shr(128, curveAssets)) // store index i\n                    mstore(add(ptr, 36), and(curveAssets, 0xffffffffffffffffffffffffffffffff)) // store index j\n                    mstore(add(ptr, 68), fromAmount) // store fromAmount\n                    mstore(add(ptr, 100), 1) // store 1\n                    // Perform the external call with the prepared calldata\n                    // Check the outcome of the call and handle failure\n                    if iszero(call(gas(), exchange, 0, ptr, 132, 0, 0)) {\n                        // The call failed; we retrieve the exact error message and revert with it\n                        returndatacopy(0, 0, returndatasize()) // Copy the error message to the start of memory\n                        revert(0, returndatasize()) // Revert with the error message\n                    }\n                }\n            }\n        }\n    }\n}\n"
      },
      "src/routers/swapExactAmountIn/direct/CurveV2SwapExactAmountIn.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IERC20 } from \"@openzeppelin/token/ERC20/IERC20.sol\";\nimport { ICurveV2SwapExactAmountIn } from \"../../../interfaces/ICurveV2SwapExactAmountIn.sol\";\n\n// Libraries\nimport { ERC20Utils } from \"../../../libraries/ERC20Utils.sol\";\n\n// Types\nimport { CurveV2Data } from \"../../../AugustusV6Types.sol\";\n\n// Utils\nimport { AugustusFees } from \"../../../fees/AugustusFees.sol\";\nimport { WETHUtils } from \"../../../util/WETHUtils.sol\";\nimport { Permit2Utils } from \"../../../util/Permit2Utils.sol\";\nimport { PauseUtils } from \"../../../util/PauseUtils.sol\";\n\n/// @title CurveV2SwapExactAmountIn\n/// @notice A contract for executing direct CurveV2 swaps\nabstract contract CurveV2SwapExactAmountIn is\n    ICurveV2SwapExactAmountIn,\n    AugustusFees,\n    WETHUtils,\n    Permit2Utils,\n    PauseUtils\n{\n    /*//////////////////////////////////////////////////////////////\n                               LIBRARIES\n    //////////////////////////////////////////////////////////////*/\n\n    using ERC20Utils for IERC20;\n\n    /*//////////////////////////////////////////////////////////////\n                          SWAP EXACT AMOUNT IN\n    //////////////////////////////////////////////////////////////*/\n\n    /// @inheritdoc ICurveV2SwapExactAmountIn\n    function swapExactAmountInOnCurveV2(\n        CurveV2Data calldata curveV2Data,\n        uint256 partnerAndFee,\n        bytes calldata permit\n    )\n        external\n        payable\n        whenNotPaused\n        returns (uint256 receivedAmount, uint256 paraswapShare, uint256 partnerShare)\n    {\n        // Dereference curveData\n        IERC20 srcToken = curveV2Data.srcToken;\n        IERC20 destToken = curveV2Data.destToken;\n        uint256 amountIn = curveV2Data.fromAmount;\n        uint256 minAmountOut = curveV2Data.toAmount;\n        uint256 quotedAmountOut = curveV2Data.quotedAmount;\n        address payable beneficiary = curveV2Data.beneficiary;\n        uint256 i = curveV2Data.i;\n        uint256 j = curveV2Data.j;\n        address poolAddress = curveV2Data.poolAddress;\n        uint256 curveData = curveV2Data.curveData;\n\n        // Check if toAmount is valid\n        if (minAmountOut == 0) {\n            revert InvalidToAmount();\n        }\n\n        // Check if beneficiary is valid\n        if (beneficiary == address(0)) {\n            beneficiary = payable(msg.sender);\n        }\n\n        // Decode curveData\n        // 160 bits for curve exchange address\n        // 1 bit for approve flag\n        // 2 bits for wrap flag\n        // 2 bits for swap type flag\n\n        address exchange;\n        bool approveFlag;\n        uint256 wrapFlag;\n        uint256 swapType;\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            exchange := and(curveData, 0xffffffffffffffffffffffffffffffffffffffff)\n            approveFlag := and(shr(160, curveData), 1)\n            wrapFlag := and(shr(161, curveData), 3)\n            swapType := and(shr(163, curveData), 3)\n        }\n\n        // Check if srcToken is ETH\n        // Transfer srcToken to augustus if not ETH\n        if (srcToken.isETH(amountIn) == 0) {\n            // Check the length of the permit field,\n            // if < 257 and > 0 we should execute regular permit\n            // and if it is >= 257 we execute permit2\n            if (permit.length < 257) {\n                // Permit if needed\n                if (permit.length > 0) {\n                    srcToken.permit(permit);\n                }\n                srcToken.safeTransferFrom(msg.sender, address(this), amountIn);\n            } else {\n                // Otherwise Permit2.permitTransferFrom\n                permit2TransferFrom(permit, address(this), amountIn);\n            }\n            // Check if approve flag is set\n            if (approveFlag) {\n                // Approve exchange\n                srcToken.approve(exchange);\n            }\n        } else {\n            // Check if approve flag is set\n            if (approveFlag) {\n                // Approve exchange\n                IERC20(WETH).approve(exchange);\n            }\n        }\n\n        // Execute swap\n        _executeSwapOnCurveV2(exchange, wrapFlag, swapType, i, j, amountIn, poolAddress);\n\n        // Check balance after swap and unwrap if needed\n        if (wrapFlag == 2) {\n            // Received amount is WETH balance\n            receivedAmount = IERC20(WETH).getBalance(address(this));\n            // Unwrap WETH\n            WETH.withdraw(receivedAmount - 1);\n            // Set receivedAmount to this contract's balance\n            receivedAmount = address(this).balance;\n        } else {\n            // Received amount is destToken balance\n            receivedAmount = destToken.getBalance(address(this));\n        }\n\n        // Check if swap succeeded\n        if (receivedAmount < minAmountOut) {\n            revert InsufficientReturnAmount();\n        }\n\n        // Process fees and transfer destToken to beneficiary\n        return processSwapExactAmountInFeesAndTransfer(\n            beneficiary, destToken, partnerAndFee, receivedAmount, quotedAmountOut\n        );\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                                PRIVATE\n    //////////////////////////////////////////////////////////////*/\n\n    function _executeSwapOnCurveV2(\n        address exchange,\n        uint256 wrapFlag,\n        uint256 swapType,\n        uint256 i,\n        uint256 j,\n        uint256 fromAmount,\n        address poolAddress\n    )\n        private\n    {\n        // Load WETH address\n        address weth = address(WETH);\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            // Load free memory pointer\n            let ptr := mload(64)\n\n            //-----------------------------------------------------------------------------------\n            // Wrap ETH if needed\n            //-----------------------------------------------------------------------------------\n\n            // Check if wrap src flag is set\n            if eq(wrapFlag, 1) {\n                // Prepare call data for WETH.deposit()\n\n                // Store function selector and\n                mstore(ptr, 0xd0e30db000000000000000000000000000000000000000000000000000000000) // deposit()\n\n                // Perform the external call with the prepared calldata\n                // Check the outcome of the call and handle failure\n                if iszero(call(gas(), weth, callvalue(), ptr, 4, 0, 0)) {\n                    // The call failed; we retrieve the exact error message and revert with it\n                    returndatacopy(0, 0, returndatasize()) // Copy the error message to the start of memory\n                    revert(0, returndatasize()) // Revert with the error message\n                }\n            }\n\n            //-----------------------------------------------------------------------------------\n            // Execute swap\n            //-----------------------------------------------------------------------------------\n\n            // Prepare call data for external call\n\n            // Check swap type\n            switch swapType\n            // 0x01 for EXCHANGE_UNDERLYING\n            case 0x01 {\n                // Store function selector for function exchange_underlying(uint256,uint256,uint256,uint256)\n                mstore(ptr, 0x65b2489b00000000000000000000000000000000000000000000000000000000) // store selector\n                mstore(add(ptr, 4), i) // store index i\n                mstore(add(ptr, 36), j) // store index j\n                mstore(add(ptr, 68), fromAmount) // store fromAmount\n                mstore(add(ptr, 100), 1) // store 1\n                // Perform the external call with the prepared calldata\n                // Check the outcome of the call and handle failure\n                if iszero(call(gas(), exchange, 0, ptr, 132, 0, 0)) {\n                    // The call failed; we retrieve the exact error message and revert with it\n                    returndatacopy(0, 0, returndatasize()) // Copy the error message to the start of memory\n                    revert(0, returndatasize()) // Revert with the error message\n                }\n            }\n            // 0x02 for EXCHANGE_GENERIC_FACTORY_ZAP\n            case 0x02 {\n                // Store function selector for function exchange(address,uint256,uint256,uint256,uint256)\n                mstore(ptr, 0x64a1455800000000000000000000000000000000000000000000000000000000)\n                mstore(add(ptr, 4), poolAddress) // store poolAddress\n                mstore(add(ptr, 36), i) // store index i\n                mstore(add(ptr, 68), j) // store index j\n                mstore(add(ptr, 100), fromAmount) // store fromAmount\n                mstore(add(ptr, 132), 1) // store 1\n                // Perform the external call with the prepared calldata\n                // Check the outcome of the call and handle failure\n                if iszero(call(gas(), exchange, 0, ptr, 164, 0, 0)) {\n                    // The call failed; we retrieve the exact error message and revert with it\n                    returndatacopy(0, 0, returndatasize()) // Copy the error message to the start of memory\n                    revert(0, returndatasize()) // Revert with the error message\n                }\n            }\n            // 0x00(default) for EXCHANGE\n            default {\n                // check send eth wrap flag\n                switch eq(wrapFlag, 0x03)\n                // if it is not set, store selector for function exchange(uint256,uint256,uint256,uint256,bool)\n                case 1 {\n                    mstore(ptr, 0x394747c500000000000000000000000000000000000000000000000000000000) // store selector\n                    mstore(add(ptr, 4), i) // store index i\n                    mstore(add(ptr, 36), j) // store index j\n                    mstore(add(ptr, 68), fromAmount) // store fromAmount\n                    mstore(add(ptr, 100), 1) // store 1\n                    mstore(add(ptr, 132), 1) // store true\n                    // Perform the external call with the prepared calldata\n                    // Check the outcome of the call and handle failure\n                    if iszero(call(gas(), exchange, callvalue(), ptr, 164, 0, 0)) {\n                        // The call failed; we retrieve the exact error message and revert with it\n                        returndatacopy(0, 0, returndatasize()) // Copy the error message to the start of memory\n                        revert(0, returndatasize()) // Revert with the error message\n                    }\n                }\n                // if it is set, store selector for function exchange(uint256,uint256,uint256,uint256)\n                default {\n                    mstore(ptr, 0x5b41b90800000000000000000000000000000000000000000000000000000000) // store selector\n                    mstore(add(ptr, 4), i) // store index i\n                    mstore(add(ptr, 36), j) // store index j\n                    mstore(add(ptr, 68), fromAmount) // store fromAmount\n                    mstore(add(ptr, 100), 1) // store 1\n                    // Perform the external call with the prepared calldata\n                    // Check the outcome of the call and handle failure\n                    if iszero(call(gas(), exchange, 0, ptr, 132, 0, 0)) {\n                        // The call failed; we retrieve the exact error message and revert with it\n                        returndatacopy(0, 0, returndatasize()) // Copy the error message to the start of memory\n                        revert(0, returndatasize()) // Revert with the error message\n                    }\n                }\n            }\n        }\n    }\n}\n"
      },
      "src/routers/swapExactAmountIn/direct/UniswapV2SwapExactAmountIn.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IERC20 } from \"@openzeppelin/token/ERC20/IERC20.sol\";\nimport { IUniswapV2SwapExactAmountIn } from \"../../../interfaces/IUniswapV2SwapExactAmountIn.sol\";\n\n// Libraries\nimport { ERC20Utils } from \"../../../libraries/ERC20Utils.sol\";\n\n// Types\nimport { UniswapV2Data } from \"../../../AugustusV6Types.sol\";\n\n// Utils\nimport { UniswapV2Utils } from \"../../../util/UniswapV2Utils.sol\";\n\n/// @title UniswapV2SwapExactAmountIn\n/// @notice A contract for executing direct swapExactAmountIn on UniswapV2 pools\nabstract contract UniswapV2SwapExactAmountIn is IUniswapV2SwapExactAmountIn, UniswapV2Utils {\n    /*//////////////////////////////////////////////////////////////\n                               LIBRARIES\n    //////////////////////////////////////////////////////////////*/\n\n    using ERC20Utils for IERC20;\n\n    /*//////////////////////////////////////////////////////////////\n                                   SWAP\n    //////////////////////////////////////////////////////////////*/\n\n    /// @inheritdoc IUniswapV2SwapExactAmountIn\n    function swapExactAmountInOnUniswapV2(\n        UniswapV2Data calldata uniData,\n        uint256 partnerAndFee,\n        bytes calldata permit\n    )\n        external\n        payable\n        whenNotPaused\n        returns (uint256 receivedAmount, uint256 paraswapShare, uint256 partnerShare)\n    {\n        // Dereference uniData\n        IERC20 srcToken = uniData.srcToken;\n        IERC20 destToken = uniData.destToken;\n        uint256 amountIn = uniData.fromAmount;\n        uint256 minAmountOut = uniData.toAmount;\n        uint256 quotedAmountOut = uniData.quotedAmount;\n        address payable beneficiary = uniData.beneficiary;\n        bytes calldata pools = uniData.pools;\n\n        // Initialize payer\n        address payer = msg.sender;\n\n        // Check if toAmount is valid\n        if (minAmountOut == 0) {\n            revert InvalidToAmount();\n        }\n\n        // Check if beneficiary is valid\n        if (beneficiary == address(0)) {\n            beneficiary = payable(msg.sender);\n        }\n\n        // Check if we need to wrap or permit\n        if (srcToken.isETH(amountIn) == 0) {\n            // Check the length of the permit field,\n            // if < 257 and > 0 we should execute regular permit\n            if (permit.length < 257) {\n                // Permit if needed\n                if (permit.length > 0) {\n                    srcToken.permit(permit);\n                }\n            }\n        } else {\n            // If it is ETH. wrap it to WETH\n            WETH.deposit{ value: amountIn }();\n            // Set srcToken to WETH\n            srcToken = WETH;\n            // Set payer to this contract\n            payer = address(this);\n        }\n\n        // Execute swap\n        _callUniswapV2PoolsSwapExactIn(amountIn, srcToken, pools, payer, permit);\n\n        // Check if destToken is ETH and unwrap\n        if (address(destToken) == address(ERC20Utils.ETH)) {\n            // Check balance of WETH\n            receivedAmount = IERC20(WETH).getBalance(address(this));\n            // Unwrap WETH\n            WETH.withdraw(receivedAmount - 1);\n            // Set receivedAmount to this contract's balance\n            receivedAmount = address(this).balance;\n        } else {\n            // Othwerwise check balance of destToken\n            receivedAmount = destToken.getBalance(address(this));\n        }\n\n        // Check if swap succeeded\n        if (receivedAmount < minAmountOut) {\n            revert InsufficientReturnAmount();\n        }\n\n        // Process fees and transfer destToken to beneficiary\n        return processSwapExactAmountInFeesAndTransfer(\n            beneficiary, destToken, partnerAndFee, receivedAmount, quotedAmountOut\n        );\n    }\n}\n"
      },
      "src/routers/swapExactAmountIn/direct/UniswapV3SwapExactAmountIn.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IERC20 } from \"@openzeppelin/token/ERC20/IERC20.sol\";\nimport { IUniswapV3SwapExactAmountIn } from \"../../../interfaces/IUniswapV3SwapExactAmountIn.sol\";\n\n// Libraries\nimport { ERC20Utils } from \"../../../libraries/ERC20Utils.sol\";\nimport { SafeCastLib } from \"@solady/utils/SafeCastLib.sol\";\n\n// Types\nimport { UniswapV3Data } from \"../../../AugustusV6Types.sol\";\n\n// Utils\nimport { UniswapV3Utils } from \"../../../util/UniswapV3Utils.sol\";\n\n/// @title UniswapV3SwapExactAmountIn\n/// @notice A contract for executing direct swapExactAmountIn on Uniswap V3\nabstract contract UniswapV3SwapExactAmountIn is IUniswapV3SwapExactAmountIn, UniswapV3Utils {\n    /*//////////////////////////////////////////////////////////////\n                               LIBRARIES\n    //////////////////////////////////////////////////////////////*/\n\n    using ERC20Utils for IERC20;\n    using SafeCastLib for uint256;\n\n    /*//////////////////////////////////////////////////////////////\n                                   SWAP\n    //////////////////////////////////////////////////////////////*/\n\n    /// @inheritdoc IUniswapV3SwapExactAmountIn\n    function swapExactAmountInOnUniswapV3(\n        UniswapV3Data calldata uniData,\n        uint256 partnerAndFee,\n        bytes calldata permit\n    )\n        external\n        payable\n        whenNotPaused\n        returns (uint256 receivedAmount, uint256 paraswapShare, uint256 partnerShare)\n    {\n        // Dereference uniData\n        IERC20 srcToken = uniData.srcToken;\n        IERC20 destToken = uniData.destToken;\n        uint256 amountIn = uniData.fromAmount;\n        uint256 minAmountOut = uniData.toAmount;\n        uint256 quotedAmountOut = uniData.quotedAmount;\n        address payable beneficiary = uniData.beneficiary;\n        bytes calldata pools = uniData.pools;\n\n        // Check if toAmount is valid\n        if (minAmountOut == 0) {\n            revert InvalidToAmount();\n        }\n\n        // Check if beneficiary is valid\n        if (beneficiary == address(0)) {\n            beneficiary = payable(msg.sender);\n        }\n\n        // Address that will pay for the swap\n        address fromAddress = msg.sender;\n\n        // Check if we need to wrap or permit\n        if (srcToken.isETH(amountIn) == 0) {\n            // Check the length of the permit field,\n            // if < 257 and > 0 we should execute regular permit\n            if (permit.length < 257) {\n                // Permit if needed\n                if (permit.length > 0) {\n                    srcToken.permit(permit);\n                }\n            }\n        } else {\n            // If it is ETH. wrap it to WETH\n            WETH.deposit{ value: amountIn }();\n            // Swap will be paid from this contract\n            fromAddress = address(this);\n        }\n\n        // Execute swap\n        receivedAmount = _callUniswapV3PoolsSwapExactAmountIn(amountIn.toInt256(), pools, fromAddress, permit);\n\n        // Check if swap succeeded\n        if (receivedAmount < minAmountOut) {\n            revert InsufficientReturnAmount();\n        }\n\n        // Check if destToken is ETH and unwrap\n        if (address(destToken) == address(ERC20Utils.ETH)) {\n            // Unwrap WETH\n            WETH.withdraw(receivedAmount);\n        }\n\n        // Process fees and transfer destToken to beneficiary\n        return processSwapExactAmountInFeesAndTransferUniV3(\n            beneficiary, destToken, partnerAndFee, receivedAmount, quotedAmountOut\n        );\n    }\n}\n"
      },
      "src/routers/swapExactAmountOut/direct/BalancerV2SwapExactAmountOut.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IERC20 } from \"@openzeppelin/token/ERC20/IERC20.sol\";\nimport { IBalancerV2SwapExactAmountOut } from \"../../../interfaces/IBalancerV2SwapExactAmountOut.sol\";\n\n// Libraries\nimport { ERC20Utils } from \"../../../libraries/ERC20Utils.sol\";\n\n// Types\nimport { BalancerV2Data } from \"../../../AugustusV6Types.sol\";\n\n// Utils\nimport { BalancerV2Utils } from \"../../../util/BalancerV2Utils.sol\";\n\n/// @title BalancerV2SwapExactAmountOut\n/// @notice A contract for executing direct swapExactAmountOut on BalancerV2 pools\nabstract contract BalancerV2SwapExactAmountOut is IBalancerV2SwapExactAmountOut, BalancerV2Utils {\n    /*//////////////////////////////////////////////////////////////\n                               LIBRARIES\n    //////////////////////////////////////////////////////////////*/\n\n    using ERC20Utils for IERC20;\n\n    /*//////////////////////////////////////////////////////////////\n                         SWAP EXACT AMOUNT OUT\n    //////////////////////////////////////////////////////////////*/\n\n    /// @inheritdoc IBalancerV2SwapExactAmountOut\n    function swapExactAmountOutOnBalancerV2(\n        BalancerV2Data calldata balancerData,\n        uint256 partnerAndFee,\n        bytes calldata permit,\n        bytes calldata data\n    )\n        external\n        payable\n        whenNotPaused\n        returns (uint256 spentAmount, uint256 receivedAmount, uint256 paraswapShare, uint256 partnerShare)\n    {\n        // Dereference balancerData\n        uint256 quotedAmountIn = balancerData.quotedAmount;\n        uint256 beneficiaryAndApproveFlag = balancerData.beneficiaryAndApproveFlag;\n        uint256 maxAmountIn = balancerData.fromAmount;\n        uint256 amountOut = balancerData.toAmount;\n\n        // Decode params\n        (IERC20 srcToken, IERC20 destToken, address payable beneficiary, bool approve) =\n            _decodeBalancerV2Params(beneficiaryAndApproveFlag, data);\n\n        // Make sure srcToken and destToken are different\n        if (srcToken == destToken) {\n            revert ArbitrageNotSupported();\n        }\n\n        // Check if toAmount is valid\n        if (amountOut == 0) {\n            revert InvalidToAmount();\n        }\n\n        // Check if beneficiary is valid\n        if (beneficiary == address(0)) {\n            beneficiary = payable(msg.sender);\n        }\n\n        // Check contract balance\n        uint256 balanceBefore = srcToken.getBalance(address(this));\n\n        // Check if srcToken is ETH\n        if (srcToken.isETH(maxAmountIn) == 0) {\n            // Check the length of the permit field,\n            // if < 257 and > 0 we should execute regular permit\n            // and if it is >= 257 we execute permit2\n            if (permit.length < 257) {\n                // Permit if needed\n                if (permit.length > 0) {\n                    srcToken.permit(permit);\n                }\n                srcToken.safeTransferFrom(msg.sender, address(this), maxAmountIn);\n            } else {\n                // Otherwise Permit2.permitTransferFrom\n                permit2TransferFrom(permit, address(this), maxAmountIn);\n            }\n            // Check if approve is needed\n            if (approve) {\n                // Approve BALANCER_VAULT to spend srcToken\n                srcToken.approve(BALANCER_VAULT);\n            }\n        } else {\n            // If srcToken is ETH, we have to deduct msg.value from balanceBefore\n            balanceBefore = balanceBefore - msg.value;\n        }\n\n        // Execute swap\n        _callBalancerV2(data);\n\n        // Check balance of destToken\n        receivedAmount = destToken.getBalance(address(this));\n\n        // Check balance of srcToken, deducting the balance before the swap if it is greater than 1\n        uint256 remainingAmount = srcToken.getBalance(address(this)) - (balanceBefore > 1 ? balanceBefore : 0);\n\n        // Check if swap succeeded\n        if (receivedAmount < amountOut) {\n            revert InsufficientReturnAmount();\n        }\n\n        // Process fees and transfer destToken and srcToken to beneficiary\n        return processSwapExactAmountOutFeesAndTransfer(\n            beneficiary,\n            srcToken,\n            destToken,\n            partnerAndFee,\n            maxAmountIn,\n            remainingAmount,\n            receivedAmount,\n            quotedAmountIn\n        );\n    }\n}\n"
      },
      "src/routers/swapExactAmountOut/direct/UniswapV2SwapExactAmountOut.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IERC20 } from \"@openzeppelin/token/ERC20/IERC20.sol\";\nimport { IUniswapV2SwapExactAmountOut } from \"../../../interfaces/IUniswapV2SwapExactAmountOut.sol\";\n\n// Libraries\nimport { ERC20Utils } from \"../../../libraries/ERC20Utils.sol\";\n\n// Types\nimport { UniswapV2Data } from \"../../../AugustusV6Types.sol\";\n\n// Utils\nimport { UniswapV2Utils } from \"../../../util/UniswapV2Utils.sol\";\n\n/// @title UniswapV2SwapExactAmountOut\n/// @notice A contract for executing direct swapExactAmountOut on UniswapV2 pools\nabstract contract UniswapV2SwapExactAmountOut is IUniswapV2SwapExactAmountOut, UniswapV2Utils {\n    /*//////////////////////////////////////////////////////////////\n                               LIBRARIES\n    //////////////////////////////////////////////////////////////*/\n\n    using ERC20Utils for IERC20;\n\n    /*//////////////////////////////////////////////////////////////\n                         SWAP EXACT AMOUNT OUT\n    //////////////////////////////////////////////////////////////*/\n\n    /// @inheritdoc IUniswapV2SwapExactAmountOut\n    function swapExactAmountOutOnUniswapV2(\n        UniswapV2Data calldata uniData,\n        uint256 partnerAndFee,\n        bytes calldata permit\n    )\n        external\n        payable\n        whenNotPaused\n        returns (uint256 spentAmount, uint256 receivedAmount, uint256 paraswapShare, uint256 partnerShare)\n    {\n        // Dereference uniData\n        IERC20 srcToken = uniData.srcToken;\n        IERC20 destToken = uniData.destToken;\n        uint256 maxAmountIn = uniData.fromAmount;\n        uint256 amountOut = uniData.toAmount;\n        uint256 quotedAmountIn = uniData.quotedAmount;\n        address payable beneficiary = uniData.beneficiary;\n        bytes calldata pools = uniData.pools;\n\n        // Check if toAmount is valid\n        if (amountOut == 0) {\n            revert InvalidToAmount();\n        }\n\n        // Check if beneficiary is valid\n        if (beneficiary == address(0)) {\n            beneficiary = payable(msg.sender);\n        }\n\n        // Init balanceBefore\n        uint256 balanceBefore;\n\n        // Check if srcToken is ETH\n        bool isFromETH = srcToken.isETH(maxAmountIn) != 0;\n\n        // Check if we need to wrap or permit\n        if (isFromETH) {\n            // Check WETH balance before\n            balanceBefore = IERC20(WETH).getBalance(address(this));\n            // If it is ETH. wrap it to WETH\n            WETH.deposit{ value: maxAmountIn }();\n            // Set srcToken to WETH\n            srcToken = WETH;\n        } else {\n            // Check srcToken balance before\n            balanceBefore = srcToken.getBalance(address(this));\n            // Check the length of the permit field,\n            // if < 257 and > 0 we should execute regular permit\n            // and if it is >= 257 we execute permit2\n            if (permit.length < 257) {\n                // Permit if needed\n                if (permit.length > 0) {\n                    srcToken.permit(permit);\n                }\n                srcToken.safeTransferFrom(msg.sender, address(this), maxAmountIn);\n            } else {\n                // Otherwise Permit2.permitTransferFrom\n                permit2TransferFrom(permit, address(this), maxAmountIn);\n            }\n        }\n\n        // Make sure srcToken and destToken are different\n        if (srcToken == destToken) {\n            revert ArbitrageNotSupported();\n        }\n\n        // Execute swap\n        _callUniswapV2PoolsSwapExactOut(amountOut, srcToken, pools);\n\n        // Check if destToken is ETH and unwrap\n        if (address(destToken) == address(ERC20Utils.ETH)) {\n            // Make sure srcToken was not WETH\n            if (srcToken == WETH) {\n                revert ArbitrageNotSupported();\n            }\n            // Check balance of WETH\n            receivedAmount = IERC20(WETH).getBalance(address(this));\n            // Leave dust if receivedAmount > amountOut\n            if (receivedAmount > amountOut) {\n                --receivedAmount;\n            }\n            // Unwrap WETH\n            WETH.withdraw(receivedAmount);\n            // Set receivedAmount to this contract's balance\n            receivedAmount = address(this).balance;\n        } else {\n            // Othwerwise check balance of destToken\n            receivedAmount = destToken.getBalance(address(this));\n        }\n\n        // Check balance of srcToken\n        uint256 remainingAmount = srcToken.getBalance(address(this));\n\n        // Check if swap succeeded\n        if (receivedAmount < amountOut) {\n            revert InsufficientReturnAmount();\n        }\n\n        // Check if srcToken is ETH and unwrap if there is remaining amount\n        if (isFromETH) {\n            // Check native balance before\n            uint256 nativeBalanceBefore = address(this).balance;\n            // If balanceBefore is greater than 1, deduct it from remainingAmount\n            remainingAmount = remainingAmount - (balanceBefore > 1 ? balanceBefore : 0);\n            // Withdraw remaining WETH if any\n            if (remainingAmount > 1) {\n                WETH.withdraw(remainingAmount - 1);\n            }\n            srcToken = ERC20Utils.ETH;\n            // If native balance before is greater than 1, deduct it from remainingAmount\n            remainingAmount = address(this).balance - (nativeBalanceBefore > 1 ? nativeBalanceBefore : 0);\n        } else {\n            // Otherwise, if balanceBefore is greater than 1, deduct it from remainingAmount\n            remainingAmount = remainingAmount - (balanceBefore > 1 ? balanceBefore : 0);\n        }\n\n        // Process fees and transfer destToken and srcToken to beneficiary\n        return processSwapExactAmountOutFeesAndTransfer(\n            beneficiary,\n            srcToken,\n            destToken,\n            partnerAndFee,\n            maxAmountIn,\n            remainingAmount,\n            receivedAmount,\n            quotedAmountIn\n        );\n    }\n}\n"
      },
      "src/routers/swapExactAmountOut/direct/UniswapV3SwapExactAmountOut.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IERC20 } from \"@openzeppelin/token/ERC20/IERC20.sol\";\nimport { IUniswapV3SwapExactAmountOut } from \"../../../interfaces/IUniswapV3SwapExactAmountOut.sol\";\n\n// Libraries\nimport { ERC20Utils } from \"../../../libraries/ERC20Utils.sol\";\nimport { SafeCastLib } from \"@solady/utils/SafeCastLib.sol\";\n\n// Types\nimport { UniswapV3Data } from \"../../../AugustusV6Types.sol\";\n\n// Utils\nimport { UniswapV3Utils } from \"../../../util/UniswapV3Utils.sol\";\n\n/// @title UniswapV3SwapExactAmountOut\n/// @notice A contract for executing direct swapExactAmountOut on UniswapV3 pools\nabstract contract UniswapV3SwapExactAmountOut is IUniswapV3SwapExactAmountOut, UniswapV3Utils {\n    /*//////////////////////////////////////////////////////////////\n                               LIBRARIES\n    //////////////////////////////////////////////////////////////*/\n\n    using ERC20Utils for IERC20;\n    using SafeCastLib for uint256;\n\n    /*//////////////////////////////////////////////////////////////\n                         SWAP EXACT AMOUNT OUT\n    //////////////////////////////////////////////////////////////*/\n\n    /// @inheritdoc IUniswapV3SwapExactAmountOut\n    function swapExactAmountOutOnUniswapV3(\n        UniswapV3Data calldata uniData,\n        uint256 partnerAndFee,\n        bytes calldata permit\n    )\n        external\n        payable\n        whenNotPaused\n        returns (uint256 spentAmount, uint256 receivedAmount, uint256 paraswapShare, uint256 partnerShare)\n    {\n        // Dereference uniData\n        IERC20 srcToken = uniData.srcToken;\n        IERC20 destToken = uniData.destToken;\n        uint256 maxAmountIn = uniData.fromAmount;\n        uint256 amountOut = uniData.toAmount;\n        uint256 quotedAmountIn = uniData.quotedAmount;\n        address payable beneficiary = uniData.beneficiary;\n        bytes calldata pools = uniData.pools;\n\n        // Check if toAmount is valid\n        if (amountOut == 0) {\n            revert InvalidToAmount();\n        }\n\n        // Check if beneficiary is valid\n        if (beneficiary == address(0)) {\n            beneficiary = payable(msg.sender);\n        }\n\n        // Address that will pay for the swap\n        address fromAddress = msg.sender;\n\n        // Check if srcToken is ETH\n        bool isFromETH = srcToken.isETH(maxAmountIn) != 0;\n\n        // If pools.length > 96, we are going to do a multi-pool swap\n        bool isMultiplePools = pools.length > 96;\n\n        // Init balance before variables\n        uint256 senderBalanceBefore;\n        uint256 balanceBefore;\n\n        // Check if we need to wrap or permit\n        if (isFromETH) {\n            // Check WETH balance before\n            balanceBefore = IERC20(WETH).getBalance(address(this));\n            // If it is ETH. wrap it to WETH\n            WETH.deposit{ value: maxAmountIn }();\n            // Swap will be paid from this contract\n            fromAddress = address(this);\n            // Set srcToken to WETH\n            srcToken = WETH;\n        } else {\n            // Check srcToken balance before\n            balanceBefore = srcToken.getBalance(address(this));\n            // Check the length of the permit field,\n            // if < 257 and > 0 we should execute regular permit\n            // and if it is >= 257 we execute permit2\n            if (permit.length < 257) {\n                // Permit if needed\n                if (permit.length > 0) {\n                    srcToken.permit(permit);\n                }\n                // if we're using multiple pools, we need to store the pre-swap balance of srcToken\n                if (isMultiplePools) {\n                    senderBalanceBefore = srcToken.getBalance(msg.sender);\n                }\n            } else {\n                // Otherwise Permit2.permitTransferFrom\n                permit2TransferFrom(permit, address(this), maxAmountIn);\n                // Swap will be paid from this contract\n                fromAddress = address(this);\n            }\n        }\n\n        // Make sure srcToken and destToken are different\n        if (srcToken == destToken) {\n            revert ArbitrageNotSupported();\n        }\n\n        // Execute swap\n        (spentAmount, receivedAmount) =\n            _callUniswapV3PoolsSwapExactAmountOut((-amountOut.toInt256()), pools, fromAddress);\n\n        // Check if swap succeeded\n        if (receivedAmount < amountOut) {\n            revert InsufficientReturnAmount();\n        }\n\n        // Check if destToken is ETH and unwrap\n        if (address(destToken) == address(ERC20Utils.ETH)) {\n            // Make sure srcToken was not WETH\n            if (srcToken == WETH) {\n                revert ArbitrageNotSupported();\n            }\n            // Unwrap WETH\n            WETH.withdraw(receivedAmount);\n        }\n\n        // Iniiialize remainingAmount\n        uint256 remainingAmount;\n\n        // Check if payer is this contract\n        if (fromAddress == address(this)) {\n            // If srcTokenwas ETH, we need to withdraw remaining WETH if any\n            if (isFromETH) {\n                // Check native balance before\n                uint256 nativeBalanceBefore = address(this).balance;\n                // Check balance of WETH, If balanceBefore is greater than 1, deduct it from remainingAmount\n                remainingAmount = IERC20(WETH).getBalance(address(this)) - (balanceBefore > 1 ? balanceBefore : 0);\n                // Withdraw remaining WETH if any\n                if (remainingAmount > 1) {\n                    // Unwrap WETH\n                    WETH.withdraw(remainingAmount - 1);\n                    // If native balance before is greater than 1, deduct it from remainingAmount\n                    remainingAmount = address(this).balance - (nativeBalanceBefore > 1 ? nativeBalanceBefore : 0);\n                }\n                // Set srcToken to ETH\n                srcToken = ERC20Utils.ETH;\n            } else {\n                // If we have executed multi-pool swap, we need to fetch the remaining amount from balance\n                if (isMultiplePools) {\n                    // Calculate spent amount and remaining amount, If balanceBefore is greater than 1, deduct it from\n                    // remainingAmount\n                    remainingAmount = srcToken.getBalance(address(this)) - (balanceBefore > 1 ? balanceBefore : 0);\n                } else {\n                    // Otherwise, remaining amount is the difference between the spent amount and the remaining balance\n                    remainingAmount = maxAmountIn - spentAmount;\n                }\n            }\n\n            // Process fees using processSwapExactAmountOutFeesAndTransfer\n            return processSwapExactAmountOutFeesAndTransfer(\n                beneficiary,\n                srcToken,\n                destToken,\n                partnerAndFee,\n                maxAmountIn,\n                remainingAmount,\n                receivedAmount,\n                quotedAmountIn\n            );\n        } else {\n            // If we have executed multi-pool swap, we need to re-calculate the remaining amount and spent amount\n            if (isMultiplePools) {\n                // Calculate spent amount and remaining amount\n                remainingAmount = srcToken.getBalance(msg.sender);\n                spentAmount = senderBalanceBefore - remainingAmount;\n            }\n            // Process fees and transfer destToken and srcToken to feeVault or partner and\n            // feeWallet if needed\n            return processSwapExactAmountOutFeesAndTransferUniV3(\n                beneficiary,\n                srcToken,\n                destToken,\n                partnerAndFee,\n                maxAmountIn,\n                receivedAmount,\n                spentAmount,\n                quotedAmountIn\n            );\n        }\n    }\n}\n"
      },
      "src/fees/AugustusFees.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IERC20 } from \"@openzeppelin/token/ERC20/IERC20.sol\";\nimport { IAugustusFeeVault } from \"../interfaces/IAugustusFeeVault.sol\";\nimport { IAugustusFees } from \"../interfaces/IAugustusFees.sol\";\n\n// Libraries\nimport { ERC20Utils } from \"../libraries/ERC20Utils.sol\";\n\n// Storage\nimport { AugustusStorage } from \"../storage/AugustusStorage.sol\";\n\n/// @title AugustusFees\n/// @notice Contract for handling fees\ncontract AugustusFees is AugustusStorage, IAugustusFees {\n    /*//////////////////////////////////////////////////////////////\n                               LIBRARIES\n    //////////////////////////////////////////////////////////////*/\n\n    using ERC20Utils for IERC20;\n\n    /*//////////////////////////////////////////////////////////////\n                               CONSTANTS\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev Fee share constants\n    uint256 public constant PARTNER_SHARE_PERCENT = 8500;\n    uint256 public constant MAX_FEE_PERCENT = 200;\n    uint256 public constant SURPLUS_PERCENT = 100;\n    uint256 public constant PARASWAP_REFERRAL_SHARE = 5000;\n    uint256 public constant PARTNER_REFERRAL_SHARE = 2500;\n    uint256 public constant PARASWAP_SURPLUS_SHARE = 5000;\n    uint256 public constant PARASWAP_SLIPPAGE_SHARE = 10_000;\n    uint256 public constant MINIMUM_SURPLUS_EPSILON_AND_ONE_WEI = 11;\n\n    /// @dev Masks for unpacking feeData\n    uint256 private constant FEE_PERCENT_IN_BASIS_POINTS_MASK = 0x3FFF;\n    uint256 private constant IS_USER_SURPLUS_MASK = 1 << 90;\n    uint256 private constant IS_DIRECT_TRANSFER_MASK = 1 << 91;\n    uint256 private constant IS_CAP_SURPLUS_MASK = 1 << 92;\n    uint256 private constant IS_SKIP_BLACKLIST_MASK = 1 << 93;\n    uint256 private constant IS_REFERRAL_MASK = 1 << 94;\n    uint256 private constant IS_TAKE_SURPLUS_MASK = 1 << 95;\n\n    /// @dev A contact that stores fees collected by the protocol\n    IAugustusFeeVault public immutable FEE_VAULT; // solhint-disable-line var-name-mixedcase\n\n    /*//////////////////////////////////////////////////////////////\n                              CONSTRUCTOR\n    //////////////////////////////////////////////////////////////*/\n\n    constructor(address _feeVault) {\n        FEE_VAULT = IAugustusFeeVault(_feeVault);\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                       SWAP EXACT AMOUNT IN FEES\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Process swapExactAmountIn fees and transfer the received amount to the beneficiary\n    /// @param destToken The received token from the swapExactAmountIn\n    /// @param partnerAndFee Packed partner and fee data\n    /// @param receivedAmount The amount of destToken received from the swapExactAmountIn\n    /// @param quotedAmount The quoted expected amount of destToken\n    /// @return returnAmount The amount of destToken transfered to the beneficiary\n    /// @return paraswapFeeShare The share of the fees for Paraswap\n    /// @return partnerFeeShare The share of the fees for the partner\n    function processSwapExactAmountInFeesAndTransfer(\n        address beneficiary,\n        IERC20 destToken,\n        uint256 partnerAndFee,\n        uint256 receivedAmount,\n        uint256 quotedAmount\n    )\n        internal\n        returns (uint256 returnAmount, uint256 paraswapFeeShare, uint256 partnerFeeShare)\n    {\n        // initialize the surplus\n        uint256 surplus;\n\n        // parse partner and fee data\n        (address payable partner, uint256 feeData) = parsePartnerAndFeeData(partnerAndFee);\n\n        // calculate the surplus, we expect there to be 1 wei dust left which we should\n        // not take into account when determining if there is surplus, we only take the\n        // surplus if it is greater than MINIMUM_SURPLUS_EPSILON_AND_ONE_WEI\n        if (receivedAmount > quotedAmount + MINIMUM_SURPLUS_EPSILON_AND_ONE_WEI) {\n            surplus = receivedAmount - quotedAmount;\n            // if the cap surplus flag is passed, we cap the surplus to 1% of the quoted amount\n            if (feeData & IS_CAP_SURPLUS_MASK != 0) {\n                uint256 cappedSurplus = (SURPLUS_PERCENT * quotedAmount) / 10_000;\n                surplus = surplus > cappedSurplus ? cappedSurplus : surplus;\n            }\n        }\n\n        // calculate remainingAmount\n        uint256 remainingAmount = receivedAmount - surplus;\n\n        // if partner address is not 0x0\n        if (partner != address(0x0)) {\n            // Check if skip blacklist flag is true\n            bool skipBlacklist = feeData & IS_SKIP_BLACKLIST_MASK != 0;\n            // Check if token is blacklisted\n            bool isBlacklisted = blacklistedTokens[destToken];\n            // If the token is blacklisted and the skipBlacklist flag is false,\n            // send the received amount to the beneficiary, we won't process fees\n            if (!skipBlacklist && isBlacklisted) {\n                // transfer the received amount to the beneficiary, keeping 1 wei dust\n                _transferAndLeaveDust(destToken, beneficiary, receivedAmount);\n                return (receivedAmount - 1, 0, 0);\n            }\n            // Check if direct transfer flag is true\n            bool isDirectTransfer = feeData & IS_DIRECT_TRANSFER_MASK != 0;\n            // partner takes fixed fees feePercent is greater than 0\n            uint256 feePercent = _getAdjustedFeePercent(feeData);\n            if (feePercent > 0) {\n                // fee base = min (receivedAmount, quotedAmount + surplus)\n                uint256 feeBase = receivedAmount > quotedAmount + surplus ? quotedAmount + surplus : receivedAmount;\n                // calculate fixed fees\n                uint256 fee = (feeBase * feePercent) / 10_000;\n                partnerFeeShare = (fee * PARTNER_SHARE_PERCENT) / 10_000;\n                paraswapFeeShare = fee - partnerFeeShare;\n                // distrubite fees from destToken\n                returnAmount = _distributeFees(\n                    receivedAmount,\n                    destToken,\n                    partner,\n                    partnerFeeShare,\n                    paraswapFeeShare,\n                    skipBlacklist,\n                    isBlacklisted,\n                    isDirectTransfer\n                );\n                // transfer the return amount to the beneficiary, keeping 1 wei dust\n                _transferAndLeaveDust(destToken, beneficiary, returnAmount);\n                return (returnAmount - 1, paraswapFeeShare, partnerFeeShare);\n            }\n            // if slippage is postive and referral flag is true\n            else if (feeData & IS_REFERRAL_MASK != 0) {\n                if (surplus > 0) {\n                    // the split is 50% for paraswap, 25% for the referrer and 25% for the user\n                    paraswapFeeShare = (surplus * PARASWAP_REFERRAL_SHARE) / 10_000;\n                    partnerFeeShare = (surplus * PARTNER_REFERRAL_SHARE) / 10_000;\n                    // distribute fees from destToken\n                    returnAmount = _distributeFees(\n                        receivedAmount,\n                        destToken,\n                        partner,\n                        partnerFeeShare,\n                        paraswapFeeShare,\n                        skipBlacklist,\n                        isBlacklisted,\n                        isDirectTransfer\n                    );\n                    // transfer the return amount to the beneficiary, keeping 1 wei dust\n                    _transferAndLeaveDust(destToken, beneficiary, returnAmount);\n                    return (returnAmount - 1, paraswapFeeShare, partnerFeeShare);\n                }\n            }\n            // if slippage is positive and takeSurplus flag is true\n            else if (feeData & IS_TAKE_SURPLUS_MASK != 0) {\n                if (surplus > 0) {\n                    // paraswap takes 50% of the surplus and partner takes the other 50%\n                    paraswapFeeShare = (surplus * PARASWAP_SURPLUS_SHARE) / 10_000;\n                    partnerFeeShare = surplus - paraswapFeeShare;\n                    // If user surplus flag is true, transfer the partner share to the user instead of the partner\n                    if (feeData & IS_USER_SURPLUS_MASK != 0) {\n                        partnerFeeShare = 0;\n                        // Transfer the paraswap share directly to the fee wallet\n                        isDirectTransfer = true;\n                    }\n                    // distrubite fees from destToken, partner takes 50% of the surplus\n                    // and paraswap takes the other 50%\n                    returnAmount = _distributeFees(\n                        receivedAmount,\n                        destToken,\n                        partner,\n                        partnerFeeShare,\n                        paraswapFeeShare,\n                        skipBlacklist,\n                        isBlacklisted,\n                        isDirectTransfer\n                    );\n                    // transfer the return amount to the beneficiary, keeping 1 wei dust\n                    _transferAndLeaveDust(destToken, beneficiary, returnAmount);\n                    return (returnAmount - 1, paraswapFeeShare, partnerFeeShare);\n                }\n            }\n        }\n\n        // if slippage is positive and partner address is 0x0 or fee percent is 0\n        // paraswap will take the surplus and transfer the rest to the beneficiary\n        // if there is no positive slippage, transfer the received amount to the beneficiary\n        if (surplus > 0) {\n            // If the token is blacklisted, send the received amount to the beneficiary\n            // we won't process fees\n            if (blacklistedTokens[destToken]) {\n                // transfer the received amount to the beneficiary, keeping 1 wei dust\n                _transferAndLeaveDust(destToken, beneficiary, receivedAmount);\n                return (receivedAmount - 1, 0, 0);\n            }\n            // transfer the remaining amount to the beneficiary, keeping 1 wei dust\n            _transferAndLeaveDust(destToken, beneficiary, remainingAmount);\n            // transfer the surplus to the fee wallet\n            destToken.safeTransfer(feeWallet, surplus);\n            return (remainingAmount - 1, surplus, 0);\n        } else {\n            // transfer the received amount to the beneficiary, keeping 1 wei dust\n            _transferAndLeaveDust(destToken, beneficiary, receivedAmount);\n            return (receivedAmount - 1, 0, 0);\n        }\n    }\n\n    /// @notice Process swapExactAmountIn fees and transfer the received amount to the beneficiary\n    /// @param destToken The received token from the swapExactAmountIn\n    /// @param partnerAndFee Packed partner and fee data\n    /// @param receivedAmount The amount of destToken received from the swapExactAmountIn\n    /// @param quotedAmount The quoted expected amount of destToken\n    /// @return returnAmount The amount of destToken transfered to the beneficiary\n    /// @return paraswapFeeShare The share of the fees for Paraswap\n    /// @return partnerFeeShare The share of the fees for the partner\n    function processSwapExactAmountInFeesAndTransferUniV3(\n        address beneficiary,\n        IERC20 destToken,\n        uint256 partnerAndFee,\n        uint256 receivedAmount,\n        uint256 quotedAmount\n    )\n        internal\n        returns (uint256 returnAmount, uint256 paraswapFeeShare, uint256 partnerFeeShare)\n    {\n        // initialize the surplus\n        uint256 surplus;\n\n        // parse partner and fee data\n        (address payable partner, uint256 feeData) = parsePartnerAndFeeData(partnerAndFee);\n\n        // calculate the surplus, we do not take the surplus into account if it is less than\n        // MINIMUM_SURPLUS_EPSILON_AND_ONE_WEI\n        if (receivedAmount > quotedAmount + MINIMUM_SURPLUS_EPSILON_AND_ONE_WEI) {\n            surplus = receivedAmount - quotedAmount;\n            // if the cap surplus flag is passed, we cap the surplus to 1% of the quoted amount\n            if (feeData & IS_CAP_SURPLUS_MASK != 0) {\n                uint256 cappedSurplus = (SURPLUS_PERCENT * quotedAmount) / 10_000;\n                surplus = surplus > cappedSurplus ? cappedSurplus : surplus;\n            }\n        }\n\n        // calculate remainingAmount\n        uint256 remainingAmount = receivedAmount - surplus;\n\n        // if partner address is not 0x0\n        if (partner != address(0x0)) {\n            // Check if skip blacklist flag is true\n            bool skipBlacklist = feeData & IS_SKIP_BLACKLIST_MASK != 0;\n            // Check if token is blacklisted\n            bool isBlacklisted = blacklistedTokens[destToken];\n            // If the token is blacklisted and the skipBlacklist flag is false,\n            // send the received amount to the beneficiary, we won't process fees\n            if (!skipBlacklist && isBlacklisted) {\n                // transfer the received amount to the beneficiary\n                destToken.safeTransfer(beneficiary, receivedAmount);\n                return (receivedAmount, 0, 0);\n            }\n            // Check if direct transfer flag is true\n            bool isDirectTransfer = feeData & IS_DIRECT_TRANSFER_MASK != 0;\n            // partner takes fixed fees feePercent is greater than 0\n            uint256 feePercent = _getAdjustedFeePercent(feeData);\n            if (feePercent > 0) {\n                // fee base = min (receivedAmount, quotedAmount + surplus)\n                uint256 feeBase = receivedAmount > quotedAmount + surplus ? quotedAmount + surplus : receivedAmount;\n                // calculate fixed fees\n                uint256 fee = (feeBase * feePercent) / 10_000;\n                partnerFeeShare = (fee * PARTNER_SHARE_PERCENT) / 10_000;\n                paraswapFeeShare = fee - partnerFeeShare;\n                // distrubite fees from destToken\n                returnAmount = _distributeFees(\n                    receivedAmount,\n                    destToken,\n                    partner,\n                    partnerFeeShare,\n                    paraswapFeeShare,\n                    skipBlacklist,\n                    isBlacklisted,\n                    isDirectTransfer\n                );\n                // transfer the return amount to the beneficiary\n                destToken.safeTransfer(beneficiary, returnAmount);\n                return (returnAmount, paraswapFeeShare, partnerFeeShare);\n            }\n            // if slippage is postive and referral flag is true\n            else if (feeData & IS_REFERRAL_MASK != 0) {\n                if (surplus > 0) {\n                    // the split is 50% for paraswap, 25% for the referrer and 25% for the user\n                    paraswapFeeShare = (surplus * PARASWAP_REFERRAL_SHARE) / 10_000;\n                    partnerFeeShare = (surplus * PARTNER_REFERRAL_SHARE) / 10_000;\n                    // distribute fees from destToken\n                    returnAmount = _distributeFees(\n                        receivedAmount,\n                        destToken,\n                        partner,\n                        partnerFeeShare,\n                        paraswapFeeShare,\n                        skipBlacklist,\n                        isBlacklisted,\n                        isDirectTransfer\n                    );\n                    // transfer the return amount to the beneficiary\n                    destToken.safeTransfer(beneficiary, returnAmount);\n                    return (returnAmount, paraswapFeeShare, partnerFeeShare);\n                }\n            }\n            // if slippage is positive and takeSurplus flag is true\n            else if (feeData & IS_TAKE_SURPLUS_MASK != 0) {\n                if (surplus > 0) {\n                    // paraswap takes 50% of the surplus and partner takes the other 50%\n                    paraswapFeeShare = (surplus * PARASWAP_SURPLUS_SHARE) / 10_000;\n                    partnerFeeShare = surplus - paraswapFeeShare;\n                    // If user surplus flag is true, transfer the partner share to the user instead of the partner\n                    if (feeData & IS_USER_SURPLUS_MASK != 0) {\n                        partnerFeeShare = 0;\n                        // Transfer the paraswap share directly to the fee wallet\n                        isDirectTransfer = true;\n                    }\n                    // distrubite fees from destToken, partner takes 50% of the surplus\n                    // and paraswap takes the other 50%\n                    returnAmount = _distributeFees(\n                        receivedAmount,\n                        destToken,\n                        partner,\n                        partnerFeeShare,\n                        paraswapFeeShare,\n                        skipBlacklist,\n                        isBlacklisted,\n                        isDirectTransfer\n                    );\n                    // transfer the return amount to the beneficiary,\n                    destToken.safeTransfer(beneficiary, returnAmount);\n                    return (returnAmount, paraswapFeeShare, partnerFeeShare);\n                }\n            }\n        }\n\n        // if slippage is positive and partner address is 0x0 or fee percent is 0\n        // paraswap will take the surplus and transfer the rest to the beneficiary\n        // if there is no positive slippage, transfer the received amount to the beneficiary\n        if (surplus > 0) {\n            // If the token is blacklisted, send the received amount to the beneficiary\n            // we won't process fees\n            if (blacklistedTokens[destToken]) {\n                // transfer the received amount to the beneficiary\n                destToken.safeTransfer(beneficiary, receivedAmount);\n                return (receivedAmount, 0, 0);\n            }\n            // transfer the remaining amount to the beneficiary\n            destToken.safeTransfer(beneficiary, remainingAmount);\n            // transfer the surplus to the fee wallet\n            destToken.safeTransfer(feeWallet, surplus);\n            return (remainingAmount, surplus, 0);\n        } else {\n            // transfer the received amount to the beneficiary\n            destToken.safeTransfer(beneficiary, receivedAmount);\n            return (receivedAmount, 0, 0);\n        }\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                       SWAP EXACT AMOUNT OUT FEES\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Process swapExactAmountOut fees and transfer the received amount and remaining amount to the\n    /// beneficiary\n    /// @param srcToken The token used to swapExactAmountOut\n    /// @param destToken The token received from the swapExactAmountOut\n    /// @param partnerAndFee Packed partner and fee data\n    /// @param maxAmountIn The amount of srcToken passed to the swapExactAmountOut\n    /// @param receivedAmount The amount of destToken received from the swapExactAmountOut\n    /// @param quotedAmount The quoted expected amount of srcToken to be used to swapExactAmountOut\n    /// @return spentAmount The amount of srcToken used to swapExactAmountOut\n    /// @return outAmount The amount of destToken transfered to the beneficiary\n    /// @return paraswapFeeShare The share of the fees for Paraswap\n    /// @return partnerFeeShare The share of the fees for the partner\n    function processSwapExactAmountOutFeesAndTransfer(\n        address beneficiary,\n        IERC20 srcToken,\n        IERC20 destToken,\n        uint256 partnerAndFee,\n        uint256 maxAmountIn,\n        uint256 remainingAmount,\n        uint256 receivedAmount,\n        uint256 quotedAmount\n    )\n        internal\n        returns (uint256 spentAmount, uint256 outAmount, uint256 paraswapFeeShare, uint256 partnerFeeShare)\n    {\n        // calculate the amount used to swapExactAmountOut\n        spentAmount = maxAmountIn - (remainingAmount > 0 ? remainingAmount - 1 : remainingAmount);\n\n        // initialize the surplus\n        uint256 surplus;\n\n        // initialize the return amount\n        uint256 returnAmount;\n\n        // parse partner and fee data\n        (address payable partner, uint256 feeData) = parsePartnerAndFeeData(partnerAndFee);\n\n        // check if the quotedAmount is bigger than the maxAmountIn\n        if (quotedAmount > maxAmountIn) {\n            revert InvalidQuotedAmount();\n        }\n\n        // calculate the surplus, we do not take the surplus into account if it is less than\n        // MINIMUM_SURPLUS_EPSILON_AND_ONE_WEI\n        if (quotedAmount > spentAmount + MINIMUM_SURPLUS_EPSILON_AND_ONE_WEI) {\n            surplus = quotedAmount - spentAmount;\n            // if the cap surplus flag is passed, we cap the surplus to 1% of the quoted amount\n            if (feeData & IS_CAP_SURPLUS_MASK != 0) {\n                uint256 cappedSurplus = (SURPLUS_PERCENT * quotedAmount) / 10_000;\n                surplus = surplus > cappedSurplus ? cappedSurplus : surplus;\n            }\n        }\n\n        // if partner address is not 0x0\n        if (partner != address(0x0)) {\n            // Check if skip blacklist flag is true\n            bool skipBlacklist = feeData & IS_SKIP_BLACKLIST_MASK != 0;\n            // Check if token is blacklisted\n            bool isBlacklisted = blacklistedTokens[srcToken];\n            // If the token is blacklisted and the skipBlacklist flag is false,\n            // send the remaining amount to the msg.sender, we won't process fees\n            if (!skipBlacklist && isBlacklisted) {\n                // transfer the remaining amount to msg.sender\n                returnAmount = _transferIfGreaterThanOne(srcToken, msg.sender, remainingAmount);\n                // transfer the received amount of destToken to the beneficiary\n                destToken.safeTransfer(beneficiary, --receivedAmount);\n                return (maxAmountIn - returnAmount, receivedAmount, 0, 0);\n            }\n            // Check if direct transfer flag is true\n            bool isDirectTransfer = feeData & IS_DIRECT_TRANSFER_MASK != 0;\n            // partner takes fixed fees feePercent is greater than 0\n            uint256 feePercent = _getAdjustedFeePercent(feeData);\n            if (feePercent > 0) {\n                // fee base = min (spentAmount, quotedAmount)\n                uint256 feeBase = spentAmount < quotedAmount ? spentAmount : quotedAmount;\n                // calculate fixed fees\n                uint256 fee = (feeBase * feePercent) / 10_000;\n                partnerFeeShare = (fee * PARTNER_SHARE_PERCENT) / 10_000;\n                paraswapFeeShare = fee - partnerFeeShare;\n                // distrubite fees from srcToken\n                returnAmount = _distributeFees(\n                    remainingAmount,\n                    srcToken,\n                    partner,\n                    partnerFeeShare,\n                    paraswapFeeShare,\n                    skipBlacklist,\n                    isBlacklisted,\n                    isDirectTransfer\n                );\n                // transfer the rest to msg.sender\n                returnAmount = _transferIfGreaterThanOne(srcToken, msg.sender, returnAmount);\n                // transfer the received amount of destToken to the beneficiary\n                destToken.safeTransfer(beneficiary, --receivedAmount);\n                return (maxAmountIn - returnAmount, receivedAmount, paraswapFeeShare, partnerFeeShare);\n            }\n            // if slippage is postive and referral flag is true\n            if (feeData & IS_REFERRAL_MASK != 0) {\n                if (surplus > 0) {\n                    // the split is 50% for paraswap, 25% for the referrer and 25% for the user\n                    paraswapFeeShare = (surplus * PARASWAP_REFERRAL_SHARE) / 10_000;\n                    partnerFeeShare = (surplus * PARTNER_REFERRAL_SHARE) / 10_000;\n                    // distribute fees from srcToken\n                    returnAmount = _distributeFees(\n                        remainingAmount,\n                        srcToken,\n                        partner,\n                        partnerFeeShare,\n                        paraswapFeeShare,\n                        skipBlacklist,\n                        isBlacklisted,\n                        isDirectTransfer\n                    );\n                    // transfer the rest to msg.sender\n                    returnAmount = _transferIfGreaterThanOne(srcToken, msg.sender, returnAmount);\n                    // transfer the received amount of destToken to the beneficiary\n                    destToken.safeTransfer(beneficiary, --receivedAmount);\n                    return (maxAmountIn - returnAmount, receivedAmount, paraswapFeeShare, partnerFeeShare);\n                }\n            }\n            // if slippage is positive and takeSurplus flag is true\n            else if (feeData & IS_TAKE_SURPLUS_MASK != 0) {\n                if (surplus > 0) {\n                    // paraswap takes 50% of the surplus and partner takes the other 50%\n                    paraswapFeeShare = (surplus * PARASWAP_SURPLUS_SHARE) / 10_000;\n                    partnerFeeShare = surplus - paraswapFeeShare;\n                    // If user surplus flag is true, transfer the partner share to the user instead of the partner\n                    if (feeData & IS_USER_SURPLUS_MASK != 0) {\n                        partnerFeeShare = 0;\n                        // Transfer the paraswap share directly to the fee wallet\n                        isDirectTransfer = true;\n                    }\n                    // distrubite fees from srcToken, partner takes 50% of the surplus\n                    // and paraswap takes the other 50%\n                    returnAmount = _distributeFees(\n                        remainingAmount,\n                        srcToken,\n                        partner,\n                        partnerFeeShare,\n                        paraswapFeeShare,\n                        skipBlacklist,\n                        isBlacklisted,\n                        isDirectTransfer\n                    );\n                    // transfer the rest to msg.sender\n                    returnAmount = _transferIfGreaterThanOne(srcToken, msg.sender, returnAmount);\n                    // transfer the received amount of destToken to the beneficiary\n                    destToken.safeTransfer(beneficiary, --receivedAmount);\n                    return (maxAmountIn - returnAmount, receivedAmount, paraswapFeeShare, partnerFeeShare);\n                }\n            }\n        }\n\n        // transfer the received amount of destToken to the beneficiary\n        destToken.safeTransfer(beneficiary, --receivedAmount);\n\n        // if slippage is positive and partner address is 0x0 or fee percent is 0\n        // paraswap will take the surplus, and transfer the rest to msg.sender\n        // if there is no positive slippage, transfer the remaining amount to msg.sender\n        if (surplus > 0) {\n            // If the token is blacklisted, send the remaining amount to the msg.sender\n            // we won't process fees\n            if (blacklistedTokens[srcToken]) {\n                // transfer the remaining amount to msg.sender\n                returnAmount = _transferIfGreaterThanOne(srcToken, msg.sender, remainingAmount);\n                return (maxAmountIn - returnAmount, receivedAmount, 0, 0);\n            }\n            // transfer the surplus to the fee wallet\n            srcToken.safeTransfer(feeWallet, surplus);\n            // transfer the remaining amount to msg.sender\n            returnAmount = _transferIfGreaterThanOne(srcToken, msg.sender, remainingAmount - surplus);\n            return (maxAmountIn - returnAmount, receivedAmount, surplus, 0);\n        } else {\n            // transfer the remaining amount to msg.sender\n            returnAmount = _transferIfGreaterThanOne(srcToken, msg.sender, remainingAmount);\n            return (maxAmountIn - returnAmount, receivedAmount, 0, 0);\n        }\n    }\n\n    /// @notice Process swapExactAmountOut fees for UniV3 swapExactAmountOut, doing a transferFrom user to the fee\n    /// vault or partner and feeWallet\n    /// @param beneficiary The user's address\n    /// @param srcToken The token used to swapExactAmountOut\n    /// @param destToken The token received from the swapExactAmountOut\n    /// @param partnerAndFee Packed partner and fee data\n    /// @param maxAmountIn The amount of srcToken passed to the swapExactAmountOut\n    /// @param receivedAmount The amount of destToken received from the swapExactAmountOut\n    /// @param spentAmount The amount of srcToken used to swapExactAmountOut\n    /// @param quotedAmount The quoted expected amount of srcToken to be used to swapExactAmountOut\n    /// @return totalSpentAmount The total amount of srcToken used to swapExactAmountOut\n    /// @return returnAmount The amount of destToken transfered to the beneficiary\n    /// @return paraswapFeeShare The share of the fees for Paraswap\n    /// @return partnerFeeShare The share of the fees for the partner\n    function processSwapExactAmountOutFeesAndTransferUniV3(\n        address beneficiary,\n        IERC20 srcToken,\n        IERC20 destToken,\n        uint256 partnerAndFee,\n        uint256 maxAmountIn,\n        uint256 receivedAmount,\n        uint256 spentAmount,\n        uint256 quotedAmount\n    )\n        internal\n        returns (uint256 totalSpentAmount, uint256 returnAmount, uint256 paraswapFeeShare, uint256 partnerFeeShare)\n    {\n        // initialize the surplus\n        uint256 surplus;\n\n        // calculate remaining amount\n        uint256 remainingAmount = maxAmountIn - spentAmount;\n\n        // parse partner and fee data\n        (address payable partner, uint256 feeData) = parsePartnerAndFeeData(partnerAndFee);\n\n        // check if the quotedAmount is bigger than the fromAmount\n        if (quotedAmount > maxAmountIn) {\n            revert InvalidQuotedAmount();\n        }\n\n        // calculate the surplus, we do not take the surplus into account if it is less than\n        // MINIMUM_SURPLUS_EPSILON_AND_ONE_WEI\n        if (quotedAmount > spentAmount + MINIMUM_SURPLUS_EPSILON_AND_ONE_WEI) {\n            surplus = quotedAmount - spentAmount;\n            // if the cap surplus flag is passed, we cap the surplus to 1% of the quoted amount\n            if (feeData & IS_CAP_SURPLUS_MASK != 0) {\n                uint256 cappedSurplus = (SURPLUS_PERCENT * quotedAmount) / 10_000;\n                surplus = surplus > cappedSurplus ? cappedSurplus : surplus;\n            }\n        }\n\n        // if partner address is not 0x0\n        if (partner != address(0x0)) {\n            // Check if skip blacklist flag is true\n            bool skipBlacklist = feeData & IS_SKIP_BLACKLIST_MASK != 0;\n            // Check if token is blacklisted\n            bool isBlacklisted = blacklistedTokens[srcToken];\n            // If the token is blacklisted and the skipBlacklist flag is false,\n            // we won't process fees\n            if (!skipBlacklist && isBlacklisted) {\n                // transfer the received amount of destToken to the beneficiary\n                destToken.safeTransfer(beneficiary, receivedAmount);\n                return (spentAmount, receivedAmount, 0, 0);\n            }\n            // Check if direct transfer flag is true\n            bool isDirectTransfer = feeData & IS_DIRECT_TRANSFER_MASK != 0;\n            // partner takes fixed fees feePercent is greater than 0\n            uint256 feePercent = _getAdjustedFeePercent(feeData);\n            if (feePercent > 0) {\n                // fee base = min (spentAmount, quotedAmount)\n                uint256 feeBase = spentAmount < quotedAmount ? spentAmount : quotedAmount;\n                // calculate fixed fees\n                uint256 fee = (feeBase * feePercent) / 10_000;\n                partnerFeeShare = (fee * PARTNER_SHARE_PERCENT) / 10_000;\n                paraswapFeeShare = fee - partnerFeeShare;\n                // distrubite fees from srcToken\n                totalSpentAmount = _distributeFeesUniV3(\n                    remainingAmount,\n                    msg.sender,\n                    srcToken,\n                    partner,\n                    partnerFeeShare,\n                    paraswapFeeShare,\n                    skipBlacklist,\n                    isBlacklisted,\n                    isDirectTransfer\n                ) + spentAmount;\n                // transfer the received amount of destToken to the beneficiary\n                destToken.safeTransfer(beneficiary, receivedAmount);\n                return (totalSpentAmount, receivedAmount, paraswapFeeShare, partnerFeeShare);\n            }\n            // if slippage is postive and referral flag is true\n            else if (feeData & IS_REFERRAL_MASK != 0) {\n                if (surplus > 0) {\n                    // the split is 50% for paraswap, 25% for the referrer and 25% for the user\n                    paraswapFeeShare = (surplus * PARASWAP_REFERRAL_SHARE) / 10_000;\n                    partnerFeeShare = (surplus * PARTNER_REFERRAL_SHARE) / 10_000;\n                    // distribute fees from srcToken\n                    totalSpentAmount = _distributeFeesUniV3(\n                        remainingAmount,\n                        msg.sender,\n                        srcToken,\n                        partner,\n                        partnerFeeShare,\n                        paraswapFeeShare,\n                        skipBlacklist,\n                        isBlacklisted,\n                        isDirectTransfer\n                    ) + spentAmount;\n                    // transfer the received amount of destToken to the beneficiary\n                    destToken.safeTransfer(beneficiary, receivedAmount);\n                    return (totalSpentAmount, receivedAmount, paraswapFeeShare, partnerFeeShare);\n                }\n            }\n            // if slippage is positive and takeSurplus flag is true\n            else if (feeData & IS_TAKE_SURPLUS_MASK != 0) {\n                if (surplus > 0) {\n                    // paraswap takes 50% of the surplus and partner takes the other 50%\n                    paraswapFeeShare = (surplus * PARASWAP_SURPLUS_SHARE) / 10_000;\n                    partnerFeeShare = surplus - paraswapFeeShare;\n                    // If user surplus flag is true, transfer the partner share to the user instead of the partner\n                    if (feeData & IS_USER_SURPLUS_MASK != 0) {\n                        partnerFeeShare = 0;\n                        // Transfer the paraswap share directly to the fee wallet\n                        isDirectTransfer = true;\n                    }\n                    //  partner takes 50% of the surplus and paraswap takes the other 50%\n                    // distrubite fees from srcToken\n                    totalSpentAmount = _distributeFeesUniV3(\n                        remainingAmount,\n                        msg.sender,\n                        srcToken,\n                        partner,\n                        partnerFeeShare,\n                        paraswapFeeShare,\n                        skipBlacklist,\n                        isBlacklisted,\n                        isDirectTransfer\n                    ) + spentAmount;\n                    // transfer the received amount of destToken to the beneficiary\n                    destToken.safeTransfer(beneficiary, receivedAmount);\n                    return (totalSpentAmount, receivedAmount, paraswapFeeShare, partnerFeeShare);\n                }\n            }\n        }\n\n        // transfer the received amount of destToken to the beneficiary\n        destToken.safeTransfer(beneficiary, receivedAmount);\n\n        // if slippage is positive and partner address is 0x0 or fee percent is 0\n        // paraswap will take the surplus\n        if (surplus > 0) {\n            // If the token is blacklisted, we won't process fees\n            if (blacklistedTokens[srcToken]) {\n                return (spentAmount, receivedAmount, 0, 0);\n            }\n            // transfer the surplus to the fee wallet\n            srcToken.safeTransferFrom(msg.sender, feeWallet, surplus);\n        }\n        return (spentAmount + surplus, receivedAmount, surplus, 0);\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                                 PUBLIC\n    //////////////////////////////////////////////////////////////*/\n\n    /// @inheritdoc IAugustusFees\n    function parsePartnerAndFeeData(uint256 partnerAndFee)\n        public\n        pure\n        returns (address payable partner, uint256 feeData)\n    {\n        // solhint-disable-next-line no-inline-assembly\n        assembly (\"memory-safe\") {\n            partner := shr(96, partnerAndFee)\n            feeData := and(partnerAndFee, 0xFFFFFFFFFFFFFFFFFFFFFFFF)\n        }\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                                PRIVATE\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Distribute fees to the partner and paraswap\n    /// @param currentBalance The current balance of the token before distributing the fees\n    /// @param token The token to distribute the fees for\n    /// @param partner The partner address\n    /// @param partnerShare The partner share\n    /// @param paraswapShare The paraswap share\n    /// @param skipBlacklist Whether to skip the blacklist and transfer the fees directly to the partner\n    /// @param isBlacklisted Whether the token is blacklisted\n    /// @param directTransfer Whether to transfer the fees directly to the partner instead of the fee vault\n    /// @return newBalance The new balance of the token after distributing the fees\n    function _distributeFees(\n        uint256 currentBalance,\n        IERC20 token,\n        address payable partner,\n        uint256 partnerShare,\n        uint256 paraswapShare,\n        bool skipBlacklist,\n        bool isBlacklisted,\n        bool directTransfer\n    )\n        private\n        returns (uint256 newBalance)\n    {\n        uint256 totalFees = partnerShare + paraswapShare;\n        if (totalFees == 0) {\n            return currentBalance;\n        } else {\n            if (skipBlacklist && isBlacklisted) {\n                // totalFees should be just the partner share, paraswap does not take fees\n                // on blacklisted tokens, the rest of the fees are sent to sender based on\n                // newBalance = currentBalance - totalFees\n                totalFees = partnerShare;\n                // revert if the balance is not enough to pay the fees\n                if (totalFees > currentBalance) {\n                    revert InsufficientBalanceToPayFees();\n                }\n                if (partnerShare > 0) {\n                    token.safeTransfer(partner, partnerShare);\n                }\n            } else {\n                // revert if the balance is not enough to pay the fees\n                if (totalFees > currentBalance) {\n                    revert InsufficientBalanceToPayFees();\n                }\n                if (directTransfer) {\n                    // transfer the fees directly to the partner and paraswap\n                    if (paraswapShare > 0) {\n                        token.safeTransfer(feeWallet, paraswapShare);\n                    }\n                    if (partnerShare > 0) {\n                        token.safeTransfer(partner, partnerShare);\n                    }\n                } else {\n                    // transfer the fees to the fee vault\n                    token.safeTransfer(address(FEE_VAULT), totalFees);\n                    // Setup fee registration data\n                    address[] memory feeAddresses = new address[](2);\n                    uint256[] memory feeAmounts = new uint256[](2);\n                    feeAddresses[0] = partner;\n                    feeAmounts[0] = partnerShare;\n                    feeAddresses[1] = feeWalletDelegate;\n                    feeAmounts[1] = paraswapShare;\n                    IAugustusFeeVault.FeeRegistration memory feeData =\n                        IAugustusFeeVault.FeeRegistration({ token: token, addresses: feeAddresses, fees: feeAmounts });\n                    // Register the fees\n                    FEE_VAULT.registerFees(feeData);\n                }\n            }\n        }\n        newBalance = currentBalance - totalFees;\n    }\n\n    /// @notice Distribute fees for UniV3\n    /// @param currentBalance The current balance of the token before distributing the fees\n    /// @param payer The user's address\n    /// @param token The token to distribute the fees for\n    /// @param partner The partner address\n    /// @param partnerShare The partner share\n    /// @param paraswapShare The paraswap share\n    /// @param skipBlacklist Whether to skip the blacklist and transfer the fees directly to the partner\n    /// @param isBlacklisted Whether the token is blacklisted\n    /// @param directTransfer Whether to transfer the fees directly to the partner instead of the fee vault\n    /// @return totalFees The total fees distributed\n    function _distributeFeesUniV3(\n        uint256 currentBalance,\n        address payer,\n        IERC20 token,\n        address payable partner,\n        uint256 partnerShare,\n        uint256 paraswapShare,\n        bool skipBlacklist,\n        bool isBlacklisted,\n        bool directTransfer\n    )\n        private\n        returns (uint256 totalFees)\n    {\n        totalFees = partnerShare + paraswapShare;\n        if (totalFees != 0) {\n            if (skipBlacklist && isBlacklisted) {\n                // totalFees should be just the partner share, paraswap does not take fees\n                // on blacklisted tokens, the rest of the fees will remain on the payer's address\n                totalFees = partnerShare;\n                // revert if the balance is not enough to pay the fees\n                if (totalFees > currentBalance) {\n                    revert InsufficientBalanceToPayFees();\n                }\n                // transfer the fees to the partner\n                if (partnerShare > 0) {\n                    // transfer the fees to the partner\n                    token.safeTransferFrom(payer, partner, partnerShare);\n                }\n            } else {\n                // revert if the balance is not enough to pay the fees\n                if (totalFees > currentBalance) {\n                    revert InsufficientBalanceToPayFees();\n                }\n                if (directTransfer) {\n                    // transfer the fees directly to the partner and paraswap\n                    if (paraswapShare > 0) {\n                        token.safeTransferFrom(payer, feeWallet, paraswapShare);\n                    }\n                    if (partnerShare > 0) {\n                        token.safeTransferFrom(payer, partner, partnerShare);\n                    }\n                } else {\n                    // transfer the fees to the fee vault\n                    token.safeTransferFrom(payer, address(FEE_VAULT), totalFees);\n                    // Setup fee registration data\n                    address[] memory feeAddresses = new address[](2);\n                    uint256[] memory feeAmounts = new uint256[](2);\n                    feeAddresses[0] = partner;\n                    feeAmounts[0] = partnerShare;\n                    feeAddresses[1] = feeWalletDelegate;\n                    feeAmounts[1] = paraswapShare;\n                    IAugustusFeeVault.FeeRegistration memory feeData =\n                        IAugustusFeeVault.FeeRegistration({ token: token, addresses: feeAddresses, fees: feeAmounts });\n                    // Register the fees\n                    FEE_VAULT.registerFees(feeData);\n                }\n            }\n            // othwerwise do not transfer the fees\n        }\n        return totalFees;\n    }\n\n    /// @notice Get the adjusted fee percent by masking feePercent with FEE_PERCENT_IN_BASIS_POINTS_MASK,\n    /// if the fee percent is bigger than MAX_FEE_PERCENT, then set it to MAX_FEE_PERCENT\n    /// @param feePercent The fee percent\n    /// @return adjustedFeePercent The adjusted fee percent\n    function _getAdjustedFeePercent(uint256 feePercent) private pure returns (uint256) {\n        // solhint-disable-next-line no-inline-assembly\n        assembly (\"memory-safe\") {\n            feePercent := and(feePercent, FEE_PERCENT_IN_BASIS_POINTS_MASK)\n            // if feePercent is bigger than MAX_FEE_PERCENT, then set it to MAX_FEE_PERCENT\n            if gt(feePercent, MAX_FEE_PERCENT) { feePercent := MAX_FEE_PERCENT }\n        }\n        return feePercent;\n    }\n\n    /// @notice Transfers amount to recipient if the amount is bigger than 1, leaving 1 wei dust on the contract\n    /// @param token The token to transfer\n    /// @param recipient The address to transfer to\n    /// @param amount The amount to transfer\n    function _transferIfGreaterThanOne(\n        IERC20 token,\n        address recipient,\n        uint256 amount\n    )\n        private\n        returns (uint256 amountOut)\n    {\n        if (amount > 1) {\n            unchecked {\n                --amount;\n            }\n            token.safeTransfer(recipient, amount);\n            return amount;\n        }\n        return 0;\n    }\n\n    /// @notice Transfer amount to beneficiary, leaving 1 wei dust on the contract\n    /// @param token The token to transfer\n    /// @param beneficiary The address to transfer to\n    /// @param amount The amount to transfer\n    function _transferAndLeaveDust(IERC20 token, address beneficiary, uint256 amount) private {\n        unchecked {\n            --amount;\n        }\n        token.safeTransfer(beneficiary, amount);\n    }\n}\n"
      },
      "src/routers/swapExactAmountIn/GenericSwapExactAmountIn.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Contracts\nimport { GenericUtils } from \"../../util/GenericUtils.sol\";\n\n// Interfaces\nimport { IERC20 } from \"@openzeppelin/token/ERC20/IERC20.sol\";\nimport { IGenericSwapExactAmountIn } from \"../../interfaces/IGenericSwapExactAmountIn.sol\";\n\n// Libraries\nimport { ERC20Utils } from \"../../libraries/ERC20Utils.sol\";\n\n// Types\nimport { GenericData } from \"../../AugustusV6Types.sol\";\n\n/// @title GenericSwapExactAmountIn\n/// @notice Router for executing generic swaps with exact amount in through an executor\nabstract contract GenericSwapExactAmountIn is IGenericSwapExactAmountIn, GenericUtils {\n    /*//////////////////////////////////////////////////////////////\n                               LIBRARIES\n    //////////////////////////////////////////////////////////////*/\n\n    using ERC20Utils for IERC20;\n\n    /*//////////////////////////////////////////////////////////////\n                          SWAP EXACT AMOUNT IN\n    //////////////////////////////////////////////////////////////*/\n\n    /// @inheritdoc IGenericSwapExactAmountIn\n    function swapExactAmountIn(\n        address executor,\n        GenericData calldata swapData,\n        uint256 partnerAndFee,\n        bytes calldata permit,\n        bytes calldata executorData\n    )\n        external\n        payable\n        whenNotPaused\n        returns (uint256 receivedAmount, uint256 paraswapShare, uint256 partnerShare)\n    {\n        // Dereference swapData\n        IERC20 destToken = swapData.destToken;\n        IERC20 srcToken = swapData.srcToken;\n        uint256 amountIn = swapData.fromAmount;\n        uint256 minAmountOut = swapData.toAmount;\n        uint256 quotedAmountOut = swapData.quotedAmount;\n        address payable beneficiary = swapData.beneficiary;\n\n        // Check if beneficiary is valid\n        if (beneficiary == address(0)) {\n            beneficiary = payable(msg.sender);\n        }\n\n        // Check if toAmount is valid\n        if (minAmountOut == 0) {\n            revert InvalidToAmount();\n        }\n\n        // Check if srcToken is ETH\n        if (srcToken.isETH(amountIn) == 0) {\n            // Check the length of the permit field,\n            // if < 257 and > 0 we should execute regular permit\n            // and if it is >= 257 we execute permit2\n            if (permit.length < 257) {\n                // Permit if needed\n                if (permit.length > 0) {\n                    srcToken.permit(permit);\n                }\n                srcToken.safeTransferFrom(msg.sender, executor, amountIn);\n            } else {\n                // Otherwise Permit2.permitTransferFrom\n                permit2TransferFrom(permit, executor, amountIn);\n            }\n        }\n\n        // Execute swap\n        _callSwapExactAmountInExecutor(executor, executorData, amountIn);\n\n        // Check balance after swap\n        receivedAmount = destToken.getBalance(address(this));\n\n        // Check if swap succeeded\n        if (receivedAmount < minAmountOut) {\n            revert InsufficientReturnAmount();\n        }\n\n        // Process fees and transfer destToken to beneficiary\n        return processSwapExactAmountInFeesAndTransfer(\n            beneficiary, destToken, partnerAndFee, receivedAmount, quotedAmountOut\n        );\n    }\n}\n"
      },
      "src/routers/swapExactAmountOut/GenericSwapExactAmountOut.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IERC20 } from \"@openzeppelin/token/ERC20/IERC20.sol\";\nimport { IGenericSwapExactAmountOut } from \"../../interfaces/IGenericSwapExactAmountOut.sol\";\n\n// Libraries\nimport { ERC20Utils } from \"../../libraries/ERC20Utils.sol\";\n\n// Types\nimport { GenericData } from \"../../AugustusV6Types.sol\";\n\n// Utils\nimport { GenericUtils } from \"../../util/GenericUtils.sol\";\n\n/// @title GenericSwapExactAmountOut\n/// @notice Router for executing generic swaps with exact amount out through an executor\nabstract contract GenericSwapExactAmountOut is IGenericSwapExactAmountOut, GenericUtils {\n    /*//////////////////////////////////////////////////////////////\n                               LIBRARIES\n    //////////////////////////////////////////////////////////////*/\n\n    using ERC20Utils for IERC20;\n\n    /*//////////////////////////////////////////////////////////////\n                         SWAP EXACT AMOUNT OUT\n    //////////////////////////////////////////////////////////////*/\n\n    /// @inheritdoc IGenericSwapExactAmountOut\n    function swapExactAmountOut(\n        address executor,\n        GenericData calldata swapData,\n        uint256 partnerAndFee,\n        bytes calldata permit,\n        bytes calldata executorData\n    )\n        external\n        payable\n        whenNotPaused\n        returns (uint256 spentAmount, uint256 receivedAmount, uint256 paraswapShare, uint256 partnerShare)\n    {\n        // Dereference swapData\n        IERC20 destToken = swapData.destToken;\n        IERC20 srcToken = swapData.srcToken;\n        uint256 maxAmountIn = swapData.fromAmount;\n        uint256 amountOut = swapData.toAmount;\n        uint256 quotedAmountIn = swapData.quotedAmount;\n        address payable beneficiary = swapData.beneficiary;\n\n        // Make sure srcToken and destToken are different\n        if (srcToken == destToken) {\n            revert ArbitrageNotSupported();\n        }\n\n        // Check if beneficiary is valid\n        if (beneficiary == address(0)) {\n            beneficiary = payable(msg.sender);\n        }\n\n        // Check if toAmount is valid\n        if (amountOut == 0) {\n            revert InvalidToAmount();\n        }\n\n        // Check contract balance\n        uint256 balanceBefore = srcToken.getBalance(address(this));\n\n        // Check if srcToken is ETH\n        // Transfer srcToken to executor if not ETH\n        if (srcToken.isETH(maxAmountIn) == 0) {\n            // Check the length of the permit field,\n            // if < 257 and > 0 we should execute regular permit\n            // and if it is >= 257 we execute permit2\n            if (permit.length < 257) {\n                // Permit if needed\n                if (permit.length > 0) {\n                    srcToken.permit(permit);\n                }\n                srcToken.safeTransferFrom(msg.sender, executor, maxAmountIn);\n            } else {\n                // Otherwise Permit2.permitTransferFrom\n                permit2TransferFrom(permit, executor, maxAmountIn);\n            }\n        } else {\n            // If srcToken is ETH, we have to deduct msg.value from balanceBefore\n            balanceBefore = balanceBefore - msg.value;\n        }\n\n        // Execute swap\n        _callSwapExactAmountOutExecutor(executor, executorData, maxAmountIn, amountOut);\n\n        // Check balance of destToken\n        receivedAmount = destToken.getBalance(address(this));\n\n        // Check balance of srcToken, deducting the balance before the swap if it is greater than 1\n        uint256 remainingAmount = srcToken.getBalance(address(this)) - (balanceBefore > 1 ? balanceBefore : 0);\n\n        // Check if swap succeeded\n        if (receivedAmount < amountOut) {\n            revert InsufficientReturnAmount();\n        }\n\n        // Process fees and transfer destToken and srcToken to beneficiary\n        return processSwapExactAmountOutFeesAndTransfer(\n            beneficiary,\n            srcToken,\n            destToken,\n            partnerAndFee,\n            maxAmountIn,\n            remainingAmount,\n            receivedAmount,\n            quotedAmountIn\n        );\n    }\n}\n"
      },
      "src/routers/general/AugustusRFQRouter.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IERC20 } from \"@openzeppelin/token/ERC20/IERC20.sol\";\nimport { IAugustusRFQRouter } from \"../../interfaces/IAugustusRFQRouter.sol\";\n\n// Libraries\nimport { ERC20Utils } from \"../../libraries/ERC20Utils.sol\";\n\n// Types\nimport { AugustusRFQData, OrderInfo } from \"../../AugustusV6Types.sol\";\n\n// Utils\nimport { AugustusRFQUtils } from \"../../util/AugustusRFQUtils.sol\";\nimport { WETHUtils } from \"../../util/WETHUtils.sol\";\nimport { PauseUtils } from \"../../util/PauseUtils.sol\";\nimport { Permit2Utils } from \"../../util/Permit2Utils.sol\";\nimport { AugustusFees } from \"../../fees/AugustusFees.sol\";\n\n/// @title AugustusRFQRouter\n/// @notice A contract for executing direct AugustusRFQ swaps\nabstract contract AugustusRFQRouter is\n    IAugustusRFQRouter,\n    AugustusRFQUtils,\n    AugustusFees,\n    WETHUtils,\n    Permit2Utils,\n    PauseUtils\n{\n    /*//////////////////////////////////////////////////////////////\n                               LIBRARIES\n    //////////////////////////////////////////////////////////////*/\n\n    using ERC20Utils for IERC20;\n\n    /*//////////////////////////////////////////////////////////////\n                             TRY BATCH FILL\n    //////////////////////////////////////////////////////////////*/\n\n    /// @inheritdoc IAugustusRFQRouter\n    // solhint-disable-next-line code-complexity\n    function swapOnAugustusRFQTryBatchFill(\n        AugustusRFQData calldata data,\n        OrderInfo[] calldata orders,\n        bytes calldata permit\n    )\n        external\n        payable\n        whenNotPaused\n        returns (uint256 spentAmount, uint256 receivedAmount)\n    {\n        // Dereference data\n        address payable beneficiary = data.beneficiary;\n        uint256 ordersLength = orders.length;\n        uint256 fromAmount = data.fromAmount;\n        uint256 toAmount = data.toAmount;\n        uint8 wrapApproveDirection = data.wrapApproveDirection;\n\n        // Decode wrapApproveDirection\n        // First 2 bits are for wrap\n        // Next 1 bit is for approve\n        // Last 1 bit is for direction\n\n        uint8 wrap;\n        bool approve;\n        bool direction;\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly (\"memory-safe\") {\n            wrap := and(3, wrapApproveDirection)\n            approve := and(shr(2, wrapApproveDirection), 1)\n            direction := and(shr(3, wrapApproveDirection), 1)\n        }\n\n        // Check if beneficiary is valid\n        if (beneficiary == address(0)) {\n            beneficiary = payable(msg.sender);\n        }\n\n        // Check if toAmount is valid\n        if (toAmount == 0) {\n            revert InvalidToAmount();\n        }\n\n        // Check if ordersLength is valid\n        if (ordersLength == 0) {\n            revert InvalidOrdersLength();\n        }\n\n        // Check if msg.sender is authorized to be the taker for all orders\n        for (uint256 i = 0; i < ordersLength; ++i) {\n            _checkAuthorization(orders[i].order.nonceAndMeta);\n        }\n\n        // Dereference srcToken and destToken\n        IERC20 srcToken = IERC20(orders[0].order.takerAsset);\n        IERC20 destToken = IERC20(orders[0].order.makerAsset);\n\n        // Check if we need to wrap or permit\n        if (wrap != 1) {\n            // If msg.value is not 0, revert\n            if (msg.value > 0) {\n                revert IncorrectEthAmount();\n            }\n\n            // Check the length of the permit field,\n            // if < 257 and > 0 we should execute regular permit\n            // and if it is >= 257 we execute permit2\n            if (permit.length < 257) {\n                // Permit if needed\n                if (permit.length > 0) {\n                    srcToken.permit(permit);\n                }\n                srcToken.safeTransferFrom(msg.sender, address(this), fromAmount);\n            } else {\n                // Otherwise Permit2.permitTransferFrom\n                permit2TransferFrom(permit, address(this), fromAmount);\n            }\n        } else {\n            // Check if msg.value is equal to fromAmount\n            if (fromAmount != msg.value) {\n                revert IncorrectEthAmount();\n            }\n            // If it is ETH. wrap it to WETH\n            WETH.deposit{ value: fromAmount }();\n        }\n\n        if (approve) {\n            // Approve srcToken to AugustusRFQ\n            srcToken.approve(address(AUGUSTUS_RFQ));\n        }\n\n        // Check if we need to execute a swapExactAmountIn or a swapExactAmountOut\n        if (!direction) {\n            // swapExactAmountIn\n            // Unwrap WETH if needed\n            if (wrap == 2) {\n                // Execute tryBatchFillOrderTakerAmount\n                AUGUSTUS_RFQ.tryBatchFillOrderTakerAmount(orders, fromAmount, address(this));\n                // Check received amount\n                receivedAmount = IERC20(WETH).getBalance(address(this));\n                // Check if swap succeeded\n                if (receivedAmount < toAmount) {\n                    revert InsufficientReturnAmount();\n                }\n                // Unwrap WETH\n                WETH.withdraw(--receivedAmount);\n                // Transfer ETH to beneficiary\n                ERC20Utils.ETH.safeTransfer(beneficiary, receivedAmount);\n            } else {\n                // Check balance of beneficiary before swap\n                uint256 beforeBalance = destToken.getBalance(beneficiary);\n                // Execute tryBatchFillOrderTakerAmount\n                AUGUSTUS_RFQ.tryBatchFillOrderTakerAmount(orders, fromAmount, beneficiary);\n                // set receivedAmount to afterBalance - beforeBalance\n                receivedAmount = destToken.getBalance(beneficiary) - beforeBalance;\n                // Check if swap succeeded\n                if (receivedAmount < toAmount) {\n                    revert InsufficientReturnAmount();\n                }\n            }\n\n            // Return spentAmount and receivedAmount\n            return (fromAmount, receivedAmount);\n        } else {\n            // swapExactAmountOut\n            // Unwrap WETH if needed\n            if (wrap == 2) {\n                // Execute tryBatchFillOrderMakerAmount\n                AUGUSTUS_RFQ.tryBatchFillOrderMakerAmount(orders, toAmount, address(this));\n                // Check remaining WETH balance\n                receivedAmount = IERC20(WETH).getBalance(address(this));\n                // Unwrap WETH\n                WETH.withdraw(--receivedAmount);\n                // Transfer ETH to beneficiary\n                ERC20Utils.ETH.safeTransfer(beneficiary, receivedAmount);\n                // Set toAmount to receivedAmount\n                toAmount = receivedAmount;\n            } else {\n                // Execute tryBatchFillOrderMakerAmount\n                AUGUSTUS_RFQ.tryBatchFillOrderMakerAmount(orders, toAmount, beneficiary);\n            }\n\n            // Check remaining amount\n            uint256 remainingAmount = srcToken.getBalance(address(this));\n\n            // Send remaining srcToken to msg.sender\n            if (remainingAmount > 1) {\n                // If srcToken was ETH\n                if (wrap == 1) {\n                    // Unwrap WETH\n                    WETH.withdraw(--remainingAmount);\n                    // Transfer ETH to msg.sender\n                    ERC20Utils.ETH.safeTransfer(msg.sender, remainingAmount);\n                } else {\n                    // Transfer remaining srcToken to msg.sender\n                    srcToken.safeTransfer(msg.sender, --remainingAmount);\n                }\n            }\n\n            // Return spentAmount and receivedAmount\n            return (fromAmount - remainingAmount, toAmount);\n        }\n    }\n}\n"
      },
      "src/util/AugustusRFQUtils.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IAugustusRFQ } from \"../interfaces/IAugustusRFQ.sol\";\nimport { IERC20 } from \"@openzeppelin/token/ERC20/IERC20.sol\";\n\n// Libraries\nimport { ERC20Utils } from \"../libraries/ERC20Utils.sol\";\n\n/// @title AugustusRFQUtils\n/// @notice A contract containing common utilities for AugustusRFQ swaps\ncontract AugustusRFQUtils {\n    /*//////////////////////////////////////////////////////////////\n                               LIBRARIES\n    //////////////////////////////////////////////////////////////*/\n\n    using ERC20Utils for IERC20;\n\n    /*//////////////////////////////////////////////////////////////\n                                 ERRORS\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev Emitted when the msg.sender is not authorized to be the taker\n    error UnauthorizedUser();\n\n    /// @dev Emitted when the orders length is 0\n    error InvalidOrdersLength();\n\n    /*//////////////////////////////////////////////////////////////\n                               CONSTANTS\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev AugustusRFQ address\n    IAugustusRFQ public immutable AUGUSTUS_RFQ; // solhint-disable-line var-name-mixedcase\n\n    /*//////////////////////////////////////////////////////////////\n                               CONSTRUCTOR\n    //////////////////////////////////////////////////////////////*/\n\n    constructor(address _augustusRFQ) {\n        AUGUSTUS_RFQ = IAugustusRFQ(_augustusRFQ);\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                                 INTERNAL\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev Check if the msg.sender is authorized to be the taker\n    function _checkAuthorization(uint256 nonceAndMeta) internal view {\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            // Parse nonceAndMeta\n            if xor(and(nonceAndMeta, 0xffffffffffffffffffffffffffffffffffffffff), 0) {\n                // If the taker is not 0, we check if the msg.sender is authorized\n                if xor(and(nonceAndMeta, 0xffffffffffffffffffffffffffffffffffffffff), caller()) {\n                    // The taker does not match the originalSender, revert\n                    mstore(0, 0x02a43f8b00000000000000000000000000000000000000000000000000000000) // function\n                        // selector for error UnauthorizedUser();\n                    revert(0, 4)\n                }\n            }\n        }\n    }\n}\n"
      },
      "src/util/BalancerV2Utils.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Contracts\nimport { AugustusFees } from \"../fees/AugustusFees.sol\";\n\n// Interfaces\nimport { IERC20 } from \"@openzeppelin/token/ERC20/IERC20.sol\";\n\n// Utils\nimport { Permit2Utils } from \"./Permit2Utils.sol\";\nimport { PauseUtils } from \"./PauseUtils.sol\";\n\n/// @title BalancerV2Utils\n/// @notice A contract containing common utilities for BalancerV2 swaps\nabstract contract BalancerV2Utils is AugustusFees, Permit2Utils, PauseUtils {\n    /*//////////////////////////////////////////////////////////////\n                                ERRORS\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev Emitted when the passed selector is invalid\n    error InvalidSelector();\n\n    /*//////////////////////////////////////////////////////////////\n                               CONSTANTS\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev BalancerV2 vault address\n    address payable public immutable BALANCER_VAULT; // solhint-disable-line var-name-mixedcase\n\n    /*//////////////////////////////////////////////////////////////\n                               CONSTRUCTOR\n    //////////////////////////////////////////////////////////////*/\n\n    constructor(address payable _balancerVault) {\n        BALANCER_VAULT = _balancerVault;\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                                 INTERNAL\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev Decode srcToken, destToken from balancerData, beneficiary and approve flag from beneficiaryAndApproveFlag\n    function _decodeBalancerV2Params(\n        uint256 beneficiaryAndApproveFlag,\n        bytes calldata balancerData\n    )\n        internal\n        pure\n        returns (IERC20 srcToken, IERC20 destToken, address payable beneficiary, bool approve)\n    {\n        // solhint-disable-next-line no-inline-assembly\n        assembly (\"memory-safe\") {\n            // Parse beneficiaryAndApproveFlag\n            beneficiary := and(beneficiaryAndApproveFlag, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)\n            approve := shr(255, beneficiaryAndApproveFlag)\n            // Load calldata without selector\n            let callDataWithoutSelector := add(4, balancerData.offset)\n            // Check selector\n            switch calldataload(balancerData.offset)\n            // If the selector is for swap(tuple singleSwap,tuple funds,uint256 limit,uint256 deadline)\n            case 0x52bbbe2900000000000000000000000000000000000000000000000000000000 {\n                // Load srcToken from singleSswap.assetIn\n                srcToken := calldataload(add(callDataWithoutSelector, 288))\n                // Load destToken from singleSswap.assetOut\n                destToken := calldataload(add(callDataWithoutSelector, 320))\n            }\n            // If the selector is for batchSwap(uint8 kind,tuple[] swaps,address[] assets,tuple funds,int256[]\n            // limits,uint256 deadline)\n            case 0x945bcec900000000000000000000000000000000000000000000000000000000 {\n                // Load assetOffset from balancerData\n                let assetsOffset := calldataload(add(callDataWithoutSelector, 64))\n                // Load assetCount at assetOffset\n                let assetsCount := calldataload(add(callDataWithoutSelector, assetsOffset))\n                // Get swapExactAmountIn type from first 32 bytes of balancerData\n                let swapType := calldataload(callDataWithoutSelector)\n                // Set fromAmount, srcToken, toAmount and destToken based on swapType\n                switch eq(swapType, 1)\n                case 1 {\n                    // Load srcToken as the last asset in balancerData.assets\n                    srcToken := calldataload(add(callDataWithoutSelector, add(assetsOffset, mul(assetsCount, 32))))\n                    // Load destToken as the first asset in balancerData.assets\n                    destToken := calldataload(add(callDataWithoutSelector, add(assetsOffset, 32)))\n                }\n                default {\n                    // Load srcToken as the first asset in balancerData.assets\n                    srcToken := calldataload(add(callDataWithoutSelector, add(assetsOffset, 32)))\n                    // Load destToken as the last asset in balancerData.assets\n                    destToken := calldataload(add(callDataWithoutSelector, add(assetsOffset, mul(assetsCount, 32))))\n                }\n            }\n            default {\n                // If the selector is invalid, revert\n                mstore(0, 0x7352d91c00000000000000000000000000000000000000000000000000000000) // store the\n                    // selector for error InvalidSelector();\n                revert(0, 4)\n            }\n            // Balancer users 0x0 as ETH address so we need to convert it\n            if eq(srcToken, 0) { srcToken := 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE }\n            if eq(destToken, 0) { destToken := 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE }\n        }\n        return (srcToken, destToken, beneficiary, approve);\n    }\n\n    /// @dev Call balancerVault with data\n    function _callBalancerV2(bytes calldata balancerData) internal {\n        address payable targetAddress = BALANCER_VAULT;\n        // solhint-disable-next-line no-inline-assembly\n        assembly (\"memory-safe\") {\n            // Load free memory pointer\n            let ptr := mload(64)\n            // Copy the balancerData to memory\n            calldatacopy(ptr, balancerData.offset, balancerData.length)\n            // Execute the call on balancerVault\n            if iszero(call(gas(), targetAddress, callvalue(), ptr, balancerData.length, 0, 0)) {\n                returndatacopy(ptr, 0, returndatasize()) // copy the revert data to memory\n                revert(ptr, returndatasize()) // revert with the revert data\n            }\n        }\n    }\n}\n"
      },
      "src/util/UniswapV2Utils.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Contracts\nimport { AugustusFees } from \"../fees/AugustusFees.sol\";\n\n// Interfaces\nimport { IERC20 } from \"@openzeppelin/token/ERC20/IERC20.sol\";\n\n// Utils\nimport { WETHUtils } from \"./WETHUtils.sol\";\nimport { Permit2Utils } from \"./Permit2Utils.sol\";\nimport { PauseUtils } from \"./PauseUtils.sol\";\n\n/// @title UniswapV2Utils\n/// @notice A contract containing common utilities for UniswapV2 swaps\nabstract contract UniswapV2Utils is AugustusFees, WETHUtils, Permit2Utils, PauseUtils {\n    /*//////////////////////////////////////////////////////////////\n                               CONSTANTS\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev Used to caluclate pool address\n    uint256 public immutable UNISWAP_V2_POOL_INIT_CODE_HASH;\n\n    /// @dev Right padded FF + UniswapV2Factory address\n    uint256 public immutable UNISWAP_V2_FACTORY_AND_FF;\n\n    /*//////////////////////////////////////////////////////////////\n                               CONSTRUCTOR\n    //////////////////////////////////////////////////////////////*/\n\n    constructor(uint256 _uniswapV2FactoryAndFF, uint256 _uniswapV2PoolInitCodeHash) {\n        UNISWAP_V2_FACTORY_AND_FF = _uniswapV2FactoryAndFF;\n        UNISWAP_V2_POOL_INIT_CODE_HASH = _uniswapV2PoolInitCodeHash;\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                               INTERNAL\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev Loops through UniswapV2 pools in backword direction and swaps exact amount out\n    function _callUniswapV2PoolsSwapExactOut(uint256 amountOut, IERC20 srcToken, bytes calldata pools) internal {\n        uint256 uniswapV2FactoryAndFF = UNISWAP_V2_FACTORY_AND_FF;\n        uint256 uniswapV2PoolInitCodeHash = UNISWAP_V2_POOL_INIT_CODE_HASH;\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            function calculatePoolAddress(\n                poolMemoryPtr, poolCalldataPtr, _uniswapV2FactoryAndFF, _uniswapV2PoolInitCodeHash\n            ) {\n                // Calculate the pool address\n                // We can do this by first calling the keccak256 function on the passed pool values and then\n                // calculating keccak256(abi.encodePacked(hex'ff', address(factory_address),\n                // keccak256(abi.encodePacked(token0, token1)), POOL_INIT_CODE_HASH));\n                // The first 20 bytes of the computed address are the pool address\n\n                // Store 0xff + factory address (right padded)\n                mstore(poolMemoryPtr, _uniswapV2FactoryAndFF)\n\n                // Store pools offset + 21 bytes (UNISWAP_V2_FACTORY_AND_FF SIZE)\n                let token0ptr := add(poolMemoryPtr, 21)\n\n                // Copy pool data (skip last bit) to free memory pointer + 21 bytes (UNISWAP_V2_FACTORY_AND_FF SIZE)\n                calldatacopy(token0ptr, poolCalldataPtr, 40)\n\n                // Calculate keccak256(abi.encode(address(token0), address(token1))\n                mstore(token0ptr, keccak256(token0ptr, 40))\n\n                // Store POOL_INIT_CODE_HASH\n                mstore(add(token0ptr, 32), _uniswapV2PoolInitCodeHash)\n\n                // Calculate address(keccak256(abi.encodePacked(hex'ff', address(factory_address),\n                // keccak256(abi.encode(token0, token1), POOL_INIT_CODE_HASH)));\n                mstore(poolMemoryPtr, and(keccak256(poolMemoryPtr, 85), 0xffffffffffffffffffffffffffffffffffffffff)) // 21\n                    // + 32 + 32\n            }\n\n            // Calculate pool count\n            let poolCount := div(pools.length, 64)\n\n            // Initilize memory pointers\n            let amounts := mload(64) // pointer for amounts array\n            let poolAddresses := add(amounts, add(mul(poolCount, 32), 32)) // pointer for pools array\n            let emptyPtr := add(poolAddresses, mul(poolCount, 32)) // pointer for empty memory\n\n            // Initialize fromAmount\n            let fromAmount := 0\n\n            // Set the final amount in the amounts array to amountOut\n            mstore(add(amounts, mul(poolCount, 0x20)), amountOut)\n\n            //---------------------------------//\n            // Calculate Pool Addresses and Amounts\n            //---------------------------------//\n\n            // Calculate pool addresses\n            for { let i := 0 } lt(i, poolCount) { i := add(i, 1) } {\n                calculatePoolAddress(\n                    add(poolAddresses, mul(i, 32)),\n                    add(pools.offset, mul(i, 64)),\n                    uniswapV2FactoryAndFF,\n                    uniswapV2PoolInitCodeHash\n                )\n            }\n\n            // Rerverse loop through pools and calculate amounts\n            for { let i := poolCount } gt(i, 0) { i := sub(i, 1) } {\n                // Use previous pool data to calculate amount in\n                let indexSub1 := sub(i, 1)\n\n                // Get pool address\n                let poolAddress := mload(add(poolAddresses, mul(indexSub1, 32)))\n\n                // Get direction\n                let direction := and(1, calldataload(add(add(pools.offset, mul(indexSub1, 64)), 32)))\n\n                // Get amount\n                let amount := mload(add(amounts, mul(i, 32)))\n\n                //---------------------------------//\n                // Calculate Amount In\n                //---------------------------------//\n\n                //---------------------------------//\n                // Get Reserves\n                //---------------------------------//\n\n                // Store the selector\n                mstore(emptyPtr, 0x0902f1ac00000000000000000000000000000000000000000000000000000000) // 'getReserves()'\n                // selector\n\n                // Perform the external 'getReserves' call - outputs directly to ptr\n                if iszero(staticcall(gas(), poolAddress, emptyPtr, 4, emptyPtr, 64)) {\n                    returndatacopy(0, 0, returndatasize()) // Copy the error message to the start of memory\n                    revert(0, returndatasize()) // Revert with the error message\n                }\n\n                // If direction is true, getReserves returns (reserve0, reserve1)\n                // If direction is false, getReserves returns (reserve1, reserve0) -> swap the values\n\n                // Load the reserve0 value returned by the 'getReserves' call.\n                let reserve1 := mload(emptyPtr)\n\n                // Load the reserve1 value returned by the 'getReserves' call.\n                let reserve0 := mload(add(emptyPtr, 32))\n\n                // Check if direction is true\n                if direction {\n                    // swap reserve0 and reserve1\n                    let temp := reserve0\n                    reserve0 := reserve1\n                    reserve1 := temp\n                }\n\n                //---------------------------------//\n\n                // Calculate numerator = reserve0 * amountOut * 10000\n                let numerator := mul(mul(reserve0, amount), 10000)\n\n                // Calculate denominator = (reserve1 - amountOut) * 9970\n                let denominator := mul(sub(reserve1, amount), 9970)\n\n                // Calculate amountIn = numerator / denominator + 1\n                fromAmount := add(div(numerator, denominator), 1)\n\n                // Store amountIn for the previous pool\n                mstore(add(amounts, mul(indexSub1, 32)), fromAmount)\n            }\n\n            //---------------------------------//\n\n            // Initialize variables\n            let poolAddress := 0\n            let nextPoolAddress := 0\n\n            //---------------------------------//\n            // Loop Swap Through Pools\n            //---------------------------------//\n\n            // Loop for each pool\n            for { let i := 0 } lt(i, poolCount) { i := add(i, 1) } {\n                // Check if it is the first pool\n                if iszero(poolAddress) {\n                    // If it is the first pool, we need to transfer amount of srcToken to poolAddress\n                    // Load first pool address\n                    poolAddress := mload(poolAddresses)\n\n                    //---------------------------------//\n                    // Transfer amount of srcToken to poolAddress\n                    //---------------------------------//\n\n                    // Transfer fromAmount of srcToken to poolAddress\n                    mstore(emptyPtr, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) // store the\n                        // selector\n                        // (function transfer(address recipient, uint256 amount))\n                    mstore(add(emptyPtr, 4), poolAddress) // store the recipient\n                    mstore(add(emptyPtr, 36), fromAmount) // store the amount\n                    pop(call(gas(), srcToken, 0, emptyPtr, 68, 0, 32)) // call transfer\n\n                    //---------------------------------//\n                }\n\n                // Adjust toAddress depending on if it is the last pool in the array\n                let toAddress := address()\n\n                // Check if it is not the last pool\n                if lt(add(i, 1), poolCount) {\n                    // Load next pool address\n                    nextPoolAddress := mload(add(poolAddresses, mul(add(i, 1), 32)))\n\n                    // Adjust toAddress to next pool address\n                    toAddress := nextPoolAddress\n                }\n\n                // Check direction\n                let direction := and(1, calldataload(add(add(pools.offset, mul(i, 64)), 32)))\n\n                // if direction is 1, amount0out is 0 and amount1out is amount[i+1]\n                // if direction is 0, amount0out is amount[i+1] and amount1out is 0\n\n                // Load amount[i+1]\n                let amount := mload(add(amounts, mul(add(i, 1), 32)))\n\n                // Initialize amount0Out and amount1Out\n                let amount0Out := amount\n                let amount1Out := 0\n\n                // Check if direction is true\n                if direction {\n                    // swap amount0Out and amount1Out\n                    let temp := amount0Out\n                    amount0Out := amount1Out\n                    amount1Out := temp\n                }\n\n                //---------------------------------//\n                // Perform Swap\n                //---------------------------------//\n\n                // Load the 'swap' selector, amount0Out, amount1Out, toAddress and data(\"\") into memory.\n                mstore(emptyPtr, 0x022c0d9f00000000000000000000000000000000000000000000000000000000)\n                // 'swap()' selector\n                mstore(add(emptyPtr, 4), amount0Out) // amount0Out\n                mstore(add(emptyPtr, 36), amount1Out) // amount1Out\n                mstore(add(emptyPtr, 68), toAddress) // toAddress\n                mstore(add(emptyPtr, 100), 0x80) // data length\n                mstore(add(emptyPtr, 132), 0) // data\n\n                // Perform the external 'swap' call\n                if iszero(call(gas(), poolAddress, 0, emptyPtr, 164, 0, 64)) {\n                    // The call failed; we retrieve the exact error message and revert with it\n                    returndatacopy(0, 0, returndatasize()) // Copy the error message to the start of memory\n                    revert(0, returndatasize()) // Revert with the error message\n                }\n\n                //---------------------------------//\n\n                // Set poolAddress to nextPoolAddress\n                poolAddress := nextPoolAddress\n            }\n\n            //---------------------------------//\n        }\n    }\n\n    /// @dev Loops through UniswapV2 pools and swaps exact amount in\n    function _callUniswapV2PoolsSwapExactIn(\n        uint256 fromAmount,\n        IERC20 srcToken,\n        bytes calldata pools,\n        address payer,\n        bytes calldata permit2\n    )\n        internal\n    {\n        uint256 uniswapV2FactoryAndFF = UNISWAP_V2_FACTORY_AND_FF;\n        uint256 uniswapV2PoolInitCodeHash = UNISWAP_V2_POOL_INIT_CODE_HASH;\n        address permit2Address = PERMIT2;\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            //---------------------------------//\n            // Loop Swap Through Pools\n            //---------------------------------//\n\n            // Calculate pool count\n            let poolCount := div(pools.length, 64)\n\n            // Initialize variables\n            let p := 0\n            let poolAddress := 0\n            let nextPoolAddress := 0\n            let direction := 0\n\n            // Loop for each pool\n            for { let i := 0 } lt(i, poolCount) { i := add(i, 1) } {\n                // Check if it is the first pool\n                if iszero(p) {\n                    //---------------------------------//\n                    // Calculate Pool Address\n                    //---------------------------------//\n\n                    // Calculate the pool address\n                    // We can do this by first calling the keccak256 function on the passed pool values and then\n                    // calculating keccak256(abi.encodePacked(hex'ff', address(factory_address),\n                    // keccak256(abi.encodePacked(token0,token1)), POOL_INIT_CODE_HASH));\n                    // The first 20 bytes of the computed address are the pool address\n\n                    // Get free memory pointer\n                    let ptr := mload(64)\n\n                    // Store 0xff + factory address (right padded)\n                    mstore(ptr, uniswapV2FactoryAndFF)\n\n                    // Store pools offset + 21 bytes (UNISWAP_V2_FACTORY_AND_FF SIZE)\n                    let token0ptr := add(ptr, 21)\n\n                    // Copy pool data (skip last bit) to free memory pointer + 21 bytes (UNISWAP_V2_FACTORY_AND_FF\n                    // SIZE)\n                    calldatacopy(token0ptr, pools.offset, 40)\n\n                    // Calculate keccak256(abi.encodePacked(address(token0), address(token1))\n                    mstore(token0ptr, keccak256(token0ptr, 40))\n\n                    // Store POOL_INIT_CODE_HASH\n                    mstore(add(token0ptr, 32), uniswapV2PoolInitCodeHash)\n\n                    // Calculate keccak256(abi.encodePacked(hex'ff', address(factory_address),\n                    // keccak256(abi.encode(token0,\n                    // token1, fee)), POOL_INIT_CODE_HASH));\n                    mstore(ptr, keccak256(ptr, 85)) // 21 + 32 + 32\n\n                    // Load pool\n                    p := mload(ptr)\n\n                    // Get the first 20 bytes of the computed address\n                    poolAddress := and(p, 0xffffffffffffffffffffffffffffffffffffffff)\n\n                    //---------------------------------//\n\n                    //---------------------------------//\n                    // Transfer fromAmount of srcToken to poolAddress\n                    //---------------------------------//\n\n                    switch eq(payer, address())\n                    // if payer is this contract, transfer fromAmount of srcToken to poolAddress\n                    case 1 {\n                        // Transfer fromAmount of srcToken to poolAddress\n                        mstore(ptr, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) // store the\n                            // selector\n                            // (function transfer(address recipient, uint256 amount))\n                        mstore(add(ptr, 4), poolAddress) // store the recipient\n                        mstore(add(ptr, 36), fromAmount) // store the amount\n                        pop(call(gas(), srcToken, 0, ptr, 68, 0, 32)) // call transfer\n                    }\n                    // othwerwise transferFrom fromAmount of srcToken to poolAddress from payer\n                    default {\n                        switch gt(permit2.length, 256)\n                        case 0 {\n                            // Transfer fromAmount of srcToken to poolAddress\n                            mstore(ptr, 0x23b872dd00000000000000000000000000000000000000000000000000000000) // store\n                                // the selector\n                            // (function transferFrom(address sender, address recipient,\n                            // uint256 amount))\n                            mstore(add(ptr, 4), payer) // store the sender\n                            mstore(add(ptr, 36), poolAddress) // store the recipient\n                            mstore(add(ptr, 68), fromAmount) // store the amount\n                            pop(call(gas(), srcToken, 0, ptr, 100, 0, 32)) // call transferFrom\n                        }\n                        default {\n                            // Otherwise Permit2.permitTransferFrom\n                            // Store function selector\n                            mstore(ptr, 0x30f28b7a00000000000000000000000000000000000000000000000000000000)\n                            // permitTransferFrom()\n                            calldatacopy(add(ptr, 4), permit2.offset, permit2.length) // Copy data to memory\n                            mstore(add(ptr, 132), poolAddress) // Store recipient\n                            mstore(add(ptr, 164), fromAmount) // Store amount\n                            mstore(add(ptr, 196), payer) // Store payer\n                            // Call permit2.permitTransferFrom and revert if call failed\n                            if iszero(call(gas(), permit2Address, 0, ptr, add(permit2.length, 4), 0, 0)) {\n                                mstore(0, 0x6b836e6b00000000000000000000000000000000000000000000000000000000) // Store\n                                    // error selector\n                                    // error Permit2Failed()\n                                revert(0, 4)\n                            }\n                        }\n                    }\n\n                    //---------------------------------//\n                }\n\n                // Direction is the first bit of the pool data\n                direction := and(1, calldataload(add(add(pools.offset, mul(i, 64)), 32)))\n\n                //---------------------------------//\n                // Calculate Amount Out\n                //---------------------------------//\n\n                //---------------------------------//\n                // Get Reserves\n                //---------------------------------//\n\n                // Get free memory pointer\n                let ptr := mload(64)\n\n                // Store the selector\n                mstore(ptr, 0x0902f1ac00000000000000000000000000000000000000000000000000000000) // 'getReserves()'\n                // selector\n\n                // Perform the external 'getReserves' call - outputs directly to ptr\n                if iszero(staticcall(gas(), poolAddress, ptr, 4, ptr, 64)) {\n                    returndatacopy(0, 0, returndatasize()) // Copy the error message to the start of memory\n                    revert(0, returndatasize()) // Revert with the error message\n                }\n\n                // If direction is true, getReserves returns (reserve0, reserve1)\n                // If direction is false, getReserves returns (reserve1, reserve0) -> swap the values\n\n                // Load the reserve0 value returned by the 'getReserves' call.\n                let reserve1 := mload(ptr)\n\n                // Load the reserve1 value returned by the 'getReserves' call.\n                let reserve0 := mload(add(ptr, 32))\n\n                // Check if direction is true\n                if direction {\n                    // swap reserve0 and reserve1\n                    let temp := reserve0\n                    reserve0 := reserve1\n                    reserve1 := temp\n                }\n\n                //---------------------------------//\n\n                // Calculate amount based on fee\n                let amountWithFee := mul(fromAmount, 9970)\n\n                // Calculate numerator = amountWithFee * reserve1\n                let numerator := mul(amountWithFee, reserve1)\n\n                // Calculate denominator = reserve0 * 10000 + amountWithFee\n                let denominator := add(mul(reserve0, 10000), amountWithFee)\n\n                // Calculate amountOut = numerator / denominator\n                let amountOut := div(numerator, denominator)\n\n                fromAmount := amountOut\n\n                // if direction is true, amount0Out is 0 and amount1Out is fromAmount,\n                // otherwise amount0Out is fromAmount and amount1Out is 0\n\n                let amount0Out := fromAmount\n                let amount1Out := 0\n\n                // swap amount0Out and amount1Out if direction is false\n                if direction {\n                    amount0Out := 0\n                    amount1Out := fromAmount\n                }\n\n                //---------------------------------//\n\n                // Adjust toAddress depending on if it is the last pool in the array\n                let toAddress := address()\n\n                // Check if it is not the last pool\n                if lt(add(i, 1), poolCount) {\n                    //---------------------------------//\n                    // Calculate Next Pool Address\n                    //---------------------------------//\n\n                    // Store 0xff + factory address (right padded)\n                    mstore(ptr, uniswapV2FactoryAndFF)\n\n                    // Store pools offset + 21 bytes (UNISWAP_V2_FACTORY_AND_FF SIZE)\n                    let token0ptr := add(ptr, 21)\n\n                    // Copy next pool data to free memory pointer + 21 bytes (UNISWAP_V2_FACTORY_AND_FF SIZE)\n                    calldatacopy(token0ptr, add(pools.offset, mul(add(i, 1), 64)), 40)\n\n                    // Calculate keccak256(abi.encodePacked(address(token0), address(token1))\n                    mstore(token0ptr, keccak256(token0ptr, 40))\n\n                    // Store POOL_INIT_CODE_HASH\n                    mstore(add(token0ptr, 32), uniswapV2PoolInitCodeHash)\n\n                    // Calculate keccak256(abi.encodePacked(hex'ff', address(factory_address),\n                    // keccak256(abi.encode(token0,\n                    // token1), POOL_INIT_CODE_HASH));\n                    mstore(ptr, keccak256(ptr, 85)) // 21 + 32 + 32\n\n                    // Load pool\n                    p := mload(ptr)\n\n                    // Get the first 20 bytes of the computed address\n                    nextPoolAddress := and(p, 0xffffffffffffffffffffffffffffffffffffffff)\n\n                    // Adjust toAddress to next pool address\n                    toAddress := nextPoolAddress\n\n                    //---------------------------------//\n                }\n\n                //---------------------------------//\n                // Perform Swap\n                //---------------------------------//\n\n                // Load the 'swap' selector, amount0Out, amount1Out, toAddress and data(\"\") into memory.\n                mstore(ptr, 0x022c0d9f00000000000000000000000000000000000000000000000000000000)\n                // 'swap()' selector\n                mstore(add(ptr, 4), amount0Out) // amount0Out\n                mstore(add(ptr, 36), amount1Out) // amount1Out\n                mstore(add(ptr, 68), toAddress) // toAddress\n                mstore(add(ptr, 100), 0x80) // data length\n                mstore(add(ptr, 132), 0) // data\n\n                // Perform the external 'swap' call\n                if iszero(call(gas(), poolAddress, 0, ptr, 164, 0, 64)) {\n                    // The call failed; we retrieve the exact error message and revert with it\n                    returndatacopy(0, 0, returndatasize()) // Copy the error message to the start of memory\n                    revert(0, returndatasize()) // Revert with the error message\n                }\n\n                //---------------------------------//\n\n                // Set poolAddress to nextPoolAddress\n                poolAddress := nextPoolAddress\n            }\n\n            //---------------------------------//\n        }\n    }\n}\n"
      },
      "src/util/UniswapV3Utils.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Contracts\nimport { AugustusFees } from \"../fees/AugustusFees.sol\";\n\n// Interfaces\nimport { IUniswapV3SwapCallback } from \"../interfaces/IUniswapV3SwapCallback.sol\";\n\n// Libraries\nimport { SafeCastLib } from \"@solady/utils/SafeCastLib.sol\";\n\n// Utils\nimport { WETHUtils } from \"./WETHUtils.sol\";\nimport { Permit2Utils } from \"./Permit2Utils.sol\";\nimport { PauseUtils } from \"./PauseUtils.sol\";\n\n/// @title UniswapV3Utils\n/// @notice A contract containing common utilities for UniswapV3 swaps\nabstract contract UniswapV3Utils is IUniswapV3SwapCallback, AugustusFees, WETHUtils, Permit2Utils, PauseUtils {\n    /*//////////////////////////////////////////////////////////////\n                               LIBRARIES\n    //////////////////////////////////////////////////////////////*/\n\n    using SafeCastLib for int256;\n\n    /*//////////////////////////////////////////////////////////////\n                                 ERRORS\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Error emitted if the caller is not a Uniswap V3 pool\n    error InvalidCaller();\n    /// @notice Error emitted if the transfer of tokens to the pool inside the callback failed\n    error CallbackTransferFailed();\n\n    /*//////////////////////////////////////////////////////////////\n                               CONSTANTS\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev Used to caluclate pool address\n    uint256 public immutable UNISWAP_V3_POOL_INIT_CODE_HASH;\n\n    /// @dev Right padded FF + UniswapV3Factory address\n    uint256 public immutable UNISWAP_V3_FACTORY_AND_FF;\n\n    /*//////////////////////////////////////////////////////////////\n                               CONSTANTS\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 private constant UNISWAP_V3_MIN_SQRT = 4_295_128_740;\n    uint256 private constant UNISWAP_V3_MAX_SQRT = 1_461_446_703_485_210_103_287_273_052_203_988_822_378_723_970_341;\n\n    /*//////////////////////////////////////////////////////////////\n                               CONSTRUCTOR\n    //////////////////////////////////////////////////////////////*/\n\n    constructor(uint256 _uniswapV3FactoryAndFF, uint256 _uniswapV3PoolInitCodeHash) {\n        UNISWAP_V3_FACTORY_AND_FF = _uniswapV3FactoryAndFF;\n        UNISWAP_V3_POOL_INIT_CODE_HASH = _uniswapV3PoolInitCodeHash;\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                                EXTERNAL\n    //////////////////////////////////////////////////////////////*/\n\n    // @inheritdoc IUniswapV3SwapCallback\n    function uniswapV3SwapCallback(\n        int256 amount0Delta,\n        int256 amount1Delta,\n        bytes calldata data\n    )\n        external\n        whenNotPaused\n    {\n        // Initialize variables\n        uint256 uniswapV3FactoryAndFF = UNISWAP_V3_FACTORY_AND_FF;\n        uint256 uniswapV3PoolInitCodeHash = UNISWAP_V3_POOL_INIT_CODE_HASH;\n        address permit2Address = PERMIT2;\n        address poolAddress;\n\n        // 160 (single pool data) + 352 (permit2 length)\n        bool isPermit2 = data.length == 512;\n\n        // Check if the caller is a UniswapV3Pool deployed by the canonical UniswapV3Factory\n        //solhint-disable-next-line no-inline-assembly\n        assembly {\n            // Pool address\n            poolAddress := caller()\n\n            // Get free memory pointer\n            let ptr := mload(64)\n\n            // We need make sure the caller is a UniswapV3Pool deployed by the canonical UniswapV3Factory\n            // 1. Prepare data for calculating the pool address\n            // Store ff+factory address, Load token0, token1, fee from bytes calldata and store pool init code hash\n\n            // Store 0xff + factory address (right padded)\n            mstore(ptr, uniswapV3FactoryAndFF)\n\n            // Store data offset + 21 bytes (UNISWAP_V3_FACTORY_AND_FF SIZE)\n            let token0Offset := add(ptr, 21)\n\n            // Copy token0, token1, fee to free memory pointer + 21 bytes (UNISWAP_V3_FACTORY_AND_FF SIZE) + 1 byte\n            // (direction)\n            calldatacopy(add(token0Offset, 1), add(data.offset, 65), 95)\n\n            // 2. Calculate the pool address\n            // We can do this by first calling the keccak256 function on the fetched values and then\n            // calculating keccak256(abi.encodePacked(hex'ff', address(factory_address),\n            // keccak256(abi.encode(token0,\n            // token1, fee)), POOL_INIT_CODE_HASH));\n            // The first 20 bytes of the computed address are the pool address\n\n            // Calculate keccak256(abi.encode(address(token0), address(token1), fee))\n            mstore(token0Offset, keccak256(token0Offset, 96))\n            // Store POOL_INIT_CODE_HASH\n            mstore(add(token0Offset, 32), uniswapV3PoolInitCodeHash)\n            // Calculate keccak256(abi.encodePacked(hex'ff', address(factory_address), keccak256(abi.encode(token0,\n            // token1, fee)), POOL_INIT_CODE_HASH));\n            mstore(ptr, keccak256(ptr, 85)) // 21 + 32 + 32\n\n            // Get the first 20 bytes of the computed address\n            let computedAddress := and(mload(ptr), 0xffffffffffffffffffffffffffffffffffffffff)\n\n            // Check if the caller matches the computed address (and revert if not)\n            if xor(poolAddress, computedAddress) {\n                mstore(0, 0x48f5c3ed00000000000000000000000000000000000000000000000000000000) // store the selector\n                    // (error InvalidCaller())\n                revert(0, 4) // revert with error selector\n            }\n        }\n\n        // Check if data length is greater than 160 bytes (1 pool)\n        // If the data length is greater than 160 bytes, we know that we are executing a multi-hop swapExactAmountOut\n        // by recursively calling swapExactAmountOut on the next pool, until we reach the last pool in the data and\n        // then we will transfer the tokens to the pool\n        if (data.length > 160 && !isPermit2) {\n            // Initialize recursive variables\n            address payer;\n            // solhint-disable-next-line no-inline-assembly\n            assembly {\n                // Copy payer address from calldata\n                payer := calldataload(164)\n            }\n            // Recursive call swapExactAmountOut\n            _callUniswapV3PoolsSwapExactAmountOut(amount0Delta > 0 ? -amount0Delta : -amount1Delta, data, payer);\n        } else {\n            // solhint-disable-next-line no-inline-assembly\n            assembly {\n                // Token to send to the pool\n                let token\n                // Amount to send to the pool\n                let amount\n\n                // Get free memory pointer\n                let ptr := mload(64)\n\n                // If the caller is the computed address, then we can safely assume that the caller is a UniswapV3Pool\n                // deployed by the canonical UniswapV3Factory\n\n                // 3. Transfer amount to the pool\n\n                // Check if amount0Delta or amount1Delta is positive and which token we need to send to the pool\n                if sgt(amount0Delta, 0) {\n                    // If amount0Delta is positive, we need to send amount0Delta token0 to the pool\n                    token := and(calldataload(add(data.offset, 64)), 0xffffffffffffffffffffffffffffffffffffffff)\n                    amount := amount0Delta\n                }\n                if sgt(amount1Delta, 0) {\n                    // If amount1Delta is positive, we need to send amount1Delta token1 to the pool\n                    token := calldataload(add(data.offset, 96))\n                    amount := amount1Delta\n                }\n\n                // Based on the data passed to the callback, we know the fromAddress that will pay for the\n                // swap, if it is this contract, we will execute the transfer() function,\n                // otherwise, we will execute transferFrom()\n\n                // Check if fromAddress is this contract\n                let fromAddress := calldataload(164)\n\n                switch eq(fromAddress, address())\n                // If fromAddress is this contract, execute transfer()\n                case 1 {\n                    // Prepare external call data\n                    mstore(ptr, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) // store the\n                        // selector\n                        // (function transfer(address recipient, uint256 amount))\n                    mstore(add(ptr, 4), poolAddress) // store the recipient\n                    mstore(add(ptr, 36), amount) // store the amount\n                    let success := call(gas(), token, 0, ptr, 68, 0, 32) // call transfer\n                    if success {\n                        switch returndatasize()\n                        // check the return data size\n                        case 0 { success := gt(extcodesize(token), 0) }\n                        default { success := and(gt(returndatasize(), 31), eq(mload(0), 1)) }\n                    }\n\n                    if iszero(success) {\n                        mstore(0, 0x1bbb4abe00000000000000000000000000000000000000000000000000000000) // store the\n                            // selector\n                            // (error CallbackTransferFailed())\n                        revert(0, 4) // revert with error selector\n                    }\n                }\n                // If fromAddress is not this contract, execute transferFrom() or permitTransferFrom()\n                default {\n                    switch isPermit2\n                    // If permit2 is not present, execute transferFrom()\n                    case 0 {\n                        mstore(ptr, 0x23b872dd00000000000000000000000000000000000000000000000000000000) // store the\n                            // selector\n                            // (function transferFrom(address sender, address recipient,\n                            // uint256 amount))\n                        mstore(add(ptr, 4), fromAddress) // store the sender\n                        mstore(add(ptr, 36), poolAddress) // store the recipient\n                        mstore(add(ptr, 68), amount) // store the amount\n                        let success := call(gas(), token, 0, ptr, 100, 0, 32) // call transferFrom\n                        if success {\n                            switch returndatasize()\n                            // check the return data size\n                            case 0 { success := gt(extcodesize(token), 0) }\n                            default { success := and(gt(returndatasize(), 31), eq(mload(0), 1)) }\n                        }\n                        if iszero(success) {\n                            mstore(0, 0x1bbb4abe00000000000000000000000000000000000000000000000000000000) // store the\n                                // selector\n                                // (error CallbackTransferFailed())\n                            revert(0, 4) // revert with error selector\n                        }\n                    }\n                    // If permit2 is present, execute permitTransferFrom()\n                    default {\n                        // Otherwise Permit2.permitTransferFrom\n                        // Store function selector\n                        mstore(ptr, 0x30f28b7a00000000000000000000000000000000000000000000000000000000)\n                        // permitTransferFrom()\n                        calldatacopy(add(ptr, 4), 292, 352) // Copy data to memory\n                        mstore(add(ptr, 132), poolAddress) // Store pool address as recipient\n                        mstore(add(ptr, 164), amount) // Store amount as amount\n                        mstore(add(ptr, 196), fromAddress) // Store payer\n                        // Call permit2.permitTransferFrom and revert if call failed\n                        if iszero(call(gas(), permit2Address, 0, ptr, 356, 0, 0)) {\n                            mstore(0, 0x6b836e6b00000000000000000000000000000000000000000000000000000000) // Store\n                                // error selector\n                                // error Permit2Failed()\n                            revert(0, 4)\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                               INTERNAL\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev Loops through pools and performs swaps\n    function _callUniswapV3PoolsSwapExactAmountIn(\n        int256 fromAmount,\n        bytes calldata pools,\n        address fromAddress,\n        bytes calldata permit2\n    )\n        internal\n        returns (uint256 receivedAmount)\n    {\n        uint256 uniswapV3FactoryAndFF = UNISWAP_V3_FACTORY_AND_FF;\n        uint256 uniswapV3PoolInitCodeHash = UNISWAP_V3_POOL_INIT_CODE_HASH;\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            //---------------------------------//\n            // Loop Swap Through Pools\n            //---------------------------------//\n\n            // Calculate pool count\n            let poolCount := div(pools.length, 96)\n\n            // Initialize variables\n            let p := 0\n            let poolAddress := 0\n            let nextPoolAddress := 0\n            let direction := 0\n            let isPermit2 := gt(permit2.length, 256)\n\n            // Get free memory pointer\n            let ptr := mload(64)\n\n            // Loop through pools\n            for { let i := 0 } lt(i, poolCount) { i := add(i, 1) } {\n                // Check if it is the first pool\n                if iszero(p) {\n                    //---------------------------------//\n                    // Calculate Pool Address\n                    //---------------------------------//\n\n                    // Calculate the pool address\n                    // We can do this by first calling the keccak256 function on the passed pool values and then\n                    // calculating keccak256(abi.encodePacked(hex'ff', address(factory_address),\n                    // keccak256(abi.encode(token0,\n                    // token1, fee)), POOL_INIT_CODE_HASH));\n                    // The first 20 bytes of the computed address are the pool address\n\n                    // Store 0xff + factory address (right padded)\n                    mstore(ptr, uniswapV3FactoryAndFF)\n\n                    // Store pools offset + 21 bytes (UNISWAP_V3_FACTORY_AND_FF SIZE)\n                    let token0ptr := add(ptr, 21)\n\n                    // Copy pool data (skip first byte) to free memory pointer + 21 bytes (UNISWAP_V3_FACTORY_AND_FF\n                    // SIZE)\n                    calldatacopy(add(token0ptr, 1), add(pools.offset, 1), 95)\n\n                    // Calculate keccak256(abi.encode(address(token0), address(token1), fee))\n                    mstore(token0ptr, keccak256(token0ptr, 96))\n\n                    // Store POOL_INIT_CODE_HASH\n                    mstore(add(token0ptr, 32), uniswapV3PoolInitCodeHash)\n\n                    // Calculate keccak256(abi.encodePacked(hex'ff', address(factory_address),\n                    // keccak256(abi.encode(token0,\n                    // token1, fee)), POOL_INIT_CODE_HASH));\n                    mstore(ptr, keccak256(ptr, 85)) // 21 + 32 + 32\n\n                    // Load pool\n                    p := mload(ptr)\n\n                    // Get the first 20 bytes of the computed address\n                    poolAddress := and(p, 0xffffffffffffffffffffffffffffffffffffffff)\n\n                    //---------------------------------//\n                }\n\n                // Direction is the first bit of the pool data\n                direction := shr(255, calldataload(add(pools.offset, mul(i, 96))))\n\n                // Check if it is not the last pool\n                if lt(add(i, 1), poolCount) {\n                    //---------------------------------//\n                    // Calculate Next Pool Address\n                    //---------------------------------//\n\n                    // Store 0xff + factory address (right padded)\n                    mstore(ptr, uniswapV3FactoryAndFF)\n\n                    // Store pools offset + 21 bytes (UNISWAP_V3_FACTORY_AND_FF SIZE)\n                    let token0ptr := add(ptr, 21)\n\n                    // Copy next pool data to free memory pointer + 21 bytes (UNISWAP_V3_FACTORY_AND_FF SIZE)\n                    calldatacopy(add(token0ptr, 1), add(add(pools.offset, 1), mul(add(i, 1), 96)), 95)\n\n                    // Calculate keccak256(abi.encode(address(token0), address(token1), fee))\n                    mstore(token0ptr, keccak256(token0ptr, 96))\n\n                    // Store POOL_INIT_CODE_HASH\n                    mstore(add(token0ptr, 32), uniswapV3PoolInitCodeHash)\n\n                    // Calculate keccak256(abi.encodePacked(hex'ff', address(factory_address),\n                    // keccak256(abi.encode(token0,\n                    // token1, fee)), POOL_INIT_CODE_HASH));\n                    mstore(ptr, keccak256(ptr, 85)) // 21 + 32 + 32\n\n                    // Load pool\n                    p := mload(ptr)\n\n                    // Get the first 20 bytes of the computed address\n                    nextPoolAddress := and(p, 0xffffffffffffffffffffffffffffffffffffffff)\n\n                    //---------------------------------//\n                }\n\n                // Adjust fromAddress and fromAmount if it's not the first pool\n                if gt(i, 0) { fromAddress := address() }\n\n                //---------------------------------//\n                // Perform Swap\n                //---------------------------------//\n\n                //---------------------------------//\n                // Return based on direction\n                //---------------------------------//\n\n                // Initialize data length\n                let dataLength := 0xa0\n\n                // Initialize total data length\n                let totalDataLength := 356\n\n                // If permit2 is present include permit2 data length in total data length\n                if eq(isPermit2, 1) {\n                    totalDataLength := add(totalDataLength, permit2.length)\n                    dataLength := add(dataLength, permit2.length)\n                }\n\n                // Return amount0 or amount1 depending on direction\n                switch direction\n                case 0 {\n                    // Prepare external call data\n                    // Store swap selector (0x128acb08)\n                    mstore(ptr, 0x128acb0800000000000000000000000000000000000000000000000000000000)\n                    // Store toAddress\n                    mstore(add(ptr, 4), address())\n                    // Store direction\n                    mstore(add(ptr, 36), 0)\n                    // Store fromAmount\n                    mstore(add(ptr, 68), fromAmount)\n                    // Store sqrtPriceLimitX96\n                    mstore(add(ptr, 100), UNISWAP_V3_MAX_SQRT)\n                    // Store data offset\n                    mstore(add(ptr, 132), 0xa0)\n                    /// Store data length\n                    mstore(add(ptr, 164), dataLength)\n                    // Store fromAddress\n                    mstore(add(ptr, 228), fromAddress)\n                    // Store token0, token1, fee\n                    calldatacopy(add(ptr, 260), add(pools.offset, mul(i, 96)), 96)\n                    // If permit2 is present, store permit2 data\n                    if eq(isPermit2, 1) {\n                        // Store permit2 data\n                        calldatacopy(add(ptr, 356), permit2.offset, permit2.length)\n                    }\n                    // Perform the external 'swap' call\n                    if iszero(call(gas(), poolAddress, 0, ptr, totalDataLength, ptr, 32)) {\n                        // store return value directly to free memory pointer\n                        // The call failed; we retrieve the exact error message and revert with it\n                        returndatacopy(0, 0, returndatasize()) // Copy the error message to the start of memory\n                        revert(0, returndatasize()) // Revert with the error message\n                    }\n                    // If direction is 0, return amount0\n                    fromAmount := mload(ptr)\n                }\n                default {\n                    // Prepare external call data\n                    // Store swap selector (0x128acb08)\n                    mstore(ptr, 0x128acb0800000000000000000000000000000000000000000000000000000000)\n                    // Store toAddress\n                    mstore(add(ptr, 4), address())\n                    // Store direction\n                    mstore(add(ptr, 36), 1)\n                    // Store fromAmount\n                    mstore(add(ptr, 68), fromAmount)\n                    // Store sqrtPriceLimitX96\n                    mstore(add(ptr, 100), UNISWAP_V3_MIN_SQRT)\n                    // Store data offset\n                    mstore(add(ptr, 132), 0xa0)\n                    /// Store data length\n                    mstore(add(ptr, 164), dataLength)\n                    // Store fromAddress\n                    mstore(add(ptr, 228), fromAddress)\n                    // Store token0, token1, fee\n                    calldatacopy(add(ptr, 260), add(pools.offset, mul(i, 96)), 96)\n                    // If permit2 is present, store permit2 data\n                    if eq(isPermit2, 1) {\n                        // Store permit2 data\n                        calldatacopy(add(ptr, 356), permit2.offset, permit2.length)\n                    }\n                    // Perform the external 'swap' call\n                    if iszero(call(gas(), poolAddress, 0, ptr, totalDataLength, ptr, 64)) {\n                        // store return value directly to free memory pointer\n                        // The call failed; we retrieve the exact error message and revert with it\n                        returndatacopy(0, 0, returndatasize()) // Copy the error message to the start of memory\n                        revert(0, returndatasize()) // Revert with the error message\n                    }\n\n                    // If direction is 1, return amount1\n                    fromAmount := mload(add(ptr, 32))\n                }\n                //---------------------------------//\n\n                //---------------------------------//\n\n                // The next pool address was already calculated so we can set it as the current pool address for the\n                // next iteration of the loop\n                poolAddress := nextPoolAddress\n\n                // fromAmount = -fromAmount\n                fromAmount := sub(0, fromAmount)\n            }\n\n            //---------------------------------//\n        }\n        return fromAmount.toUint256();\n    }\n\n    /// @dev Recursively loops through pools and performs swaps\n    function _callUniswapV3PoolsSwapExactAmountOut(\n        int256 fromAmount,\n        bytes calldata pools,\n        address fromAddress\n    )\n        internal\n        returns (uint256 spentAmount, uint256 receivedAmount)\n    {\n        uint256 uniswapV3FactoryAndFF = UNISWAP_V3_FACTORY_AND_FF;\n        uint256 uniswapV3PoolInitCodeHash = UNISWAP_V3_POOL_INIT_CODE_HASH;\n\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            //---------------------------------//\n            // Adjust data received from recursive call\n            //---------------------------------//\n\n            // Initialize variables\n            let poolsStartOffset := pools.offset\n            let poolsLength := pools.length\n            let previousPoolAddress := 0\n\n            // Check if pools length is not divisible by 96\n            if gt(mod(pools.length, 96), 0) {\n                // Check if pools length is greater than 128 bytes (1 pool)\n                if gt(pools.length, 160) {\n                    // Get the previous pool address from the first 20 bytes of pool data\n                    previousPoolAddress := and(calldataload(pools.offset), 0xffffffffffffffffffffffffffffffffffffffff)\n                    // Relculate the offset to skip data\n                    poolsStartOffset := add(pools.offset, 160)\n                    // Recalculate the length to skip data\n                    poolsLength := sub(pools.length, 160)\n                }\n            }\n\n            // Get free memory pointer\n            let ptr := mload(64)\n\n            //---------------------------------//\n            // Calculate Pool Address\n            //---------------------------------//\n\n            // Calculate the pool address\n            // We can do this by first calling the keccak256 function on the passed pool values and then\n            // calculating keccak256(abi.encodePacked(hex'ff', address(factory_address),\n            // keccak256(abi.encode(token0,\n            // token1, fee)), POOL_INIT_CODE_HASH));\n            // The first 20 bytes of the computed address are the pool address\n\n            // Store 0xff + factory address (right padded)\n            mstore(ptr, uniswapV3FactoryAndFF)\n\n            // Store pools offset + 21 bytes (UNISWAP_V3_FACTORY_AND_FF SIZE)\n            let token0ptr := add(ptr, 21)\n\n            // Copy pool data (skip first byte) to free memory pointer + 21 bytes (UNISWAP_V3_FACTORY_AND_FF\n            // SIZE)\n            calldatacopy(add(token0ptr, 1), add(poolsStartOffset, 1), 95)\n\n            // Calculate keccak256(abi.encode(address(token0), address(token1), fee))\n            mstore(token0ptr, keccak256(token0ptr, 96))\n\n            // Store POOL_INIT_CODE_HASH\n            mstore(add(token0ptr, 32), uniswapV3PoolInitCodeHash)\n\n            // Calculate keccak256(abi.encodePacked(hex'ff', address(factory_address),\n            // keccak256(abi.encode(token0,\n            // token1, fee)), POOL_INIT_CODE_HASH));\n            mstore(ptr, keccak256(ptr, 85)) // 21 + 32 + 32\n\n            // Load pool\n            let p := mload(ptr)\n\n            // Get the first 20 bytes of the computed address\n            let poolAddress := and(p, 0xffffffffffffffffffffffffffffffffffffffff)\n\n            //---------------------------------//\n\n            //---------------------------------//\n            // Adjust toAddress\n            //---------------------------------//\n\n            let toAddress := address()\n\n            // If it's not the first entry to recursion, we use the pool address from the previous pool as\n            // the toAddress\n            if xor(previousPoolAddress, 0) { toAddress := previousPoolAddress }\n\n            //---------------------------------//\n\n            // Direction is the first bit of the pool data\n            let direction := shr(255, calldataload(poolsStartOffset))\n\n            //---------------------------------//\n            // Perform Swap\n            //---------------------------------//\n\n            //---------------------------------//\n            // Return based on direction\n            //---------------------------------//\n\n            // Return amount0 or amount1 depending on direction\n            switch direction\n            case 0 {\n                // Prepare external call data\n                // Store swap selector (0x128acb08)\n                mstore(ptr, 0x128acb0800000000000000000000000000000000000000000000000000000000)\n                // Store toAddress\n                mstore(add(ptr, 4), toAddress)\n                // Store direction\n                mstore(add(ptr, 36), 0)\n                // Store fromAmount\n                mstore(add(ptr, 68), fromAmount)\n                // Store sqrtPriceLimitX96\n                mstore(add(ptr, 100), UNISWAP_V3_MAX_SQRT)\n                // Store data offset\n                mstore(add(ptr, 132), 0xa0)\n                /// Store data length\n                mstore(add(ptr, 164), add(64, poolsLength))\n                // Store poolAddress\n                mstore(add(ptr, 196), poolAddress)\n                // Store fromAddress\n                mstore(add(ptr, 228), fromAddress)\n                // Store token0, token1, fee\n                calldatacopy(add(ptr, 260), poolsStartOffset, poolsLength)\n\n                // Perform the external 'swap' call\n                if iszero(call(gas(), poolAddress, 0, ptr, add(poolsLength, 260), ptr, 64)) {\n                    // store return value directly to free memory pointer\n                    // The call failed; we retrieve the exact error message and revert with it\n                    returndatacopy(0, 0, returndatasize()) // Copy the error message to the start of memory\n                    revert(0, returndatasize()) // Revert with the error message\n                }\n                // If direction is 0, return amount0 as fromAmount\n                fromAmount := mload(ptr)\n                // return amount1 as spentAmount\n                spentAmount := mload(add(ptr, 32))\n            }\n            default {\n                // Prepare external call data\n                // Store swap selector (0x128acb08)\n                mstore(ptr, 0x128acb0800000000000000000000000000000000000000000000000000000000)\n                // Store toAddress\n                mstore(add(ptr, 4), toAddress)\n                // Store direction\n                mstore(add(ptr, 36), 1)\n                // Store fromAmount\n                mstore(add(ptr, 68), fromAmount)\n                // Store sqrtPriceLimitX96\n                mstore(add(ptr, 100), UNISWAP_V3_MIN_SQRT)\n                // Store data offset\n                mstore(add(ptr, 132), 0xa0)\n                /// Store data length\n                mstore(add(ptr, 164), add(64, poolsLength))\n                // Store poolAddress\n                mstore(add(ptr, 196), poolAddress)\n                // Store fromAddress\n                mstore(add(ptr, 228), fromAddress)\n                // Store token0, token1, fee\n                calldatacopy(add(ptr, 260), poolsStartOffset, poolsLength)\n\n                // Perform the external 'swap' call\n                if iszero(call(gas(), poolAddress, 0, ptr, add(poolsLength, 260), ptr, 64)) {\n                    // store return value directly to free memory pointer\n                    // The call failed; we retrieve the exact error message and revert with it\n                    returndatacopy(0, 0, returndatasize()) // Copy the error message to the start of memory\n                    revert(0, returndatasize()) // Revert with the error message\n                }\n\n                // If direction is 1, return amount1 as fromAmount\n                fromAmount := mload(add(ptr, 32))\n                // return amount0 as spentAmount\n                spentAmount := mload(ptr)\n            }\n            //---------------------------------//\n\n            //---------------------------------//\n\n            // fromAmount = -fromAmount\n            fromAmount := sub(0, fromAmount)\n        }\n        return (spentAmount, fromAmount.toUint256());\n    }\n}\n"
      },
      "src/util/WETHUtils.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IWETH } from \"../interfaces/IWETH.sol\";\n\n/// @title WETHUtils\n/// @notice A contract containing common utilities for WETH\nabstract contract WETHUtils {\n    /*//////////////////////////////////////////////////////////////\n                                CONSTANTS\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev WETH address\n    IWETH public immutable WETH;\n\n    /*//////////////////////////////////////////////////////////////\n                                CONSTRUCTOR\n    //////////////////////////////////////////////////////////////*/\n\n    constructor(address _weth) {\n        WETH = IWETH(_weth);\n    }\n}\n"
      },
      "src/util/Permit2Utils.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n/// @title Permit2Utils\n/// @notice A contract containing common utilities for Permit2\nabstract contract Permit2Utils {\n    /*//////////////////////////////////////////////////////////////\n                                 ERRORS\n    //////////////////////////////////////////////////////////////*/\n\n    error Permit2Failed();\n\n    /*//////////////////////////////////////////////////////////////\n                                CONSTANTS\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev Permit2 address\n    address public immutable PERMIT2; // solhint-disable-line var-name-mixedcase\n\n    /*//////////////////////////////////////////////////////////////\n                                CONSTRUCTOR\n    //////////////////////////////////////////////////////////////*/\n\n    constructor(address _permit2) {\n        PERMIT2 = _permit2;\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                                INTERNAL\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev Parses data and executes permit2.permitTransferFrom, reverts if it fails\n    function permit2TransferFrom(bytes calldata data, address recipient, uint256 amount) internal {\n        address targetAddress = PERMIT2;\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            // Get free memory pointer\n            let ptr := mload(64)\n            // Store function selector\n            mstore(ptr, 0x30f28b7a00000000000000000000000000000000000000000000000000000000) // permitTransferFrom()\n            // Copy data to memory\n            calldatacopy(add(ptr, 4), data.offset, data.length)\n            // Store recipient\n            mstore(add(ptr, 132), recipient)\n            // Store amount\n            mstore(add(ptr, 164), amount)\n            // Store owner\n            mstore(add(ptr, 196), caller())\n            // Call permit2.permitTransferFrom and revert if call failed\n            if iszero(call(gas(), targetAddress, 0, ptr, add(data.length, 4), 0, 0)) {\n                mstore(0, 0x6b836e6b00000000000000000000000000000000000000000000000000000000) // Store error selector\n                    // error Permit2Failed()\n                revert(0, 4)\n            }\n        }\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"
      },
      "src/interfaces/IBalancerV2SwapExactAmountIn.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IErrors } from \"./IErrors.sol\";\n\n// Types\nimport { BalancerV2Data } from \"../AugustusV6Types.sol\";\n\n/// @title IBalancerV2SwapExactAmountIn\n/// @notice Interface for executing swapExactAmountIn directly on Balancer V2 pools\ninterface IBalancerV2SwapExactAmountIn is IErrors {\n    /*//////////////////////////////////////////////////////////////\n                          SWAP EXACT AMOUNT IN\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Executes a swapExactAmountIn on Balancer V2 pools\n    /// @param balancerData Struct containing data for the swap\n    /// @param partnerAndFee packed partner address and fee percentage, the first 12 bytes is the feeData and the last\n    /// 20 bytes is the partner address\n    /// @param permit Permit data for the swap\n    /// @param data The calldata to execute\n    /// the first 20 bytes are the beneficiary address and the left most bit is the approve flag\n    /// @return receivedAmount The amount of destToken received after fees\n    /// @return paraswapShare The share of the fees for Paraswap\n    /// @return partnerShare The share of the fees for the partner\n    function swapExactAmountInOnBalancerV2(\n        BalancerV2Data calldata balancerData,\n        uint256 partnerAndFee,\n        bytes calldata permit,\n        bytes calldata data\n    )\n        external\n        payable\n        returns (uint256 receivedAmount, uint256 paraswapShare, uint256 partnerShare);\n}\n"
      },
      "src/libraries/ERC20Utils.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IERC20 } from \"@openzeppelin/token/ERC20/IERC20.sol\";\n\n/// @title ERC20Utils\n/// @notice Optimized functions for ERC20 tokens\nlibrary ERC20Utils {\n    /*//////////////////////////////////////////////////////////////\n                                ERRORS\n    //////////////////////////////////////////////////////////////*/\n\n    error IncorrectEthAmount();\n    error PermitFailed();\n    error TransferFromFailed();\n    error TransferFailed();\n    error ApprovalFailed();\n\n    /*//////////////////////////////////////////////////////////////\n                               CONSTANTS\n    //////////////////////////////////////////////////////////////*/\n\n    IERC20 internal constant ETH = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);\n\n    /*//////////////////////////////////////////////////////////////\n                                APPROVE\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev Vendored from Solady by @vectorized - SafeTransferLib.approveWithRetry\n    /// https://github.com/Vectorized/solady/src/utils/SafeTransferLib.sol#L325\n    /// Instead of approving a specific amount, this function approves for uint256(-1) (type(uint256).max).\n    function approve(IERC20 token, address to) internal {\n        // solhint-disable-next-line no-inline-assembly\n        assembly (\"memory-safe\") {\n            mstore(0x14, to) // Store the `to` argument.\n            mstore(0x34, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) // Store the `amount`\n                // argument (type(uint256).max).\n            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.\n            // Perform the approval, retrying upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n                )\n            ) {\n                mstore(0x34, 0) // Store 0 for the `amount`.\n                mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.\n                pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.\n                mstore(0x34, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) // Store\n                    // type(uint256).max for the `amount`.\n                // Retry the approval, reverting upon failure.\n                if iszero(\n                    and(\n                        or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                        call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n                    )\n                ) {\n                    mstore(0, 0x8164f84200000000000000000000000000000000000000000000000000000000)\n                    // store the selector (error ApprovalFailed())\n                    revert(0, 4) // revert with error selector\n                }\n            }\n            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.\n        }\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                                PERMIT\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev Executes an ERC20 permit and reverts if invalid length is provided\n    function permit(IERC20 token, bytes calldata data) internal {\n        // solhint-disable-next-line no-inline-assembly\n        assembly (\"memory-safe\") {\n            // check the permit length\n            switch data.length\n            // 32 * 7 = 224 EIP2612 Permit\n            case 224 {\n                let x := mload(64) // get the free memory pointer\n                mstore(x, 0xd505accf00000000000000000000000000000000000000000000000000000000) // store the selector\n                    // function permit(address owner, address spender, uint256\n                    // amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n                calldatacopy(add(x, 4), data.offset, 224) // store the args\n                pop(call(gas(), token, 0, x, 228, 0, 32)) // call ERC20 permit, skip checking return data\n            }\n            // 32 * 8 = 256 DAI-Style Permit\n            case 256 {\n                let x := mload(64) // get the free memory pointer\n                mstore(x, 0x8fcbaf0c00000000000000000000000000000000000000000000000000000000) // store the selector\n                    // function permit(address holder, address spender, uint256\n                    // nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s)\n                calldatacopy(add(x, 4), data.offset, 256) // store the args\n                pop(call(gas(), token, 0, x, 260, 0, 32)) // call ERC20 permit, skip checking return data\n            }\n            default {\n                mstore(0, 0xb78cb0dd00000000000000000000000000000000000000000000000000000000) // store the selector\n                    // (error PermitFailed())\n                revert(0, 4)\n            }\n        }\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                                 ETH\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev Returns 1 if the token is ETH, 0 if not ETH\n    function isETH(IERC20 token, uint256 amount) internal view returns (uint256 fromETH) {\n        // solhint-disable-next-line no-inline-assembly\n        assembly (\"memory-safe\") {\n            // If token is ETH\n            if eq(token, 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {\n                // if msg.value is not equal to fromAmount, then revert\n                if xor(amount, callvalue()) {\n                    mstore(0, 0x8b6ebb4d00000000000000000000000000000000000000000000000000000000) // store the selector\n                        // (error IncorrectEthAmount())\n                    revert(0, 4) // revert with error selector\n                }\n                // return 1 if ETH\n                fromETH := 1\n            }\n            // If token is not ETH\n            if xor(token, 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {\n                // if msg.value is not equal to 0, then revert\n                if gt(callvalue(), 0) {\n                    mstore(0, 0x8b6ebb4d00000000000000000000000000000000000000000000000000000000) // store the selector\n                    // (error IncorrectEthAmount())\n                    revert(0, 4) // revert with error selector\n                }\n            }\n        }\n        // return 0 if not ETH\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                                TRANSFER\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev Executes transfer and reverts if it fails, works for both ETH and ERC20 transfers\n    function safeTransfer(IERC20 token, address recipient, uint256 amount) internal returns (bool success) {\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            switch eq(token, 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)\n            // ETH\n            case 1 {\n                // transfer ETH\n                // Cap gas at 10000 to avoid reentrancy\n                success := call(10000, recipient, amount, 0, 0, 0, 0)\n            }\n            // ERC20\n            default {\n                let x := mload(64) // get the free memory pointer\n                mstore(x, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) // store the selector\n                    // (function transfer(address recipient, uint256 amount))\n                mstore(add(x, 4), recipient) // store the recipient\n                mstore(add(x, 36), amount) // store the amount\n                success := call(gas(), token, 0, x, 68, 0, 32) // call transfer\n                if success {\n                    switch returndatasize()\n                    // check the return data size\n                    case 0 { success := gt(extcodesize(token), 0) }\n                    default { success := and(gt(returndatasize(), 31), eq(mload(0), 1)) }\n                }\n            }\n            if iszero(success) {\n                mstore(0, 0x90b8ec1800000000000000000000000000000000000000000000000000000000) // store the selector\n                    // (error TransferFailed())\n                revert(0, 4) // revert with error selector\n            }\n        }\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                             TRANSFER FROM\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev Executes transferFrom and reverts if it fails\n    function safeTransferFrom(\n        IERC20 srcToken,\n        address sender,\n        address recipient,\n        uint256 amount\n    )\n        internal\n        returns (bool success)\n    {\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            let x := mload(64) // get the free memory pointer\n            mstore(x, 0x23b872dd00000000000000000000000000000000000000000000000000000000) // store the selector\n                // (function transferFrom(address sender, address recipient,\n                // uint256 amount))\n            mstore(add(x, 4), sender) // store the sender\n            mstore(add(x, 36), recipient) // store the recipient\n            mstore(add(x, 68), amount) // store the amount\n            success := call(gas(), srcToken, 0, x, 100, 0, 32) // call transferFrom\n            if success {\n                switch returndatasize()\n                // check the return data size\n                case 0 { success := gt(extcodesize(srcToken), 0) }\n                default { success := and(gt(returndatasize(), 31), eq(mload(0), 1)) }\n            }\n            if iszero(success) {\n                mstore(x, 0x7939f42400000000000000000000000000000000000000000000000000000000) // store the selector\n                    // (error TransferFromFailed())\n                revert(x, 4) // revert with error selector\n            }\n        }\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                                BALANCE\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev Returns the balance of an account, works for both ETH and ERC20 tokens\n    function getBalance(IERC20 token, address account) internal view returns (uint256 balanceOf) {\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            switch eq(token, 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)\n            // ETH\n            case 1 { balanceOf := balance(account) }\n            // ERC20\n            default {\n                let x := mload(64) // get the free memory pointer\n                mstore(x, 0x70a0823100000000000000000000000000000000000000000000000000000000) // store the selector\n                    // (function balanceOf(address account))\n                mstore(add(x, 4), account) // store the account\n                let success := staticcall(gas(), token, x, 36, x, 32) // call balanceOf\n                if success { balanceOf := mload(x) } // load the balance\n            }\n        }\n    }\n}\n"
      },
      "src/AugustusV6Types.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IERC20 } from \"@openzeppelin/token/ERC20/IERC20.sol\";\n\n/*//////////////////////////////////////////////////////////////\n                        GENERIC SWAP DATA\n//////////////////////////////////////////////////////////////*/\n\n/// @notice Struct containg data for generic swapExactAmountIn/swapExactAmountOut\n/// @param srcToken The token to swap from\n/// @param destToken The token to swap to\n/// @param fromAmount The amount of srcToken to swap\n/// = amountIn for swapExactAmountIn and maxAmountIn for swapExactAmountOut\n/// @param toAmount The minimum amount of destToken to receive\n/// = minAmountOut for swapExactAmountIn and amountOut for swapExactAmountOut\n/// @param quotedAmount The quoted expected amount of destToken/srcToken\n/// = quotedAmountOut for swapExactAmountIn and quotedAmountIn for swapExactAmountOut\n/// @param metadata Packed uuid and additional metadata\n/// @param beneficiary The address to send the swapped tokens to\nstruct GenericData {\n    IERC20 srcToken;\n    IERC20 destToken;\n    uint256 fromAmount;\n    uint256 toAmount;\n    uint256 quotedAmount;\n    bytes32 metadata;\n    address payable beneficiary;\n}\n\n/*//////////////////////////////////////////////////////////////\n                            UNISWAPV2\n//////////////////////////////////////////////////////////////*/\n\n/// @notice Struct for UniswapV2 swapExactAmountIn/swapExactAmountOut data\n/// @param srcToken The token to swap from\n/// @param destToken The token to swap to\n/// @param fromAmount The amount of srcToken to swap\n/// = amountIn for swapExactAmountIn and maxAmountIn for swapExactAmountOut\n/// @param quotedAmount The quoted expected amount of destToken/srcToken\n/// = quotedAmountOut for swapExactAmountIn and quotedAmountIn for swapExactAmountOut\n/// @param toAmount The minimum amount of destToken to receive\n/// = minAmountOut for swapExactAmountIn and amountOut for swapExactAmountOut\n/// @param metadata Packed uuid and additional metadata\n/// @param beneficiary The address to send the swapped tokens to\n/// @param pools data consisting of concatenated token0 and token1 address for each pool with the direction flag being\n/// the right most bit of the packed token0-token1 pair bytes used in the path\nstruct UniswapV2Data {\n    IERC20 srcToken;\n    IERC20 destToken;\n    uint256 fromAmount;\n    uint256 toAmount;\n    uint256 quotedAmount;\n    bytes32 metadata;\n    address payable beneficiary;\n    bytes pools;\n}\n\n/*//////////////////////////////////////////////////////////////\n                            UNISWAPV3\n//////////////////////////////////////////////////////////////*/\n\n/// @notice Struct for UniswapV3 swapExactAmountIn/swapExactAmountOut data\n/// @param srcToken The token to swap from\n/// @param destToken The token to swap to\n/// @param fromAmount The amount of srcToken to swap\n/// = amountIn for swapExactAmountIn and maxAmountIn for swapExactAmountOut\n/// @param quotedAmount The quoted expected amount of destToken/srcToken\n/// = quotedAmountOut for swapExactAmountIn and quotedAmountIn for swapExactAmountOut\n/// @param toAmount The minimum amount of destToken to receive\n/// = minAmountOut for swapExactAmountIn and amountOut for swapExactAmountOut\n/// @param metadata Packed uuid and additional metadata\n/// @param beneficiary The address to send the swapped tokens to\n/// @param pools data consisting of concatenated token0-\n/// token1-fee bytes for each pool used in the path, with the direction flag being the left most bit of token0 in the\n/// concatenated bytes\nstruct UniswapV3Data {\n    IERC20 srcToken;\n    IERC20 destToken;\n    uint256 fromAmount;\n    uint256 toAmount;\n    uint256 quotedAmount;\n    bytes32 metadata;\n    address payable beneficiary;\n    bytes pools;\n}\n\n/*//////////////////////////////////////////////////////////////\n                            CURVE V1\n//////////////////////////////////////////////////////////////*/\n\n/// @notice Struct for CurveV1 swapExactAmountIn data\n/// @param curveData Packed data for the Curve pool, first 160 bits is the target exchange address,\n/// the 161st bit is the approve flag, bits from (162 - 163) are used for the wrap flag,\n//// bits from (164 - 165) are used for the swapType flag and the last 91 bits are unused:\n/// Approve Flag - a) 0 -> do not approve b) 1 -> approve\n/// Wrap Flag - a) 0 -> do not wrap b) 1 -> wrap native & srcToken == eth\n/// c) 2 -> unwrap and destToken == eth d) 3 - >srcToken == eth && do not wrap\n/// Swap Type Flag -  a) 0 -> EXCHANGE b) 1 -> EXCHANGE_UNDERLYING\n/// @param curveAssets Packed uint128 index i and uint128 index j of the pool\n/// The first 128 bits is the index i and the second 128 bits is the index j\n/// @param srcToken The token to swap from\n/// @param destToken The token to swap to\n/// @param fromAmount The amount of srcToken to swap\n/// = amountIn for swapExactAmountIn and maxAmountIn for swapExactAmountOut\n/// @param toAmount The minimum amount that must be recieved\n/// = minAmountOut for swapExactAmountIn and amountOut for swapExactAmountOut\n/// @param quotedAmount The expected amount of destToken to be recieved\n/// = quotedAmountOut for swapExactAmountIn and quotedAmountIn for swapExactAmountOut\n/// @param metadata Packed uuid and additional metadata\n/// @param beneficiary The address to send the swapped tokens to\nstruct CurveV1Data {\n    uint256 curveData;\n    uint256 curveAssets;\n    IERC20 srcToken;\n    IERC20 destToken;\n    uint256 fromAmount;\n    uint256 toAmount;\n    uint256 quotedAmount;\n    bytes32 metadata;\n    address payable beneficiary;\n}\n\n/*//////////////////////////////////////////////////////////////\n                            CURVE V2\n//////////////////////////////////////////////////////////////*/\n\n/// @notice Struct for CurveV2 swapExactAmountIn data\n/// @param curveData Packed data for the Curve pool, first 160 bits is the target exchange address,\n/// the 161st bit is the approve flag, bits from (162 - 163) are used for the wrap flag,\n//// bits from (164 - 165) are used for the swapType flag and the last 91 bits are unused\n/// Approve Flag - a) 0 -> do not approve b) 1 -> approve\n/// Approve Flag - a) 0 -> do not approve b) 1 -> approve\n/// Wrap Flag - a) 0 -> do not wrap b) 1 -> wrap native & srcToken == eth\n/// c) 2 -> unwrap and destToken == eth d) 3 - >srcToken == eth && do not wrap\n/// Swap Type Flag -  a) 0 -> EXCHANGE b) 1 -> EXCHANGE_UNDERLYING c) 2 -> EXCHANGE_UNDERLYING_FACTORY_ZAP\n/// @param i The index of the srcToken\n/// @param j The index of the destToken\n/// The first 128 bits is the index i and the second 128 bits is the index j\n/// @param poolAddress The address of the CurveV2 pool (only used for EXCHANGE_UNDERLYING_FACTORY_ZAP)\n/// @param srcToken The token to swap from\n/// @param destToken The token to swap to\n/// @param fromAmount The amount of srcToken to swap\n/// = amountIn for swapExactAmountIn and maxAmountIn for swapExactAmountOut\n/// @param toAmount The minimum amount that must be recieved\n/// = minAmountOut for swapExactAmountIn and amountOut for swapExactAmountOut\n/// @param quotedAmount The expected amount of destToken to be recieved\n/// = quotedAmountOut for swapExactAmountIn and quotedAmountIn for swapExactAmountOut\n/// @param metadata Packed uuid and additional metadata\n/// @param beneficiary The address to send the swapped tokens to\nstruct CurveV2Data {\n    uint256 curveData;\n    uint256 i;\n    uint256 j;\n    address poolAddress;\n    IERC20 srcToken;\n    IERC20 destToken;\n    uint256 fromAmount;\n    uint256 toAmount;\n    uint256 quotedAmount;\n    bytes32 metadata;\n    address payable beneficiary;\n}\n\n/*//////////////////////////////////////////////////////////////\n                            BALANCER V2\n//////////////////////////////////////////////////////////////*/\n\n/// @notice Struct for BalancerV2 swapExactAmountIn data\n/// @param fromAmount The amount of srcToken to swap\n/// = amountIn for swapExactAmountIn and maxAmountIn for swapExactAmountOut\n/// @param toAmount The minimum amount of destToken to receive\n/// = minAmountOut for swapExactAmountIn and amountOut for swapExactAmountOut\n/// @param quotedAmount The quoted expected amount of destToken/srcToken\n/// = quotedAmountOut for swapExactAmountIn and quotedAmountIn for swapExactAmountOut\n/// @param metadata Packed uuid and additional metadata\n/// @param beneficiaryAndApproveFlag The beneficiary address and approve flag packed into one uint256,\n/// the first 20 bytes are the beneficiary address and the left most bit is the approve flag\nstruct BalancerV2Data {\n    uint256 fromAmount;\n    uint256 toAmount;\n    uint256 quotedAmount;\n    bytes32 metadata;\n    uint256 beneficiaryAndApproveFlag;\n}\n\n/*//////////////////////////////////////////////////////////////\n                            MAKERPSM\n//////////////////////////////////////////////////////////////*/\n\n/// @notice Struct for Maker PSM swapExactAmountIn data\n/// @param srcToken The token to swap from\n/// @param destToken The token to swap to\n/// @param fromAmount The amount of srcToken to swap\n/// = amountIn for swapExactAmountIn and maxAmountIn for swapExactAmountOut\n/// @param toAmount The minimum amount of destToken to receive\n/// = minAmountOut for swapExactAmountIn and amountOut for swapExactAmountOut\n/// @param toll Used to calculate gem amount for the swapExactAmountIn\n/// @param to18ConversionFactor Used to calculate gem amount for the swapExactAmountIn\n/// @param gemJoinAddress The address of the gemJoin contract\n/// @param exchange The address of the exchange contract\n/// @param metadata Packed uuid and additional metadata\n/// @param beneficiaryDirectionApproveFlag The beneficiary address, swap direction and approve flag packed\n/// into one uint256, the first 20 bytes are the beneficiary address, the left most bit is the approve flag and the\n/// second left most bit is the swap direction flag, 0 for swapExactAmountIn and 1 for swapExactAmountOut\nstruct MakerPSMData {\n    IERC20 srcToken;\n    IERC20 destToken;\n    uint256 fromAmount;\n    uint256 toAmount;\n    uint256 toll;\n    uint256 to18ConversionFactor;\n    address exchange;\n    address gemJoinAddress;\n    bytes32 metadata;\n    uint256 beneficiaryDirectionApproveFlag;\n}\n\n/*//////////////////////////////////////////////////////////////\n                            AUGUSTUS RFQ\n//////////////////////////////////////////////////////////////*/\n\n/// @notice Order struct for Augustus RFQ\n/// @param nonceAndMeta The nonce and meta data packed into one uint256,\n/// the first 160 bits is the user address and the last 96 bits is the nonce\n/// @param expiry The expiry of the order\n/// @param makerAsset The address of the maker asset\n/// @param takerAsset The address of the taker asset\n/// @param maker The address of the maker\n/// @param taker The address of the taker, if the taker is address(0) anyone can take the order\n/// @param makerAmount The amount of makerAsset\n/// @param takerAmount The amount of takerAsset\nstruct Order {\n    uint256 nonceAndMeta;\n    uint128 expiry;\n    address makerAsset;\n    address takerAsset;\n    address maker;\n    address taker;\n    uint256 makerAmount;\n    uint256 takerAmount;\n}\n\n/// @notice Struct containing order info for Augustus RFQ\n/// @param order The order struct\n/// @param signature The signature for the order\n/// @param takerTokenFillAmount The amount of takerToken to fill\n/// @param permitTakerAsset The permit data for the taker asset\n/// @param permitMakerAsset The permit data for the maker asset\nstruct OrderInfo {\n    Order order;\n    bytes signature;\n    uint256 takerTokenFillAmount;\n    bytes permitTakerAsset;\n    bytes permitMakerAsset;\n}\n\n/// @notice Struct containing common data for executing swaps on Augustus RFQ\n/// @param fromAmount The amount of srcToken to swap\n/// = amountIn for swapExactAmountIn and maxAmountIn for swapExactAmountOut\n/// @param toAmount The minimum amount of destToken to receive\n/// = minAmountOut for swapExactAmountIn and amountOut for swapExactAmountOut\n/// @param wrapApproveDirection The wrap, approve and direction flag packed into one uint8,\n/// the first 2 bits is wrap flag (10 for wrap dest, 01 for wrap src, 00 for no wrap), the next bit is the approve flag\n/// (1 for approve, 0 for no approve) and the last bit is the direction flag (0 for swapExactAmountIn and 1 for\n/// swapExactAmountOut)\n/// @param metadata Packed uuid and additional metadata\nstruct AugustusRFQData {\n    uint256 fromAmount;\n    uint256 toAmount;\n    uint8 wrapApproveDirection;\n    bytes32 metadata;\n    address payable beneficiary;\n}\n"
      },
      "src/interfaces/ICurveV1SwapExactAmountIn.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IErrors } from \"./IErrors.sol\";\n\n// Types\nimport { CurveV1Data } from \"../AugustusV6Types.sol\";\n\n/// @title ICurveV1SwapExactAmountIn\n/// @notice Interface for direct swaps on Curve V1\ninterface ICurveV1SwapExactAmountIn is IErrors {\n    /*//////////////////////////////////////////////////////////////\n                          SWAP EXACT AMOUNT IN\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Executes a swapExactAmountIn on Curve V1 pools\n    /// @param curveV1Data Struct containing data for the swap\n    /// @param partnerAndFee packed partner address and fee percentage, the first 12 bytes is the feeData and the last\n    /// 20 bytes is the partner address\n    /// @param permit Permit data for the swap\n    /// @return receivedAmount The amount of destToken received after fees\n    /// @return paraswapShare The share of the fees for Paraswap\n    /// @return partnerShare The share of the fees for the partner\n    function swapExactAmountInOnCurveV1(\n        CurveV1Data calldata curveV1Data,\n        uint256 partnerAndFee,\n        bytes calldata permit\n    )\n        external\n        payable\n        returns (uint256 receivedAmount, uint256 paraswapShare, uint256 partnerShare);\n}\n"
      },
      "src/util/PauseUtils.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Storage\nimport { AugustusStorage } from \"../storage/AugustusStorage.sol\";\n\n/// @title PauseUtils\n/// @notice Provides a modifier to check if the contract is paused\nabstract contract PauseUtils is AugustusStorage {\n    /*//////////////////////////////////////////////////////////////\n                                ERRORS\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Error emitted when the contract is paused\n    error ContractPaused();\n\n    /*//////////////////////////////////////////////////////////////\n                               MODIFIERS\n    //////////////////////////////////////////////////////////////*/\n\n    // Check if the contract is paused, if it is, revert\n    modifier whenNotPaused() {\n        if (paused) {\n            revert ContractPaused();\n        }\n        _;\n    }\n}\n"
      },
      "src/interfaces/ICurveV2SwapExactAmountIn.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IErrors } from \"./IErrors.sol\";\n\n// Types\nimport { CurveV2Data } from \"../AugustusV6Types.sol\";\n\n/// @title ICurveV2SwapExactAmountIn\n/// @notice Interface for direct swaps on Curve V2\ninterface ICurveV2SwapExactAmountIn is IErrors {\n    /*//////////////////////////////////////////////////////////////\n                          SWAP EXACT AMOUNT IN\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Executes a swapExactAmountIn on Curve V2 pools\n    /// @param curveV2Data Struct containing data for the swap\n    /// @param partnerAndFee packed partner address and fee percentage, the first 12 bytes is the feeData and the last\n    /// 20 bytes is the partner address\n    /// @param permit Permit data for the swap\n    /// @return receivedAmount The amount of destToken received after fees\n    /// @return paraswapShare The share of the fees for Paraswap\n    /// @return partnerShare The share of the fees for the partner\n    function swapExactAmountInOnCurveV2(\n        CurveV2Data calldata curveV2Data,\n        uint256 partnerAndFee,\n        bytes calldata permit\n    )\n        external\n        payable\n        returns (uint256 receivedAmount, uint256 paraswapShare, uint256 partnerShare);\n}\n"
      },
      "src/interfaces/IUniswapV2SwapExactAmountIn.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IErrors } from \"./IErrors.sol\";\n\n// Types\nimport { UniswapV2Data } from \"../AugustusV6Types.sol\";\n\n/// @title IUniswapV2SwapExactAmountIn\n/// @notice Interface for direct swaps on Uniswap V2\ninterface IUniswapV2SwapExactAmountIn is IErrors {\n    /*//////////////////////////////////////////////////////////////\n                         SWAP EXACT AMOUNT OUT\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Executes a swapExactAmountIn on Uniswap V2 pools\n    /// @param uniData struct containing data for the swap\n    /// @param partnerAndFee packed partner address and fee percentage, the first 12 bytes is the feeData and the last\n    /// 20 bytes is the partner address\n    /// @param permit The permit data\n    /// @return receivedAmount The amount of destToken received after fees\n    /// @return paraswapShare The share of the fees for Paraswap\n    /// @return partnerShare The share of the fees for the partner\n    function swapExactAmountInOnUniswapV2(\n        UniswapV2Data calldata uniData,\n        uint256 partnerAndFee,\n        bytes calldata permit\n    )\n        external\n        payable\n        returns (uint256 receivedAmount, uint256 paraswapShare, uint256 partnerShare);\n}\n"
      },
      "src/interfaces/IUniswapV3SwapExactAmountIn.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IErrors } from \"./IErrors.sol\";\n\n// Types\nimport { UniswapV3Data } from \"../AugustusV6Types.sol\";\n\n/// @title IUniswapV3SwapExactAmountIn\n/// @notice Interface for executing direct swapExactAmountIn on Uniswap V3\ninterface IUniswapV3SwapExactAmountIn is IErrors {\n    /*//////////////////////////////////////////////////////////////\n                          SWAP EXACT AMOUNT IN\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Executes a swapExactAmountIn on Uniswap V3 pools\n    /// @param uniData struct containing data for the swap\n    /// @param partnerAndFee packed partner address and fee percentage, the first 12 bytes is the feeData and the last\n    /// 20 bytes is the partner address\n    /// @param permit The permit data\n    /// @return receivedAmount The amount of destToken received after fees\n    /// @return paraswapShare The share of the fees for Paraswap\n    /// @return partnerShare The share of the fees for the partner\n    function swapExactAmountInOnUniswapV3(\n        UniswapV3Data calldata uniData,\n        uint256 partnerAndFee,\n        bytes calldata permit\n    )\n        external\n        payable\n        returns (uint256 receivedAmount, uint256 paraswapShare, uint256 partnerShare);\n}\n"
      },
      "lib/solady/src/utils/SafeCastLib.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Safe integer casting library that reverts on overflow.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeCastLib.sol)\n/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol)\nlibrary SafeCastLib {\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                       CUSTOM ERRORS                        */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    error Overflow();\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*          UNSIGNED INTEGER SAFE CASTING OPERATIONS          */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    function toUint8(uint256 x) internal pure returns (uint8) {\n        if (x >= 1 << 8) _revertOverflow();\n        return uint8(x);\n    }\n\n    function toUint16(uint256 x) internal pure returns (uint16) {\n        if (x >= 1 << 16) _revertOverflow();\n        return uint16(x);\n    }\n\n    function toUint24(uint256 x) internal pure returns (uint24) {\n        if (x >= 1 << 24) _revertOverflow();\n        return uint24(x);\n    }\n\n    function toUint32(uint256 x) internal pure returns (uint32) {\n        if (x >= 1 << 32) _revertOverflow();\n        return uint32(x);\n    }\n\n    function toUint40(uint256 x) internal pure returns (uint40) {\n        if (x >= 1 << 40) _revertOverflow();\n        return uint40(x);\n    }\n\n    function toUint48(uint256 x) internal pure returns (uint48) {\n        if (x >= 1 << 48) _revertOverflow();\n        return uint48(x);\n    }\n\n    function toUint56(uint256 x) internal pure returns (uint56) {\n        if (x >= 1 << 56) _revertOverflow();\n        return uint56(x);\n    }\n\n    function toUint64(uint256 x) internal pure returns (uint64) {\n        if (x >= 1 << 64) _revertOverflow();\n        return uint64(x);\n    }\n\n    function toUint72(uint256 x) internal pure returns (uint72) {\n        if (x >= 1 << 72) _revertOverflow();\n        return uint72(x);\n    }\n\n    function toUint80(uint256 x) internal pure returns (uint80) {\n        if (x >= 1 << 80) _revertOverflow();\n        return uint80(x);\n    }\n\n    function toUint88(uint256 x) internal pure returns (uint88) {\n        if (x >= 1 << 88) _revertOverflow();\n        return uint88(x);\n    }\n\n    function toUint96(uint256 x) internal pure returns (uint96) {\n        if (x >= 1 << 96) _revertOverflow();\n        return uint96(x);\n    }\n\n    function toUint104(uint256 x) internal pure returns (uint104) {\n        if (x >= 1 << 104) _revertOverflow();\n        return uint104(x);\n    }\n\n    function toUint112(uint256 x) internal pure returns (uint112) {\n        if (x >= 1 << 112) _revertOverflow();\n        return uint112(x);\n    }\n\n    function toUint120(uint256 x) internal pure returns (uint120) {\n        if (x >= 1 << 120) _revertOverflow();\n        return uint120(x);\n    }\n\n    function toUint128(uint256 x) internal pure returns (uint128) {\n        if (x >= 1 << 128) _revertOverflow();\n        return uint128(x);\n    }\n\n    function toUint136(uint256 x) internal pure returns (uint136) {\n        if (x >= 1 << 136) _revertOverflow();\n        return uint136(x);\n    }\n\n    function toUint144(uint256 x) internal pure returns (uint144) {\n        if (x >= 1 << 144) _revertOverflow();\n        return uint144(x);\n    }\n\n    function toUint152(uint256 x) internal pure returns (uint152) {\n        if (x >= 1 << 152) _revertOverflow();\n        return uint152(x);\n    }\n\n    function toUint160(uint256 x) internal pure returns (uint160) {\n        if (x >= 1 << 160) _revertOverflow();\n        return uint160(x);\n    }\n\n    function toUint168(uint256 x) internal pure returns (uint168) {\n        if (x >= 1 << 168) _revertOverflow();\n        return uint168(x);\n    }\n\n    function toUint176(uint256 x) internal pure returns (uint176) {\n        if (x >= 1 << 176) _revertOverflow();\n        return uint176(x);\n    }\n\n    function toUint184(uint256 x) internal pure returns (uint184) {\n        if (x >= 1 << 184) _revertOverflow();\n        return uint184(x);\n    }\n\n    function toUint192(uint256 x) internal pure returns (uint192) {\n        if (x >= 1 << 192) _revertOverflow();\n        return uint192(x);\n    }\n\n    function toUint200(uint256 x) internal pure returns (uint200) {\n        if (x >= 1 << 200) _revertOverflow();\n        return uint200(x);\n    }\n\n    function toUint208(uint256 x) internal pure returns (uint208) {\n        if (x >= 1 << 208) _revertOverflow();\n        return uint208(x);\n    }\n\n    function toUint216(uint256 x) internal pure returns (uint216) {\n        if (x >= 1 << 216) _revertOverflow();\n        return uint216(x);\n    }\n\n    function toUint224(uint256 x) internal pure returns (uint224) {\n        if (x >= 1 << 224) _revertOverflow();\n        return uint224(x);\n    }\n\n    function toUint232(uint256 x) internal pure returns (uint232) {\n        if (x >= 1 << 232) _revertOverflow();\n        return uint232(x);\n    }\n\n    function toUint240(uint256 x) internal pure returns (uint240) {\n        if (x >= 1 << 240) _revertOverflow();\n        return uint240(x);\n    }\n\n    function toUint248(uint256 x) internal pure returns (uint248) {\n        if (x >= 1 << 248) _revertOverflow();\n        return uint248(x);\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*           SIGNED INTEGER SAFE CASTING OPERATIONS           */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    function toInt8(int256 x) internal pure returns (int8) {\n        int8 y = int8(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt16(int256 x) internal pure returns (int16) {\n        int16 y = int16(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt24(int256 x) internal pure returns (int24) {\n        int24 y = int24(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt32(int256 x) internal pure returns (int32) {\n        int32 y = int32(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt40(int256 x) internal pure returns (int40) {\n        int40 y = int40(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt48(int256 x) internal pure returns (int48) {\n        int48 y = int48(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt56(int256 x) internal pure returns (int56) {\n        int56 y = int56(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt64(int256 x) internal pure returns (int64) {\n        int64 y = int64(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt72(int256 x) internal pure returns (int72) {\n        int72 y = int72(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt80(int256 x) internal pure returns (int80) {\n        int80 y = int80(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt88(int256 x) internal pure returns (int88) {\n        int88 y = int88(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt96(int256 x) internal pure returns (int96) {\n        int96 y = int96(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt104(int256 x) internal pure returns (int104) {\n        int104 y = int104(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt112(int256 x) internal pure returns (int112) {\n        int112 y = int112(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt120(int256 x) internal pure returns (int120) {\n        int120 y = int120(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt128(int256 x) internal pure returns (int128) {\n        int128 y = int128(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt136(int256 x) internal pure returns (int136) {\n        int136 y = int136(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt144(int256 x) internal pure returns (int144) {\n        int144 y = int144(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt152(int256 x) internal pure returns (int152) {\n        int152 y = int152(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt160(int256 x) internal pure returns (int160) {\n        int160 y = int160(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt168(int256 x) internal pure returns (int168) {\n        int168 y = int168(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt176(int256 x) internal pure returns (int176) {\n        int176 y = int176(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt184(int256 x) internal pure returns (int184) {\n        int184 y = int184(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt192(int256 x) internal pure returns (int192) {\n        int192 y = int192(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt200(int256 x) internal pure returns (int200) {\n        int200 y = int200(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt208(int256 x) internal pure returns (int208) {\n        int208 y = int208(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt216(int256 x) internal pure returns (int216) {\n        int216 y = int216(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt224(int256 x) internal pure returns (int224) {\n        int224 y = int224(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt232(int256 x) internal pure returns (int232) {\n        int232 y = int232(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt240(int256 x) internal pure returns (int240) {\n        int240 y = int240(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    function toInt248(int256 x) internal pure returns (int248) {\n        int248 y = int248(x);\n        if (x != y) _revertOverflow();\n        return y;\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*               OTHER SAFE CASTING OPERATIONS                */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    function toInt256(uint256 x) internal pure returns (int256) {\n        if (x >= 1 << 255) _revertOverflow();\n        return int256(x);\n    }\n\n    function toUint256(int256 x) internal pure returns (uint256) {\n        if (x < 0) _revertOverflow();\n        return uint256(x);\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                      PRIVATE HELPERS                       */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    function _revertOverflow() private pure {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Store the function selector of `Overflow()`.\n            mstore(0x00, 0x35278d12)\n            // Revert with (offset, size).\n            revert(0x1c, 0x04)\n        }\n    }\n}\n"
      },
      "src/interfaces/IBalancerV2SwapExactAmountOut.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IErrors } from \"./IErrors.sol\";\n\n// Types\nimport { BalancerV2Data } from \"../AugustusV6Types.sol\";\n\n/// @title IBalancerV2SwapExactAmountOut\n/// @notice Interface for executing swapExactAmountOut directly on Balancer V2 pools\ninterface IBalancerV2SwapExactAmountOut is IErrors {\n    /*//////////////////////////////////////////////////////////////\n                         SWAP EXACT AMOUNT OUT\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Executes a swapExactAmountOut on Balancer V2 pools\n    /// @param balancerData Struct containing data for the swap\n    /// @param partnerAndFee packed partner address and fee percentage, the first 12 bytes is the feeData and the last\n    /// 20 bytes is the partner address\n    /// @param permit Permit data for the swap\n    /// @param data The calldata to execute\n    /// @return spentAmount The actual amount of tokens used to swap\n    /// @return receivedAmount The amount of tokens received\n    /// @return paraswapShare The share of the fees for Paraswap\n    /// @return partnerShare The share of the fees for the partner\n    function swapExactAmountOutOnBalancerV2(\n        BalancerV2Data calldata balancerData,\n        uint256 partnerAndFee,\n        bytes calldata permit,\n        bytes calldata data\n    )\n        external\n        payable\n        returns (uint256 spentAmount, uint256 receivedAmount, uint256 paraswapShare, uint256 partnerShare);\n}\n"
      },
      "src/interfaces/IUniswapV2SwapExactAmountOut.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IErrors } from \"./IErrors.sol\";\n\n// Types\nimport { UniswapV2Data } from \"../AugustusV6Types.sol\";\n\n/// @title IUniswapV2SwapExactAmountOut\n/// @notice Interface for direct swapExactAmountOut on Uniswap V2\ninterface IUniswapV2SwapExactAmountOut is IErrors {\n    /*//////////////////////////////////////////////////////////////\n                          SWAP EXACT AMOUNT IN\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Executes a swapExactAmountOut on Uniswap V2 pools\n    /// @param swapData struct containing data for the swap\n    /// @param partnerAndFee packed partner address and fee percentage, the first 12 bytes is the feeData and the last\n    /// 20 bytes is the partner address\n    /// @param permit The permit data\n    /// @return spentAmount The actual amount of tokens used to swap\n    /// @return receivedAmount The amount of tokens received\n    /// @return paraswapShare The share of the fees for Paraswap\n    /// @return partnerShare The share of the fees for the partner\n    function swapExactAmountOutOnUniswapV2(\n        UniswapV2Data calldata swapData,\n        uint256 partnerAndFee,\n        bytes calldata permit\n    )\n        external\n        payable\n        returns (uint256 spentAmount, uint256 receivedAmount, uint256 paraswapShare, uint256 partnerShare);\n}\n"
      },
      "src/interfaces/IUniswapV3SwapExactAmountOut.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IErrors } from \"./IErrors.sol\";\n\n// Types\nimport { UniswapV3Data } from \"../AugustusV6Types.sol\";\n\n/// @title IUniswapV3SwapExactAmountOut\n/// @notice Interface for executing direct swapExactAmountOut on Uniswap V3\ninterface IUniswapV3SwapExactAmountOut is IErrors {\n    /*//////////////////////////////////////////////////////////////\n                         SWAP EXACT AMOUNT OUT\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Executes a swapExactAmountOut on Uniswap V3 pools\n    /// @param swapData struct containing data for the swap\n    /// @param partnerAndFee packed partner address and fee percentage, the first 12 bytes is the feeData and the last\n    /// 20 bytes is the partner address\n    /// @param permit The permit data\n    /// @return spentAmount The actual amount of tokens used to swap\n    /// @return receivedAmount The amount of tokens received\n    /// @return paraswapShare The share of the fees for Paraswap\n    /// @return partnerShare The share of the fees for the partner\n    function swapExactAmountOutOnUniswapV3(\n        UniswapV3Data calldata swapData,\n        uint256 partnerAndFee,\n        bytes calldata permit\n    )\n        external\n        payable\n        returns (uint256 spentAmount, uint256 receivedAmount, uint256 paraswapShare, uint256 partnerShare);\n}\n"
      },
      "src/interfaces/IAugustusFeeVault.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IERC20 } from \"@openzeppelin/token/ERC20/IERC20.sol\";\n\n/// @title IAugustusFeeVault\n/// @notice Interface for the AugustusFeeVault contract\ninterface IAugustusFeeVault {\n    /*//////////////////////////////////////////////////////////////\n                                 ERRORS\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Error emitted when withdraw amount is zero or exceeds the stored amount\n    error InvalidWithdrawAmount();\n\n    /// @notice Error emmitted when caller is not an approved augustus contract\n    error UnauthorizedCaller();\n\n    /// @notice Error emitted when an invalid parameter length is passed\n    error InvalidParameterLength();\n\n    /// @notice Error emitted when batch withdraw fails\n    error BatchCollectFailed();\n\n    /*//////////////////////////////////////////////////////////////\n                                 EVENTS\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Emitted when an augustus contract approval status is set\n    /// @param augustus The augustus contract address\n    /// @param approved The approval status\n    event AugustusApprovalSet(address indexed augustus, bool approved);\n\n    /*//////////////////////////////////////////////////////////////\n                                STRUCTS\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Struct to register fees\n    /// @param addresses The addresses to register fees for\n    /// @param token The token to register fees for\n    /// @param fees The fees to register\n    struct FeeRegistration {\n        address[] addresses;\n        IERC20 token;\n        uint256[] fees;\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                                COLLECT\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Allows partners to withdraw fees allocated to them and stored in the vault\n    /// @param token The token to withdraw fees in\n    /// @param amount The amount of fees to withdraw\n    /// @param recipient The address to send the fees to\n    /// @return success Whether the transfer was successful or not\n    function withdrawSomeERC20(IERC20 token, uint256 amount, address recipient) external returns (bool success);\n\n    /// @notice Allows partners to withdraw all fees allocated to them and stored in the vault for a given token\n    /// @param token The token to withdraw fees in\n    /// @param recipient The address to send the fees to\n    /// @return success Whether the transfer was successful or not\n    function withdrawAllERC20(IERC20 token, address recipient) external returns (bool success);\n\n    /// @notice Allows partners to withdraw all fees allocated to them and stored in the vault for multiple tokens\n    /// @param tokens The tokens to withdraw fees i\n    /// @param recipient The address to send the fees to\n    /// @return success Whether the transfer was successful or not\n    function batchWithdrawAllERC20(IERC20[] calldata tokens, address recipient) external returns (bool success);\n\n    /// @notice Allows partners to withdraw fees allocated to them and stored in the vault\n    /// @param tokens The tokens to withdraw fees in\n    /// @param amounts The amounts of fees to withdraw\n    /// @param recipient The address to send the fees to\n    /// @return success Whether the transfer was successful or not\n    function batchWithdrawSomeERC20(\n        IERC20[] calldata tokens,\n        uint256[] calldata amounts,\n        address recipient\n    )\n        external\n        returns (bool success);\n\n    /*//////////////////////////////////////////////////////////////\n                            BALANCE GETTERS\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Get the balance of a given token for a given partner\n    /// @param token The token to get the balance of\n    /// @param partner The partner to get the balance for\n    /// @return feeBalance The balance of the given token for the given partner\n    function getBalance(IERC20 token, address partner) external view returns (uint256 feeBalance);\n\n    /// @notice Get the balances of a given partner for multiple tokens\n    /// @param tokens The tokens to get the balances of\n    /// @param partner The partner to get the balances for\n    /// @return feeBalances The balances of the given tokens for the given partner\n    function batchGetBalance(\n        IERC20[] calldata tokens,\n        address partner\n    )\n        external\n        view\n        returns (uint256[] memory feeBalances);\n\n    /// @notice Returns the unallocated fees for a given token\n    /// @param token The token to get the unallocated fees for\n    /// @return unallocatedFees The unallocated fees for the given token\n    function getUnallocatedFees(IERC20 token) external view returns (uint256 unallocatedFees);\n\n    /*//////////////////////////////////////////////////////////////\n                                 OWNER\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Registers the given feeData to the vault\n    /// @param feeData The fee registration data\n    function registerFees(FeeRegistration memory feeData) external;\n\n    /// @notice Sets the augustus contract approval status\n    /// @param augustus The augustus contract address\n    /// @param approved The approval status\n    function setAugustusApproval(address augustus, bool approved) external;\n\n    /// @notice Sets the contract pause state\n    /// @param _isPaused The new pause state\n    function setContractPauseState(bool _isPaused) external;\n}\n"
      },
      "src/interfaces/IAugustusFees.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n/// @title IAugustusFees\n/// @notice Interface for the AugustusFees contract, which handles the fees for the Augustus aggregator\ninterface IAugustusFees {\n    /*//////////////////////////////////////////////////////////////\n                                ERRORS\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Error emmited when the balance is not enough to pay the fees\n    error InsufficientBalanceToPayFees();\n\n    /// @notice Error emmited when the quotedAmount is bigger than the fromAmount\n    error InvalidQuotedAmount();\n\n    /*//////////////////////////////////////////////////////////////\n                                 PUBLIC\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Parses the `partnerAndFee` parameter to extract the partner address and fee data.\n    /// @dev `partnerAndFee` is a uint256 value where data is packed in a specific bit layout.\n    ///\n    ///      The bit layout for `partnerAndFee` is as follows:\n    ///      - The most significant 160 bits (positions 255 to 96) represent the partner address.\n    ///      - Bits 95 to 92 are reserved for flags indicating various fee processing conditions:\n    ///          - 95th bit: `IS_TAKE_SURPLUS_MASK` - Partner takes surplus\n    ///          - 94th bit: `IS_REFERRAL_MASK` - Referral takes surplus\n    ///          - 93rd bit: `IS_SKIP_BLACKLIST_MASK` - Bypass token blacklist when processing fees\n    ///          - 92nd bit: `IS_CAP_SURPLUS_MASK` - Cap surplus to 1% of quoted amount\n    ///      - The least significant 16 bits (positions 15 to 0) encode the fee percentage.\n    ///\n    /// @param partnerAndFee Packed uint256 containing both partner address and fee data.\n    /// @return partner The extracted partner address as a payable address.\n    /// @return feeData The extracted fee data containing the fee percentage and flags.\n    function parsePartnerAndFeeData(uint256 partnerAndFee)\n        external\n        pure\n        returns (address payable partner, uint256 feeData);\n}\n"
      },
      "src/storage/AugustusStorage.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IERC20 } from \"@openzeppelin/token/ERC20/IERC20.sol\";\n\n// @title AugustusStorage\n// @notice Inherited storage layout for AugustusV6,\n// contracts should inherit this contract to access the storage layout\ncontract AugustusStorage {\n    /*//////////////////////////////////////////////////////////////\n                               FEES\n    //////////////////////////////////////////////////////////////*/\n\n    // @dev Mapping of tokens to boolean indicating if token is blacklisted for fee collection\n    mapping(IERC20 token => bool isBlacklisted) public blacklistedTokens;\n\n    // @dev Fee wallet to directly transfer paraswap share to\n    address payable public feeWallet;\n\n    // @dev Fee wallet address to register the paraswap share to in the fee vault\n    address payable public feeWalletDelegate;\n\n    /*//////////////////////////////////////////////////////////////\n                                CONTROL\n    //////////////////////////////////////////////////////////////*/\n\n    // @dev Contract paused state\n    bool public paused;\n}\n"
      },
      "src/util/GenericUtils.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Contracts\nimport { AugustusFees } from \"../fees/AugustusFees.sol\";\n\n// Utils\nimport { Permit2Utils } from \"./Permit2Utils.sol\";\nimport { PauseUtils } from \"./PauseUtils.sol\";\n\n/// @title GenericUtils\n/// @notice A contract containing common utilities for Generic swaps\nabstract contract GenericUtils is AugustusFees, Permit2Utils, PauseUtils {\n    /*//////////////////////////////////////////////////////////////\n                                INTERNAL\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev Call executor with executorData and amountIn\n    function _callSwapExactAmountInExecutor(\n        address executor,\n        bytes calldata executorData,\n        uint256 amountIn\n    )\n        internal\n    {\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            // get the length of the executorData\n            // + 4 bytes for the selector\n            // + 32 bytes for fromAmount\n            // + 32 bytes for sender\n            let totalLength := add(executorData.length, 68)\n            calldatacopy(add(0x7c, 4), executorData.offset, executorData.length) // store the executorData\n            mstore(add(0x7c, add(4, executorData.length)), amountIn) // store the amountIn\n            mstore(add(0x7c, add(36, executorData.length)), caller()) // store the sender\n            // call executor and forward call value\n            if iszero(call(gas(), executor, callvalue(), 0x7c, totalLength, 0, 0)) {\n                returndatacopy(0x7c, 0, returndatasize()) // copy the revert data to memory\n                revert(0x7c, returndatasize()) // revert with the revert data\n            }\n        }\n    }\n\n    /// @dev Call executor with executorData, maxAmountIn, amountOut\n    function _callSwapExactAmountOutExecutor(\n        address executor,\n        bytes calldata executorData,\n        uint256 maxAmountIn,\n        uint256 amountOut\n    )\n        internal\n    {\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            // get the length of the executorData\n            // + 4 bytes for the selector\n            // + 32 bytes for fromAmount\n            // + 32 bytes for toAmount\n            // + 32 bytes for sender\n            let totalLength := add(executorData.length, 100)\n            calldatacopy(add(0x7c, 4), executorData.offset, executorData.length) // store the executorData\n            mstore(add(0x7c, add(4, executorData.length)), maxAmountIn) // store the maxAmountIn\n            mstore(add(0x7c, add(36, executorData.length)), amountOut) // store the amountOut\n            mstore(add(0x7c, add(68, executorData.length)), caller()) // store the sender\n            // call executor and forward call value\n            if iszero(call(gas(), executor, callvalue(), 0x7c, totalLength, 0, 0)) {\n                returndatacopy(0x7c, 0, returndatasize()) // copy the revert data to memory\n                revert(0x7c, returndatasize()) // revert with the revert data\n            }\n        }\n    }\n}\n"
      },
      "src/interfaces/IGenericSwapExactAmountIn.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IErrors } from \"./IErrors.sol\";\n\n// Types\nimport { GenericData } from \"../AugustusV6Types.sol\";\n\n/// @title IGenericSwapExactAmountIn\n/// @notice Interface for executing a generic swapExactAmountIn through an Augustus executor\ninterface IGenericSwapExactAmountIn is IErrors {\n    /*//////////////////////////////////////////////////////////////\n                          SWAP EXACT AMOUNT IN\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Executes a generic swapExactAmountIn using the given executorData on the given executor\n    /// @param executor The address of the executor contract to use\n    /// @param swapData Generic data containing the swap information\n    /// @param partnerAndFee packed partner address and fee percentage, the first 12 bytes is the feeData and the last\n    /// 20 bytes is the partner address\n    /// @param permit The permit data\n    /// @param executorData The data to execute on the executor\n    /// @return receivedAmount The amount of destToken received after fees\n    /// @return paraswapShare The share of the fees for Paraswap\n    /// @return partnerShare The share of the fees for the partner\n    function swapExactAmountIn(\n        address executor,\n        GenericData calldata swapData,\n        uint256 partnerAndFee,\n        bytes calldata permit,\n        bytes calldata executorData\n    )\n        external\n        payable\n        returns (uint256 receivedAmount, uint256 paraswapShare, uint256 partnerShare);\n}\n"
      },
      "src/interfaces/IGenericSwapExactAmountOut.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IErrors } from \"./IErrors.sol\";\n\n// Types\nimport { GenericData } from \"../AugustusV6Types.sol\";\n\n/// @title IGenericSwapExactAmountOut\n/// @notice Interface for executing a generic swapExactAmountOut through an Augustus executor\ninterface IGenericSwapExactAmountOut is IErrors {\n    /*//////////////////////////////////////////////////////////////\n                         SWAP EXACT AMOUNT OUT\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Executes a generic swapExactAmountOut using the given executorData on the given executor\n    /// @param executor The address of the executor contract to use\n    /// @param swapData Generic data containing the swap information\n    /// @param partnerAndFee packed partner address and fee percentage, the first 12 bytes is the feeData and the last\n    /// 20 bytes is the partner address\n    /// @param permit The permit data\n    /// @param executorData The data to execute on the executor\n    /// @return spentAmount The actual amount of tokens used to swap\n    /// @return receivedAmount The amount of tokens received from the swap\n    /// @return paraswapShare The share of the fees for Paraswap\n    /// @return partnerShare The share of the fees for the partner\n    function swapExactAmountOut(\n        address executor,\n        GenericData calldata swapData,\n        uint256 partnerAndFee,\n        bytes calldata permit,\n        bytes calldata executorData\n    )\n        external\n        payable\n        returns (uint256 spentAmount, uint256 receivedAmount, uint256 paraswapShare, uint256 partnerShare);\n}\n"
      },
      "src/interfaces/IAugustusRFQRouter.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n// Interfaces\nimport { IErrors } from \"./IErrors.sol\";\n\n// Types\nimport { AugustusRFQData, OrderInfo } from \"../AugustusV6Types.sol\";\n\n/// @title IAugustusRFQRouter\n/// @notice Interface for direct swaps on AugustusRFQ\ninterface IAugustusRFQRouter is IErrors {\n    /*//////////////////////////////////////////////////////////////\n                                 ERRORS\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Emitted when the passed msg.value is not equal to the fromAmount\n    error IncorrectEthAmount();\n\n    /*//////////////////////////////////////////////////////////////\n                             TRY BATCH FILL\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Executes a tryBatchFillTakerAmount or tryBatchFillMakerAmount call on AugustusRFQ\n    /// the function that is executed is defined by the direction flag in the data param\n    /// @param data Struct containing common data for AugustusRFQ\n    /// @param orders An array containing AugustusRFQ orderInfo data\n    /// @param permit Permit data for the swap\n    /// @return spentAmount The amount of tokens spent\n    /// @return receivedAmount The amount of tokens received\n    function swapOnAugustusRFQTryBatchFill(\n        AugustusRFQData calldata data,\n        OrderInfo[] calldata orders,\n        bytes calldata permit\n    )\n        external\n        payable\n        returns (uint256 spentAmount, uint256 receivedAmount);\n}\n"
      },
      "src/interfaces/IAugustusRFQ.sol": {
        "content": "// SPDX-License-Identifier: ISC\n\npragma solidity 0.8.22;\npragma abicoder v2;\n\n// Types\nimport { Order, OrderInfo } from \"../AugustusV6Types.sol\";\n\ninterface IAugustusRFQ {\n    /// @dev Allows taker to fill an order\n    /// @param order Order quote to fill\n    /// @param signature Signature of the maker corresponding to the order\n    function fillOrder(Order calldata order, bytes calldata signature) external;\n\n    /// @dev The same as fillOrder but allows sender to specify the target beneficiary address\n    /// @param order Order quote to fill\n    /// @param signature Signature of the maker corresponding to the order\n    /// @param target Address of the receiver\n    function fillOrderWithTarget(Order calldata order, bytes calldata signature, address target) external;\n\n    /// @dev Allows taker to fill an order partially\n    /// @param order Order quote to fill\n    /// @param signature Signature of the maker corresponding to the order\n    /// @param takerTokenFillAmount Maximum taker token to fill this order with.\n    function partialFillOrder(\n        Order calldata order,\n        bytes calldata signature,\n        uint256 takerTokenFillAmount\n    )\n        external\n        returns (uint256 makerTokenFilledAmount);\n\n    /// @dev Same as `partialFillOrder` but it allows to specify the destination address\n    ///  @param order Order quote to fill\n    ///  @param signature Signature of the maker corresponding to the order\n    ///  @param takerTokenFillAmount Maximum taker token to fill this order with.\n    ///  @param target Address that will receive swap funds\n    function partialFillOrderWithTarget(\n        Order calldata order,\n        bytes calldata signature,\n        uint256 takerTokenFillAmount,\n        address target\n    )\n        external\n        returns (uint256 makerTokenFilledAmount);\n\n    /// @dev Same as `partialFillOrderWithTarget` but it allows to pass permit\n    ///  @param order Order quote to fill\n    ///  @param signature Signature of the maker corresponding to the order\n    ///  @param takerTokenFillAmount Maximum taker token to fill this order with.\n    ///  @param target Address that will receive swap funds\n    ///  @param permitTakerAsset Permit calldata for taker\n    ///  @param permitMakerAsset Permit calldata for maker\n    function partialFillOrderWithTargetPermit(\n        Order calldata order,\n        bytes calldata signature,\n        uint256 takerTokenFillAmount,\n        address target,\n        bytes calldata permitTakerAsset,\n        bytes calldata permitMakerAsset\n    )\n        external\n        returns (uint256 makerTokenFilledAmount);\n\n    /// @dev batch fills orders until the takerFillAmount is swapped\n    /// @dev skip the order if it fails\n    /// @param orderInfos OrderInfo to fill\n    /// @param takerFillAmount total taker amount to fill\n    /// @param target Address of receiver\n\n    function tryBatchFillOrderTakerAmount(\n        OrderInfo[] calldata orderInfos,\n        uint256 takerFillAmount,\n        address target\n    )\n        external;\n\n    /// @dev batch fills orders until the makerFillAmount is swapped\n    /// @dev skip the order if it fails\n    /// @param orderInfos OrderInfo to fill\n    /// @param makerFillAmount total maker amount to fill\n    /// @param target Address of receiver\n    function tryBatchFillOrderMakerAmount(\n        OrderInfo[] calldata orderInfos,\n        uint256 makerFillAmount,\n        address target\n    )\n        external;\n}\n"
      },
      "src/interfaces/IUniswapV3SwapCallback.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n/// @title Callback for IUniswapV3PoolActions#swap\n/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface\ninterface IUniswapV3SwapCallback {\n    /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.\n    /// @dev In the implementation you must pay the pool tokens owed for the swap.\n    /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.\n    /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.\n    /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by\n    /// the end of the swap. If positive, the callback must send that amount of token0 to the pool.\n    /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by\n    /// the end of the swap. If positive, the callback must send that amount of token1 to the pool.\n    /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call\n    function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external;\n}\n"
      },
      "src/interfaces/IWETH.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\nimport { IERC20 } from \"@openzeppelin/token/ERC20/IERC20.sol\";\n\n/// @title IWETH\n/// @notice An interface for WETH IERC20\ninterface IWETH is IERC20 {\n    function deposit() external payable;\n    function withdraw(uint256 amount) external;\n}\n"
      },
      "src/interfaces/IErrors.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n/// @title IErrors\n/// @notice Common interface for errors\ninterface IErrors {\n    /*//////////////////////////////////////////////////////////////\n                                 ERRORS\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Emitted when the returned amount is less than the minimum amount\n    error InsufficientReturnAmount();\n\n    /// @notice Emitted when the specified toAmount is less than the minimum amount (2)\n    error InvalidToAmount();\n\n    /// @notice Emmited when the srcToken and destToken are the same\n    error ArbitrageNotSupported();\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "@prb/test/=lib/prb-test/src/",
        "forge-std/=lib/forge-std/src/",
        "@openzeppelin/=lib/openzeppelin-contracts/contracts/",
        "@solady/=lib/solady/src/",
        "@create3/=lib/create3-factory/src/",
        "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
        "create3-factory/=lib/create3-factory/",
        "ds-test/=lib/forge-std/lib/ds-test/src/",
        "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
        "openzeppelin-contracts/=lib/openzeppelin-contracts/",
        "prb-test/=lib/prb-test/src/",
        "solady/=lib/solady/",
        "solidity-bytes-utils/=lib/solidity-bytes-utils/contracts/",
        "solmate/=lib/create3-factory/lib/solmate/src/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 1000000
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "none",
        "appendCBOR": true
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "shanghai",
      "viaIR": true,
      "libraries": {}
    }
  }}