{
  "language": "Solidity",
  "sources": {
    "contracts/deployer/MasterDeployer.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"../interfaces/IPoolFactory.sol\";\nimport \"../utils/TridentOwnable.sol\";\n\n/// @notice Trident pool deployer contract with template factory whitelist.\n/// @author Mudit Gupta.\ncontract MasterDeployer is TridentOwnable {\n    event DeployPool(address indexed factory, address indexed pool, bytes deployData);\n    event AddToWhitelist(address indexed factory);\n    event RemoveFromWhitelist(address indexed factory);\n    event BarFeeUpdated(uint256 indexed barFee);\n\n    uint256 public barFee;\n    address public immutable barFeeTo;\n    address public immutable bento;\n\n    uint256 internal constant MAX_FEE = 10000; // @dev 100%.\n\n    mapping(address => bool) public pools;\n    mapping(address => bool) public whitelistedFactories;\n\n    constructor(\n        uint256 _barFee,\n        address _barFeeTo,\n        address _bento\n    ) {\n        require(_barFee <= MAX_FEE, \"INVALID_BAR_FEE\");\n        require(_barFeeTo != address(0), \"ZERO_ADDRESS\");\n        require(_bento != address(0), \"ZERO_ADDRESS\");\n\n        barFee = _barFee;\n        barFeeTo = _barFeeTo;\n        bento = _bento;\n    }\n\n    function deployPool(address _factory, bytes calldata _deployData) external returns (address pool) {\n        require(whitelistedFactories[_factory], \"FACTORY_NOT_WHITELISTED\");\n        pool = IPoolFactory(_factory).deployPool(_deployData);\n        pools[pool] = true;\n        emit DeployPool(_factory, pool, _deployData);\n    }\n\n    function addToWhitelist(address _factory) external onlyOwner {\n        whitelistedFactories[_factory] = true;\n        emit AddToWhitelist(_factory);\n    }\n\n    function removeFromWhitelist(address _factory) external onlyOwner {\n        whitelistedFactories[_factory] = false;\n        emit RemoveFromWhitelist(_factory);\n    }\n\n    function setBarFee(uint256 _barFee) external onlyOwner {\n        require(_barFee <= MAX_FEE, \"INVALID_BAR_FEE\");\n        barFee = _barFee;\n        emit BarFeeUpdated(_barFee);\n    }\n}\n"
    },
    "contracts/interfaces/IPoolFactory.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\n/// @notice Trident pool deployment interface.\ninterface IPoolFactory {\n    function deployPool(bytes calldata _deployData) external returns (address pool);\n\n    function configAddress(bytes32 data) external returns (address pool);\n}\n"
    },
    "contracts/utils/TridentOwnable.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\n/// @notice Trident access control contract.\n/// @author Adapted from https://github.com/boringcrypto/BoringSolidity/blob/master/contracts/BoringOwnable.sol, License-Identifier: MIT.\ncontract TridentOwnable {\n    address public owner;\n    address public pendingOwner;\n\n    event TransferOwner(address indexed sender, address indexed recipient);\n    event TransferOwnerClaim(address indexed sender, address indexed recipient);\n\n    /// @notice Initialize and grant deployer account (`msg.sender`) `owner` access role.\n    constructor() {\n        owner = msg.sender;\n        emit TransferOwner(address(0), msg.sender);\n    }\n\n    /// @notice Access control modifier that requires modified function to be called by `owner` account.\n    modifier onlyOwner() {\n        require(msg.sender == owner, \"NOT_OWNER\");\n        _;\n    }\n\n    /// @notice `pendingOwner` can claim `owner` account.\n    function claimOwner() external {\n        require(msg.sender == pendingOwner, \"NOT_PENDING_OWNER\");\n        emit TransferOwner(owner, msg.sender);\n        owner = msg.sender;\n        pendingOwner = address(0);\n    }\n\n    /// @notice Transfer `owner` account.\n    /// @param recipient Account granted `owner` access control.\n    /// @param direct If 'true', ownership is directly transferred.\n    function transferOwner(address recipient, bool direct) external onlyOwner {\n        require(recipient != address(0), \"ZERO_ADDRESS\");\n        if (direct) {\n            owner = recipient;\n            emit TransferOwner(msg.sender, recipient);\n        } else {\n            pendingOwner = recipient;\n            emit TransferOwnerClaim(msg.sender, recipient);\n        }\n    }\n}\n"
    },
    "contracts/migration/TridentSushiRollCP.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity 0.8.7;\n\nimport \"../utils/TridentBatchable.sol\";\nimport \"../utils/TridentPermit.sol\";\nimport \"../interfaces/IBentoBoxMinimal.sol\";\nimport \"../interfaces/ITridentRouter.sol\";\nimport \"../interfaces/IMasterDeployer.sol\";\nimport \"../interfaces/IPoolFactory.sol\";\nimport \"../interfaces/IUniswapV2Minimal.sol\";\nimport \"../interfaces/IPool.sol\";\n\n/// @notice Liquidity migrator from UniV2 style pool to Trident Constant product pool.\ncontract TridentSushiRollCP is TridentBatchable, TridentPermit {\n    error MinimumOutput();\n\n    IBentoBoxMinimal internal immutable bentoBox;\n    IPoolFactory internal immutable poolFactory;\n    IMasterDeployer internal immutable masterDeployer;\n\n    constructor(\n        IBentoBoxMinimal _bentoBox,\n        IPoolFactory _poolFactory,\n        IMasterDeployer _masterDeployer\n    ) {\n        bentoBox = _bentoBox;\n        poolFactory = _poolFactory;\n        masterDeployer = _masterDeployer;\n    }\n\n    /** @notice Function to migrate existing Sushiswap or other Uniswap V2 style pools to Trident.\n        @param pair Uniswap V2 style liquidity pool address.\n        @param amount Liquidity amount (Lp token balance) to be migrated.\n        @param swapFee Swap fee of the Trident CP pool we are migrating into.\n        @param twapSupport Whether the Trident CP pool we are migrating into supports twap oracles.\n        @param minReceived Slippage protection for minting liquidity on the Trident CP pool.\n        @dev If the pool with the current conditions doesn't exist it will be deployed. */\n    function migrate(\n        IUniswapV2Minimal pair,\n        uint256 amount,\n        uint256 swapFee,\n        bool twapSupport,\n        uint256 minReceived\n    ) external returns (uint256 liquidity) {\n        address token0 = pair.token0();\n        address token1 = pair.token1();\n\n        bytes memory poolData = abi.encode(token0, token1, swapFee, twapSupport);\n        address tridentPool = poolFactory.configAddress(keccak256(poolData));\n\n        if (tridentPool == address(0)) {\n            tridentPool = masterDeployer.deployPool(address(poolFactory), poolData);\n        }\n\n        pair.transferFrom(msg.sender, address(pair), amount);\n        (uint256 amount0, uint256 amount1) = pair.burn(address(bentoBox));\n\n        bentoBox.deposit(token0, address(bentoBox), tridentPool, amount0, 0);\n        bentoBox.deposit(token1, address(bentoBox), tridentPool, amount1, 0);\n\n        liquidity = IPool(tridentPool).mint(abi.encode(msg.sender));\n\n        if (liquidity < minReceived) revert MinimumOutput();\n    }\n}\n"
    },
    "contracts/utils/TridentBatchable.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\n/// @notice Generic contract exposing the batch call functionality.\nabstract contract TridentBatchable {\n    /// @notice Provides batch function calls for this contract and returns the data from all of them if they all succeed.\n    /// Adapted from https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol, License-Identifier: GPL-2.0-or-later.\n    /// @dev The `msg.value` should not be trusted for any method callable from this function.\n    /// @param data ABI-encoded params for each of the calls to make to this contract.\n    /// @return results The results from each of the calls passed in via `data`.\n    function batch(bytes[] calldata data) external payable returns (bytes[] memory results) {\n        results = new bytes[](data.length);\n\n        for (uint256 i = 0; i < data.length; i++) {\n            (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n            if (!success) {\n                // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n                if (result.length < 68) revert();\n                assembly {\n                    result := add(result, 0x04)\n                }\n                revert(abi.decode(result, (string)));\n            }\n\n            results[i] = result;\n        }\n    }\n}\n"
    },
    "contracts/utils/TridentPermit.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\n/// @notice Generic contract exposing the permit functionality.\nabstract contract TridentPermit {\n    error PermitFailed();\n\n    /// @notice Provides EIP-2612 signed approval for this contract to spend user tokens.\n    /// @param token Address of ERC-20 token.\n    /// @param amount Token amount to grant spending right over.\n    /// @param deadline Termination for signed approval (UTC timestamp in seconds).\n    /// @param v The recovery byte of the signature.\n    /// @param r Half of the ECDSA signature pair.\n    /// @param s Half of the ECDSA signature pair.\n    function permitThis(\n        address token,\n        uint256 amount,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external {\n        (bool success, ) = token.call(abi.encodeWithSelector(0xd505accf, msg.sender, address(this), amount, deadline, v, r, s)); // permit(address,address,uint256,uint256,uint8,bytes32,bytes32).\n        if (!success) revert PermitFailed();\n    }\n\n    /// @notice Provides DAI-derived signed approval for this contract to spend user tokens.\n    /// @param token Address of ERC-20 token.\n    /// @param nonce Token owner's nonce - increases at each call to {permit}.\n    /// @param expiry Termination for signed approval - UTC timestamp in seconds.\n    /// @param v The recovery byte of the signature.\n    /// @param r Half of the ECDSA signature pair.\n    /// @param s Half of the ECDSA signature pair.\n    function permitThisAllowed(\n        address token,\n        uint256 nonce,\n        uint256 expiry,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external {\n        (bool success, ) = token.call(abi.encodeWithSelector(0x8fcbaf0c, msg.sender, address(this), nonce, expiry, true, v, r, s)); // permit(address,address,uint256,uint256,bool,uint8,bytes32,bytes32).\n        if (!success) revert PermitFailed();\n    }\n}\n"
    },
    "contracts/interfaces/IBentoBoxMinimal.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\nimport \"../libraries/RebaseLibrary.sol\";\n\n/// @notice Minimal BentoBox vault interface.\n/// @dev `token` is aliased as `address` from `IERC20` for simplicity.\ninterface IBentoBoxMinimal {\n    /// @notice Balance per ERC-20 token per account in shares.\n    function balanceOf(address, address) external view returns (uint256);\n\n    /// @dev Helper function to represent an `amount` of `token` in shares.\n    /// @param token The ERC-20 token.\n    /// @param amount The `token` amount.\n    /// @param roundUp If the result `share` should be rounded up.\n    /// @return share The token amount represented in shares.\n    function toShare(\n        address token,\n        uint256 amount,\n        bool roundUp\n    ) external view returns (uint256 share);\n\n    /// @dev Helper function to represent shares back into the `token` amount.\n    /// @param token The ERC-20 token.\n    /// @param share The amount of shares.\n    /// @param roundUp If the result should be rounded up.\n    /// @return amount The share amount back into native representation.\n    function toAmount(\n        address token,\n        uint256 share,\n        bool roundUp\n    ) external view returns (uint256 amount);\n\n    /// @notice Registers this contract so that users can approve it for BentoBox.\n    function registerProtocol() external;\n\n    /// @notice Deposit an amount of `token` represented in either `amount` or `share`.\n    /// @param token The ERC-20 token to deposit.\n    /// @param from which account to pull the tokens.\n    /// @param to which account to push the tokens.\n    /// @param amount Token amount in native representation to deposit.\n    /// @param share Token amount represented in shares to deposit. Takes precedence over `amount`.\n    /// @return amountOut The amount deposited.\n    /// @return shareOut The deposited amount represented in shares.\n    function deposit(\n        address token,\n        address from,\n        address to,\n        uint256 amount,\n        uint256 share\n    ) external payable returns (uint256 amountOut, uint256 shareOut);\n\n    /// @notice Withdraws an amount of `token` from a user account.\n    /// @param token_ The ERC-20 token to withdraw.\n    /// @param from which user to pull the tokens.\n    /// @param to which user to push the tokens.\n    /// @param amount of tokens. Either one of `amount` or `share` needs to be supplied.\n    /// @param share Like above, but `share` takes precedence over `amount`.\n    function withdraw(\n        address token_,\n        address from,\n        address to,\n        uint256 amount,\n        uint256 share\n    ) external returns (uint256 amountOut, uint256 shareOut);\n\n    /// @notice Transfer shares from a user account to another one.\n    /// @param token The ERC-20 token to transfer.\n    /// @param from which user to pull the tokens.\n    /// @param to which user to push the tokens.\n    /// @param share The amount of `token` in shares.\n    function transfer(\n        address token,\n        address from,\n        address to,\n        uint256 share\n    ) external;\n\n    /// @dev Reads the Rebase `totals`from storage for a given token\n    function totals(address token) external view returns (Rebase memory total);\n\n    /// @dev Approves users' BentoBox assets to a \"master\" contract.\n    function setMasterContractApproval(\n        address user,\n        address masterContract,\n        bool approved,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n}\n"
    },
    "contracts/interfaces/ITridentRouter.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\n/// @notice Trident pool router interface.\ninterface ITridentRouter {\n    struct Path {\n        address pool;\n        bytes data;\n    }\n\n    struct ExactInputSingleParams {\n        uint256 amountIn;\n        uint256 amountOutMinimum;\n        address pool;\n        address tokenIn;\n        bytes data;\n    }\n\n    struct ExactInputParams {\n        address tokenIn;\n        uint256 amountIn;\n        uint256 amountOutMinimum;\n        Path[] path;\n    }\n\n    struct TokenInput {\n        address token;\n        bool native;\n        uint256 amount;\n    }\n\n    struct InitialPath {\n        address tokenIn;\n        address pool;\n        bool native;\n        uint256 amount;\n        bytes data;\n    }\n\n    struct PercentagePath {\n        address tokenIn;\n        address pool;\n        uint64 balancePercentage; // Multiplied by 10^6. 100% = 100_000_000\n        bytes data;\n    }\n\n    struct Output {\n        address token;\n        address to;\n        bool unwrapBento;\n        uint256 minAmount;\n    }\n\n    struct ComplexPathParams {\n        InitialPath[] initialPath;\n        PercentagePath[] percentagePath;\n        Output[] output;\n    }\n}\n"
    },
    "contracts/interfaces/IMasterDeployer.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\n/// @notice Trident pool deployer interface.\ninterface IMasterDeployer {\n    function barFee() external view returns (uint256);\n\n    function barFeeTo() external view returns (address);\n\n    function bento() external view returns (address);\n\n    function migrator() external view returns (address);\n\n    function pools(address pool) external view returns (bool);\n\n    function deployPool(address factory, bytes calldata deployData) external returns (address);\n}\n"
    },
    "contracts/interfaces/IUniswapV2Minimal.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"./IERC20.sol\";\n\n/// @notice Minimal Uniswap V2 LP interface.\ninterface IUniswapV2Minimal is IERC20 {\n    function token0() external view returns (address);\n\n    function token1() external view returns (address);\n\n    function burn(address to) external returns (uint256 amount0, uint256 amount1);\n}\n"
    },
    "contracts/interfaces/IPool.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.5.0;\npragma experimental ABIEncoderV2;\n\n/// @notice Trident pool interface.\ninterface IPool {\n    /// @notice Executes a swap from one token to another.\n    /// @dev The input tokens must've already been sent to the pool.\n    /// @param data ABI-encoded params that the pool requires.\n    /// @return finalAmountOut The amount of output tokens that were sent to the user.\n    function swap(bytes calldata data) external returns (uint256 finalAmountOut);\n\n    /// @notice Executes a swap from one token to another with a callback.\n    /// @dev This function allows borrowing the output tokens and sending the input tokens in the callback.\n    /// @param data ABI-encoded params that the pool requires.\n    /// @return finalAmountOut The amount of output tokens that were sent to the user.\n    function flashSwap(bytes calldata data) external returns (uint256 finalAmountOut);\n\n    /// @notice Mints liquidity tokens.\n    /// @param data ABI-encoded params that the pool requires.\n    /// @return liquidity The amount of liquidity tokens that were minted for the user.\n    function mint(bytes calldata data) external returns (uint256 liquidity);\n\n    /// @notice Burns liquidity tokens.\n    /// @dev The input LP tokens must've already been sent to the pool.\n    /// @param data ABI-encoded params that the pool requires.\n    /// @return withdrawnAmounts The amount of various output tokens that were sent to the user.\n    function burn(bytes calldata data) external returns (TokenAmount[] memory withdrawnAmounts);\n\n    /// @notice Burns liquidity tokens for a single output token.\n    /// @dev The input LP tokens must've already been sent to the pool.\n    /// @param data ABI-encoded params that the pool requires.\n    /// @return amountOut The amount of output tokens that were sent to the user.\n    function burnSingle(bytes calldata data) external returns (uint256 amountOut);\n\n    /// @return A unique identifier for the pool type.\n    function poolIdentifier() external pure returns (bytes32);\n\n    /// @return An array of tokens supported by the pool.\n    function getAssets() external view returns (address[] memory);\n\n    /// @notice Simulates a trade and returns the expected output.\n    /// @dev The pool does not need to include a trade simulator directly in itself - it can use a library.\n    /// @param data ABI-encoded params that the pool requires.\n    /// @return finalAmountOut The amount of output tokens that will be sent to the user if the trade is executed.\n    function getAmountOut(bytes calldata data) external view returns (uint256 finalAmountOut);\n\n    /// @notice Simulates a trade and returns the expected output.\n    /// @dev The pool does not need to include a trade simulator directly in itself - it can use a library.\n    /// @param data ABI-encoded params that the pool requires.\n    /// @return finalAmountIn The amount of input tokens that are required from the user if the trade is executed.\n    function getAmountIn(bytes calldata data) external view returns (uint256 finalAmountIn);\n\n    /// @dev This event must be emitted on all swaps.\n    event Swap(address indexed recipient, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut);\n\n    /// @dev This struct frames output tokens for burns.\n    struct TokenAmount {\n        address token;\n        uint256 amount;\n    }\n}\n"
    },
    "contracts/libraries/RebaseLibrary.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity ^0.8;\n\nstruct Rebase {\n    uint128 elastic;\n    uint128 base;\n}\n\n/// @notice A rebasing library\nlibrary RebaseLibrary {\n    /// @notice Calculates the base value in relationship to `elastic` and `total`.\n    function toBase(Rebase memory total, uint256 elastic) internal pure returns (uint256 base) {\n        if (total.elastic == 0) {\n            base = elastic;\n        } else {\n            base = (elastic * total.base) / total.elastic;\n        }\n    }\n\n    /// @notice Calculates the elastic value in relationship to `base` and `total`.\n    function toElastic(Rebase memory total, uint256 base) internal pure returns (uint256 elastic) {\n        if (total.base == 0) {\n            elastic = base;\n        } else {\n            elastic = (base * total.elastic) / total.base;\n        }\n    }\n}\n"
    },
    "contracts/interfaces/IERC20.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\n/// @dev Use a library or custom safeTransfer{From} functions when dealing with unknown tokens!\ninterface IERC20 {\n    function balanceOf(address account) external view returns (uint256);\n\n    function totalSupply() external view returns (uint256);\n\n    function transferFrom(\n        address sender,\n        address recipient,\n        uint256 amount\n    ) external returns (bool);\n\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    function approve(address spender, uint256 amount) external returns (bool);\n}\n"
    },
    "contracts/TridentRouter.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"./interfaces/IPool.sol\";\nimport \"./interfaces/ITridentRouter.sol\";\nimport \"./utils/RouterHelper.sol\";\n\n/// @notice Router contract that helps in swapping across Trident pools.\ncontract TridentRouter is ITridentRouter, RouterHelper {\n    /// @dev Used to ensure that `tridentSwapCallback` is called only by the authorized address.\n    /// These are set when someone calls a flash swap and reset afterwards.\n    address internal cachedMsgSender;\n    address internal cachedPool;\n\n    mapping(address => bool) internal whitelistedPools;\n\n    constructor(\n        IBentoBoxMinimal bento,\n        IMasterDeployer masterDeployer,\n        address wETH\n    ) RouterHelper(bento, masterDeployer, wETH) {}\n\n    receive() external payable {\n        require(msg.sender == wETH);\n    }\n\n    /// @notice Swaps token A to token B directly. Swaps are done on `bento` tokens.\n    /// @param params This includes the address of token A, pool, amount of token A to swap,\n    /// minimum amount of token B after the swap and data required by the pool for the swap.\n    /// @dev Ensure that the pool is trusted before calling this function. The pool can steal users' tokens.\n    function exactInputSingle(ExactInputSingleParams calldata params) public payable returns (uint256 amountOut) {\n        // @dev Prefund the pool with token A.\n        bento.transfer(params.tokenIn, msg.sender, params.pool, params.amountIn);\n        // @dev Trigger the swap in the pool.\n        amountOut = IPool(params.pool).swap(params.data);\n        // @dev Ensure that the slippage wasn't too much. This assumes that the pool is honest.\n        require(amountOut >= params.amountOutMinimum, \"TOO_LITTLE_RECEIVED\");\n    }\n\n    /// @notice Swaps token A to token B indirectly by using multiple hops.\n    /// @param params This includes the addresses of the tokens, pools, amount of token A to swap,\n    /// minimum amount of token B after the swap and data required by the pools for the swaps.\n    /// @dev Ensure that the pools are trusted before calling this function. The pools can steal users' tokens.\n    function exactInput(ExactInputParams calldata params) public payable returns (uint256 amountOut) {\n        // @dev Pay the first pool directly.\n        bento.transfer(params.tokenIn, msg.sender, params.path[0].pool, params.amountIn);\n        // @dev Call every pool in the path.\n        // Pool `N` should transfer its output tokens to pool `N+1` directly.\n        // The last pool should transfer its output tokens to the user.\n        // If the user wants to unwrap `wETH`, the final destination should be this contract and\n        // a batch call should be made to `unwrapWETH`.\n        for (uint256 i; i < params.path.length; i++) {\n            // We don't necessarily need this check but saving users from themselves.\n            isWhiteListed(params.path[i].pool);\n            amountOut = IPool(params.path[i].pool).swap(params.path[i].data);\n        }\n        // @dev Ensure that the slippage wasn't too much. This assumes that the pool is honest.\n        require(amountOut >= params.amountOutMinimum, \"TOO_LITTLE_RECEIVED\");\n    }\n\n    /// @notice Swaps token A to token B by using callbacks.\n    /// @param path Addresses of the pools and data required by the pools for the swaps.\n    /// @param amountOutMinimum Minimum amount of token B after the swap.\n    /// @dev Ensure that the pools are trusted before calling this function. The pools can steal users' tokens.\n    /// This function will unlikely be used in production but it shows how to use callbacks. One use case will be arbitrage.\n    function exactInputLazy(uint256 amountOutMinimum, Path[] calldata path) public payable returns (uint256 amountOut) {\n        // @dev Call every pool in the path.\n        // Pool `N` should transfer its output tokens to pool `N+1` directly.\n        // The last pool should transfer its output tokens to the user.\n        for (uint256 i; i < path.length; i++) {\n            isWhiteListed(path[i].pool);\n            // @dev The cached `msg.sender` is used as the funder when the callback happens.\n            cachedMsgSender = msg.sender;\n            // @dev The cached pool must be the address that calls the callback.\n            cachedPool = path[i].pool;\n            amountOut = IPool(path[i].pool).flashSwap(path[i].data);\n        }\n        // @dev Resets the `cachedPool` to get a refund.\n        // `1` is used as the default value to avoid the storage slot being released.\n        cachedMsgSender = address(1);\n        cachedPool = address(1);\n        require(amountOut >= amountOutMinimum, \"TOO_LITTLE_RECEIVED\");\n    }\n\n    /// @notice Swaps token A to token B directly. It's the same as `exactInputSingle` except\n    /// it takes raw ERC-20 tokens from the users and deposits them into `bento`.\n    /// @param params This includes the address of token A, pool, amount of token A to swap,\n    /// minimum amount of token B after the swap and data required by the pool for the swap.\n    /// @dev Ensure that the pool is trusted before calling this function. The pool can steal users' tokens.\n    function exactInputSingleWithNativeToken(ExactInputSingleParams calldata params) public payable returns (uint256 amountOut) {\n        // @dev Deposits the native ERC-20 token from the user into the pool's `bento`.\n        _depositToBentoBox(params.tokenIn, params.pool, params.amountIn);\n        // @dev Trigger the swap in the pool.\n        amountOut = IPool(params.pool).swap(params.data);\n        // @dev Ensure that the slippage wasn't too much. This assumes that the pool is honest.\n        require(amountOut >= params.amountOutMinimum, \"TOO_LITTLE_RECEIVED\");\n    }\n\n    /// @notice Swaps token A to token B indirectly by using multiple hops. It's the same as `exactInput` except\n    /// it takes raw ERC-20 tokens from the users and deposits them into `bento`.\n    /// @param params This includes the addresses of the tokens, pools, amount of token A to swap,\n    /// minimum amount of token B after the swap and data required by the pools for the swaps.\n    /// @dev Ensure that the pools are trusted before calling this function. The pools can steal users' tokens.\n    function exactInputWithNativeToken(ExactInputParams calldata params) public payable returns (uint256 amountOut) {\n        // @dev Deposits the native ERC-20 token from the user into the pool's `bento`.\n        _depositToBentoBox(params.tokenIn, params.path[0].pool, params.amountIn);\n        // @dev Call every pool in the path.\n        // Pool `N` should transfer its output tokens to pool `N+1` directly.\n        // The last pool should transfer its output tokens to the user.\n        for (uint256 i; i < params.path.length; i++) {\n            isWhiteListed(params.path[i].pool);\n            amountOut = IPool(params.path[i].pool).swap(params.path[i].data);\n        }\n        // @dev Ensure that the slippage wasn't too much. This assumes that the pool is honest.\n        require(amountOut >= params.amountOutMinimum, \"TOO_LITTLE_RECEIVED\");\n    }\n\n    /// @notice Swaps multiple input tokens to multiple output tokens using multiple paths, in different percentages.\n    /// For example, you can swap 50 DAI + 100 USDC into 60% ETH and 40% BTC.\n    /// @param params This includes everything needed for the swap. Look at the `ComplexPathParams` struct for more details.\n    /// @dev This function is not optimized for single swaps and should only be used in complex cases where\n    /// the amounts are large enough that minimizing slippage by using multiple paths is worth the extra gas.\n    function complexPath(ComplexPathParams calldata params) public payable {\n        // @dev Deposit all initial tokens to respective pools and initiate the swaps.\n        // Input tokens come from the user - output goes to following pools.\n        for (uint256 i; i < params.initialPath.length; i++) {\n            if (params.initialPath[i].native) {\n                _depositToBentoBox(params.initialPath[i].tokenIn, params.initialPath[i].pool, params.initialPath[i].amount);\n            } else {\n                bento.transfer(params.initialPath[i].tokenIn, msg.sender, params.initialPath[i].pool, params.initialPath[i].amount);\n            }\n            isWhiteListed(params.initialPath[i].pool);\n            IPool(params.initialPath[i].pool).swap(params.initialPath[i].data);\n        }\n        // @dev Do all the middle swaps. Input comes from previous pools - output goes to following pools.\n        for (uint256 i; i < params.percentagePath.length; i++) {\n            uint256 balanceShares = bento.balanceOf(params.percentagePath[i].tokenIn, address(this));\n            uint256 transferShares = (balanceShares * params.percentagePath[i].balancePercentage) / uint256(10)**8;\n            bento.transfer(params.percentagePath[i].tokenIn, address(this), params.percentagePath[i].pool, transferShares);\n            isWhiteListed(params.percentagePath[i].pool);\n            IPool(params.percentagePath[i].pool).swap(params.percentagePath[i].data);\n        }\n        // @dev Do all the final swaps. Input comes from previous pools - output goes to the user.\n        for (uint256 i; i < params.output.length; i++) {\n            uint256 balanceShares = bento.balanceOf(params.output[i].token, address(this));\n            require(balanceShares >= params.output[i].minAmount, \"TOO_LITTLE_RECEIVED\");\n            if (params.output[i].unwrapBento) {\n                bento.withdraw(params.output[i].token, address(this), params.output[i].to, 0, balanceShares);\n            } else {\n                bento.transfer(params.output[i].token, address(this), params.output[i].to, balanceShares);\n            }\n        }\n    }\n\n    /// @notice Add liquidity to a pool.\n    /// @param tokenInput Token address and amount to add as liquidity.\n    /// @param pool Pool address to add liquidity to.\n    /// @param minLiquidity Minimum output liquidity - caps slippage.\n    /// @param data Data required by the pool to add liquidity.\n    function addLiquidity(\n        TokenInput[] memory tokenInput,\n        address pool,\n        uint256 minLiquidity,\n        bytes calldata data\n    ) public payable returns (uint256 liquidity) {\n        isWhiteListed(pool);\n        // @dev Send all input tokens to the pool.\n        for (uint256 i; i < tokenInput.length; i++) {\n            if (tokenInput[i].native) {\n                _depositToBentoBox(tokenInput[i].token, pool, tokenInput[i].amount);\n            } else {\n                bento.transfer(tokenInput[i].token, msg.sender, pool, tokenInput[i].amount);\n            }\n        }\n        liquidity = IPool(pool).mint(data);\n        require(liquidity >= minLiquidity, \"NOT_ENOUGH_LIQUIDITY_MINTED\");\n    }\n\n    /// @notice Add liquidity to a pool using callbacks - same as `addLiquidity`, but now with callbacks.\n    /// @dev The input tokens are sent to the pool during the callback.\n    function addLiquidityLazy(\n        address pool,\n        uint256 minLiquidity,\n        bytes calldata data\n    ) public payable returns (uint256 liquidity) {\n        isWhiteListed(pool);\n        cachedMsgSender = msg.sender;\n        cachedPool = pool;\n        liquidity = IPool(pool).mint(data);\n        cachedMsgSender = address(1);\n        cachedPool = address(1);\n        require(liquidity >= minLiquidity, \"NOT_ENOUGH_LIQUIDITY_MINTED\");\n    }\n\n    /// @notice Burn liquidity tokens to get back `bento` tokens.\n    /// @param pool Pool address.\n    /// @param liquidity Amount of liquidity tokens to burn.\n    /// @param data Data required by the pool to burn liquidity.\n    /// @param minWithdrawals Minimum amount of `bento` tokens to be returned.\n    function burnLiquidity(\n        address pool,\n        uint256 liquidity,\n        bytes calldata data,\n        IPool.TokenAmount[] memory minWithdrawals\n    ) public {\n        isWhiteListed(pool);\n        safeTransferFrom(pool, msg.sender, pool, liquidity);\n        IPool.TokenAmount[] memory withdrawnLiquidity = IPool(pool).burn(data);\n        for (uint256 i; i < minWithdrawals.length; i++) {\n            uint256 j;\n            for (; j < withdrawnLiquidity.length; j++) {\n                if (withdrawnLiquidity[j].token == minWithdrawals[i].token) {\n                    require(withdrawnLiquidity[j].amount >= minWithdrawals[i].amount, \"TOO_LITTLE_RECEIVED\");\n                    break;\n                }\n            }\n            // @dev A token that is present in `minWithdrawals` is missing from `withdrawnLiquidity`.\n            require(j < withdrawnLiquidity.length, \"INCORRECT_TOKEN_WITHDRAWN\");\n        }\n    }\n\n    /// @notice Burn liquidity tokens to get back `bento` tokens.\n    /// @dev The tokens are swapped automatically and the output is in a single token.\n    /// @param pool Pool address.\n    /// @param liquidity Amount of liquidity tokens to burn.\n    /// @param data Data required by the pool to burn liquidity.\n    /// @param minWithdrawal Minimum amount of tokens to be returned.\n    function burnLiquiditySingle(\n        address pool,\n        uint256 liquidity,\n        bytes calldata data,\n        uint256 minWithdrawal\n    ) public {\n        isWhiteListed(pool);\n        // @dev Use 'liquidity = 0' for prefunding.\n        safeTransferFrom(pool, msg.sender, pool, liquidity);\n        uint256 withdrawn = IPool(pool).burnSingle(data);\n        require(withdrawn >= minWithdrawal, \"TOO_LITTLE_RECEIVED\");\n    }\n\n    /// @notice Used by the pool 'flashSwap' functionality to take input tokens from the user.\n    function tridentSwapCallback(bytes calldata data) external {\n        require(msg.sender == cachedPool, \"UNAUTHORIZED_CALLBACK\");\n        TokenInput memory tokenInput = abi.decode(data, (TokenInput));\n        // @dev Transfer the requested tokens to the pool.\n        if (tokenInput.native) {\n            _depositFromUserToBentoBox(tokenInput.token, cachedMsgSender, msg.sender, tokenInput.amount);\n        } else {\n            bento.transfer(tokenInput.token, cachedMsgSender, msg.sender, tokenInput.amount);\n        }\n        // @dev Resets the `msg.sender`'s authorization.\n        cachedMsgSender = address(1);\n    }\n\n    /// @notice Can be used by the pool 'mint' functionality to take tokens from the user.\n    function tridentMintCallback(bytes calldata data) external {\n        require(msg.sender == cachedPool, \"UNAUTHORIZED_CALLBACK\");\n        TokenInput[] memory tokenInput = abi.decode(data, (TokenInput[]));\n        // @dev Transfer the requested tokens to the pool.\n        for (uint256 i; i < tokenInput.length; i++) {\n            if (tokenInput[i].native) {\n                _depositFromUserToBentoBox(tokenInput[i].token, cachedMsgSender, msg.sender, tokenInput[i].amount);\n            } else {\n                bento.transfer(tokenInput[i].token, cachedMsgSender, msg.sender, tokenInput[i].amount);\n            }\n        }\n        // @dev Resets the `msg.sender`'s authorization.\n        cachedMsgSender = address(1);\n    }\n\n    /// @notice Recover mistakenly sent `bento` tokens.\n    function sweepBentoBoxToken(\n        address token,\n        uint256 amount,\n        address recipient\n    ) external {\n        bento.transfer(token, address(this), recipient, amount);\n    }\n\n    /// @notice Recover mistakenly sent ERC-20 tokens.\n    function sweepNativeToken(\n        address token,\n        uint256 amount,\n        address recipient\n    ) external {\n        safeTransfer(token, recipient, amount);\n    }\n\n    /// @notice Recover mistakenly sent ETH.\n    function refundETH() external payable {\n        if (address(this).balance != 0) safeTransferETH(msg.sender, address(this).balance);\n    }\n\n    /// @notice Unwrap this contract's `wETH` into ETH\n    function unwrapWETH(uint256 amountMinimum, address recipient) external {\n        uint256 balanceWETH = balanceOfThis(wETH);\n        require(balanceWETH >= amountMinimum, \"INSUFFICIENT_WETH\");\n        if (balanceWETH != 0) {\n            withdrawFromWETH(balanceWETH);\n            safeTransferETH(recipient, balanceWETH);\n        }\n    }\n\n    /// @notice Deposit from the user's wallet into BentoBox.\n    /// @dev Amount is the native token amount. We let BentoBox do the conversion into shares.\n    function _depositToBentoBox(\n        address token,\n        address recipient,\n        uint256 amount\n    ) internal {\n        bento.deposit{value: token == USE_ETHEREUM ? amount : 0}(token, msg.sender, recipient, amount, 0);\n    }\n\n    /// @notice Same effect as _depositToBentoBox() but with a sender parameter.\n    function _depositFromUserToBentoBox(\n        address token,\n        address sender,\n        address recipient,\n        uint256 amount\n    ) internal {\n        bento.deposit{value: token == USE_ETHEREUM ? amount : 0}(token, sender, recipient, amount, 0);\n    }\n\n    function isWhiteListed(address pool) internal {\n        if (!whitelistedPools[pool]) {\n            require(masterDeployer.pools(pool), \"INVALID POOL\");\n            whitelistedPools[pool] = true;\n        }\n    }\n}\n"
    },
    "contracts/utils/RouterHelper.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"../interfaces/IBentoBoxMinimal.sol\";\nimport \"../interfaces/IMasterDeployer.sol\";\nimport \"../TridentRouter.sol\";\nimport \"./TridentPermit.sol\";\n\n/// @notice Trident router helper contract.\ncontract RouterHelper is TridentPermit {\n    /// @notice BentoBox token vault.\n    IBentoBoxMinimal public immutable bento;\n    /// @notice Trident AMM master deployer contract.\n    IMasterDeployer public immutable masterDeployer;\n    /// @notice ERC-20 token for wrapped ETH (v9).\n    address internal immutable wETH;\n    /// @notice The user should use 0x0 if they want to deposit ETH\n    address constant USE_ETHEREUM = address(0);\n\n    constructor(\n        IBentoBoxMinimal _bento,\n        IMasterDeployer _masterDeployer,\n        address _wETH\n    ) {\n        bento = _bento;\n        masterDeployer = _masterDeployer;\n        wETH = _wETH;\n        _bento.registerProtocol();\n    }\n\n    /// @notice Provides batch function calls for this contract and returns the data from all of them if they all succeed.\n    /// Adapted from https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol, License-Identifier: GPL-2.0-or-later.\n    /// @dev The `msg.value` should not be trusted for any method callable from this function.\n    /// @dev Uses a modified version of the batch function - preventing multiple calls of the single input swap functions\n    /// @param data ABI-encoded params for each of the calls to make to this contract.\n    /// @return results The results from each of the calls passed in via `data`.\n    function batch(bytes[] calldata data) external payable returns (bytes[] memory results) {\n        results = new bytes[](data.length);\n        // We only allow one exactInputSingle call to be made in a single batch call.\n        // This is not really needed but we want to save users from signing malicious payloads.\n        // We also don't want nested batch calls.\n        bool swapCalled;\n        for (uint256 i = 0; i < data.length; i++) {\n            bytes4 selector = getSelector(data[i]);\n            if (selector == TridentRouter.exactInputSingle.selector || selector == TridentRouter.exactInputSingleWithNativeToken.selector) {\n                require(!swapCalled, \"Swap called twice\");\n                swapCalled = true;\n            } else {\n                require(selector != this.batch.selector, \"Nested Batch\");\n            }\n\n            (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n            if (!success) {\n                // Next 5 lines from https://ethereum.stackexchange.com/a/83577.\n                if (result.length < 68) revert();\n                assembly {\n                    result := add(result, 0x04)\n                }\n                revert(abi.decode(result, (string)));\n            }\n            results[i] = result;\n        }\n    }\n\n    function deployPool(address factory, bytes calldata deployData) external payable returns (address) {\n        return masterDeployer.deployPool(factory, deployData);\n    }\n\n    /// @notice Helper function to allow batching of BentoBox master contract approvals so the first trade can happen in one transaction.\n    function approveMasterContract(\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external payable {\n        bento.setMasterContractApproval(msg.sender, address(this), true, v, r, s);\n    }\n\n    /// @notice Provides gas-optimized balance check on this contract to avoid redundant extcodesize check in addition to returndatasize check.\n    /// @param token Address of ERC-20 token.\n    /// @return balance Token amount held by this contract.\n    function balanceOfThis(address token) internal view returns (uint256 balance) {\n        (bool success, bytes memory data) = token.staticcall(abi.encodeWithSelector(0x70a08231, address(this))); // @dev balanceOf(address).\n        require(success && data.length >= 32, \"BALANCE_OF_FAILED\");\n        balance = abi.decode(data, (uint256));\n    }\n\n    /// @notice Provides 'safe' ERC-20 {transfer} for tokens that don't consistently return true/false.\n    /// @param token Address of ERC-20 token.\n    /// @param recipient Account to send tokens to.\n    /// @param amount Token amount to send.\n    function safeTransfer(\n        address token,\n        address recipient,\n        uint256 amount\n    ) internal {\n        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, recipient, amount)); // @dev transfer(address,uint256).\n        require(success && (data.length == 0 || abi.decode(data, (bool))), \"TRANSFER_FAILED\");\n    }\n\n    /// @notice Provides 'safe' ERC-20 {transferFrom} for tokens that don't consistently return true/false.\n    /// @param token Address of ERC-20 token.\n    /// @param sender Account to send tokens from.\n    /// @param recipient Account to send tokens to.\n    /// @param amount Token amount to send.\n    function safeTransferFrom(\n        address token,\n        address sender,\n        address recipient,\n        uint256 amount\n    ) internal {\n        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, sender, recipient, amount)); // @dev transferFrom(address,address,uint256).\n        require(success && (data.length == 0 || abi.decode(data, (bool))), \"TRANSFER_FROM_FAILED\");\n    }\n\n    /// @notice Provides low-level `wETH` {withdraw}.\n    /// @param amount Token amount to unwrap into ETH.\n    function withdrawFromWETH(uint256 amount) internal {\n        (bool success, ) = wETH.call(abi.encodeWithSelector(0x2e1a7d4d, amount)); // @dev withdraw(uint256).\n        require(success, \"WITHDRAW_FROM_WETH_FAILED\");\n    }\n\n    /// @notice Provides 'safe' ETH transfer.\n    /// @param recipient Account to send ETH to.\n    /// @param amount ETH amount to send.\n    function safeTransferETH(address recipient, uint256 amount) internal {\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"ETH_TRANSFER_FAILED\");\n    }\n\n    /**\n     * @notice function to extract the selector of a bytes calldata\n     * @param _data the calldata bytes\n     */\n    function getSelector(bytes memory _data) internal pure returns (bytes4 sig) {\n        assembly {\n            sig := mload(add(_data, 32))\n        }\n    }\n}\n"
    },
    "contracts/migration/TridentSushiRollReference.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../utils/TridentBatchable.sol\";\nimport \"../utils/TridentPermit.sol\";\n\n/// @notice Interface for handling Balancer V1 LP.\ninterface IBalancerV1 {\n    function getFinalTokens() external view returns (address[] memory);\n\n    function exitPool(uint256 poolAmountIn, uint256[] calldata minAmountsOut) external;\n}\n\n/// @notice Interface for handling Balancer V2 LP - `assets` aliased to address for code simplicity.\ninterface IBalancerV2 {\n    struct ExitPoolRequest {\n        address[] assets;\n        uint256[] minAmountsOut;\n        bytes userData;\n        bool toInternalBalance;\n    }\n\n    /// @notice Returns asset tokens from a Balancer V2 pool.\n    function getPoolTokens(bytes32 poolId) external view returns (address[] memory);\n\n    /// @notice Exits liquidity tokens from a Balancer V2 pool.\n    function exitPool(\n        bytes32 poolId,\n        address sender,\n        address recipient,\n        ExitPoolRequest calldata request\n    ) external;\n}\n\n/// @notice Minimal Uniswap V2 LP interface.\ninterface IUniswapV2Minimal {\n    function token0() external view returns (address);\n\n    function token1() external view returns (address);\n\n    function burn(address to) external returns (uint256 amount0, uint256 amount1);\n}\n\n/// @notice Interface for handling Uniswap V3 LP.\ninterface IUniswapV3 {\n    /// @notice Returns the position information associated with a given token ID.\n    /// @dev Throws if the token ID is not valid.\n    /// @param tokenId The ID of the token that represents the position\n    /// @return nonce The nonce for permits\n    /// @return operator The address that is approved for spending\n    /// @return token0 The address of the token0 for a specific pool\n    /// @return token1 The address of the token1 for a specific pool\n    /// @return fee The fee associated with the pool\n    /// @return tickLower The lower end of the tick range for the position\n    /// @return tickUpper The higher end of the tick range for the position\n    /// @return liquidity The liquidity of the position\n    /// @return feeGrowthInside0LastX128 The fee growth of token0 as of the last action on the individual position\n    /// @return feeGrowthInside1LastX128 The fee growth of token1 as of the last action on the individual position\n    /// @return tokensOwed0 The uncollected amount of token0 owed to the position as of the last computation\n    /// @return tokensOwed1 The uncollected amount of token1 owed to the position as of the last computation\n    function positions(uint256 tokenId)\n        external\n        view\n        returns (\n            uint96 nonce,\n            address operator,\n            address token0,\n            address token1,\n            uint24 fee,\n            int24 tickLower,\n            int24 tickUpper,\n            uint128 liquidity,\n            uint256 feeGrowthInside0LastX128,\n            uint256 feeGrowthInside1LastX128,\n            uint128 tokensOwed0,\n            uint128 tokensOwed1\n        );\n\n    struct DecreaseLiquidityParams {\n        uint256 tokenId;\n        uint128 liquidity;\n        uint256 amount0Min;\n        uint256 amount1Min;\n        uint256 deadline;\n    }\n\n    struct CollectParams {\n        uint256 tokenId;\n        address recipient;\n        uint128 amount0Max;\n        uint128 amount1Max;\n    }\n\n    // @notice Decreases the amount of liquidity in a position and accounts it to the position\n    /// @param params tokenId The ID of the token for which liquidity is being decreased,\n    /// amount The amount by which liquidity will be decreased,\n    /// amount0Min The minimum amount of token0 that should be accounted for the burned liquidity,\n    /// amount1Min The minimum amount of token1 that should be accounted for the burned liquidity,\n    /// deadline The time by which the transaction must be included to effect the change\n    /// @return amount0 The amount of token0 accounted to the position's tokens owed\n    /// @return amount1 The amount of token1 accounted to the position's tokens owed\n    function decreaseLiquidity(DecreaseLiquidityParams calldata params) external payable returns (uint256 amount0, uint256 amount1);\n\n    /// @notice Collects up to a maximum amount of fees owed to a specific position to the recipient\n    /// @param params tokenId The ID of the NFT for which tokens are being collected,\n    /// recipient The account that should receive the tokens,\n    /// amount0Max The maximum amount of token0 to collect,\n    /// amount1Max The maximum amount of token1 to collect\n    /// @return amount0 The amount of fees collected in token0\n    /// @return amount1 The amount of fees collected in token1\n    function collect(CollectParams calldata params) external payable returns (uint256 amount0, uint256 amount1);\n}\n\n/// @notice Minimal Trident pool router interface.\ninterface ITridentRouterMinimal {\n    struct TokenInput {\n        address token;\n        bool native;\n        uint256 amount;\n    }\n\n    /// @notice Add liquidity to a pool.\n    /// @param tokenInput Token address and amount to add as liquidity.\n    /// @param pool Pool address to add liquidity to.\n    /// @param minLiquidity Minimum output liquidity - caps slippage.\n    /// @param data Data required by the pool to add liquidity.\n    function addLiquidity(\n        TokenInput[] calldata tokenInput,\n        address pool,\n        uint256 minLiquidity,\n        bytes calldata data\n    ) external payable returns (uint256 liquidity);\n}\n\n/// @notice Liquidity migrator for Trident from popular pool types.\ncontract TridentSushiRoll {\n    /* IBalancerV2 internal immutable balancerVault;\n    IUniswapV3 internal immutable uniNonfungiblePositionManager;\n    ITridentRouterMinimal internal immutable tridentRouter;\n\n    constructor(\n        IBalancerV2 _balancerVault,\n        IUniswapV3 _uniNonfungiblePositionManager,\n        ITridentRouterMinimal _tridentRouter\n    ) {\n        balancerVault = _balancerVault;\n        uniNonfungiblePositionManager = _uniNonfungiblePositionManager;\n        tridentRouter = _tridentRouter;\n    }\n\n    // **** BAL MIGRATOR **** //\n    // --------------------- //\n\n    function migrateFromBalancerV1toTrident(\n        IBalancerV1 bPool,\n        uint256 poolAmountIn,\n        uint256[] calldata minAmountsOut,\n        address tridentPool,\n        uint256 minLiquidity,\n        bytes calldata data\n    ) external returns (uint256 liquidity) {\n        address[] memory tokens = bPool.getFinalTokens();\n\n        bPool.exitPool(poolAmountIn, minAmountsOut);\n\n        ITridentRouterMinimal.TokenInput[] memory input = new ITridentRouterMinimal.TokenInput[](tokens.length);\n\n        unchecked {\n            for (uint256 i; i < tokens.length; i++) {\n                input[i].token = tokens[i];\n                input[i].native = true;\n                input[i].amount = IERC20(tokens[i]).balanceOf(address(this));\n                IERC20(tokens[i]).approve(address(tridentRouter), input[i].amount);\n            }\n        }\n\n        liquidity = tridentRouter.addLiquidity(input, tridentPool, minLiquidity, data);\n    }\n\n    function migrateFromBalancerV2toTrident(\n        bytes32 poolId,\n        IBalancerV2.ExitPoolRequest calldata request,\n        address tridentPool,\n        uint256 minLiquidity,\n        bytes calldata data\n    ) external returns (uint256 liquidity) {\n        address[] memory tokens = balancerVault.getPoolTokens(poolId);\n\n        balancerVault.exitPool(poolId, msg.sender, address(this), request);\n\n        ITridentRouterMinimal.TokenInput[] memory input = new ITridentRouterMinimal.TokenInput[](tokens.length);\n\n        unchecked {\n            for (uint256 i; i < tokens.length; i++) {\n                input[i].token = tokens[i];\n                input[i].native = true;\n                input[i].amount = IERC20(tokens[i]).balanceOf(address(this));\n                IERC20(tokens[i]).approve(address(tridentRouter), input[i].amount);\n            }\n        }\n\n        liquidity = tridentRouter.addLiquidity(input, tridentPool, minLiquidity, data);\n    }\n\n    // **** UNI MIGRATOR **** //\n    // --------------------- //\n\n    function migrateFromUniswapV2toTrident(\n        address pair,\n        uint256 _liquidity,\n        address pool,\n        uint256 minLiquidity,\n        bytes calldata data\n    ) external returns (uint256 liquidity) {\n        IERC20(pair).transferFrom(msg.sender, address(pair), _liquidity);\n\n        IUniswapV2Minimal(pair).burn(address(this));\n\n        ITridentRouterMinimal.TokenInput[] memory input = new ITridentRouterMinimal.TokenInput[](2);\n\n        IERC20 token0 = IERC20(IUniswapV2Minimal(pair).token0());\n        IERC20 token1 = IERC20(IUniswapV2Minimal(pair).token1());\n\n        input[0].token = address(token0);\n        input[0].native = true;\n        input[0].amount = token0.balanceOf(address(this));\n\n        input[1].token = address(token1);\n        input[1].native = true;\n        input[1].amount = token1.balanceOf(address(this));\n\n        token0.approve(address(tridentRouter), input[0].amount);\n        token1.approve(address(tridentRouter), input[1].amount);\n\n        liquidity = ITridentRouterMinimal(tridentRouter).addLiquidity(input, pool, minLiquidity, data);\n    }\n\n    function migrateFromUniswapV3toTrident(\n        IUniswapV3.DecreaseLiquidityParams calldata decreaseLiqParams,\n        IUniswapV3.CollectParams calldata collectParams,\n        address tridentPool,\n        uint256 minLiquidity,\n        bytes calldata data\n    ) external returns (uint256 liquidity) {\n        uniNonfungiblePositionManager.decreaseLiquidity(decreaseLiqParams);\n        uniNonfungiblePositionManager.collect(collectParams);\n\n        ITridentRouterMinimal.TokenInput[] memory input = new ITridentRouterMinimal.TokenInput[](2);\n\n        (, , address token0, , , , , , , , , ) = uniNonfungiblePositionManager.positions(decreaseLiqParams.tokenId);\n        (, , , address token1, , , , , , , , ) = uniNonfungiblePositionManager.positions(decreaseLiqParams.tokenId);\n\n        input[0].token = token0;\n        input[0].native = true;\n        input[0].amount = IERC20(token0).balanceOf(address(this));\n\n        input[1].token = token1;\n        input[1].native = true;\n        input[1].amount = IERC20(token1).balanceOf(address(this));\n\n        liquidity = tridentRouter.addLiquidity(input, tridentPool, minLiquidity, data);\n    } */\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `recipient`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address recipient, uint256 amount) 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 `amount` as the allowance of `spender` over the 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 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\n     * allowance mechanism. `amount` 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(\n        address sender,\n        address recipient,\n        uint256 amount\n    ) external returns (bool);\n\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"
    },
    "contracts/pool/concentrated/ConcentratedLiquidityPoolManager.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"../../interfaces/concentratedPool/IConcentratedLiquidityPoolManager.sol\";\nimport \"../../interfaces/concentratedPool/IPositionManager.sol\";\nimport \"../../interfaces/IMasterDeployer.sol\";\nimport \"../../interfaces/IBentoBoxMinimal.sol\";\nimport \"../../interfaces/ITridentRouter.sol\";\nimport \"../../libraries/concentratedPool/FullMath.sol\";\nimport \"../../libraries/concentratedPool/TickMath.sol\";\nimport \"../../libraries/concentratedPool/DyDxMath.sol\";\nimport \"../../utils/TridentBatchable.sol\";\nimport \"./TridentNFT.sol\";\n\n/// @notice Trident Concentrated Liquidity Pool periphery contract that combines non-fungible position management and staking.\ncontract ConcentratedLiquidityPoolManager is IPositionManager, IConcentratedLiquidityPoolManagerStruct, TridentNFT, TridentBatchable {\n    event IncreaseLiquidity(address indexed pool, address indexed owner, uint256 indexed positionId, uint128 liquidity);\n    event DecreaseLiquidity(address indexed pool, address indexed owner, uint256 indexed positionId, uint128 liquidity);\n\n    IBentoBoxMinimal public immutable bento;\n    IMasterDeployer public immutable masterDeployer;\n\n    mapping(uint256 => Position) public positions;\n\n    constructor(address _masterDeployer) {\n        masterDeployer = IMasterDeployer(_masterDeployer);\n        IBentoBoxMinimal _bento = IBentoBoxMinimal(IMasterDeployer(_masterDeployer).bento());\n        _bento.registerProtocol();\n        bento = _bento;\n        _mint(address(0));\n    }\n\n    function positionMintCallback(\n        address recipient,\n        int24 lower,\n        int24 upper,\n        uint128 amount,\n        uint256 feeGrowthInside0,\n        uint256 feeGrowthInside1,\n        uint256 _positionId\n    ) external override returns (uint256 positionId) {\n        require(IMasterDeployer(masterDeployer).pools(msg.sender), \"NOT_POOL\");\n\n        if (_positionId == 0) {\n            // We mint a new NFT.\n            positions[totalSupply] = Position({\n                pool: IConcentratedLiquidityPool(msg.sender),\n                liquidity: amount,\n                lower: lower,\n                upper: upper,\n                latestAddition: uint32(block.timestamp),\n                feeGrowthInside0: feeGrowthInside0,\n                feeGrowthInside1: feeGrowthInside1\n            });\n            positionId = totalSupply;\n            _mint(recipient);\n            emit IncreaseLiquidity(msg.sender, recipient, positionId, amount);\n        } else if (amount > 0) {\n            // We increase liquidity for an existing NFT.\n            Position storage position = positions[_positionId];\n            require(_positionId < totalSupply, \"INVALID_POSITION\");\n            require(position.lower == lower && position.upper == upper, \"RANGE_MIS_MATCH\");\n            require(position.feeGrowthInside0 == feeGrowthInside0 && position.feeGrowthInside1 == feeGrowthInside1, \"UNCLAIMED\");\n            position.liquidity += amount;\n            position.latestAddition = uint32(block.timestamp);\n            emit IncreaseLiquidity(msg.sender, recipient, positionId, amount);\n        }\n    }\n\n    function decreaseLiquidity(\n        uint256 tokenId,\n        uint128 amount,\n        address recipient,\n        bool unwrapBento\n    ) external {\n        require(msg.sender == ownerOf[tokenId], \"NOT_ID_OWNER\");\n        Position storage position = positions[tokenId];\n\n        IPool.TokenAmount[] memory withdrawAmounts;\n        IPool.TokenAmount[] memory feeAmounts;\n        uint256 oldLiquidity;\n\n        if (amount < position.liquidity) {\n            (withdrawAmounts, feeAmounts, oldLiquidity) = position.pool.decreaseLiquidity(\n                position.lower,\n                position.upper,\n                amount,\n                address(this),\n                false\n            );\n\n            (position.feeGrowthInside0, position.feeGrowthInside1) = position.pool.rangeFeeGrowth(position.lower, position.upper);\n\n            position.liquidity -= amount;\n        } else {\n            (withdrawAmounts, feeAmounts, oldLiquidity) = position.pool.decreaseLiquidity(\n                position.lower,\n                position.upper,\n                position.liquidity,\n                address(this),\n                false\n            );\n\n            delete positions[tokenId];\n\n            _burn(tokenId);\n        }\n\n        uint256 token0Amount = withdrawAmounts[0].amount + ((feeAmounts[0].amount * amount) / oldLiquidity);\n        uint256 token1Amount = withdrawAmounts[1].amount + ((feeAmounts[1].amount * amount) / oldLiquidity);\n\n        _transfer(withdrawAmounts[0].token, address(this), recipient, token0Amount, unwrapBento);\n        _transfer(withdrawAmounts[1].token, address(this), recipient, token1Amount, unwrapBento);\n\n        emit DecreaseLiquidity(address(position.pool), msg.sender, tokenId, amount);\n    }\n\n    function collect(\n        uint256 tokenId,\n        address recipient,\n        bool unwrapBento\n    ) public returns (uint256 token0amount, uint256 token1amount) {\n        require(msg.sender == ownerOf[tokenId], \"NOT_ID_OWNER\");\n        Position storage position = positions[tokenId];\n\n        address[] memory tokens = position.pool.getAssets();\n        address token0 = tokens[0];\n        address token1 = tokens[1];\n\n        (token0amount, token1amount, position.feeGrowthInside0, position.feeGrowthInside1) = positionFees(tokenId);\n\n        uint256 balance0 = bento.balanceOf(token0, address(this));\n        uint256 balance1 = bento.balanceOf(token1, address(this));\n\n        if (balance0 < token0amount || balance1 < token1amount) {\n            (uint256 amount0fees, uint256 amount1fees) = position.pool.collect(position.lower, position.upper, address(this), false);\n\n            uint256 newBalance0 = amount0fees + balance0;\n            uint256 newBalance1 = amount1fees + balance1;\n\n            /// @dev Rounding errors due to frequent claiming of other users in the same position may cost us some wei units\n            if (token0amount > newBalance0) token0amount = newBalance0;\n            if (token1amount > newBalance1) token1amount = newBalance1;\n        }\n\n        _transfer(token0, address(this), recipient, token0amount, unwrapBento);\n        _transfer(token1, address(this), recipient, token1amount, unwrapBento);\n    }\n\n    /// @notice Returns the claimable fees and the fee growth accumulators of a given position.\n    function positionFees(uint256 tokenId)\n        public\n        view\n        returns (\n            uint256 token0amount,\n            uint256 token1amount,\n            uint256 feeGrowthInside0,\n            uint256 feeGrowthInside1\n        )\n    {\n        Position memory position = positions[tokenId];\n\n        (feeGrowthInside0, feeGrowthInside1) = position.pool.rangeFeeGrowth(position.lower, position.upper);\n\n        token0amount = FullMath.mulDiv(\n            feeGrowthInside0 - position.feeGrowthInside0,\n            position.liquidity,\n            0x100000000000000000000000000000000\n        );\n\n        token1amount = FullMath.mulDiv(\n            feeGrowthInside1 - position.feeGrowthInside1,\n            position.liquidity,\n            0x100000000000000000000000000000000\n        );\n    }\n\n    function _transfer(\n        address token,\n        address from,\n        address to,\n        uint256 shares,\n        bool unwrapBento\n    ) internal {\n        if (unwrapBento) {\n            bento.withdraw(token, from, to, 0, shares);\n        } else {\n            bento.transfer(token, from, to, shares);\n        }\n    }\n}\n"
    },
    "contracts/interfaces/concentratedPool/IConcentratedLiquidityPoolManager.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"./IConcentratedLiquidityPool.sol\";\nimport \"./../ITridentNFT.sol\";\n\n/// @notice Trident concentrated liquidity manager contract Struct.\n/// @dev Split out struct and function declarations due to solidity quirks.\ninterface IConcentratedLiquidityPoolManagerStruct {\n    struct Position {\n        IConcentratedLiquidityPool pool;\n        uint128 liquidity;\n        int24 lower;\n        int24 upper;\n        uint32 latestAddition;\n        uint256 feeGrowthInside0; /// @dev Per unit of liquidity.\n        uint256 feeGrowthInside1;\n    }\n}\n\n/// @notice Trident concentrated liquidity manager contract interface.\ninterface IConcentratedLiquidityPoolManager is IConcentratedLiquidityPoolManagerStruct, ITridentNFT {\n    function positions(uint256) external view returns (Position memory);\n\n    function bento() external view returns (IBentoBoxMinimal);\n}\n"
    },
    "contracts/interfaces/concentratedPool/IPositionManager.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\n/// @notice Trident concentrated Liquidity pool mint callback receiver.\ninterface IPositionManager {\n    function positionMintCallback(\n        address recipient,\n        int24 lower,\n        int24 upper,\n        uint128 amount,\n        uint256 feeGrowthInside0,\n        uint256 feeGrowthInside1,\n        uint256 positionId\n    ) external returns (uint256 _positionId);\n}\n"
    },
    "contracts/libraries/concentratedPool/FullMath.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\n/// @notice Math library that facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision.\n/// @author Adapted from https://github.com/Uniswap/uniswap-v3-core/blob/main/contracts/libraries/FullMath.sol.\n/// @dev Handles \"phantom overflow\", i.e., allows multiplication and division where an intermediate value overflows 256 bits.\nlibrary FullMath {\n    /// @notice Calculates floor(a×b÷denominator) with full precision - throws if result overflows an uint256 or denominator == 0.\n    /// @param a The multiplicand.\n    /// @param b The multiplier.\n    /// @param denominator The divisor.\n    /// @return result The 256-bit result.\n    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.\n    function mulDiv(\n        uint256 a,\n        uint256 b,\n        uint256 denominator\n    ) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = a * b.\n            // Compute the product mod 2**256 and mod 2**256 - 1,\n            // then use the Chinese Remainder Theorem to reconstruct\n            // the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2**256 + prod0.\n            uint256 prod0; // Least significant 256 bits of the product.\n            uint256 prod1; // Most significant 256 bits of the product.\n            assembly {\n                let mm := mulmod(a, b, not(0))\n                prod0 := mul(a, b)\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                require(denominator > 0);\n                assembly {\n                    result := div(prod0, denominator)\n                }\n                return result;\n            }\n            // Make sure the result is less than 2**256 -\n            // also prevents denominator == 0.\n            require(denominator > prod1);\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n            // Make division exact by subtracting the remainder from [prod1 prod0] -\n            // compute remainder using mulmod.\n            uint256 remainder;\n            assembly {\n                remainder := mulmod(a, b, denominator)\n            }\n            // Subtract 256 bit number from 512 bit number.\n            assembly {\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n            // Factor powers of two out of denominator -\n            // compute largest power of two divisor of denominator\n            // (always >= 1).\n            uint256 twos = uint256(-int256(denominator)) & denominator;\n            // Divide denominator by power of two.\n            assembly {\n                denominator := div(denominator, twos)\n            }\n            // Divide [prod1 prod0] by the factors of two.\n            assembly {\n                prod0 := div(prod0, twos)\n            }\n            // Shift in bits from prod1 into prod0. For this we need\n            // to flip `twos` such that it is 2**256 / twos -\n            // if twos is zero, then it becomes one.\n            assembly {\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n            prod0 |= prod1 * twos;\n            // Invert denominator mod 2**256 -\n            // now that denominator is an odd number, it has an inverse\n            // modulo 2**256 such that denominator * inv = 1 mod 2**256.\n            // Compute the inverse by starting with a seed that is correct\n            // for four bits. That is, denominator * inv = 1 mod 2**4.\n            uint256 inv = (3 * denominator) ^ 2;\n            // Now use Newton-Raphson iteration to improve the precision.\n            // Thanks to Hensel's lifting lemma, this also works in modular\n            // arithmetic, doubling the correct bits in each step.\n            inv *= 2 - denominator * inv; // Inverse mod 2**8.\n            inv *= 2 - denominator * inv; // Inverse mod 2**16.\n            inv *= 2 - denominator * inv; // Inverse mod 2**32.\n            inv *= 2 - denominator * inv; // Inverse mod 2**64.\n            inv *= 2 - denominator * inv; // Inverse mod 2**128.\n            inv *= 2 - denominator * inv; // Inverse mod 2**256.\n            // Because the division is now exact we can divide by multiplying\n            // with the modular inverse of denominator. This will give us the\n            // correct result modulo 2**256. Since the precoditions guarantee\n            // that the outcome is less than 2**256, this is the final result.\n            // We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inv;\n            return result;\n        }\n    }\n\n    /// @notice Calculates ceil(a×b÷denominator) with full precision - throws if result overflows an uint256 or denominator == 0.\n    /// @param a The multiplicand.\n    /// @param b The multiplier.\n    /// @param denominator The divisor.\n    /// @return result The 256-bit result.\n    function mulDivRoundingUp(\n        uint256 a,\n        uint256 b,\n        uint256 denominator\n    ) internal pure returns (uint256 result) {\n        result = mulDiv(a, b, denominator);\n        unchecked {\n            if (mulmod(a, b, denominator) != 0) {\n                require(result < type(uint256).max);\n                result++;\n            }\n        }\n    }\n}\n"
    },
    "contracts/libraries/concentratedPool/TickMath.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later\n\npragma solidity >=0.8.0;\n\n/// @notice Math library for computing sqrt price for ticks of size 1.0001, i.e., sqrt(1.0001^tick) as fixed point Q64.96 numbers - supports\n/// prices between 2**-128 and 2**128 - 1.\n/// @author Adapted from https://github.com/Uniswap/uniswap-v3-core/blob/main/contracts/libraries/TickMath.sol.\nlibrary TickMath {\n    /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128.\n    int24 internal constant MIN_TICK = -887272;\n    /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128 - 1.\n    int24 internal constant MAX_TICK = -MIN_TICK;\n    /// @dev The minimum value that can be returned from #getSqrtRatioAtTick - equivalent to getSqrtRatioAtTick(MIN_TICK).\n    uint160 internal constant MIN_SQRT_RATIO = 4295128739;\n    /// @dev The maximum value that can be returned from #getSqrtRatioAtTick - equivalent to getSqrtRatioAtTick(MAX_TICK).\n    uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;\n\n    error TickOutOfBounds();\n    error PriceOutOfBounds();\n\n    /// @notice Calculates sqrt(1.0001^tick) * 2^96.\n    /// @dev Throws if |tick| > max tick.\n    /// @param tick The input tick for the above formula.\n    /// @return sqrtPriceX96 Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)\n    /// at the given tick.\n    function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {\n        uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n        if (absTick > uint256(uint24(MAX_TICK))) revert TickOutOfBounds();\n        unchecked {\n            uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;\n            if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;\n            if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;\n            if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;\n            if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;\n            if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;\n            if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;\n            if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;\n            if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;\n            if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;\n            if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;\n            if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;\n            if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;\n            if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;\n            if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;\n            if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;\n            if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;\n            if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;\n            if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;\n            if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;\n\n            if (tick > 0) ratio = type(uint256).max / ratio;\n            // This divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.\n            // We then downcast because we know the result always fits within 160 bits due to our tick input constraint.\n            // We round up in the division so getTickAtSqrtRatio of the output price is always consistent.\n            sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));\n        }\n    }\n\n    /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio.\n    /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may\n    /// ever return.\n    /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96.\n    /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio.\n    function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) {\n        // Second inequality must be < because the price can never reach the price at the max tick.\n        if (sqrtPriceX96 < MIN_SQRT_RATIO || sqrtPriceX96 >= MAX_SQRT_RATIO) revert PriceOutOfBounds();\n        uint256 ratio = uint256(sqrtPriceX96) << 32;\n\n        uint256 r = ratio;\n        uint256 msb;\n\n        assembly {\n            let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := shl(5, gt(r, 0xFFFFFFFF))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := shl(4, gt(r, 0xFFFF))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := shl(3, gt(r, 0xFF))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := shl(2, gt(r, 0xF))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := shl(1, gt(r, 0x3))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := gt(r, 0x1)\n            msb := or(msb, f)\n        }\n        unchecked {\n            if (msb >= 128) r = ratio >> (msb - 127);\n            else r = ratio << (127 - msb);\n\n            int256 log_2 = (int256(msb) - 128) << 64;\n\n            assembly {\n                r := shr(127, mul(r, r))\n                let f := shr(128, r)\n                log_2 := or(log_2, shl(63, f))\n                r := shr(f, r)\n            }\n            assembly {\n                r := shr(127, mul(r, r))\n                let f := shr(128, r)\n                log_2 := or(log_2, shl(62, f))\n                r := shr(f, r)\n            }\n            assembly {\n                r := shr(127, mul(r, r))\n                let f := shr(128, r)\n                log_2 := or(log_2, shl(61, f))\n                r := shr(f, r)\n            }\n            assembly {\n                r := shr(127, mul(r, r))\n                let f := shr(128, r)\n                log_2 := or(log_2, shl(60, f))\n                r := shr(f, r)\n            }\n            assembly {\n                r := shr(127, mul(r, r))\n                let f := shr(128, r)\n                log_2 := or(log_2, shl(59, f))\n                r := shr(f, r)\n            }\n            assembly {\n                r := shr(127, mul(r, r))\n                let f := shr(128, r)\n                log_2 := or(log_2, shl(58, f))\n                r := shr(f, r)\n            }\n            assembly {\n                r := shr(127, mul(r, r))\n                let f := shr(128, r)\n                log_2 := or(log_2, shl(57, f))\n                r := shr(f, r)\n            }\n            assembly {\n                r := shr(127, mul(r, r))\n                let f := shr(128, r)\n                log_2 := or(log_2, shl(56, f))\n                r := shr(f, r)\n            }\n            assembly {\n                r := shr(127, mul(r, r))\n                let f := shr(128, r)\n                log_2 := or(log_2, shl(55, f))\n                r := shr(f, r)\n            }\n            assembly {\n                r := shr(127, mul(r, r))\n                let f := shr(128, r)\n                log_2 := or(log_2, shl(54, f))\n                r := shr(f, r)\n            }\n            assembly {\n                r := shr(127, mul(r, r))\n                let f := shr(128, r)\n                log_2 := or(log_2, shl(53, f))\n                r := shr(f, r)\n            }\n            assembly {\n                r := shr(127, mul(r, r))\n                let f := shr(128, r)\n                log_2 := or(log_2, shl(52, f))\n                r := shr(f, r)\n            }\n            assembly {\n                r := shr(127, mul(r, r))\n                let f := shr(128, r)\n                log_2 := or(log_2, shl(51, f))\n                r := shr(f, r)\n            }\n            assembly {\n                r := shr(127, mul(r, r))\n                let f := shr(128, r)\n                log_2 := or(log_2, shl(50, f))\n            }\n\n            int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number.\n\n            int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128);\n            int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128);\n\n            tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow;\n        }\n    }\n}\n"
    },
    "contracts/libraries/concentratedPool/DyDxMath.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"./FullMath.sol\";\nimport \"./UnsafeMath.sol\";\n\n/// @notice Math library that facilitates ranged liquidity calculations.\nlibrary DyDxMath {\n    function getDy(\n        uint256 liquidity,\n        uint256 priceLower,\n        uint256 priceUpper,\n        bool roundUp\n    ) internal pure returns (uint256 dy) {\n        unchecked {\n            if (roundUp) {\n                dy = FullMath.mulDivRoundingUp(liquidity, priceUpper - priceLower, 0x1000000000000000000000000);\n            } else {\n                dy = FullMath.mulDiv(liquidity, priceUpper - priceLower, 0x1000000000000000000000000);\n            }\n        }\n    }\n\n    function getDx(\n        uint256 liquidity,\n        uint256 priceLower,\n        uint256 priceUpper,\n        bool roundUp\n    ) internal pure returns (uint256 dx) {\n        unchecked {\n            if (roundUp) {\n                dx = UnsafeMath.divRoundingUp(FullMath.mulDivRoundingUp(liquidity << 96, priceUpper - priceLower, priceUpper), priceLower);\n            } else {\n                dx = FullMath.mulDiv(liquidity << 96, priceUpper - priceLower, priceUpper) / priceLower;\n            }\n        }\n    }\n\n    function getLiquidityForAmounts(\n        uint256 priceLower,\n        uint256 priceUpper,\n        uint256 currentPrice,\n        uint256 dy,\n        uint256 dx\n    ) public pure returns (uint256 liquidity) {\n        unchecked {\n            if (priceUpper <= currentPrice) {\n                liquidity = FullMath.mulDiv(dy, 0x1000000000000000000000000, priceUpper - priceLower);\n            } else if (currentPrice <= priceLower) {\n                liquidity = FullMath.mulDiv(\n                    dx,\n                    FullMath.mulDiv(priceLower, priceUpper, 0x1000000000000000000000000),\n                    priceUpper - priceLower\n                );\n            } else {\n                uint256 liquidity0 = FullMath.mulDiv(\n                    dx,\n                    FullMath.mulDiv(priceUpper, currentPrice, 0x1000000000000000000000000),\n                    priceUpper - currentPrice\n                );\n                uint256 liquidity1 = FullMath.mulDiv(dy, 0x1000000000000000000000000, currentPrice - priceLower);\n                liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1;\n            }\n        }\n    }\n\n    function getAmountsForLiquidity(\n        uint256 priceLower,\n        uint256 priceUpper,\n        uint256 currentPrice,\n        uint256 liquidityAmount,\n        bool roundUp\n    ) internal pure returns (uint128 token0amount, uint128 token1amount) {\n        if (priceUpper <= currentPrice) {\n            // Only supply `token1` (`token1` is Y).\n            token1amount = uint128(DyDxMath.getDy(liquidityAmount, priceLower, priceUpper, roundUp));\n        } else if (currentPrice <= priceLower) {\n            // Only supply `token0` (`token0` is X).\n            token0amount = uint128(DyDxMath.getDx(liquidityAmount, priceLower, priceUpper, roundUp));\n        } else {\n            // Supply both tokens.\n            token0amount = uint128(DyDxMath.getDx(liquidityAmount, currentPrice, priceUpper, roundUp));\n            token1amount = uint128(DyDxMath.getDy(liquidityAmount, priceLower, currentPrice, roundUp));\n        }\n    }\n}\n"
    },
    "contracts/pool/concentrated/TridentNFT.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\n/// @notice Trident Concentrated Liquidity Pool ERC-721 implementation with ERC-20/EIP-2612-like extensions,\n// as well as partially, MetaData and Enumerable extensions.\n/// @author Adapted from RariCapital, https://github.com/Rari-Capital/solmate/blob/main/src/erc721/ERC721.sol,\n// License-Identifier: AGPL-3.0-only, and Shoyu, https://github.com/sushiswap/shoyu/blob/master/contracts/base/BaseNFT721.sol,\n// License-Identifier: MIT.\nabstract contract TridentNFT {\n    event Transfer(address indexed sender, address indexed recipient, uint256 indexed tokenId);\n    event Approval(address indexed owner, address indexed spender, uint256 indexed tokenId);\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    string public constant name = \"TridentNFT\";\n    string public constant symbol = \"tNFT\";\n    /// @notice Tracks total liquidity range positions.\n    uint256 public totalSupply;\n    /// @notice 'owner' -> balance mapping.\n    mapping(address => uint256) public balanceOf;\n    /// @notice `tokenId` -> 'owner' mapping.\n    mapping(uint256 => address) public ownerOf;\n    /// @notice `tokenId` -> 'spender' mapping.\n    mapping(uint256 => address) public getApproved;\n    /// @notice 'owner' -> 'operator' status mapping.\n    mapping(address => mapping(address => bool)) public isApprovedForAll;\n\n    /// @notice EIP-712 typehash for this contract's {permit} struct for {approve}.\n    bytes32 public constant PERMIT_TYPEHASH = keccak256(\"Permit(address spender,uint256 tokenId,uint256 nonce,uint256 deadline)\");\n    /// @notice EIP-712 typehash for this contract's {permitAll} struct for {setApprovalForAll}.\n    bytes32 public constant PERMIT_ALL_TYPEHASH = keccak256(\"Permit(address owner,address spender,uint256 nonce,uint256 deadline)\");\n\n    /// @notice Chain Id at this contract's deployment.\n    uint256 internal immutable DOMAIN_SEPARATOR_CHAIN_ID;\n    /// @notice EIP-712 typehash for this contract's domain at deployment.\n    bytes32 internal immutable _DOMAIN_SEPARATOR;\n    /// @notice 'tokenId' -> `nonce` mapping used in {permit} for {approve}.\n    mapping(uint256 => uint256) public nonces;\n    /// @notice 'owner' -> `tokenId` mapping used in {permitAll} for {setApprovalForAll}.\n    mapping(address => uint256) public noncesForAll;\n\n    constructor() {\n        DOMAIN_SEPARATOR_CHAIN_ID = block.chainid;\n        _DOMAIN_SEPARATOR = _calculateDomainSeparator();\n    }\n\n    function _calculateDomainSeparator() internal view returns (bytes32 domainSeperator) {\n        domainSeperator = keccak256(\n            abi.encode(\n                keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n                keccak256(bytes(name)),\n                keccak256(bytes(\"1\")),\n                block.chainid,\n                address(this)\n            )\n        );\n    }\n\n    /// @notice EIP-712 typehash for this contract's domain.\n    function DOMAIN_SEPARATOR() public view returns (bytes32 domainSeperator) {\n        domainSeperator = block.chainid == DOMAIN_SEPARATOR_CHAIN_ID ? _DOMAIN_SEPARATOR : _calculateDomainSeparator();\n    }\n\n    /// @notice Provides ERC-165-compatible confirmation for ERC-721 interfaces supported by this contract.\n    /// @param interfaceId XOR of all function selectors in the reference interface.\n    /// @return supported Returns 'true' if `interfaceId` is flagged as implemented.\n    function supportsInterface(bytes4 interfaceId) external pure returns (bool supported) {\n        supported = interfaceId == 0x80ac58cd || interfaceId == 0x5b5e139f;\n    }\n\n    /// @notice Approves `tokenId` from `msg.sender` 'owner' or 'operator' to be spent by `spender`.\n    /// @param spender Address of the party that can pull `tokenId` from 'owner''s account.\n    /// @param tokenId The Id to approve for `spender`.\n    function approve(address spender, uint256 tokenId) external {\n        address owner = ownerOf[tokenId];\n        require(msg.sender == owner || isApprovedForAll[owner][msg.sender], \"NOT_APPROVED\");\n        getApproved[tokenId] = spender;\n        emit Approval(owner, spender, tokenId);\n    }\n\n    /// @notice Approves an 'operator' for `msg.sender` 'owner' that can spend or {approve} spends of 'owner''s `tokenId`s.\n    /// @param operator Address of the party that can pull `tokenId`s from 'owner''s account or approve others to do same.\n    /// @param approved The approval status of `operator`.\n    function setApprovalForAll(address operator, bool approved) external {\n        require(operator != address(0), \"INVALID_OPERATOR\");\n        isApprovedForAll[msg.sender][operator] = approved;\n        emit ApprovalForAll(msg.sender, operator, approved);\n    }\n\n    /// @notice Transfers `tokenId` from 'owner' to `recipient`. Caller needs ownership.\n    /// @param recipient The address to move `tokenId` to.\n    /// @param tokenId The Id to move.\n    function transfer(address recipient, uint256 tokenId) external {\n        require(msg.sender == ownerOf[tokenId], \"NOT_OWNER\");\n        _transfer(msg.sender, recipient, tokenId);\n    }\n\n    /// @notice Transfers `tokenId` from 'owner' to `recipient`. Caller needs ownership or approval from 'owner'.\n    /// @param recipient The address to move `tokenId` to.\n    /// @param tokenId The Id to move.\n    function transferFrom(\n        address,\n        address recipient,\n        uint256 tokenId\n    ) public {\n        address owner = ownerOf[tokenId];\n        require(msg.sender == owner || msg.sender == getApproved[tokenId] || isApprovedForAll[owner][msg.sender], \"NOT_APPROVED\");\n        _transfer(owner, recipient, tokenId);\n    }\n\n    /// @notice Transfers `tokenId` from 'owner' to `recipient` with no data. Caller needs ownership or approval from 'owner',\n    /// and `recipient` must have compatible {onERC721Received} function.\n    /// @param recipient The address to move `tokenId` to.\n    /// @param tokenId The Id to move.\n    function safeTransferFrom(\n        address,\n        address recipient,\n        uint256 tokenId\n    ) external {\n        safeTransferFrom(address(0), recipient, tokenId, \"\");\n    }\n\n    /// @notice Transfers `tokenId` from 'owner' to `recipient` with data. Caller needs ownership or approval from 'owner',\n    /// and `recipient` must have compatible {onERC721Received} function.\n    /// @param recipient The address to move `tokenId` to.\n    /// @param tokenId The Id to move.\n    function safeTransferFrom(\n        address,\n        address recipient,\n        uint256 tokenId,\n        bytes memory data\n    ) public {\n        transferFrom(address(0), recipient, tokenId);\n        if (recipient.code.length != 0) {\n            /// @dev `onERC721Received(address,address,uint,bytes)`.\n            (, bytes memory returned) = recipient.staticcall(abi.encodeWithSelector(0x150b7a02, msg.sender, address(0), tokenId, data));\n            bytes4 selector = abi.decode(returned, (bytes4));\n            require(selector == 0x150b7a02, \"NOT_ERC721_RECEIVER\");\n        }\n    }\n\n    /// @notice Triggers an approval from 'owner' to `spender` for a given `tokenId`.\n    /// @param spender The address to be approved.\n    /// @param tokenId The Id that is approved for `spender`.\n    /// @param deadline The time at which to expire the signature.\n    /// @param v The recovery byte of the signature.\n    /// @param r Half of the ECDSA signature pair.\n    /// @param s Half of the ECDSA signature pair.\n    function permit(\n        address spender,\n        uint256 tokenId,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external {\n        require(deadline >= block.timestamp, \"PERMIT_DEADLINE_EXPIRED\");\n        address owner = ownerOf[tokenId];\n        /// @dev This is reasonably safe from overflow - incrementing `nonces` beyond\n        // 'type(uint256).max' is exceedingly unlikely compared to optimization benefits.\n        unchecked {\n            bytes32 digest = keccak256(\n                abi.encodePacked(\n                    \"\\x19\\x01\",\n                    DOMAIN_SEPARATOR(),\n                    keccak256(abi.encode(PERMIT_TYPEHASH, spender, tokenId, nonces[tokenId]++, deadline))\n                )\n            );\n            address recoveredAddress = ecrecover(digest, v, r, s);\n            require(recoveredAddress != address(0), \"INVALID_PERMIT_SIGNATURE\");\n            require(recoveredAddress == owner || isApprovedForAll[owner][recoveredAddress], \"INVALID_SIGNER\");\n        }\n        getApproved[tokenId] = spender;\n        emit Approval(owner, spender, tokenId);\n    }\n\n    /// @notice Triggers an approval from 'owner' to `operator` that can spend or {approve} spends of 'owner''s `tokenId`s.\n    /// @param owner The address to be approved.\n    /// @param operator Address of the party that can pull `tokenId`s from 'owner''s account or approve others to do same.\n    /// @param deadline The time at which to expire the signature.\n    /// @param v The recovery byte of the signature.\n    /// @param r Half of the ECDSA signature pair.\n    /// @param s Half of the ECDSA signature pair.\n    function permitAll(\n        address owner,\n        address operator,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external {\n        require(deadline >= block.timestamp, \"PERMIT_DEADLINE_EXPIRED\");\n        /// @dev This is reasonably safe from overflow - incrementing `nonces` beyond\n        // 'type(uint256).max' is exceedingly unlikely compared to optimization benefits.\n        unchecked {\n            bytes32 digest = keccak256(\n                abi.encodePacked(\n                    \"\\x19\\x01\",\n                    DOMAIN_SEPARATOR(),\n                    keccak256(abi.encode(PERMIT_ALL_TYPEHASH, owner, operator, noncesForAll[owner]++, deadline))\n                )\n            );\n            address recoveredAddress = ecrecover(digest, v, r, s);\n            require(\n                (recoveredAddress != address(0) && recoveredAddress == owner) || isApprovedForAll[owner][recoveredAddress],\n                \"INVALID_PERMIT_SIGNATURE\"\n            );\n        }\n        isApprovedForAll[owner][operator] = true;\n        emit ApprovalForAll(owner, operator, true);\n    }\n\n    function _mint(address recipient) internal {\n        /// @dev This is reasonably safe from overflow - incrementing beyond\n        // 'type(uint256).max' is exceedingly unlikely compared to optimization benefits.\n        unchecked {\n            uint256 tokenId = totalSupply++;\n            require(ownerOf[tokenId] == address(0), \"ALREADY_MINTED\");\n            balanceOf[recipient]++;\n            ownerOf[tokenId] = recipient;\n            emit Transfer(address(0), recipient, tokenId);\n        }\n    }\n\n    function _burn(uint256 tokenId) internal {\n        // @dev We tranfer the NFT to address(0) rather than burning to keep Total Supply static.\n        address owner = ownerOf[tokenId];\n        require(owner != address(0), \"NOT_MINTED\");\n        _transfer(owner, address(0), tokenId);\n    }\n\n    function _transfer(\n        address from,\n        address to,\n        uint256 tokenId\n    ) internal {\n        /// @dev This is safe from under/overflow -\n        // ownership is checked against decrement,\n        // and sum of all user balances can't reasonably exceed type(uint256).max (see {_mint}).\n        unchecked {\n            balanceOf[from]--;\n            balanceOf[to]++;\n        }\n        delete getApproved[tokenId];\n        ownerOf[tokenId] = to;\n        emit Transfer(from, to, tokenId);\n    }\n}\n"
    },
    "contracts/interfaces/concentratedPool/IConcentratedLiquidityPool.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"./../IPool.sol\";\nimport \"./../IBentoBoxMinimal.sol\";\nimport \"./../IMasterDeployer.sol\";\nimport \"../../libraries/concentratedPool/Ticks.sol\";\n\n/// @notice Trident Concentrated Liquidity Pool interface.\ninterface IConcentratedLiquidityPool is IPool {\n    function price() external view returns (uint160);\n\n    function token0() external view returns (address);\n\n    function token1() external view returns (address);\n\n    function ticks(int24 _tick) external view returns (Ticks.Tick memory tick);\n\n    function feeGrowthGlobal0() external view returns (uint256);\n\n    function feeGrowthGlobal1() external view returns (uint256);\n\n    function rangeFeeGrowth(int24 lowerTick, int24 upperTick) external view returns (uint256 feeGrowthInside0, uint256 feeGrowthInside1);\n\n    function collect(\n        int24,\n        int24,\n        address,\n        bool\n    ) external returns (uint256 amount0fees, uint256 amount1fees);\n\n    function decreaseLiquidity(\n        int24 lower,\n        int24 upper,\n        uint128 amount,\n        address recipient,\n        bool unwrapBento\n    )\n        external\n        returns (\n            TokenAmount[] memory withdrawnAmounts,\n            TokenAmount[] memory feesWithdrawn,\n            uint256 oldLiquidity\n        );\n\n    function getImmutables()\n        external\n        view\n        returns (\n            uint128 _MAX_TICK_LIQUIDITY,\n            uint24 _tickSpacing,\n            uint24 _swapFee,\n            address _barFeeTo,\n            IBentoBoxMinimal _bento,\n            IMasterDeployer _masterDeployer,\n            address _token0,\n            address _token1\n        );\n\n    function getPriceAndNearestTicks() external view returns (uint160 _price, int24 _nearestTick);\n\n    function getTokenProtocolFees() external view returns (uint128 _token0ProtocolFee, uint128 _token1ProtocolFee);\n\n    function getReserves() external view returns (uint128 _reserve0, uint128 _reserve1);\n\n    function getSecondsGrowthAndLastObservation() external view returns (uint160 _secondGrowthGlobal, uint32 _lastObservation);\n}\n"
    },
    "contracts/interfaces/ITridentNFT.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\n/// @notice Trident NFT interface.\ninterface ITridentNFT {\n    function ownerOf(uint256) external view returns (address);\n}\n"
    },
    "contracts/libraries/concentratedPool/Ticks.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"./TickMath.sol\";\n\n/// @notice Tick management library for ranged liquidity.\nlibrary Ticks {\n    struct Tick {\n        int24 previousTick;\n        int24 nextTick;\n        uint128 liquidity;\n        uint256 feeGrowthOutside0; // Per unit of liquidity.\n        uint256 feeGrowthOutside1;\n        uint160 secondsGrowthOutside;\n    }\n\n    function getMaxLiquidity(uint24 _tickSpacing) public pure returns (uint128) {\n        return type(uint128).max / uint128(uint24(TickMath.MAX_TICK) / (2 * uint24(_tickSpacing)));\n    }\n\n    function cross(\n        mapping(int24 => Tick) storage ticks,\n        int24 nextTickToCross,\n        uint160 secondsGrowthGlobal,\n        uint256 currentLiquidity,\n        uint256 feeGrowthGlobal,\n        bool zeroForOne\n    ) internal returns (uint256, int24) {\n        ticks[nextTickToCross].secondsGrowthOutside = secondsGrowthGlobal - ticks[nextTickToCross].secondsGrowthOutside;\n        if (zeroForOne) {\n            // Moving forward through the linked list.\n            if (nextTickToCross % 2 == 0) {\n                currentLiquidity -= ticks[nextTickToCross].liquidity;\n            } else {\n                currentLiquidity += ticks[nextTickToCross].liquidity;\n            }\n            nextTickToCross = ticks[nextTickToCross].previousTick;\n            ticks[nextTickToCross].feeGrowthOutside0 = feeGrowthGlobal - ticks[nextTickToCross].feeGrowthOutside0;\n        } else {\n            // Moving backwards through the linked list.\n            if (nextTickToCross % 2 == 0) {\n                currentLiquidity += ticks[nextTickToCross].liquidity;\n            } else {\n                currentLiquidity -= ticks[nextTickToCross].liquidity;\n            }\n            nextTickToCross = ticks[nextTickToCross].nextTick;\n            ticks[nextTickToCross].feeGrowthOutside1 = feeGrowthGlobal - ticks[nextTickToCross].feeGrowthOutside1;\n        }\n\n        return (currentLiquidity, nextTickToCross);\n    }\n\n    function insert(\n        mapping(int24 => Tick) storage ticks,\n        uint256 feeGrowthGlobal0,\n        uint256 feeGrowthGlobal1,\n        uint160 secondsGrowthGlobal,\n        int24 lowerOld,\n        int24 lower,\n        int24 upperOld,\n        int24 upper,\n        uint128 amount,\n        int24 nearestTick,\n        uint160 currentPrice\n    ) public returns (int24) {\n        require(lower < upper, \"WRONG_ORDER\");\n        require(TickMath.MIN_TICK <= lower, \"LOWER_RANGE\");\n        require(upper <= TickMath.MAX_TICK, \"UPPER_RANGE\");\n\n        {\n            // Stack overflow.\n            uint128 currentLowerLiquidity = ticks[lower].liquidity;\n            if (currentLowerLiquidity != 0 || lower == TickMath.MIN_TICK) {\n                // We are adding liquidity to an existing tick.\n                ticks[lower].liquidity = currentLowerLiquidity + amount;\n            } else {\n                // We are inserting a new tick.\n                Ticks.Tick storage old = ticks[lowerOld];\n                int24 oldNextTick = old.nextTick;\n\n                require((old.liquidity != 0 || lowerOld == TickMath.MIN_TICK) && lowerOld < lower && lower < oldNextTick, \"LOWER_ORDER\");\n\n                if (lower <= nearestTick) {\n                    ticks[lower] = Ticks.Tick(lowerOld, oldNextTick, amount, feeGrowthGlobal0, feeGrowthGlobal1, secondsGrowthGlobal);\n                } else {\n                    ticks[lower] = Ticks.Tick(lowerOld, oldNextTick, amount, 0, 0, 0);\n                }\n\n                old.nextTick = lower;\n                ticks[oldNextTick].previousTick = lower;\n            }\n        }\n\n        uint128 currentUpperLiquidity = ticks[upper].liquidity;\n        if (currentUpperLiquidity != 0 || upper == TickMath.MAX_TICK) {\n            // We are adding liquidity to an existing tick.\n            ticks[upper].liquidity = currentUpperLiquidity + amount;\n        } else {\n            // Inserting a new tick.\n            Ticks.Tick storage old = ticks[upperOld];\n            int24 oldNextTick = old.nextTick;\n\n            require(old.liquidity != 0 && oldNextTick > upper && upperOld < upper, \"UPPER_ORDER\");\n\n            if (upper <= nearestTick) {\n                ticks[upper] = Ticks.Tick(upperOld, oldNextTick, amount, feeGrowthGlobal0, feeGrowthGlobal1, secondsGrowthGlobal);\n            } else {\n                ticks[upper] = Ticks.Tick(upperOld, oldNextTick, amount, 0, 0, 0);\n            }\n            old.nextTick = upper;\n            ticks[oldNextTick].previousTick = upper;\n        }\n\n        int24 actualNearestTick = TickMath.getTickAtSqrtRatio(currentPrice);\n\n        if (nearestTick < upper && upper <= actualNearestTick) {\n            nearestTick = upper;\n        } else if (nearestTick < lower && lower <= actualNearestTick) {\n            nearestTick = lower;\n        }\n\n        return nearestTick;\n    }\n\n    function remove(\n        mapping(int24 => Tick) storage ticks,\n        int24 lower,\n        int24 upper,\n        uint128 amount,\n        int24 nearestTick\n    ) public returns (int24) {\n        Ticks.Tick storage current = ticks[lower];\n\n        if (lower != TickMath.MIN_TICK && current.liquidity == amount) {\n            // Delete lower tick.\n            Ticks.Tick storage previous = ticks[current.previousTick];\n            Ticks.Tick storage next = ticks[current.nextTick];\n\n            previous.nextTick = current.nextTick;\n            next.previousTick = current.previousTick;\n\n            if (nearestTick == lower) nearestTick = current.previousTick;\n\n            delete ticks[lower];\n        } else {\n            unchecked {\n                current.liquidity -= amount;\n            }\n        }\n\n        current = ticks[upper];\n\n        if (upper != TickMath.MAX_TICK && current.liquidity == amount) {\n            // Delete upper tick.\n            Ticks.Tick storage previous = ticks[current.previousTick];\n            Ticks.Tick storage next = ticks[current.nextTick];\n\n            previous.nextTick = current.nextTick;\n            next.previousTick = current.previousTick;\n\n            if (nearestTick == upper) nearestTick = current.previousTick;\n\n            delete ticks[upper];\n        } else {\n            unchecked {\n                current.liquidity -= amount;\n            }\n        }\n\n        return nearestTick;\n    }\n}\n"
    },
    "contracts/libraries/concentratedPool/UnsafeMath.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later\n\npragma solidity >=0.5.0;\n\n/// @notice Math library that contains methods that perform common math functions but do not do any overflow or underflow checks.\n/// @author Adapted from https://github.com/Uniswap/uniswap-v3-core/blob/main/contracts/libraries/UnsafeMath.sol.\nlibrary UnsafeMath {\n    /// @notice Returns ceil(x / y).\n    /// @dev Division by 0 has unspecified behavior, and must be checked externally.\n    /// @param x The dividend.\n    /// @param y The divisor.\n    /// @return z The quotient, ceil(x / y).\n    function divRoundingUp(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        assembly {\n            z := add(div(x, y), gt(mod(x, y), 0))\n        }\n    }\n}\n"
    },
    "contracts/pool/concentrated/ConcentratedLiquidityPool.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"../../interfaces/IBentoBoxMinimal.sol\";\nimport \"../../interfaces/IMasterDeployer.sol\";\nimport \"../../interfaces/IPool.sol\";\nimport \"../../interfaces/concentratedPool/IPositionManager.sol\";\nimport \"../../interfaces/ITridentCallee.sol\";\nimport \"../../interfaces/ITridentRouter.sol\";\nimport \"../../libraries/concentratedPool/FullMath.sol\";\nimport \"../../libraries/concentratedPool/TickMath.sol\";\nimport \"../../libraries/concentratedPool/UnsafeMath.sol\";\nimport \"../../libraries/concentratedPool/DyDxMath.sol\";\nimport \"../../libraries/concentratedPool/SwapLib.sol\";\nimport \"../../libraries/concentratedPool/Ticks.sol\";\n\n/// @notice Trident exchange pool template implementing concentrated liquidity for swapping between an ERC-20 token pair.\n/// @dev Amounts are considered to be in Bentobox shared\ncontract ConcentratedLiquidityPool is IPool {\n    using Ticks for mapping(int24 => Ticks.Tick);\n\n    event Mint(address indexed owner, uint256 amount0, uint256 amount1);\n    event Burn(address indexed owner, uint256 amount0, uint256 amount1);\n    event Collect(address indexed sender, uint256 amount0, uint256 amount1);\n    event Sync(uint256 reserveShares0, uint256 reserveShares1);\n\n    bytes32 public constant override poolIdentifier = \"Trident:ConcentratedLiquidity\";\n\n    uint24 internal constant MAX_FEE = 100000; /// @dev Maximum `swapFee` is 10%.\n    /// @dev References for tickSpacing:\n    /// 100 tickSpacing -> 2% between ticks.\n    uint24 internal immutable tickSpacing;\n    uint24 internal immutable swapFee; /// @dev 1000 corresponds to 0.1% fee. Fee is measured in pips.\n    uint128 internal immutable MAX_TICK_LIQUIDITY;\n\n    address internal immutable barFeeTo;\n    IBentoBoxMinimal internal immutable bento;\n    IMasterDeployer internal immutable masterDeployer;\n\n    address internal immutable token0;\n    address internal immutable token1;\n\n    uint128 public liquidity;\n\n    uint160 internal secondsGrowthGlobal; /// @dev Multiplied by 2^128.\n    uint32 internal lastObservation;\n\n    uint256 public feeGrowthGlobal0; /// @dev All fee growth counters are multiplied by 2^128.\n    uint256 public feeGrowthGlobal1;\n\n    uint256 public barFee;\n\n    uint128 internal token0ProtocolFee;\n    uint128 internal token1ProtocolFee;\n\n    uint128 internal reserve0; /// @dev `bento` share balance tracker.\n    uint128 internal reserve1;\n\n    uint160 internal price; /// @dev Sqrt of price aka. √(y/x), multiplied by 2^96.\n    int24 internal nearestTick; /// @dev Tick that is just below the current price.\n\n    uint256 internal unlocked;\n\n    mapping(int24 => Ticks.Tick) public ticks;\n    mapping(address => mapping(int24 => mapping(int24 => Position))) public positions;\n\n    struct Position {\n        uint128 liquidity;\n        uint256 feeGrowthInside0Last;\n        uint256 feeGrowthInside1Last;\n    }\n\n    struct SwapCache {\n        uint256 feeAmount;\n        uint256 totalFeeAmount;\n        uint256 protocolFee;\n        uint256 feeGrowthGlobal;\n        uint256 currentPrice;\n        uint256 currentLiquidity;\n        uint256 input;\n        int24 nextTickToCross;\n    }\n\n    struct MintParams {\n        int24 lowerOld;\n        int24 lower;\n        int24 upperOld;\n        int24 upper;\n        uint256 amount0Desired;\n        uint256 amount1Desired;\n        bool token0native;\n        bool token1native;\n        address positionOwner; // To mint an NFT the positionOwner should be set to the positionManager contract.\n        address positionRecipient;\n        uint256 positionId;\n    }\n\n    /// @dev Error list to optimize around pool requirements.\n    error Locked();\n    error ZeroAddress();\n    error InvalidToken();\n    error InvalidSwapFee();\n    error LiquidityOverflow();\n    error Token0Missing();\n    error Token1Missing();\n    error InvalidTick();\n    error LowerEven();\n    error UpperOdd();\n    error MaxTickLiquidity();\n    error Overflow();\n\n    modifier lock() {\n        if (unlocked == 2) revert Locked();\n        unlocked = 2;\n        _;\n        unlocked = 1;\n    }\n\n    /// @dev Only set immutable variables here - state changes made here will not be used.\n    constructor(bytes memory _deployData, IMasterDeployer _masterDeployer) {\n        (address _token0, address _token1, uint24 _swapFee, uint160 _price, uint24 _tickSpacing) = abi.decode(\n            _deployData,\n            (address, address, uint24, uint160, uint24)\n        );\n\n        if (_token0 == address(0)) revert ZeroAddress();\n        if (_token0 == address(this)) revert InvalidToken();\n        if (_token1 == address(this)) revert InvalidToken();\n        if (_swapFee > MAX_FEE) revert InvalidSwapFee();\n\n        token0 = _token0;\n        token1 = _token1;\n        swapFee = _swapFee;\n        price = _price;\n        tickSpacing = _tickSpacing;\n        // Prevents global liquidity overflow in the case all ticks are initialised.\n        MAX_TICK_LIQUIDITY = Ticks.getMaxLiquidity(_tickSpacing);\n        ticks[TickMath.MIN_TICK] = Ticks.Tick(TickMath.MIN_TICK, TickMath.MAX_TICK, uint128(0), 0, 0, 0);\n        ticks[TickMath.MAX_TICK] = Ticks.Tick(TickMath.MIN_TICK, TickMath.MAX_TICK, uint128(0), 0, 0, 0);\n        nearestTick = TickMath.MIN_TICK;\n        bento = IBentoBoxMinimal(_masterDeployer.bento());\n        barFeeTo = _masterDeployer.barFeeTo();\n        barFee = _masterDeployer.barFee();\n        masterDeployer = _masterDeployer;\n        unlocked = 1;\n    }\n\n    /// @dev Mints LP tokens - should be called via the router after transferring `bento` tokens.\n    /// The router must ensure that sufficient liquidity has been minted.\n    function mint(bytes calldata data) public override lock returns (uint256 _liquidity) {\n        MintParams memory mintParams = abi.decode(data, (MintParams));\n\n        uint256 priceLower = uint256(TickMath.getSqrtRatioAtTick(mintParams.lower));\n        uint256 priceUpper = uint256(TickMath.getSqrtRatioAtTick(mintParams.upper));\n        uint256 currentPrice = uint256(price);\n\n        _liquidity = DyDxMath.getLiquidityForAmounts(\n            priceLower,\n            priceUpper,\n            currentPrice,\n            mintParams.amount1Desired,\n            mintParams.amount0Desired\n        );\n\n        unchecked {\n            (uint256 amount0fees, uint256 amount1fees, ) = _updatePosition(\n                mintParams.positionOwner,\n                mintParams.lower,\n                mintParams.upper,\n                int128(uint128(_liquidity))\n            );\n            if (amount0fees > 0) {\n                _transfer(token0, amount0fees, mintParams.positionOwner, false);\n                reserve0 -= uint128(amount0fees);\n            }\n            if (amount1fees > 0) {\n                _transfer(token1, amount1fees, mintParams.positionOwner, false);\n                reserve1 -= uint128(amount1fees);\n            }\n        }\n\n        unchecked {\n            if (priceLower < currentPrice && currentPrice < priceUpper) liquidity += uint128(_liquidity);\n        }\n\n        _ensureTickSpacing(mintParams.lower, mintParams.upper);\n\n        nearestTick = Ticks.insert(\n            ticks,\n            feeGrowthGlobal0,\n            feeGrowthGlobal1,\n            secondsGrowthGlobal,\n            mintParams.lowerOld,\n            mintParams.lower,\n            mintParams.upperOld,\n            mintParams.upper,\n            uint128(_liquidity),\n            nearestTick,\n            uint160(currentPrice)\n        );\n\n        (uint128 amount0Actual, uint128 amount1Actual) = DyDxMath.getAmountsForLiquidity(\n            priceLower,\n            priceUpper,\n            currentPrice,\n            _liquidity,\n            true\n        );\n\n        {\n            ITridentRouter.TokenInput[] memory callbackData = new ITridentRouter.TokenInput[](2);\n            callbackData[0] = ITridentRouter.TokenInput(token0, mintParams.token0native, amount0Actual);\n            callbackData[1] = ITridentRouter.TokenInput(token1, mintParams.token1native, amount1Actual);\n            ITridentCallee(msg.sender).tridentMintCallback(abi.encode(callbackData));\n        }\n\n        unchecked {\n            if (amount0Actual != 0) {\n                if (amount0Actual + reserve0 > _balance(token0)) revert Token0Missing();\n                reserve0 += amount0Actual;\n            }\n\n            if (amount1Actual != 0) {\n                if (amount1Actual + reserve1 > _balance(token1)) revert Token1Missing();\n                reserve1 += amount1Actual;\n            }\n        }\n\n        (uint256 feeGrowth0, uint256 feeGrowth1) = rangeFeeGrowth(mintParams.lower, mintParams.upper);\n\n        if (mintParams.positionRecipient != address(0)) {\n            IPositionManager(mintParams.positionOwner).positionMintCallback(\n                mintParams.positionRecipient,\n                mintParams.lower,\n                mintParams.upper,\n                uint128(_liquidity),\n                feeGrowth0,\n                feeGrowth1,\n                mintParams.positionId\n            );\n        }\n\n        emit Mint(mintParams.positionOwner, amount0Actual, amount1Actual);\n    }\n\n    /// @notice Burn function that cannpt conform to the IPool interface due to having three return values.\n    /// @dev Burns LP tokens sent to this contract.\n    function decreaseLiquidity(\n        int24 lower,\n        int24 upper,\n        uint128 amount,\n        address recipient,\n        bool unwrapBento\n    )\n        public\n        returns (\n            IPool.TokenAmount[] memory withdrawnAmounts,\n            IPool.TokenAmount[] memory feesWithdrawn,\n            uint256 oldLiquidity\n        )\n    {\n        uint256 amount0;\n        uint256 amount1;\n\n        {\n            uint160 priceLower = TickMath.getSqrtRatioAtTick(lower);\n            uint160 priceUpper = TickMath.getSqrtRatioAtTick(upper);\n            uint160 currentPrice = price;\n\n            unchecked {\n                if (priceLower < currentPrice && currentPrice < priceUpper) liquidity -= amount;\n            }\n\n            (amount0, amount1) = DyDxMath.getAmountsForLiquidity(\n                uint256(priceLower),\n                uint256(priceUpper),\n                uint256(currentPrice),\n                uint256(amount),\n                false\n            );\n        }\n\n        {\n            // Ensure no overflow happens when we cast to int128.\n            if (amount > uint128(type(int128).max)) revert Overflow();\n\n            uint256 amount0fees;\n            uint256 amount1fees;\n            (amount0fees, amount1fees, oldLiquidity) = _updatePosition(msg.sender, lower, upper, -int128(amount));\n\n            withdrawnAmounts = new TokenAmount[](2);\n            withdrawnAmounts[0] = TokenAmount({token: token0, amount: amount0});\n            withdrawnAmounts[1] = TokenAmount({token: token1, amount: amount1});\n\n            feesWithdrawn = new TokenAmount[](2);\n            feesWithdrawn[0] = TokenAmount({token: token0, amount: amount0fees});\n            feesWithdrawn[1] = TokenAmount({token: token1, amount: amount1fees});\n\n            unchecked {\n                amount0 += amount0fees;\n                amount1 += amount1fees;\n            }\n        }\n\n        unchecked {\n            reserve0 -= uint128(amount0);\n            reserve1 -= uint128(amount1);\n        }\n\n        _transferBothTokens(recipient, amount0, amount1, unwrapBento);\n\n        nearestTick = Ticks.remove(ticks, lower, upper, amount, nearestTick);\n        emit Burn(msg.sender, amount0, amount1);\n    }\n\n    function burn(bytes calldata) public pure override returns (IPool.TokenAmount[] memory) {\n        revert();\n    }\n\n    function burnSingle(bytes calldata) public pure override returns (uint256) {\n        revert();\n    }\n\n    function collect(\n        int24 lower,\n        int24 upper,\n        address recipient,\n        bool unwrapBento\n    ) public lock returns (uint256 amount0fees, uint256 amount1fees) {\n        (amount0fees, amount1fees, ) = _updatePosition(msg.sender, lower, upper, 0);\n\n        _transferBothTokens(recipient, amount0fees, amount1fees, unwrapBento);\n\n        reserve0 -= uint128(amount0fees);\n        reserve1 -= uint128(amount1fees);\n\n        emit Collect(msg.sender, amount0fees, amount1fees);\n    }\n\n    /// @dev Swaps one token for another. The router must prefund this contract and ensure there isn't too much slippage\n    /// - price is √(y/x)\n    /// - x is token0\n    /// - zero for one -> price will move down.\n    function swap(bytes memory data) public override lock returns (uint256 amountOut) {\n        (bool zeroForOne, uint256 inAmount, address recipient, bool unwrapBento) = abi.decode(data, (bool, uint256, address, bool));\n\n        SwapCache memory cache = SwapCache({\n            feeAmount: 0,\n            totalFeeAmount: 0,\n            protocolFee: 0,\n            feeGrowthGlobal: zeroForOne ? feeGrowthGlobal1 : feeGrowthGlobal0,\n            currentPrice: uint256(price),\n            currentLiquidity: uint256(liquidity),\n            input: inAmount,\n            nextTickToCross: zeroForOne ? nearestTick : ticks[nearestTick].nextTick\n        });\n\n        unchecked {\n            uint256 timestamp = block.timestamp;\n            uint256 diff = timestamp - uint256(lastObservation); // Underflow in 2106. Don't do staking rewards in the year 2106.\n            if (diff > 0 && liquidity > 0) {\n                lastObservation = uint32(timestamp);\n                secondsGrowthGlobal += uint160((diff << 128) / liquidity);\n            }\n        }\n\n        while (cache.input != 0) {\n            uint256 nextTickPrice = uint256(TickMath.getSqrtRatioAtTick(cache.nextTickToCross));\n            uint256 output = 0;\n            bool cross = false;\n\n            if (zeroForOne) {\n                // Trading token 0 (x) for token 1 (y).\n                // Price is decreasing.\n                // Maximum input amount within current tick range: Δx = Δ(1/√𝑃) · L.\n                uint256 maxDx = DyDxMath.getDx(cache.currentLiquidity, nextTickPrice, cache.currentPrice, false);\n\n                if (cache.input <= maxDx) {\n                    // We can swap within the current range.\n                    uint256 liquidityPadded = cache.currentLiquidity << 96;\n                    // Calculate new price after swap: √𝑃[new] =  L · √𝑃 / (L + Δx · √𝑃)\n                    // This is derrived from Δ(1/√𝑃) = Δx/L\n                    // where Δ(1/√𝑃) is 1/√𝑃[old] - 1/√𝑃[new] and we solve for √𝑃[new].\n                    // In case of an owerflow we can use: √𝑃[new] = L / (L / √𝑃 + Δx).\n                    // This is derrived by dividing the original fraction by √𝑃 on both sides.\n                    uint256 newPrice = uint256(\n                        FullMath.mulDivRoundingUp(liquidityPadded, cache.currentPrice, liquidityPadded + cache.currentPrice * cache.input)\n                    );\n\n                    if (!(nextTickPrice <= newPrice && newPrice < cache.currentPrice)) {\n                        // Overflow. We use a modified version of the formula.\n                        newPrice = uint160(UnsafeMath.divRoundingUp(liquidityPadded, liquidityPadded / cache.currentPrice + cache.input));\n                    }\n                    // Based on the price difference calculate the output of th swap: Δy = Δ√P · L.\n                    output = DyDxMath.getDy(cache.currentLiquidity, newPrice, cache.currentPrice, false);\n                    cache.currentPrice = newPrice;\n                    cache.input = 0;\n                } else {\n                    // Execute swap step and cross the tick.\n                    output = DyDxMath.getDy(cache.currentLiquidity, nextTickPrice, cache.currentPrice, false);\n                    cache.currentPrice = nextTickPrice;\n                    cross = true;\n                    cache.input -= maxDx;\n                }\n            } else {\n                // Price is increasing.\n                // Maximum swap amount within the current tick range: Δy = Δ√P · L.\n                uint256 maxDy = DyDxMath.getDy(cache.currentLiquidity, cache.currentPrice, nextTickPrice, false);\n\n                if (cache.input <= maxDy) {\n                    // We can swap within the current range.\n                    // Calculate new price after swap: ΔP = Δy/L.\n                    uint256 newPrice = cache.currentPrice +\n                        FullMath.mulDiv(cache.input, 0x1000000000000000000000000, cache.currentLiquidity);\n                    // Calculate output of swap\n                    // - Δx = Δ(1/√P) · L.\n                    output = DyDxMath.getDx(cache.currentLiquidity, cache.currentPrice, newPrice, false);\n                    cache.currentPrice = newPrice;\n                    cache.input = 0;\n                } else {\n                    // Swap & cross the tick.\n                    output = DyDxMath.getDx(cache.currentLiquidity, cache.currentPrice, nextTickPrice, false);\n                    cache.currentPrice = nextTickPrice;\n                    cross = true;\n                    cache.input -= maxDy;\n                }\n            }\n            (cache.totalFeeAmount, amountOut, cache.protocolFee, cache.feeGrowthGlobal) = SwapLib.handleFees(\n                output,\n                swapFee,\n                barFee,\n                cache.currentLiquidity,\n                cache.totalFeeAmount,\n                amountOut,\n                cache.protocolFee,\n                cache.feeGrowthGlobal\n            );\n            if (cross) {\n                (cache.currentLiquidity, cache.nextTickToCross) = Ticks.cross(\n                    ticks,\n                    cache.nextTickToCross,\n                    secondsGrowthGlobal,\n                    cache.currentLiquidity,\n                    cache.feeGrowthGlobal,\n                    zeroForOne\n                );\n                if (cache.currentLiquidity == 0) {\n                    // We step into a zone that has liquidity - or we reach the end of the linked list.\n                    cache.currentPrice = uint256(TickMath.getSqrtRatioAtTick(cache.nextTickToCross));\n                    (cache.currentLiquidity, cache.nextTickToCross) = Ticks.cross(\n                        ticks,\n                        cache.nextTickToCross,\n                        secondsGrowthGlobal,\n                        cache.currentLiquidity,\n                        cache.feeGrowthGlobal,\n                        zeroForOne\n                    );\n                }\n            }\n        }\n\n        price = uint160(cache.currentPrice);\n\n        int24 newNearestTick = zeroForOne ? cache.nextTickToCross : ticks[cache.nextTickToCross].previousTick;\n\n        if (nearestTick != newNearestTick) {\n            nearestTick = newNearestTick;\n            liquidity = uint128(cache.currentLiquidity);\n        }\n\n        _updateReserves(zeroForOne, uint128(inAmount), amountOut);\n\n        _updateFees(zeroForOne, cache.feeGrowthGlobal, uint128(cache.protocolFee));\n\n        if (zeroForOne) {\n            _transfer(token1, amountOut, recipient, unwrapBento);\n            emit Swap(recipient, token0, token1, inAmount, amountOut);\n        } else {\n            _transfer(token0, amountOut, recipient, unwrapBento);\n            emit Swap(recipient, token1, token0, inAmount, amountOut);\n        }\n    }\n\n    /// @dev Reserved for IPool.\n    function flashSwap(bytes calldata) public pure override returns (uint256) {\n        revert();\n    }\n\n    /// @dev Updates `barFee` for Trident protocol.\n    function updateBarFee() public {\n        barFee = IMasterDeployer(masterDeployer).barFee();\n    }\n\n    /// @dev Collects fees for Trident protocol.\n    function collectProtocolFee() public lock returns (uint128 amount0, uint128 amount1) {\n        if (token0ProtocolFee > 1) {\n            amount0 = token0ProtocolFee - 1;\n            token0ProtocolFee = 1;\n            reserve0 -= amount0;\n            _transfer(token0, amount0, barFeeTo, false);\n        }\n        if (token1ProtocolFee > 1) {\n            amount1 = token1ProtocolFee - 1;\n            token1ProtocolFee = 1;\n            reserve1 -= amount1;\n            _transfer(token1, amount1, barFeeTo, false);\n        }\n    }\n\n    function _ensureTickSpacing(int24 lower, int24 upper) internal view {\n        if (lower % int24(tickSpacing) != 0) revert InvalidTick();\n        if ((lower / int24(tickSpacing)) % 2 != 0) revert LowerEven();\n        if (upper % int24(tickSpacing) != 0) revert InvalidTick();\n        if ((upper / int24(tickSpacing)) % 2 == 0) revert UpperOdd();\n    }\n\n    function _updateReserves(\n        bool zeroForOne,\n        uint128 inAmount,\n        uint256 amountOut\n    ) internal {\n        if (zeroForOne) {\n            uint256 balance0 = _balance(token0);\n            uint128 newBalance = reserve0 + inAmount;\n            if (uint256(newBalance) > balance0) revert Token0Missing();\n            reserve0 = newBalance;\n            reserve1 -= uint128(amountOut);\n        } else {\n            uint256 balance1 = _balance(token1);\n            uint128 newBalance = reserve1 + inAmount;\n            if (uint256(newBalance) > balance1) revert Token1Missing();\n            reserve1 = newBalance;\n            reserve0 -= uint128(amountOut);\n        }\n    }\n\n    function _updateFees(\n        bool zeroForOne,\n        uint256 feeGrowthGlobal,\n        uint128 protocolFee\n    ) internal {\n        if (zeroForOne) {\n            feeGrowthGlobal1 = feeGrowthGlobal;\n            token1ProtocolFee += protocolFee;\n        } else {\n            feeGrowthGlobal0 = feeGrowthGlobal;\n            token0ProtocolFee += protocolFee;\n        }\n    }\n\n    function _updatePosition(\n        address owner,\n        int24 lower,\n        int24 upper,\n        int128 amount\n    )\n        internal\n        returns (\n            uint256 amount0fees,\n            uint256 amount1fees,\n            uint256 oldLiquidity\n        )\n    {\n        Position storage position = positions[owner][lower][upper];\n\n        (uint256 growth0current, uint256 growth1current) = rangeFeeGrowth(lower, upper);\n        amount0fees = FullMath.mulDiv(\n            growth0current - position.feeGrowthInside0Last,\n            position.liquidity,\n            0x100000000000000000000000000000000\n        );\n\n        amount1fees = FullMath.mulDiv(\n            growth1current - position.feeGrowthInside1Last,\n            position.liquidity,\n            0x100000000000000000000000000000000\n        );\n\n        oldLiquidity = position.liquidity;\n\n        if (amount < 0) {\n            position.liquidity -= uint128(-amount);\n        }\n\n        if (amount > 0) {\n            position.liquidity += uint128(amount);\n            if (position.liquidity > MAX_TICK_LIQUIDITY) revert LiquidityOverflow();\n        }\n\n        position.feeGrowthInside0Last = growth0current;\n        position.feeGrowthInside1Last = growth1current;\n    }\n\n    function _balance(address token) internal view returns (uint256 balance) {\n        balance = bento.balanceOf(token, address(this));\n    }\n\n    function _transfer(\n        address token,\n        uint256 shares,\n        address to,\n        bool unwrapBento\n    ) internal {\n        if (unwrapBento) {\n            bento.withdraw(token, address(this), to, 0, shares);\n        } else {\n            bento.transfer(token, address(this), to, shares);\n        }\n    }\n\n    function _transferBothTokens(\n        address to,\n        uint256 shares0,\n        uint256 shares1,\n        bool unwrapBento\n    ) internal {\n        if (unwrapBento) {\n            bento.withdraw(token0, address(this), to, 0, shares0);\n            bento.withdraw(token1, address(this), to, 0, shares1);\n        } else {\n            bento.transfer(token0, address(this), to, shares0);\n            bento.transfer(token1, address(this), to, shares1);\n        }\n    }\n\n    /// @dev Generic formula for fee growth inside a range: (globalGrowth - growthBelow - growthAbove)\n    /// - available counters: global, outside u, outside v.\n\n    ///                  u         ▼         v\n    /// ----|----|-------|xxxxxxxxxxxxxxxxxxx|--------|--------- (global - feeGrowthOutside(u) - feeGrowthOutside(v))\n\n    ///             ▼    u                   v\n    /// ----|----|-------|xxxxxxxxxxxxxxxxxxx|--------|--------- (global - (global - feeGrowthOutside(u)) - feeGrowthOutside(v))\n\n    ///                  u                   v    ▼\n    /// ----|----|-------|xxxxxxxxxxxxxxxxxxx|--------|--------- (global - feeGrowthOutside(u) - (global - feeGrowthOutside(v)))\n\n    /// @notice Calculates the fee growth inside a range (per unit of liquidity).\n    /// @dev Multiply `rangeFeeGrowth` delta by the provided liquidity to get accrued fees for some period.\n    function rangeFeeGrowth(int24 lowerTick, int24 upperTick) public view returns (uint256 feeGrowthInside0, uint256 feeGrowthInside1) {\n        int24 currentTick = nearestTick;\n\n        Ticks.Tick storage lower = ticks[lowerTick];\n        Ticks.Tick storage upper = ticks[upperTick];\n\n        // Calculate fee growth below & above.\n        uint256 _feeGrowthGlobal0 = feeGrowthGlobal0;\n        uint256 _feeGrowthGlobal1 = feeGrowthGlobal1;\n        uint256 feeGrowthBelow0;\n        uint256 feeGrowthBelow1;\n        uint256 feeGrowthAbove0;\n        uint256 feeGrowthAbove1;\n\n        if (lowerTick <= currentTick) {\n            feeGrowthBelow0 = lower.feeGrowthOutside0;\n            feeGrowthBelow1 = lower.feeGrowthOutside1;\n        } else {\n            feeGrowthBelow0 = _feeGrowthGlobal0 - lower.feeGrowthOutside0;\n            feeGrowthBelow1 = _feeGrowthGlobal1 - lower.feeGrowthOutside1;\n        }\n\n        if (currentTick < upperTick) {\n            feeGrowthAbove0 = upper.feeGrowthOutside0;\n            feeGrowthAbove1 = upper.feeGrowthOutside1;\n        } else {\n            feeGrowthAbove0 = _feeGrowthGlobal0 - upper.feeGrowthOutside0;\n            feeGrowthAbove1 = _feeGrowthGlobal1 - upper.feeGrowthOutside1;\n        }\n\n        feeGrowthInside0 = _feeGrowthGlobal0 - feeGrowthBelow0 - feeGrowthAbove0;\n        feeGrowthInside1 = _feeGrowthGlobal1 - feeGrowthBelow1 - feeGrowthAbove1;\n    }\n\n    function getAssets() public view override returns (address[] memory assets) {\n        assets = new address[](2);\n        assets[0] = token0;\n        assets[1] = token1;\n    }\n\n    /// @dev Reserved for IPool.\n    function getAmountOut(bytes calldata) public pure override returns (uint256) {\n        revert();\n    }\n\n    /// @dev Reserved for IPool.\n    function getAmountIn(bytes calldata) public pure override returns (uint256) {\n        revert();\n    }\n\n    function getImmutables()\n        public\n        view\n        returns (\n            uint128 _MAX_TICK_LIQUIDITY,\n            uint24 _tickSpacing,\n            uint24 _swapFee,\n            address _barFeeTo,\n            IBentoBoxMinimal _bento,\n            IMasterDeployer _masterDeployer,\n            address _token0,\n            address _token1\n        )\n    {\n        _MAX_TICK_LIQUIDITY = MAX_TICK_LIQUIDITY;\n        _tickSpacing = tickSpacing;\n        _swapFee = swapFee; // 1000 corresponds to 0.1% fee.\n        _barFeeTo = barFeeTo;\n        _bento = bento;\n        _masterDeployer = masterDeployer;\n        _token0 = token0;\n        _token1 = token1;\n    }\n\n    function getPriceAndNearestTicks() public view returns (uint160 _price, int24 _nearestTick) {\n        _price = price;\n        _nearestTick = nearestTick;\n    }\n\n    function getTokenProtocolFees() public view returns (uint128 _token0ProtocolFee, uint128 _token1ProtocolFee) {\n        _token0ProtocolFee = token0ProtocolFee;\n        _token1ProtocolFee = token1ProtocolFee;\n    }\n\n    function getReserves() public view returns (uint128 _reserve0, uint128 _reserve1) {\n        _reserve0 = reserve0;\n        _reserve1 = reserve1;\n    }\n\n    function getSecondsGrowthAndLastObservation() public view returns (uint160 _secondsGrowthGlobal, uint32 _lastObservation) {\n        _secondsGrowthGlobal = secondsGrowthGlobal;\n        _lastObservation = lastObservation;\n    }\n}\n"
    },
    "contracts/interfaces/ITridentCallee.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\n/// @notice Trident pool callback interface.\ninterface ITridentCallee {\n    function tridentSwapCallback(bytes calldata data) external;\n\n    function tridentMintCallback(bytes calldata data) external;\n}\n"
    },
    "contracts/libraries/concentratedPool/SwapLib.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"./FullMath.sol\";\n\n/// @notice Math library that facilitates fee handling for Trident Concentrated Liquidity Pools.\nlibrary SwapLib {\n    function handleFees(\n        uint256 output,\n        uint24 swapFee,\n        uint256 barFee,\n        uint256 currentLiquidity,\n        uint256 totalFeeAmount,\n        uint256 amountOut,\n        uint256 protocolFee,\n        uint256 feeGrowthGlobal\n    )\n        internal\n        pure\n        returns (\n            uint256,\n            uint256,\n            uint256,\n            uint256\n        )\n    {\n        uint256 feeAmount = FullMath.mulDivRoundingUp(output, swapFee, 1e6);\n\n        totalFeeAmount += feeAmount;\n\n        amountOut += output - feeAmount;\n\n        // Calculate `protocolFee` and convert pips to bips.\n        uint256 feeDelta = FullMath.mulDivRoundingUp(feeAmount, barFee, 1e4);\n\n        protocolFee += feeDelta;\n\n        // Updating `feeAmount` based on the protocolFee.\n        feeAmount -= feeDelta;\n\n        feeGrowthGlobal += FullMath.mulDiv(feeAmount, 0x100000000000000000000000000000000, currentLiquidity);\n\n        return (totalFeeAmount, amountOut, protocolFee, feeGrowthGlobal);\n    }\n}\n"
    },
    "contracts/pool/concentrated/ConcentratedLiquidityPoolFactory.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"./ConcentratedLiquidityPool.sol\";\nimport \"../PoolDeployer.sol\";\n\n/// @notice Contract for deploying Trident exchange Concentrated Liquidity Pool with configurations.\n/// @author Mudit Gupta.\ncontract ConcentratedLiquidityPoolFactory is PoolDeployer {\n    constructor(address _masterDeployer) PoolDeployer(_masterDeployer) {}\n\n    function deployPool(bytes memory _deployData) external returns (address pool) {\n        (address tokenA, address tokenB, uint24 swapFee, uint160 price, uint24 tickSpacing) = abi.decode(\n            _deployData,\n            (address, address, uint24, uint160, uint24)\n        );\n        if (tokenA > tokenB) {\n            (tokenA, tokenB) = (tokenB, tokenA);\n        }\n        // @dev Strips any extra data.\n        _deployData = abi.encode(tokenA, tokenB, swapFee, price, tickSpacing);\n\n        address[] memory tokens = new address[](2);\n        tokens[0] = tokenA;\n        tokens[1] = tokenB;\n\n        // @dev Salt is not actually needed since `_deployData` is part of creationCode and already contains the salt.\n        bytes32 salt = keccak256(_deployData);\n        pool = address(new ConcentratedLiquidityPool{salt: salt}(_deployData, IMasterDeployer(masterDeployer)));\n        _registerPool(pool, tokens, salt);\n    }\n}\n"
    },
    "contracts/pool/PoolDeployer.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\n/// @notice Trident pool deployer for whitelisted template factories.\n/// @author Mudit Gupta.\nabstract contract PoolDeployer {\n    address public immutable masterDeployer;\n\n    mapping(address => mapping(address => address[])) public pools;\n    mapping(bytes32 => address) public configAddress;\n\n    error UnauthorisedDeployer();\n    error ZeroAddress();\n    error InvalidTokenOrder();\n\n    modifier onlyMaster() {\n        if (msg.sender != masterDeployer) revert UnauthorisedDeployer();\n        _;\n    }\n\n    constructor(address _masterDeployer) {\n        if (_masterDeployer == address(0)) revert ZeroAddress();\n        masterDeployer = _masterDeployer;\n    }\n\n    function _registerPool(\n        address pool,\n        address[] memory tokens,\n        bytes32 salt\n    ) internal onlyMaster {\n        // @dev Store the address of the deployed contract.\n        configAddress[salt] = pool;\n        // @dev Attacker used underflow, it was not very effective. poolimon!\n        // null token array would cause deployment to fail via out of bounds memory axis/gas limit.\n        unchecked {\n            for (uint256 i; i < tokens.length - 1; i++) {\n                if (tokens[i] >= tokens[i + 1]) revert InvalidTokenOrder();\n                for (uint256 j = i + 1; j < tokens.length; j++) {\n                    pools[tokens[i]][tokens[j]].push(pool);\n                    pools[tokens[j]][tokens[i]].push(pool);\n                }\n            }\n        }\n    }\n\n    function poolsCount(address token0, address token1) external view returns (uint256 count) {\n        count = pools[token0][token1].length;\n    }\n\n    function getPools(\n        address token0,\n        address token1,\n        uint256 startIndex,\n        uint256 count\n    ) external view returns (address[] memory pairPools) {\n        pairPools = new address[](count);\n        for (uint256 i = 0; i < count; i++) {\n            pairPools[i] = pools[token0][token1][startIndex + i];\n        }\n    }\n}\n"
    },
    "contracts/pool/IndexPoolFactory.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"./IndexPool.sol\";\nimport \"./PoolDeployer.sol\";\n\n/// @notice Contract for deploying Trident exchange Index Pool with configurations.\n/// @author Mudit Gupta\ncontract IndexPoolFactory is PoolDeployer {\n    constructor(address _masterDeployer) PoolDeployer(_masterDeployer) {}\n\n    function deployPool(bytes memory _deployData) external returns (address pool) {\n        (address[] memory tokens, uint136[] memory weights, uint256 swapFee) = abi.decode(_deployData, (address[], uint136[], uint256));\n\n        // @dev Strips any extra data.\n        _deployData = abi.encode(tokens, weights, swapFee);\n\n        // @dev Salt is not actually needed since `_deployData` is part of creationCode and already contains the salt.\n        bytes32 salt = keccak256(_deployData);\n        pool = address(new IndexPool{salt: salt}(_deployData, masterDeployer));\n        _registerPool(pool, tokens, salt);\n    }\n}\n"
    },
    "contracts/pool/IndexPool.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"../interfaces/IBentoBoxMinimal.sol\";\nimport \"../interfaces/IMasterDeployer.sol\";\nimport \"../interfaces/IPool.sol\";\nimport \"../interfaces/ITridentCallee.sol\";\nimport \"./TridentERC20.sol\";\n\n/// @notice Trident exchange pool template with constant mean formula for swapping among an array of ERC-20 tokens.\n/// @dev The reserves are stored as bento shares.\n///      The curve is applied to shares as well. This pool does not care about the underlying amounts.\ncontract IndexPool is IPool, TridentERC20 {\n    event Mint(address indexed sender, address tokenIn, uint256 amountIn, address indexed recipient);\n    event Burn(address indexed sender, address tokenOut, uint256 amountOut, address indexed recipient);\n\n    uint256 public immutable swapFee;\n\n    address public immutable barFeeTo;\n    IBentoBoxMinimal public immutable bento;\n    IMasterDeployer public immutable masterDeployer;\n\n    uint256 internal constant BASE = 10**18;\n    uint256 internal constant MIN_TOKENS = 2;\n    uint256 internal constant MAX_TOKENS = 8;\n    uint256 internal constant MIN_FEE = BASE / 10**6;\n    uint256 internal constant MAX_FEE = BASE / 10;\n    uint256 internal constant MIN_WEIGHT = BASE;\n    uint256 internal constant MAX_WEIGHT = BASE * 50;\n    uint256 internal constant MAX_TOTAL_WEIGHT = BASE * 50;\n    uint256 internal constant MIN_BALANCE = BASE / 10**12;\n    uint256 internal constant INIT_POOL_SUPPLY = BASE * 100;\n    uint256 internal constant MIN_POW_BASE = 1;\n    uint256 internal constant MAX_POW_BASE = (2 * BASE) - 1;\n    uint256 internal constant POW_PRECISION = BASE / 10**10;\n    uint256 internal constant MAX_IN_RATIO = BASE / 2;\n    uint256 internal constant MAX_OUT_RATIO = (BASE / 3) + 1;\n\n    uint136 internal totalWeight;\n    address[] internal tokens;\n\n    uint256 public barFee;\n\n    bytes32 public constant override poolIdentifier = \"Trident:Index\";\n\n    uint256 internal unlocked;\n    modifier lock() {\n        require(unlocked == 1, \"LOCKED\");\n        unlocked = 2;\n        _;\n        unlocked = 1;\n    }\n\n    mapping(address => Record) public records;\n    struct Record {\n        uint120 reserve;\n        uint136 weight;\n    }\n\n    constructor(bytes memory _deployData, address _masterDeployer) {\n        (address[] memory _tokens, uint136[] memory _weights, uint256 _swapFee) = abi.decode(_deployData, (address[], uint136[], uint256));\n        // @dev Factory ensures that the tokens are sorted.\n        require(_tokens.length == _weights.length, \"INVALID_ARRAYS\");\n        require(MIN_FEE <= _swapFee && _swapFee <= MAX_FEE, \"INVALID_SWAP_FEE\");\n        require(MIN_TOKENS <= _tokens.length && _tokens.length <= MAX_TOKENS, \"INVALID_TOKENS_LENGTH\");\n\n        for (uint256 i = 0; i < _tokens.length; i++) {\n            require(_tokens[i] != address(0), \"ZERO_ADDRESS\");\n            require(MIN_WEIGHT <= _weights[i] && _weights[i] <= MAX_WEIGHT, \"INVALID_WEIGHT\");\n            records[_tokens[i]] = Record({reserve: 0, weight: _weights[i]});\n            tokens.push(_tokens[i]);\n            totalWeight += _weights[i];\n        }\n\n        require(totalWeight <= MAX_TOTAL_WEIGHT, \"MAX_TOTAL_WEIGHT\");\n        // @dev This burns initial LP supply.\n        _mint(address(0), INIT_POOL_SUPPLY);\n\n        swapFee = _swapFee;\n        barFee = IMasterDeployer(_masterDeployer).barFee();\n        barFeeTo = IMasterDeployer(_masterDeployer).barFeeTo();\n        bento = IBentoBoxMinimal(IMasterDeployer(_masterDeployer).bento());\n        masterDeployer = IMasterDeployer(_masterDeployer);\n        unlocked = 1;\n    }\n\n    /// @dev Mints LP tokens - should be called via the router after transferring `bento` tokens.\n    /// The router must ensure that sufficient LP tokens are minted by using the return value.\n    function mint(bytes calldata data) public override lock returns (uint256 liquidity) {\n        (address recipient, uint256 toMint) = abi.decode(data, (address, uint256));\n\n        uint120 ratio = uint120(_div(toMint, totalSupply));\n\n        for (uint256 i = 0; i < tokens.length; i++) {\n            address tokenIn = tokens[i];\n            uint120 reserve = records[tokenIn].reserve;\n            // @dev If token balance is '0', initialize with `ratio`.\n            uint120 amountIn = reserve != 0 ? uint120(_mul(ratio, reserve)) : ratio;\n            require(amountIn >= MIN_BALANCE, \"MIN_BALANCE\");\n            // @dev Check Trident router has sent `amountIn` for skim into pool.\n            unchecked {\n                // @dev This is safe from overflow - only logged amounts handled.\n                require(_balance(tokenIn) >= amountIn + reserve, \"NOT_RECEIVED\");\n                records[tokenIn].reserve += amountIn;\n            }\n            emit Mint(msg.sender, tokenIn, amountIn, recipient);\n        }\n        _mint(recipient, toMint);\n        liquidity = toMint;\n    }\n\n    /// @dev Burns LP tokens sent to this contract. The router must ensure that the user gets sufficient output tokens.\n    function burn(bytes calldata data) public override lock returns (IPool.TokenAmount[] memory withdrawnAmounts) {\n        (address recipient, bool unwrapBento, uint256 toBurn) = abi.decode(data, (address, bool, uint256));\n\n        uint256 ratio = _div(toBurn, totalSupply);\n\n        withdrawnAmounts = new TokenAmount[](tokens.length);\n\n        _burn(address(this), toBurn);\n\n        for (uint256 i = 0; i < tokens.length; i++) {\n            address tokenOut = tokens[i];\n            uint256 balance = records[tokenOut].reserve;\n            uint120 amountOut = uint120(_mul(ratio, balance));\n            require(amountOut != 0, \"ZERO_OUT\");\n            // @dev This is safe from underflow - only logged amounts handled.\n            unchecked {\n                records[tokenOut].reserve -= amountOut;\n            }\n            _transfer(tokenOut, amountOut, recipient, unwrapBento);\n            withdrawnAmounts[i] = TokenAmount({token: tokenOut, amount: amountOut});\n            emit Burn(msg.sender, tokenOut, amountOut, recipient);\n        }\n    }\n\n    /// @dev Burns LP tokens sent to this contract and swaps one of the output tokens for another\n    /// - i.e., the user gets a single token out by burning LP tokens.\n    function burnSingle(bytes calldata data) public override lock returns (uint256 amountOut) {\n        (address tokenOut, address recipient, bool unwrapBento, uint256 toBurn) = abi.decode(data, (address, address, bool, uint256));\n\n        Record storage outRecord = records[tokenOut];\n\n        amountOut = _computeSingleOutGivenPoolIn(outRecord.reserve, outRecord.weight, totalSupply, totalWeight, toBurn, swapFee);\n\n        require(amountOut <= _mul(outRecord.reserve, MAX_OUT_RATIO), \"MAX_OUT_RATIO\");\n        // @dev This is safe from underflow - only logged amounts handled.\n        unchecked {\n            outRecord.reserve -= uint120(amountOut);\n        }\n        _burn(address(this), toBurn);\n        _transfer(tokenOut, amountOut, recipient, unwrapBento);\n        emit Burn(msg.sender, tokenOut, amountOut, recipient);\n    }\n\n    /// @dev Swaps one token for another. The router must prefund this contract and ensure there isn't too much slippage.\n    function swap(bytes calldata data) public override lock returns (uint256 amountOut) {\n        (address tokenIn, address tokenOut, address recipient, bool unwrapBento, uint256 amountIn) = abi.decode(\n            data,\n            (address, address, address, bool, uint256)\n        );\n\n        Record storage inRecord = records[tokenIn];\n        Record storage outRecord = records[tokenOut];\n\n        require(amountIn <= _mul(inRecord.reserve, MAX_IN_RATIO), \"MAX_IN_RATIO\");\n\n        amountOut = _getAmountOut(amountIn, inRecord.reserve, inRecord.weight, outRecord.reserve, outRecord.weight);\n        // @dev Check Trident router has sent `amountIn` for skim into pool.\n        unchecked {\n            // @dev This is safe from under/overflow - only logged amounts handled.\n            require(_balance(tokenIn) >= amountIn + inRecord.reserve, \"NOT_RECEIVED\");\n            inRecord.reserve += uint120(amountIn);\n            outRecord.reserve -= uint120(amountOut);\n        }\n        _transfer(tokenOut, amountOut, recipient, unwrapBento);\n        emit Swap(recipient, tokenIn, tokenOut, amountIn, amountOut);\n    }\n\n    /// @dev Swaps one token for another. The router must support swap callbacks and ensure there isn't too much slippage.\n    function flashSwap(bytes calldata data) public override lock returns (uint256 amountOut) {\n        (address tokenIn, address tokenOut, address recipient, bool unwrapBento, uint256 amountIn, bytes memory context) = abi.decode(\n            data,\n            (address, address, address, bool, uint256, bytes)\n        );\n\n        Record storage inRecord = records[tokenIn];\n        Record storage outRecord = records[tokenOut];\n\n        require(amountIn <= _mul(inRecord.reserve, MAX_IN_RATIO), \"MAX_IN_RATIO\");\n\n        amountOut = _getAmountOut(amountIn, inRecord.reserve, inRecord.weight, outRecord.reserve, outRecord.weight);\n\n        ITridentCallee(msg.sender).tridentSwapCallback(context);\n        // @dev Check Trident router has sent `amountIn` for skim into pool.\n        unchecked {\n            // @dev This is safe from under/overflow - only logged amounts handled.\n            require(_balance(tokenIn) >= amountIn + inRecord.reserve, \"NOT_RECEIVED\");\n            inRecord.reserve += uint120(amountIn);\n            outRecord.reserve -= uint120(amountOut);\n        }\n        _transfer(tokenOut, amountOut, recipient, unwrapBento);\n        emit Swap(recipient, tokenIn, tokenOut, amountIn, amountOut);\n    }\n\n    /// @dev Updates `barFee` for Trident protocol.\n    function updateBarFee() public {\n        barFee = IMasterDeployer(masterDeployer).barFee();\n    }\n\n    function _balance(address token) internal view returns (uint256 balance) {\n        balance = bento.balanceOf(token, address(this));\n    }\n\n    function _getAmountOut(\n        uint256 tokenInAmount,\n        uint256 tokenInBalance,\n        uint256 tokenInWeight,\n        uint256 tokenOutBalance,\n        uint256 tokenOutWeight\n    ) internal view returns (uint256 amountOut) {\n        uint256 weightRatio = _div(tokenInWeight, tokenOutWeight);\n        // @dev This is safe from under/overflow - only logged amounts handled.\n        unchecked {\n            uint256 adjustedIn = _mul(tokenInAmount, (BASE - swapFee));\n            uint256 a = _div(tokenInBalance, tokenInBalance + adjustedIn);\n            uint256 b = _compute(a, weightRatio);\n            uint256 c = BASE - b;\n            amountOut = _mul(tokenOutBalance, c);\n        }\n    }\n\n    function _compute(uint256 base, uint256 exp) internal pure returns (uint256 output) {\n        require(MIN_POW_BASE <= base && base <= MAX_POW_BASE, \"INVALID_BASE\");\n\n        uint256 whole = (exp / BASE) * BASE;\n        uint256 remain = exp - whole;\n        uint256 wholePow = _pow(base, whole / BASE);\n\n        if (remain == 0) output = wholePow;\n\n        uint256 partialResult = _powApprox(base, remain, POW_PRECISION);\n        output = _mul(wholePow, partialResult);\n    }\n\n    function _computeSingleOutGivenPoolIn(\n        uint256 tokenOutBalance,\n        uint256 tokenOutWeight,\n        uint256 _totalSupply,\n        uint256 _totalWeight,\n        uint256 toBurn,\n        uint256 _swapFee\n    ) internal pure returns (uint256 amountOut) {\n        uint256 normalizedWeight = _div(tokenOutWeight, _totalWeight);\n        uint256 newPoolSupply = _totalSupply - toBurn;\n        uint256 poolRatio = _div(newPoolSupply, _totalSupply);\n        uint256 tokenOutRatio = _pow(poolRatio, _div(BASE, normalizedWeight));\n        uint256 newBalanceOut = _mul(tokenOutRatio, tokenOutBalance);\n        uint256 tokenAmountOutBeforeSwapFee = tokenOutBalance - newBalanceOut;\n        uint256 zaz = (BASE - normalizedWeight) * _swapFee;\n        amountOut = _mul(tokenAmountOutBeforeSwapFee, (BASE - zaz));\n    }\n\n    function _pow(uint256 a, uint256 n) internal pure returns (uint256 output) {\n        output = n % 2 != 0 ? a : BASE;\n        for (n /= 2; n != 0; n /= 2) a = a * a;\n        if (n % 2 != 0) output = output * a;\n    }\n\n    function _powApprox(\n        uint256 base,\n        uint256 exp,\n        uint256 precision\n    ) internal pure returns (uint256 sum) {\n        uint256 a = exp;\n        (uint256 x, bool xneg) = _subFlag(base, BASE);\n        uint256 term = BASE;\n        sum = term;\n        bool negative;\n\n        for (uint256 i = 1; term >= precision; i++) {\n            uint256 bigK = i * BASE;\n            (uint256 c, bool cneg) = _subFlag(a, (bigK - BASE));\n            term = _mul(term, _mul(c, x));\n            term = _div(term, bigK);\n            if (term == 0) break;\n            if (xneg) negative = !negative;\n            if (cneg) negative = !negative;\n            if (negative) {\n                sum = sum - term;\n            } else {\n                sum = sum + term;\n            }\n        }\n    }\n\n    function _subFlag(uint256 a, uint256 b) internal pure returns (uint256 difference, bool flag) {\n        // @dev This is safe from underflow - if/else flow performs checks.\n        unchecked {\n            if (a >= b) {\n                (difference, flag) = (a - b, false);\n            } else {\n                (difference, flag) = (b - a, true);\n            }\n        }\n    }\n\n    function _mul(uint256 a, uint256 b) internal pure returns (uint256 c2) {\n        uint256 c0 = a * b;\n        uint256 c1 = c0 + (BASE / 2);\n        c2 = c1 / BASE;\n    }\n\n    function _div(uint256 a, uint256 b) internal pure returns (uint256 c2) {\n        uint256 c0 = a * BASE;\n        uint256 c1 = c0 + (b / 2);\n        c2 = c1 / b;\n    }\n\n    function _transfer(\n        address token,\n        uint256 shares,\n        address to,\n        bool unwrapBento\n    ) internal {\n        if (unwrapBento) {\n            bento.withdraw(token, address(this), to, 0, shares);\n        } else {\n            bento.transfer(token, address(this), to, shares);\n        }\n    }\n\n    function getAssets() public view override returns (address[] memory assets) {\n        assets = tokens;\n    }\n\n    function getAmountOut(bytes calldata data) public view override returns (uint256 amountOut) {\n        (uint256 tokenInAmount, uint256 tokenInBalance, uint256 tokenInWeight, uint256 tokenOutBalance, uint256 tokenOutWeight) = abi\n            .decode(data, (uint256, uint256, uint256, uint256, uint256));\n        amountOut = _getAmountOut(tokenInAmount, tokenInBalance, tokenInWeight, tokenOutBalance, tokenOutWeight);\n    }\n\n    function getAmountIn(bytes calldata) public pure override returns (uint256) {\n        revert();\n    }\n\n    function getReservesAndWeights() public view returns (uint256[] memory reserves, uint136[] memory weights) {\n        uint256 length = tokens.length;\n        reserves = new uint256[](length);\n        weights = new uint136[](length);\n        // @dev This is safe from overflow - `tokens` `length` is bound to '8'.\n        unchecked {\n            for (uint256 i = 0; i < length; i++) {\n                reserves[i] = records[tokens[i]].reserve;\n                weights[i] = records[tokens[i]].weight;\n            }\n        }\n    }\n}\n"
    },
    "contracts/pool/TridentERC20.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\n/// @notice Trident pool ERC-20 with EIP-2612 extension.\n/// @author Adapted from RariCapital, https://github.com/Rari-Capital/solmate/blob/main/src/erc20/ERC20.sol,\n/// License-Identifier: AGPL-3.0-only.\nabstract contract TridentERC20 {\n    event Transfer(address indexed sender, address indexed recipient, uint256 amount);\n    event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n    string public constant name = \"Sushi LP Token\";\n    string public constant symbol = \"SLP\";\n    uint8 public constant decimals = 18;\n\n    uint256 public totalSupply;\n    /// @notice owner -> balance mapping.\n    mapping(address => uint256) public balanceOf;\n    /// @notice owner -> spender -> allowance mapping.\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    /// @notice Chain Id at this contract's deployment.\n    uint256 internal immutable DOMAIN_SEPARATOR_CHAIN_ID;\n    /// @notice EIP-712 typehash for this contract's domain at deployment.\n    bytes32 internal immutable _DOMAIN_SEPARATOR;\n    /// @notice EIP-712 typehash for this contract's {permit} struct.\n    bytes32 public constant PERMIT_TYPEHASH =\n        keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n    /// @notice owner -> nonce mapping used in {permit}.\n    mapping(address => uint256) public nonces;\n\n    constructor() {\n        DOMAIN_SEPARATOR_CHAIN_ID = block.chainid;\n        _DOMAIN_SEPARATOR = _calculateDomainSeparator();\n    }\n\n    function _calculateDomainSeparator() internal view returns (bytes32 domainSeperator) {\n        domainSeperator = keccak256(\n            abi.encode(\n                keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n                keccak256(bytes(name)),\n                keccak256(bytes(\"1\")),\n                block.chainid,\n                address(this)\n            )\n        );\n    }\n\n    /// @notice EIP-712 typehash for this contract's domain.\n    function DOMAIN_SEPARATOR() public view returns (bytes32 domainSeperator) {\n        domainSeperator = block.chainid == DOMAIN_SEPARATOR_CHAIN_ID ? _DOMAIN_SEPARATOR : _calculateDomainSeparator();\n    }\n\n    /// @notice Approves `amount` from `msg.sender` to be spent by `spender`.\n    /// @param spender Address of the party that can pull tokens from `msg.sender`'s account.\n    /// @param amount The maximum collective `amount` that `spender` can pull.\n    /// @return (bool) Returns 'true' if succeeded.\n    function approve(address spender, uint256 amount) external returns (bool) {\n        allowance[msg.sender][spender] = amount;\n        emit Approval(msg.sender, spender, amount);\n        return true;\n    }\n\n    /// @notice Transfers `amount` tokens from `msg.sender` to `recipient`.\n    /// @param recipient The address to move tokens to.\n    /// @param amount The token `amount` to move.\n    /// @return (bool) Returns 'true' if succeeded.\n    function transfer(address recipient, uint256 amount) external returns (bool) {\n        balanceOf[msg.sender] -= amount;\n        // @dev This is safe from overflow - the sum of all user\n        // balances can't exceed 'type(uint256).max'.\n        unchecked {\n            balanceOf[recipient] += amount;\n        }\n        emit Transfer(msg.sender, recipient, amount);\n        return true;\n    }\n\n    /// @notice Transfers `amount` tokens from `sender` to `recipient`. Caller needs approval from `from`.\n    /// @param sender Address to pull tokens `from`.\n    /// @param recipient The address to move tokens to.\n    /// @param amount The token `amount` to move.\n    /// @return (bool) Returns 'true' if succeeded.\n    function transferFrom(\n        address sender,\n        address recipient,\n        uint256 amount\n    ) external returns (bool) {\n        if (allowance[sender][msg.sender] != type(uint256).max) {\n            allowance[sender][msg.sender] -= amount;\n        }\n        balanceOf[sender] -= amount;\n        // @dev This is safe from overflow - the sum of all user\n        // balances can't exceed 'type(uint256).max'.\n        unchecked {\n            balanceOf[recipient] += amount;\n        }\n        emit Transfer(sender, recipient, amount);\n        return true;\n    }\n\n    /// @notice Triggers an approval from `owner` to `spender`.\n    /// @param owner The address to approve from.\n    /// @param spender The address to be approved.\n    /// @param amount The number of tokens that are approved (2^256-1 means infinite).\n    /// @param deadline The time at which to expire the signature.\n    /// @param v The recovery byte of the signature.\n    /// @param r Half of the ECDSA signature pair.\n    /// @param s Half of the ECDSA signature pair.\n    function permit(\n        address owner,\n        address spender,\n        uint256 amount,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external {\n        require(deadline >= block.timestamp, \"PERMIT_DEADLINE_EXPIRED\");\n        bytes32 digest = keccak256(\n            abi.encodePacked(\n                \"\\x19\\x01\",\n                DOMAIN_SEPARATOR(),\n                keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, amount, nonces[owner]++, deadline))\n            )\n        );\n        address recoveredAddress = ecrecover(digest, v, r, s);\n        require(recoveredAddress != address(0) && recoveredAddress == owner, \"INVALID_PERMIT_SIGNATURE\");\n        allowance[recoveredAddress][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    function _mint(address recipient, uint256 amount) internal {\n        totalSupply += amount;\n        // @dev This is safe from overflow - the sum of all user\n        // balances can't exceed 'type(uint256).max'.\n        unchecked {\n            balanceOf[recipient] += amount;\n        }\n        emit Transfer(address(0), recipient, amount);\n    }\n\n    function _burn(address sender, uint256 amount) internal {\n        balanceOf[sender] -= amount;\n        // @dev This is safe from underflow - users won't ever\n        // have a balance larger than `totalSupply`.\n        unchecked {\n            totalSupply -= amount;\n        }\n        emit Transfer(sender, address(0), amount);\n    }\n}\n"
    },
    "contracts/pool/HybridPool.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"../interfaces/IBentoBoxMinimal.sol\";\nimport \"../interfaces/IMasterDeployer.sol\";\nimport \"../interfaces/IPool.sol\";\nimport \"../interfaces/ITridentCallee.sol\";\nimport \"../libraries/MathUtils.sol\";\nimport \"./TridentERC20.sol\";\nimport \"../libraries/RebaseLibrary.sol\";\n\n/// @notice Trident exchange pool template with hybrid like-kind formula for swapping between an ERC-20 token pair.\n/// @dev The reserves are stored as bento shares. However, the stableswap invariant is applied to the underlying amounts.\n///      The API uses the underlying amounts.\ncontract HybridPool is IPool, TridentERC20 {\n    using MathUtils for uint256;\n    using RebaseLibrary for Rebase;\n\n    event Mint(address indexed sender, uint256 amount0, uint256 amount1, address indexed recipient, uint256 liquidity);\n    event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed recipient, uint256 liquidity);\n    event Sync(uint256 reserve0, uint256 reserve1);\n\n    uint256 internal constant MINIMUM_LIQUIDITY = 10**3;\n    uint8 internal constant PRECISION = 112;\n\n    /// @dev Constant value used as max loop limit.\n    uint256 private constant MAX_LOOP_LIMIT = 256;\n    uint256 internal constant MAX_FEE = 10000; // @dev 100%.\n    uint256 public immutable swapFee;\n\n    IBentoBoxMinimal public immutable bento;\n    IMasterDeployer public immutable masterDeployer;\n    address public immutable barFeeTo;\n    address public immutable token0;\n    address public immutable token1;\n    uint256 public immutable A;\n    uint256 internal immutable N_A; // @dev 2 * A.\n    uint256 internal constant A_PRECISION = 100;\n\n    /// @dev Multipliers for each pooled token's precision to get to POOL_PRECISION_DECIMALS.\n    /// For example, TBTC has 18 decimals, so the multiplier should be 1. WBTC\n    /// has 8, so the multiplier should be 10 ** 18 / 10 ** 8 => 10 ** 10.\n    uint256 public immutable token0PrecisionMultiplier;\n    uint256 public immutable token1PrecisionMultiplier;\n\n    uint256 public barFee;\n\n    uint128 internal reserve0;\n    uint128 internal reserve1;\n    uint256 internal dLast;\n\n    bytes32 public constant override poolIdentifier = \"Trident:HybridPool\";\n\n    uint256 internal unlocked;\n    modifier lock() {\n        require(unlocked == 1, \"LOCKED\");\n        unlocked = 2;\n        _;\n        unlocked = 1;\n    }\n\n    constructor(bytes memory _deployData, address _masterDeployer) {\n        (address _token0, address _token1, uint256 _swapFee, uint256 a) = abi.decode(_deployData, (address, address, uint256, uint256));\n\n        // @dev Factory ensures that the tokens are sorted.\n        require(_token0 != address(0), \"ZERO_ADDRESS\");\n        require(_token0 != _token1, \"IDENTICAL_ADDRESSES\");\n        require(_swapFee <= MAX_FEE, \"INVALID_SWAP_FEE\");\n        require(a != 0, \"ZERO_A\");\n\n        token0 = _token0;\n        token1 = _token1;\n        swapFee = _swapFee;\n        barFee = IMasterDeployer(_masterDeployer).barFee();\n        barFeeTo = IMasterDeployer(_masterDeployer).barFeeTo();\n        bento = IBentoBoxMinimal(IMasterDeployer(_masterDeployer).bento());\n        masterDeployer = IMasterDeployer(_masterDeployer);\n        A = a;\n        N_A = 2 * a;\n        token0PrecisionMultiplier = uint256(10)**(decimals - TridentERC20(_token0).decimals());\n        token1PrecisionMultiplier = uint256(10)**(decimals - TridentERC20(_token1).decimals());\n        unlocked = 1;\n    }\n\n    /// @dev Mints LP tokens - should be called via the router after transferring `bento` tokens.\n    /// The router must ensure that sufficient LP tokens are minted by using the return value.\n    function mint(bytes calldata data) public override lock returns (uint256 liquidity) {\n        address recipient = abi.decode(data, (address));\n        (uint256 _reserve0, uint256 _reserve1) = _getReserves();\n        (uint256 balance0, uint256 balance1) = _balance();\n\n        uint256 newLiq = _computeLiquidity(balance0, balance1);\n        uint256 amount0 = balance0 - _reserve0;\n        uint256 amount1 = balance1 - _reserve1;\n        (uint256 fee0, uint256 fee1) = _nonOptimalMintFee(amount0, amount1, _reserve0, _reserve1);\n        _reserve0 += uint112(fee0);\n        _reserve1 += uint112(fee1);\n\n        (uint256 _totalSupply, uint256 oldLiq) = _mintFee(_reserve0, _reserve1);\n\n        if (_totalSupply == 0) {\n            require(amount0 > 0 && amount1 > 0, \"INVALID_AMOUNTS\");\n            liquidity = newLiq - MINIMUM_LIQUIDITY;\n            _mint(address(0), MINIMUM_LIQUIDITY);\n        } else {\n            liquidity = ((newLiq - oldLiq) * _totalSupply) / oldLiq;\n        }\n        require(liquidity != 0, \"INSUFFICIENT_LIQUIDITY_MINTED\");\n        _mint(recipient, liquidity);\n        _updateReserves();\n\n        dLast = newLiq;\n        uint256 liquidityForEvent = liquidity;\n        emit Mint(msg.sender, amount0, amount1, recipient, liquidityForEvent);\n    }\n\n    /// @dev Burns LP tokens sent to this contract. The router must ensure that the user gets sufficient output tokens.\n    function burn(bytes calldata data) public override lock returns (IPool.TokenAmount[] memory withdrawnAmounts) {\n        (address recipient, bool unwrapBento) = abi.decode(data, (address, bool));\n        (uint256 balance0, uint256 balance1) = _balance();\n        uint256 liquidity = balanceOf[address(this)];\n\n        (uint256 _totalSupply, ) = _mintFee(balance0, balance1);\n\n        uint256 amount0 = (liquidity * balance0) / _totalSupply;\n        uint256 amount1 = (liquidity * balance1) / _totalSupply;\n\n        _burn(address(this), liquidity);\n        _transfer(token0, amount0, recipient, unwrapBento);\n        _transfer(token1, amount1, recipient, unwrapBento);\n\n        _updateReserves();\n\n        withdrawnAmounts = new TokenAmount[](2);\n        withdrawnAmounts[0] = TokenAmount({token: token0, amount: amount0});\n        withdrawnAmounts[1] = TokenAmount({token: token1, amount: amount1});\n\n        dLast = _computeLiquidity(balance0 - amount0, balance1 - amount1);\n\n        emit Burn(msg.sender, amount0, amount1, recipient, liquidity);\n    }\n\n    /// @dev Burns LP tokens sent to this contract and swaps one of the output tokens for another\n    /// - i.e., the user gets a single token out by burning LP tokens.\n    function burnSingle(bytes calldata data) public override lock returns (uint256 amountOut) {\n        (address tokenOut, address recipient, bool unwrapBento) = abi.decode(data, (address, address, bool));\n        (uint256 balance0, uint256 balance1) = _balance();\n        uint256 liquidity = balanceOf[address(this)];\n\n        (uint256 _totalSupply, ) = _mintFee(balance0, balance1);\n\n        uint256 amount0 = (liquidity * balance0) / _totalSupply;\n        uint256 amount1 = (liquidity * balance1) / _totalSupply;\n\n        _burn(address(this), liquidity);\n        dLast = _computeLiquidity(balance0 - amount0, balance1 - amount1);\n\n        // Swap tokens\n        if (tokenOut == token1) {\n            // @dev Swap `token0` for `token1`.\n            // @dev Calculate `amountOut` as if the user first withdrew balanced liquidity and then swapped `token0` for `token1`.\n            amount1 += _getAmountOut(amount0, balance0 - amount0, balance1 - amount1, true);\n            _transfer(token1, amount1, recipient, unwrapBento);\n            amountOut = amount1;\n            amount0 = 0;\n        } else {\n            // @dev Swap `token1` for `token0`.\n            require(tokenOut == token0, \"INVALID_OUTPUT_TOKEN\");\n            amount0 += _getAmountOut(amount1, balance0 - amount0, balance1 - amount1, false);\n            _transfer(token0, amount0, recipient, unwrapBento);\n            amountOut = amount0;\n            amount1 = 0;\n        }\n        _updateReserves();\n        emit Burn(msg.sender, amount0, amount1, recipient, liquidity);\n    }\n\n    /// @dev Swaps one token for another. The router must prefund this contract and ensure there isn't too much slippage.\n    function swap(bytes calldata data) public override lock returns (uint256 amountOut) {\n        (address tokenIn, address recipient, bool unwrapBento) = abi.decode(data, (address, address, bool));\n        (uint256 _reserve0, uint256 _reserve1, uint256 balance0, uint256 balance1) = _getReservesAndBalances();\n        uint256 amountIn;\n        address tokenOut;\n\n        if (tokenIn == token0) {\n            tokenOut = token1;\n            unchecked {\n                amountIn = balance0 - _reserve0;\n            }\n            amountOut = _getAmountOut(amountIn, _reserve0, _reserve1, true);\n        } else {\n            require(tokenIn == token1, \"INVALID_INPUT_TOKEN\");\n            tokenOut = token0;\n            unchecked {\n                amountIn = balance1 - _reserve1;\n            }\n            amountOut = _getAmountOut(amountIn, _reserve0, _reserve1, false);\n        }\n        _transfer(tokenOut, amountOut, recipient, unwrapBento);\n        _updateReserves();\n        emit Swap(recipient, tokenIn, tokenOut, amountIn, amountOut);\n    }\n\n    /// @dev Swaps one token for another with payload. The router must support swap callbacks and ensure there isn't too much slippage.\n    function flashSwap(bytes calldata data) public override lock returns (uint256 amountOut) {\n        (address tokenIn, address recipient, bool unwrapBento, uint256 amountIn, bytes memory context) = abi.decode(\n            data,\n            (address, address, bool, uint256, bytes)\n        );\n        (uint256 _reserve0, uint256 _reserve1) = _getReserves();\n        address tokenOut;\n\n        if (tokenIn == token0) {\n            tokenOut = token1;\n            amountIn = bento.toAmount(token0, amountIn, false);\n            amountOut = _getAmountOut(amountIn, _reserve0, _reserve1, true);\n            _processSwap(token1, recipient, amountOut, context, unwrapBento);\n            uint256 balance0 = bento.toAmount(token0, bento.balanceOf(token0, address(this)), false);\n            require(balance0 - _reserve0 >= amountIn, \"INSUFFICIENT_AMOUNT_IN\");\n        } else {\n            require(tokenIn == token1, \"INVALID_INPUT_TOKEN\");\n            tokenOut = token0;\n            amountIn = bento.toAmount(token1, amountIn, false);\n            amountOut = _getAmountOut(amountIn, _reserve0, _reserve1, false);\n            _processSwap(token0, recipient, amountOut, context, unwrapBento);\n            uint256 balance1 = bento.toAmount(token1, bento.balanceOf(token1, address(this)), false);\n            require(balance1 - _reserve1 >= amountIn, \"INSUFFICIENT_AMOUNT_IN\");\n        }\n        _updateReserves();\n        emit Swap(recipient, tokenIn, tokenOut, amountIn, amountOut);\n    }\n\n    /// @dev Updates `barFee` for Trident protocol.\n    function updateBarFee() public {\n        barFee = masterDeployer.barFee();\n    }\n\n    function _processSwap(\n        address tokenOut,\n        address to,\n        uint256 amountOut,\n        bytes memory data,\n        bool unwrapBento\n    ) internal {\n        _transfer(tokenOut, amountOut, to, unwrapBento);\n        if (data.length != 0) ITridentCallee(msg.sender).tridentSwapCallback(data);\n    }\n\n    function _getReserves() internal view returns (uint256 _reserve0, uint256 _reserve1) {\n        (_reserve0, _reserve1) = (reserve0, reserve1);\n        _reserve0 = bento.toAmount(token0, _reserve0, false);\n        _reserve1 = bento.toAmount(token1, _reserve1, false);\n    }\n\n    function _getReservesAndBalances()\n        internal\n        view\n        returns (\n            uint256 _reserve0,\n            uint256 _reserve1,\n            uint256 balance0,\n            uint256 balance1\n        )\n    {\n        (_reserve0, _reserve1) = (reserve0, reserve1);\n        balance0 = bento.balanceOf(token0, address(this));\n        balance1 = bento.balanceOf(token1, address(this));\n        Rebase memory total0 = bento.totals(token0);\n        Rebase memory total1 = bento.totals(token1);\n\n        _reserve0 = total0.toElastic(_reserve0);\n        _reserve1 = total1.toElastic(_reserve1);\n        balance0 = total0.toElastic(balance0);\n        balance1 = total1.toElastic(balance1);\n    }\n\n    function _updateReserves() internal {\n        (uint256 _reserve0, uint256 _reserve1) = _balance();\n        require(_reserve0 < type(uint128).max && _reserve1 < type(uint128).max, \"OVERFLOW\");\n        reserve0 = uint128(_reserve0);\n        reserve1 = uint128(_reserve1);\n        emit Sync(_reserve0, _reserve1);\n    }\n\n    function _balance() internal view returns (uint256 balance0, uint256 balance1) {\n        balance0 = bento.toAmount(token0, bento.balanceOf(token0, address(this)), false);\n        balance1 = bento.toAmount(token1, bento.balanceOf(token1, address(this)), false);\n    }\n\n    function _getAmountOut(\n        uint256 amountIn,\n        uint256 _reserve0,\n        uint256 _reserve1,\n        bool token0In\n    ) internal view returns (uint256 dy) {\n        unchecked {\n            uint256 adjustedReserve0 = _reserve0 * token0PrecisionMultiplier;\n            uint256 adjustedReserve1 = _reserve1 * token1PrecisionMultiplier;\n            uint256 feeDeductedAmountIn = amountIn - (amountIn * swapFee) / MAX_FEE;\n            uint256 d = _computeLiquidityFromAdjustedBalances(adjustedReserve0, adjustedReserve1);\n\n            if (token0In) {\n                uint256 x = adjustedReserve0 + (feeDeductedAmountIn * token0PrecisionMultiplier);\n                uint256 y = _getY(x, d);\n                dy = adjustedReserve1 - y - 1;\n                dy /= token1PrecisionMultiplier;\n            } else {\n                uint256 x = adjustedReserve1 + (feeDeductedAmountIn * token1PrecisionMultiplier);\n                uint256 y = _getY(x, d);\n                dy = adjustedReserve0 - y - 1;\n                dy /= token0PrecisionMultiplier;\n            }\n        }\n    }\n\n    function _transfer(\n        address token,\n        uint256 amount,\n        address to,\n        bool unwrapBento\n    ) internal {\n        if (unwrapBento) {\n            bento.withdraw(token, address(this), to, amount, 0);\n        } else {\n            bento.transfer(token, address(this), to, bento.toShare(token, amount, false));\n        }\n    }\n\n    /// @notice Get D, the StableSwap invariant, based on a set of balances and a particular A.\n    /// See the StableSwap paper for details.\n    /// @dev Originally https://github.com/saddle-finance/saddle-contract/blob/0b76f7fb519e34b878aa1d58cffc8d8dc0572c12/contracts/SwapUtils.sol#L319.\n    /// @return liquidity The invariant, at the precision of the pool.\n    function _computeLiquidity(uint256 _reserve0, uint256 _reserve1) internal view returns (uint256 liquidity) {\n        unchecked {\n            uint256 adjustedReserve0 = _reserve0 * token0PrecisionMultiplier;\n            uint256 adjustedReserve1 = _reserve1 * token1PrecisionMultiplier;\n            liquidity = _computeLiquidityFromAdjustedBalances(adjustedReserve0, adjustedReserve1);\n        }\n    }\n\n    function _computeLiquidityFromAdjustedBalances(uint256 xp0, uint256 xp1) internal view returns (uint256 computed) {\n        uint256 s = xp0 + xp1;\n\n        if (s == 0) {\n            computed = 0;\n        }\n        uint256 prevD;\n        uint256 D = s;\n        for (uint256 i = 0; i < MAX_LOOP_LIMIT; i++) {\n            uint256 dP = (((D * D) / xp0) * D) / xp1 / 4;\n            prevD = D;\n            D = (((N_A * s) / A_PRECISION + 2 * dP) * D) / ((N_A / A_PRECISION - 1) * D + 3 * dP);\n            if (D.within1(prevD)) {\n                break;\n            }\n        }\n        computed = D;\n    }\n\n    /// @notice Calculate the new balances of the tokens given the indexes of the token\n    /// that is swapped from (FROM) and the token that is swapped to (TO).\n    /// This function is used as a helper function to calculate how much TO token\n    /// the user should receive on swap.\n    /// @dev Originally https://github.com/saddle-finance/saddle-contract/blob/0b76f7fb519e34b878aa1d58cffc8d8dc0572c12/contracts/SwapUtils.sol#L432.\n    /// @param x The new total amount of FROM token.\n    /// @return y The amount of TO token that should remain in the pool.\n    function _getY(uint256 x, uint256 D) internal view returns (uint256 y) {\n        uint256 c = (D * D) / (x * 2);\n        c = (c * D) / ((N_A * 2) / A_PRECISION);\n        uint256 b = x + ((D * A_PRECISION) / N_A);\n        uint256 yPrev;\n        y = D;\n        // @dev Iterative approximation.\n        for (uint256 i = 0; i < MAX_LOOP_LIMIT; i++) {\n            yPrev = y;\n            y = (y * y + c) / (y * 2 + b - D);\n            if (y.within1(yPrev)) {\n                break;\n            }\n        }\n    }\n\n    function _mintFee(uint256 _reserve0, uint256 _reserve1) internal returns (uint256 _totalSupply, uint256 d) {\n        _totalSupply = totalSupply;\n        uint256 _dLast = dLast;\n        if (_dLast != 0) {\n            d = _computeLiquidity(_reserve0, _reserve1);\n            if (d > _dLast) {\n                // @dev `barFee` % of increase in liquidity.\n                // It's going to be slightly less than `barFee` % in reality due to the math.\n                uint256 liquidity = (_totalSupply * (d - _dLast) * barFee) / d / MAX_FEE;\n                if (liquidity != 0) {\n                    _mint(barFeeTo, liquidity);\n                    _totalSupply += liquidity;\n                }\n            }\n        }\n    }\n\n    /// @dev This fee is charged to cover for `swapFee` when users add unbalanced liquidity.\n    function _nonOptimalMintFee(\n        uint256 _amount0,\n        uint256 _amount1,\n        uint256 _reserve0,\n        uint256 _reserve1\n    ) internal view returns (uint256 token0Fee, uint256 token1Fee) {\n        if (_reserve0 == 0 || _reserve1 == 0) return (0, 0);\n        uint256 amount1Optimal = (_amount0 * _reserve1) / _reserve0;\n\n        if (amount1Optimal <= _amount1) {\n            token1Fee = (swapFee * (_amount1 - amount1Optimal)) / (2 * MAX_FEE);\n        } else {\n            uint256 amount0Optimal = (_amount1 * _reserve0) / _reserve1;\n            token0Fee = (swapFee * (_amount0 - amount0Optimal)) / (2 * MAX_FEE);\n        }\n    }\n\n    function getAssets() public view override returns (address[] memory assets) {\n        assets = new address[](2);\n        assets[0] = token0;\n        assets[1] = token1;\n    }\n\n    function getAmountOut(bytes calldata data) public view override returns (uint256 finalAmountOut) {\n        (address tokenIn, uint256 amountIn) = abi.decode(data, (address, uint256));\n        (uint256 _reserve0, uint256 _reserve1) = _getReserves();\n        amountIn = bento.toAmount(tokenIn, amountIn, false);\n\n        if (tokenIn == token0) {\n            finalAmountOut = bento.toShare(token1, _getAmountOut(amountIn, _reserve0, _reserve1, true), false);\n        } else {\n            require(tokenIn == token1, \"INVALID_INPUT_TOKEN\");\n            finalAmountOut = bento.toShare(token0, _getAmountOut(amountIn, _reserve0, _reserve1, false), false);\n        }\n    }\n\n    function getAmountIn(bytes calldata) public pure override returns (uint256) {\n        revert();\n    }\n\n    function getReserves() public view returns (uint256 _reserve0, uint256 _reserve1) {\n        (_reserve0, _reserve1) = _getReserves();\n    }\n\n    function getVirtualPrice() public view returns (uint256 virtualPrice) {\n        (uint256 _reserve0, uint256 _reserve1) = _getReserves();\n        uint256 d = _computeLiquidity(_reserve0, _reserve1);\n        virtualPrice = (d * (uint256(10)**decimals)) / totalSupply;\n    }\n}\n"
    },
    "contracts/libraries/MathUtils.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\n/// @notice A library that contains functions for calculating differences between two uint256.\n/// @author Adapted from https://github.com/saddle-finance/saddle-contract/blob/master/contracts/MathUtils.sol.\nlibrary MathUtils {\n    /// @notice Compares a and b and returns 'true' if the difference between a and b\n    /// is less than 1 or equal to each other.\n    /// @param a uint256 to compare with.\n    /// @param b uint256 to compare with.\n    function within1(uint256 a, uint256 b) internal pure returns (bool) {\n        unchecked {\n            if (a > b) {\n                return a - b <= 1;\n            }\n            return b - a <= 1;\n        }\n    }\n}\n"
    },
    "contracts/pool/HybridPoolFactory.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"./HybridPool.sol\";\nimport \"./PoolDeployer.sol\";\n\n/// @notice Contract for deploying Trident exchange Hybrid Pool with configurations.\n/// @author Mudit Gupta.\ncontract HybridPoolFactory is PoolDeployer {\n    constructor(address _masterDeployer) PoolDeployer(_masterDeployer) {}\n\n    function deployPool(bytes memory _deployData) external returns (address pool) {\n        (address tokenA, address tokenB, uint256 swapFee, uint256 a) = abi.decode(_deployData, (address, address, uint256, uint256));\n\n        if (tokenA > tokenB) {\n            (tokenA, tokenB) = (tokenB, tokenA);\n        }\n\n        // @dev Strips any extra data.\n        _deployData = abi.encode(tokenA, tokenB, swapFee, a);\n        address[] memory tokens = new address[](2);\n        tokens[0] = tokenA;\n        tokens[1] = tokenB;\n\n        // @dev Salt is not actually needed since `_deployData` is part of creationCode and already contains the salt.\n        bytes32 salt = keccak256(_deployData);\n        pool = address(new HybridPool{salt: salt}(_deployData, masterDeployer));\n        _registerPool(pool, tokens, salt);\n    }\n}\n"
    },
    "contracts/pool/franchised/FranchisedIndexPool.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"../../interfaces/IBentoBoxMinimal.sol\";\nimport \"../../interfaces/IMasterDeployer.sol\";\nimport \"../../interfaces/IPool.sol\";\nimport \"../../interfaces/ITridentCallee.sol\";\nimport \"./TridentFranchisedERC20.sol\";\n\n/// @notice Trident exchange franchised pool template with constant mean formula for swapping among an array of ERC-20 tokens.\n/// @dev The reserves are stored as bento shares.\n///      The curve is applied to shares as well. This pool does not care about the underlying amounts.\ncontract FranchisedIndexPool is IPool, TridentFranchisedERC20 {\n    event Mint(address indexed sender, address tokenIn, uint256 amountIn, address indexed recipient);\n    event Burn(address indexed sender, address tokenOut, uint256 amountOut, address indexed recipient);\n\n    uint256 public immutable swapFee;\n\n    address public immutable barFeeTo;\n    address public immutable bento;\n    address public immutable masterDeployer;\n\n    uint256 internal constant BASE = 10**18;\n    uint256 internal constant MIN_TOKENS = 2;\n    uint256 internal constant MAX_TOKENS = 8;\n    uint256 internal constant MIN_FEE = BASE / 10**6;\n    uint256 internal constant MAX_FEE = BASE / 10;\n    uint256 internal constant MIN_WEIGHT = BASE;\n    uint256 internal constant MAX_WEIGHT = BASE * 50;\n    uint256 internal constant MAX_TOTAL_WEIGHT = BASE * 50;\n    uint256 internal constant MIN_BALANCE = BASE / 10**12;\n    uint256 internal constant INIT_POOL_SUPPLY = BASE * 100;\n    uint256 internal constant MIN_POW_BASE = 1;\n    uint256 internal constant MAX_POW_BASE = (2 * BASE) - 1;\n    uint256 internal constant POW_PRECISION = BASE / 10**10;\n    uint256 internal constant MAX_IN_RATIO = BASE / 2;\n    uint256 internal constant MAX_OUT_RATIO = (BASE / 3) + 1;\n\n    uint136 internal totalWeight;\n    address[] internal tokens;\n\n    uint256 public barFee;\n\n    bytes32 public constant override poolIdentifier = \"Trident:FranchisedIndex\";\n\n    uint256 internal unlocked;\n    modifier lock() {\n        require(unlocked == 1, \"LOCKED\");\n        unlocked = 2;\n        _;\n        unlocked = 1;\n    }\n\n    mapping(address => Record) public records;\n    struct Record {\n        uint120 reserve;\n        uint136 weight;\n    }\n\n    constructor(bytes memory _deployData, address _masterDeployer) {\n        (\n            address[] memory _tokens,\n            uint136[] memory _weights,\n            uint256 _swapFee,\n            address _whiteListManager,\n            address _operator,\n            bool _level2\n        ) = abi.decode(_deployData, (address[], uint136[], uint256, address, address, bool));\n        // @dev Factory ensures that the tokens are sorted.\n        require(_tokens.length == _weights.length, \"INVALID_ARRAYS\");\n        require(MIN_FEE <= _swapFee && _swapFee <= MAX_FEE, \"INVALID_SWAP_FEE\");\n        require(MIN_TOKENS <= _tokens.length && _tokens.length <= MAX_TOKENS, \"INVALID_TOKENS_LENGTH\");\n\n        TridentFranchisedERC20.initialize(_whiteListManager, _operator, _level2);\n\n        for (uint256 i = 0; i < _tokens.length; i++) {\n            require(_tokens[i] != address(0), \"ZERO_ADDRESS\");\n            require(MIN_WEIGHT <= _weights[i] && _weights[i] <= MAX_WEIGHT, \"INVALID_WEIGHT\");\n            records[_tokens[i]] = Record({reserve: 0, weight: _weights[i]});\n            tokens.push(_tokens[i]);\n            totalWeight += _weights[i];\n        }\n\n        require(totalWeight <= MAX_TOTAL_WEIGHT, \"MAX_TOTAL_WEIGHT\");\n        // @dev This burns initial LP supply.\n        _mint(address(0), INIT_POOL_SUPPLY);\n\n        (, bytes memory _barFee) = _masterDeployer.staticcall(abi.encodeWithSelector(IMasterDeployer.barFee.selector));\n        (, bytes memory _barFeeTo) = _masterDeployer.staticcall(abi.encodeWithSelector(IMasterDeployer.barFeeTo.selector));\n        (, bytes memory _bento) = _masterDeployer.staticcall(abi.encodeWithSelector(IMasterDeployer.bento.selector));\n\n        swapFee = _swapFee;\n        barFee = abi.decode(_barFee, (uint256));\n        barFeeTo = abi.decode(_barFeeTo, (address));\n        bento = abi.decode(_bento, (address));\n        masterDeployer = _masterDeployer;\n        unlocked = 1;\n    }\n\n    /// @dev Mints LP tokens - should be called via the router after transferring `bento` tokens.\n    /// The router must ensure that sufficient LP tokens are minted by using the return value.\n    function mint(bytes calldata data) public override lock returns (uint256 liquidity) {\n        (address recipient, uint256 toMint) = abi.decode(data, (address, uint256));\n        _checkWhiteList(recipient);\n        uint120 ratio = uint120(_div(toMint, totalSupply));\n\n        for (uint256 i = 0; i < tokens.length; i++) {\n            address tokenIn = tokens[i];\n            uint120 reserve = records[tokenIn].reserve;\n            // @dev If token balance is '0', initialize with `ratio`.\n            uint120 amountIn = reserve != 0 ? uint120(_mul(ratio, reserve)) : ratio;\n            require(amountIn >= MIN_BALANCE, \"MIN_BALANCE\");\n            // @dev Check Trident router has sent `amountIn` for skim into pool.\n            unchecked {\n                // @dev This is safe from overflow - only logged amounts handled.\n                require(_balance(tokenIn) >= amountIn + reserve, \"NOT_RECEIVED\");\n                records[tokenIn].reserve += amountIn;\n            }\n            emit Mint(msg.sender, tokenIn, amountIn, recipient);\n        }\n        _mint(recipient, toMint);\n        liquidity = toMint;\n    }\n\n    /// @dev Burns LP tokens sent to this contract. The router must ensure that the user gets sufficient output tokens.\n    function burn(bytes calldata data) public override lock returns (IPool.TokenAmount[] memory withdrawnAmounts) {\n        (address recipient, bool unwrapBento, uint256 toBurn) = abi.decode(data, (address, bool, uint256));\n        _checkWhiteList(recipient);\n        uint256 ratio = _div(toBurn, totalSupply);\n\n        withdrawnAmounts = new TokenAmount[](tokens.length);\n\n        _burn(address(this), toBurn);\n\n        for (uint256 i = 0; i < tokens.length; i++) {\n            address tokenOut = tokens[i];\n            uint256 balance = records[tokenOut].reserve;\n            uint120 amountOut = uint120(_mul(ratio, balance));\n            require(amountOut != 0, \"ZERO_OUT\");\n            // @dev This is safe from underflow - only logged amounts handled.\n            unchecked {\n                records[tokenOut].reserve -= amountOut;\n            }\n            _transfer(tokenOut, amountOut, recipient, unwrapBento);\n            withdrawnAmounts[i] = TokenAmount({token: tokenOut, amount: amountOut});\n            emit Burn(msg.sender, tokenOut, amountOut, recipient);\n        }\n    }\n\n    /// @dev Burns LP tokens sent to this contract and swaps one of the output tokens for another\n    /// - i.e., the user gets a single token out by burning LP tokens.\n    function burnSingle(bytes calldata data) public override lock returns (uint256 amountOut) {\n        (address tokenOut, address recipient, bool unwrapBento, uint256 toBurn) = abi.decode(data, (address, address, bool, uint256));\n        _checkWhiteList(recipient);\n        Record storage outRecord = records[tokenOut];\n\n        amountOut = _computeSingleOutGivenPoolIn(outRecord.reserve, outRecord.weight, totalSupply, totalWeight, toBurn, swapFee);\n\n        require(amountOut <= _mul(outRecord.reserve, MAX_OUT_RATIO), \"MAX_OUT_RATIO\");\n        // @dev This is safe from underflow - only logged amounts handled.\n        unchecked {\n            outRecord.reserve -= uint120(amountOut);\n        }\n        _burn(address(this), toBurn);\n        _transfer(tokenOut, amountOut, recipient, unwrapBento);\n        emit Burn(msg.sender, tokenOut, amountOut, recipient);\n    }\n\n    /// @dev Swaps one token for another. The router must prefund this contract and ensure there isn't too much slippage.\n    function swap(bytes calldata data) public override lock returns (uint256 amountOut) {\n        (address tokenIn, address tokenOut, address recipient, bool unwrapBento, uint256 amountIn) = abi.decode(\n            data,\n            (address, address, address, bool, uint256)\n        );\n        if (level2) _checkWhiteList(recipient);\n        Record storage inRecord = records[tokenIn];\n        Record storage outRecord = records[tokenOut];\n\n        require(amountIn <= _mul(inRecord.reserve, MAX_IN_RATIO), \"MAX_IN_RATIO\");\n\n        amountOut = _getAmountOut(amountIn, inRecord.reserve, inRecord.weight, outRecord.reserve, outRecord.weight);\n        // @dev Check Trident router has sent `amountIn` for skim into pool.\n        unchecked {\n            // @dev This is safe from under/overflow - only logged amounts handled.\n            require(_balance(tokenIn) >= amountIn + inRecord.reserve, \"NOT_RECEIVED\");\n            inRecord.reserve += uint120(amountIn);\n            outRecord.reserve -= uint120(amountOut);\n        }\n        _transfer(tokenOut, amountOut, recipient, unwrapBento);\n        emit Swap(recipient, tokenIn, tokenOut, amountIn, amountOut);\n    }\n\n    /// @dev Swaps one token for another. The router must support swap callbacks and ensure there isn't too much slippage.\n    function flashSwap(bytes calldata data) public override lock returns (uint256 amountOut) {\n        (address tokenIn, address tokenOut, address recipient, bool unwrapBento, uint256 amountIn, bytes memory context) = abi.decode(\n            data,\n            (address, address, address, bool, uint256, bytes)\n        );\n        if (level2) _checkWhiteList(recipient);\n        Record storage inRecord = records[tokenIn];\n        Record storage outRecord = records[tokenOut];\n\n        require(amountIn <= _mul(inRecord.reserve, MAX_IN_RATIO), \"MAX_IN_RATIO\");\n\n        amountOut = _getAmountOut(amountIn, inRecord.reserve, inRecord.weight, outRecord.reserve, outRecord.weight);\n\n        ITridentCallee(msg.sender).tridentSwapCallback(context);\n        // @dev Check Trident router has sent `amountIn` for skim into pool.\n        unchecked {\n            // @dev This is safe from under/overflow - only logged amounts handled.\n            require(_balance(tokenIn) >= amountIn + inRecord.reserve, \"NOT_RECEIVED\");\n            inRecord.reserve += uint120(amountIn);\n            outRecord.reserve -= uint120(amountOut);\n        }\n        _transfer(tokenOut, amountOut, recipient, unwrapBento);\n        emit Swap(recipient, tokenIn, tokenOut, amountIn, amountOut);\n    }\n\n    /// @dev Updates `barFee` for Trident protocol.\n    function updateBarFee() public {\n        (, bytes memory _barFee) = masterDeployer.staticcall(abi.encodeWithSelector(IMasterDeployer.barFee.selector));\n        barFee = abi.decode(_barFee, (uint256));\n    }\n\n    function _balance(address token) internal view returns (uint256 balance) {\n        (, bytes memory data) = bento.staticcall(abi.encodeWithSelector(IBentoBoxMinimal.balanceOf.selector, token, address(this)));\n        balance = abi.decode(data, (uint256));\n    }\n\n    function _getAmountOut(\n        uint256 tokenInAmount,\n        uint256 tokenInBalance,\n        uint256 tokenInWeight,\n        uint256 tokenOutBalance,\n        uint256 tokenOutWeight\n    ) internal view returns (uint256 amountOut) {\n        uint256 weightRatio = _div(tokenInWeight, tokenOutWeight);\n        // @dev This is safe from under/overflow - only logged amounts handled.\n        unchecked {\n            uint256 adjustedIn = _mul(tokenInAmount, (BASE - swapFee));\n            uint256 a = _div(tokenInBalance, tokenInBalance + adjustedIn);\n            uint256 b = _compute(a, weightRatio);\n            uint256 c = BASE - b;\n            amountOut = _mul(tokenOutBalance, c);\n        }\n    }\n\n    function _compute(uint256 base, uint256 exp) internal pure returns (uint256 output) {\n        require(MIN_POW_BASE <= base && base <= MAX_POW_BASE, \"INVALID_BASE\");\n\n        uint256 whole = (exp / BASE) * BASE;\n        uint256 remain = exp - whole;\n        uint256 wholePow = _pow(base, whole / BASE);\n\n        if (remain == 0) output = wholePow;\n\n        uint256 partialResult = _powApprox(base, remain, POW_PRECISION);\n        output = _mul(wholePow, partialResult);\n    }\n\n    function _computeSingleOutGivenPoolIn(\n        uint256 tokenOutBalance,\n        uint256 tokenOutWeight,\n        uint256 _totalSupply,\n        uint256 _totalWeight,\n        uint256 toBurn,\n        uint256 _swapFee\n    ) internal pure returns (uint256 amountOut) {\n        uint256 normalizedWeight = _div(tokenOutWeight, _totalWeight);\n        uint256 newPoolSupply = _totalSupply - toBurn;\n        uint256 poolRatio = _div(newPoolSupply, _totalSupply);\n        uint256 tokenOutRatio = _pow(poolRatio, _div(BASE, normalizedWeight));\n        uint256 newBalanceOut = _mul(tokenOutRatio, tokenOutBalance);\n        uint256 tokenAmountOutBeforeSwapFee = tokenOutBalance - newBalanceOut;\n        uint256 zaz = (BASE - normalizedWeight) * _swapFee;\n        amountOut = _mul(tokenAmountOutBeforeSwapFee, (BASE - zaz));\n    }\n\n    function _pow(uint256 a, uint256 n) internal pure returns (uint256 output) {\n        output = n % 2 != 0 ? a : BASE;\n        for (n /= 2; n != 0; n /= 2) a = a * a;\n        if (n % 2 != 0) output = output * a;\n    }\n\n    function _powApprox(\n        uint256 base,\n        uint256 exp,\n        uint256 precision\n    ) internal pure returns (uint256 sum) {\n        uint256 a = exp;\n        (uint256 x, bool xneg) = _subFlag(base, BASE);\n        uint256 term = BASE;\n        sum = term;\n        bool negative;\n\n        for (uint256 i = 1; term >= precision; i++) {\n            uint256 bigK = i * BASE;\n            (uint256 c, bool cneg) = _subFlag(a, (bigK - BASE));\n            term = _mul(term, _mul(c, x));\n            term = _div(term, bigK);\n            if (term == 0) break;\n            if (xneg) negative = !negative;\n            if (cneg) negative = !negative;\n            if (negative) {\n                sum = sum - term;\n            } else {\n                sum = sum + term;\n            }\n        }\n    }\n\n    function _subFlag(uint256 a, uint256 b) internal pure returns (uint256 difference, bool flag) {\n        // @dev This is safe from underflow - if/else flow performs checks.\n        unchecked {\n            if (a >= b) {\n                (difference, flag) = (a - b, false);\n            } else {\n                (difference, flag) = (b - a, true);\n            }\n        }\n    }\n\n    function _mul(uint256 a, uint256 b) internal pure returns (uint256 c2) {\n        uint256 c0 = a * b;\n        uint256 c1 = c0 + (BASE / 2);\n        c2 = c1 / BASE;\n    }\n\n    function _div(uint256 a, uint256 b) internal pure returns (uint256 c2) {\n        uint256 c0 = a * BASE;\n        uint256 c1 = c0 + (b / 2);\n        c2 = c1 / b;\n    }\n\n    function _transfer(\n        address token,\n        uint256 shares,\n        address to,\n        bool unwrapBento\n    ) internal {\n        if (unwrapBento) {\n            (bool success, ) = bento.call(abi.encodeWithSelector(IBentoBoxMinimal.withdraw.selector, token, address(this), to, 0, shares));\n            require(success, \"WITHDRAW_FAILED\");\n        } else {\n            (bool success, ) = bento.call(abi.encodeWithSelector(IBentoBoxMinimal.transfer.selector, token, address(this), to, shares));\n            require(success, \"TRANSFER_FAILED\");\n        }\n    }\n\n    function getAssets() public view override returns (address[] memory assets) {\n        assets = tokens;\n    }\n\n    function getAmountOut(bytes calldata data) public view override returns (uint256 amountOut) {\n        (uint256 tokenInAmount, uint256 tokenInBalance, uint256 tokenInWeight, uint256 tokenOutBalance, uint256 tokenOutWeight) = abi\n            .decode(data, (uint256, uint256, uint256, uint256, uint256));\n        amountOut = _getAmountOut(tokenInAmount, tokenInBalance, tokenInWeight, tokenOutBalance, tokenOutWeight);\n    }\n\n    function getAmountIn(bytes calldata) public pure override returns (uint256) {\n        revert();\n    }\n\n    function getReservesAndWeights() public view returns (uint256[] memory reserves, uint136[] memory weights) {\n        uint256 length = tokens.length;\n        reserves = new uint256[](length);\n        weights = new uint136[](length);\n        // @dev This is safe from overflow - `tokens` `length` is bound to '8'.\n        unchecked {\n            for (uint256 i = 0; i < length; i++) {\n                reserves[i] = records[tokens[i]].reserve;\n                weights[i] = records[tokens[i]].weight;\n            }\n        }\n    }\n}\n"
    },
    "contracts/pool/franchised/TridentFranchisedERC20.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"../../interfaces/IWhiteListManager.sol\";\n\n/// @notice Trident franchised pool ERC-20 with EIP-2612 extension.\n/// @author Adapted from RariCapital, https://github.com/Rari-Capital/solmate/blob/main/src/erc20/ERC20.sol,\n/// License-Identifier: AGPL-3.0-only.\nabstract contract TridentFranchisedERC20 {\n    event Approval(address indexed owner, address indexed spender, uint256 amount);\n    event Transfer(address indexed sender, address indexed recipient, uint256 amount);\n\n    string public constant name = \"Sushi Franchised LP Token\";\n    string public constant symbol = \"SLP\";\n    uint8 public constant decimals = 18;\n\n    address public whiteListManager;\n    address public operator;\n    bool public level2;\n\n    uint256 public totalSupply;\n    /// @notice owner -> balance mapping.\n    mapping(address => uint256) public balanceOf;\n    /// @notice owner -> spender -> allowance mapping.\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    /// @notice The EIP-712 typehash for this contract's {permit} struct.\n    bytes32 public constant PERMIT_TYPEHASH =\n        keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n    /// @notice The EIP-712 typehash for this contract's domain.\n    bytes32 public immutable DOMAIN_SEPARATOR;\n    /// @notice owner -> nonce mapping used in {permit}.\n    mapping(address => uint256) public nonces;\n\n    constructor() {\n        DOMAIN_SEPARATOR = keccak256(\n            abi.encode(\n                keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n                keccak256(bytes(name)),\n                keccak256(bytes(\"1\")),\n                block.chainid,\n                address(this)\n            )\n        );\n    }\n\n    /// @dev Initializes whitelist settings from pool.\n    function initialize(\n        address _whiteListManager,\n        address _operator,\n        bool _level2\n    ) internal {\n        whiteListManager = _whiteListManager;\n        operator = _operator;\n        if (_level2) level2 = true;\n    }\n\n    /// @notice Approves `amount` from `msg.sender` to be spent by `spender`.\n    /// @param spender Address of the party that can pull tokens from `msg.sender`'s account.\n    /// @param amount The maximum collective `amount` that `spender` can pull.\n    /// @return (bool) Returns 'true' if succeeded.\n    function approve(address spender, uint256 amount) external returns (bool) {\n        allowance[msg.sender][spender] = amount;\n        emit Approval(msg.sender, spender, amount);\n        return true;\n    }\n\n    /// @notice Transfers `amount` tokens from `msg.sender` to `recipient`.\n    /// @param recipient The address to move tokens to.\n    /// @param amount The token `amount` to move.\n    /// @return (bool) Returns 'true' if succeeded.\n    function transfer(address recipient, uint256 amount) external returns (bool) {\n        if (level2) _checkWhiteList(recipient);\n        balanceOf[msg.sender] -= amount;\n        // @dev This is safe from overflow - the sum of all user\n        // balances can't exceed 'type(uint256).max'.\n        unchecked {\n            balanceOf[recipient] += amount;\n        }\n        emit Transfer(msg.sender, recipient, amount);\n        return true;\n    }\n\n    /// @notice Transfers `amount` tokens from `sender` to `recipient`. Caller needs approval from `from`.\n    /// @param sender Address to pull tokens `from`.\n    /// @param recipient The address to move tokens to.\n    /// @param amount The token `amount` to move.\n    /// @return (bool) Returns 'true' if succeeded.\n    function transferFrom(\n        address sender,\n        address recipient,\n        uint256 amount\n    ) external returns (bool) {\n        if (level2) _checkWhiteList(recipient);\n        if (allowance[sender][msg.sender] != type(uint256).max) {\n            allowance[sender][msg.sender] -= amount;\n        }\n        balanceOf[sender] -= amount;\n        // @dev This is safe from overflow - the sum of all user\n        // balances can't exceed 'type(uint256).max'.\n        unchecked {\n            balanceOf[recipient] += amount;\n        }\n        emit Transfer(sender, recipient, amount);\n        return true;\n    }\n\n    /// @notice Triggers an approval from `owner` to `spender`.\n    /// @param owner The address to approve from.\n    /// @param spender The address to be approved.\n    /// @param amount The number of tokens that are approved (2^256-1 means infinite).\n    /// @param deadline The time at which to expire the signature.\n    /// @param v The recovery byte of the signature.\n    /// @param r Half of the ECDSA signature pair.\n    /// @param s Half of the ECDSA signature pair.\n    function permit(\n        address owner,\n        address spender,\n        uint256 amount,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external {\n        require(deadline >= block.timestamp, \"PERMIT_DEADLINE_EXPIRED\");\n        bytes32 digest = keccak256(\n            abi.encodePacked(\n                \"\\x19\\x01\",\n                DOMAIN_SEPARATOR,\n                keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, amount, nonces[owner]++, deadline))\n            )\n        );\n        address recoveredAddress = ecrecover(digest, v, r, s);\n        require(recoveredAddress != address(0) && recoveredAddress == owner, \"INVALID_PERMIT_SIGNATURE\");\n        allowance[recoveredAddress][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    function _mint(address recipient, uint256 amount) internal {\n        totalSupply += amount;\n        // @dev This is safe from overflow - the sum of all user\n        // balances can't exceed 'type(uint256).max'.\n        unchecked {\n            balanceOf[recipient] += amount;\n        }\n        emit Transfer(address(0), recipient, amount);\n    }\n\n    function _burn(address sender, uint256 amount) internal {\n        balanceOf[sender] -= amount;\n        // @dev This is safe from underflow - users won't ever\n        // have a balance larger than `totalSupply`.\n        unchecked {\n            totalSupply -= amount;\n        }\n        emit Transfer(sender, address(0), amount);\n    }\n\n    /// @dev Checks `whiteListManager` for pool `operator` and given user `account`.\n    function _checkWhiteList(address account) internal view {\n        (, bytes memory _whitelisted) = whiteListManager.staticcall(\n            abi.encodeWithSelector(IWhiteListManager.whitelistedAccounts.selector, operator, account)\n        );\n        bool whitelisted = abi.decode(_whitelisted, (bool));\n        require(whitelisted, \"NOT_WHITELISTED\");\n    }\n}\n"
    },
    "contracts/interfaces/IWhiteListManager.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\n/// @notice Trident franchised pool whitelist manager interface.\ninterface IWhiteListManager {\n    function whitelistedAccounts(address operator, address account) external returns (bool);\n}\n"
    },
    "contracts/pool/franchised/FranchisedHybridPool.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"../../interfaces/IBentoBoxMinimal.sol\";\nimport \"../../interfaces/IMasterDeployer.sol\";\nimport \"../../interfaces/IPool.sol\";\nimport \"../../interfaces/ITridentCallee.sol\";\nimport \"../../libraries/MathUtils.sol\";\nimport \"./TridentFranchisedERC20.sol\";\n\n/// @notice Trident exchange franchised pool template with hybrid like-kind formula for swapping between an ERC-20 token pair.\n/// @dev The reserves are stored as bento shares. However, the stableswap invariant is applied to the underlying amounts.\n///      The API uses the underlying amounts.\ncontract FranchisedHybridPool is IPool, TridentFranchisedERC20 {\n    using MathUtils for uint256;\n\n    event Mint(address indexed sender, uint256 amount0, uint256 amount1, address indexed recipient, uint256 liquidity);\n    event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed recipient, uint256 liquidity);\n    event Sync(uint256 reserve0, uint256 reserve1);\n\n    uint256 internal constant MINIMUM_LIQUIDITY = 10**3;\n    uint8 internal constant PRECISION = 112;\n\n    /// @dev Constant value used as max loop limit.\n    uint256 internal constant MAX_LOOP_LIMIT = 256;\n    uint256 internal constant MAX_FEE = 10000; // @dev 100%.\n    uint256 public immutable swapFee;\n\n    address public immutable barFeeTo;\n    address public immutable bento;\n    address public immutable masterDeployer;\n    address public immutable token0;\n    address public immutable token1;\n    uint256 public immutable A;\n    uint256 internal immutable N_A; // @dev 2 * A.\n    uint256 internal constant A_PRECISION = 100;\n\n    /// @dev Multipliers for each pooled token's precision to get to POOL_PRECISION_DECIMALS.\n    /// For example, TBTC has 18 decimals, so the multiplier should be 1. WBTC\n    /// has 8, so the multiplier should be 10 ** 18 / 10 ** 8 => 10 ** 10.\n    uint256 public immutable token0PrecisionMultiplier;\n    uint256 public immutable token1PrecisionMultiplier;\n\n    uint256 public barFee;\n\n    uint128 internal reserve0;\n    uint128 internal reserve1;\n\n    bytes32 public constant override poolIdentifier = \"Trident:FranchisedHybrid\";\n\n    uint256 internal unlocked;\n    modifier lock() {\n        require(unlocked == 1, \"LOCKED\");\n        unlocked = 2;\n        _;\n        unlocked = 1;\n    }\n\n    constructor(bytes memory _deployData, address _masterDeployer) {\n        (address _token0, address _token1, uint256 _swapFee, uint256 a, address _whiteListManager, address _operator, bool _level2) = abi\n            .decode(_deployData, (address, address, uint256, uint256, address, address, bool));\n\n        // @dev Factory ensures that the tokens are sorted.\n        require(_token0 != address(0), \"ZERO_ADDRESS\");\n        require(_token0 != _token1, \"IDENTICAL_ADDRESSES\");\n        require(_swapFee <= MAX_FEE, \"INVALID_SWAP_FEE\");\n        require(a != 0, \"ZERO_A\");\n\n        TridentFranchisedERC20.initialize(_whiteListManager, _operator, _level2);\n\n        (, bytes memory _barFee) = _masterDeployer.staticcall(abi.encodeWithSelector(IMasterDeployer.barFee.selector));\n        (, bytes memory _barFeeTo) = _masterDeployer.staticcall(abi.encodeWithSelector(IMasterDeployer.barFeeTo.selector));\n        (, bytes memory _bento) = _masterDeployer.staticcall(abi.encodeWithSelector(IMasterDeployer.bento.selector));\n        (, bytes memory _decimals0) = _token0.staticcall(abi.encodeWithSelector(0x313ce567)); // @dev 'decimals()'.\n        (, bytes memory _decimals1) = _token1.staticcall(abi.encodeWithSelector(0x313ce567)); // @dev 'decimals()'.\n\n        token0 = _token0;\n        token1 = _token1;\n        swapFee = _swapFee;\n        barFee = abi.decode(_barFee, (uint256));\n        barFeeTo = abi.decode(_barFeeTo, (address));\n        bento = abi.decode(_bento, (address));\n        masterDeployer = _masterDeployer;\n        A = a;\n        N_A = 2 * a;\n        token0PrecisionMultiplier = 10**(decimals - abi.decode(_decimals0, (uint8)));\n        token1PrecisionMultiplier = 10**(decimals - abi.decode(_decimals1, (uint8)));\n        unlocked = 1;\n    }\n\n    /// @dev Mints LP tokens - should be called via the router after transferring `bento` tokens.\n    /// The router must ensure that sufficient LP tokens are minted by using the return value.\n    function mint(bytes calldata data) public override lock returns (uint256 liquidity) {\n        address recipient = abi.decode(data, (address));\n        _checkWhiteList(recipient);\n        (uint256 _reserve0, uint256 _reserve1) = _getReserves();\n        (uint256 balance0, uint256 balance1) = _balance();\n        uint256 _totalSupply = totalSupply;\n\n        uint256 amount0 = balance0 - _reserve0;\n        uint256 amount1 = balance1 - _reserve1;\n        (uint256 fee0, uint256 fee1) = _nonOptimalMintFee(amount0, amount1, _reserve0, _reserve1);\n        uint256 newLiq = _computeLiquidity(balance0 - fee0, balance1 - fee1);\n\n        if (_totalSupply == 0) {\n            liquidity = newLiq - MINIMUM_LIQUIDITY;\n            _mint(address(0), MINIMUM_LIQUIDITY);\n        } else {\n            uint256 oldLiq = _computeLiquidity(_reserve0, _reserve1);\n            liquidity = ((newLiq - oldLiq) * _totalSupply) / oldLiq;\n        }\n        require(liquidity != 0, \"INSUFFICIENT_LIQUIDITY_MINTED\");\n        _mint(recipient, liquidity);\n        _updateReserves();\n        uint256 liquidityForEvent = liquidity;\n        emit Mint(msg.sender, amount0, amount1, recipient, liquidityForEvent);\n    }\n\n    /// @dev Burns LP tokens sent to this contract. The router must ensure that the user gets sufficient output tokens.\n    function burn(bytes calldata data) public override lock returns (IPool.TokenAmount[] memory withdrawnAmounts) {\n        (address recipient, bool unwrapBento) = abi.decode(data, (address, bool));\n        _checkWhiteList(recipient);\n        (uint256 balance0, uint256 balance1) = _balance();\n        uint256 _totalSupply = totalSupply;\n        uint256 liquidity = balanceOf[address(this)];\n\n        uint256 amount0 = (liquidity * balance0) / _totalSupply;\n        uint256 amount1 = (liquidity * balance1) / _totalSupply;\n\n        _burn(address(this), liquidity);\n        _transfer(token0, amount0, recipient, unwrapBento);\n        _transfer(token1, amount1, recipient, unwrapBento);\n\n        balance0 -= _toShare(token0, amount0);\n        balance1 -= _toShare(token1, amount1);\n\n        _updateReserves();\n\n        withdrawnAmounts = new TokenAmount[](2);\n        withdrawnAmounts[0] = TokenAmount({token: token0, amount: amount0});\n        withdrawnAmounts[1] = TokenAmount({token: token1, amount: amount1});\n\n        emit Burn(msg.sender, amount0, amount1, recipient, liquidity);\n    }\n\n    /// @dev Burns LP tokens sent to this contract and swaps one of the output tokens for another\n    /// - i.e., the user gets a single token out by burning LP tokens.\n    function burnSingle(bytes calldata data) public override lock returns (uint256 amountOut) {\n        (address tokenOut, address recipient, bool unwrapBento) = abi.decode(data, (address, address, bool));\n        _checkWhiteList(recipient);\n        (uint256 _reserve0, uint256 _reserve1) = _getReserves();\n        (uint256 balance0, uint256 balance1) = _balance();\n        uint256 _totalSupply = totalSupply;\n        uint256 liquidity = balanceOf[address(this)];\n\n        uint256 amount0 = (liquidity * balance0) / _totalSupply;\n        uint256 amount1 = (liquidity * balance1) / _totalSupply;\n\n        _burn(address(this), liquidity);\n\n        if (tokenOut == token1) {\n            // @dev Swap `token0` for `token1`.\n            // @dev Calculate `amountOut` as if the user first withdrew balanced liquidity and then swapped `token0` for `token1`.\n            uint256 fee = _handleFee(token0, amount0);\n            amount1 += _getAmountOut(amount0 - fee, _reserve0 - amount0, _reserve1 - amount1, true);\n            _transfer(token1, amount1, recipient, unwrapBento);\n            balance0 -= _toShare(token0, amount0);\n            amountOut = amount1;\n            amount0 = 0;\n        } else {\n            // @dev Swap `token1` for `token0`.\n            require(tokenOut == token0, \"INVALID_OUTPUT_TOKEN\");\n            uint256 fee = _handleFee(token1, amount1);\n            amount0 += _getAmountOut(amount1 - fee, _reserve0 - amount0, _reserve1 - amount1, false);\n            _transfer(token0, amount0, recipient, unwrapBento);\n            balance1 -= _toShare(token1, amount1);\n            amountOut = amount0;\n            amount1 = 0;\n        }\n        _updateReserves();\n        emit Burn(msg.sender, amount0, amount1, recipient, liquidity);\n    }\n\n    /// @dev Swaps one token for another. The router must prefund this contract and ensure there isn't too much slippage.\n    function swap(bytes calldata data) public override lock returns (uint256 amountOut) {\n        (address tokenIn, address recipient, bool unwrapBento) = abi.decode(data, (address, address, bool));\n        if (level2) _checkWhiteList(recipient);\n        (uint256 _reserve0, uint256 _reserve1) = _getReserves();\n        (uint256 balance0, uint256 balance1) = _balance();\n        uint256 amountIn;\n        address tokenOut;\n\n        if (tokenIn == token0) {\n            tokenOut = token1;\n            amountIn = balance0 - _reserve0;\n            uint256 fee = _handleFee(tokenIn, amountIn);\n            amountOut = _getAmountOut(amountIn - fee, _reserve0, _reserve1, true);\n        } else {\n            require(tokenIn == token1, \"INVALID_INPUT_TOKEN\");\n            tokenOut = token0;\n            amountIn = balance1 - _reserve1;\n            uint256 fee = _handleFee(tokenIn, amountIn);\n            amountOut = _getAmountOut(amountIn - fee, _reserve0, _reserve1, false);\n        }\n        _transfer(tokenOut, amountOut, recipient, unwrapBento);\n        _updateReserves();\n        emit Swap(recipient, tokenIn, tokenOut, amountIn, amountOut);\n    }\n\n    /// @dev Swaps one token for another with payload. The router must support swap callbacks and ensure there isn't too much slippage.\n    function flashSwap(bytes calldata data) public override lock returns (uint256 amountOut) {\n        (address tokenIn, address recipient, bool unwrapBento, uint256 amountIn, bytes memory context) = abi.decode(\n            data,\n            (address, address, bool, uint256, bytes)\n        );\n        if (level2) _checkWhiteList(recipient);\n        (uint256 _reserve0, uint256 _reserve1) = _getReserves();\n        address tokenOut;\n        uint256 fee;\n\n        if (tokenIn == token0) {\n            tokenOut = token1;\n            amountIn = _toAmount(token0, amountIn);\n            fee = (amountIn * swapFee) / MAX_FEE;\n            amountOut = _getAmountOut(amountIn - fee, _reserve0, _reserve1, true);\n            _processSwap(token1, recipient, amountOut, context, unwrapBento);\n            uint256 balance0 = _toAmount(token0, __balance(token0));\n            require(balance0 - _reserve0 >= amountIn, \"INSUFFICIENT_AMOUNT_IN\");\n        } else {\n            require(tokenIn == token1, \"INVALID_INPUT_TOKEN\");\n            tokenOut = token0;\n            amountIn = _toAmount(token1, amountIn);\n            fee = (amountIn * swapFee) / MAX_FEE;\n            amountOut = _getAmountOut(amountIn - fee, _reserve0, _reserve1, false);\n            _processSwap(token0, recipient, amountOut, context, unwrapBento);\n            uint256 balance1 = _toAmount(token1, __balance(token1));\n            require(balance1 - _reserve1 >= amountIn, \"INSUFFICIENT_AMOUNT_IN\");\n        }\n        _transfer(tokenIn, fee, barFeeTo, false);\n        _updateReserves();\n        emit Swap(recipient, tokenIn, tokenOut, amountIn, amountOut);\n    }\n\n    /// @dev Updates `barFee` for Trident protocol.\n    function updateBarFee() public {\n        (, bytes memory _barFee) = masterDeployer.staticcall(abi.encodeWithSelector(IMasterDeployer.barFee.selector));\n        barFee = abi.decode(_barFee, (uint256));\n    }\n\n    function _processSwap(\n        address tokenOut,\n        address to,\n        uint256 amountOut,\n        bytes memory data,\n        bool unwrapBento\n    ) internal {\n        _transfer(tokenOut, amountOut, to, unwrapBento);\n        if (data.length != 0) ITridentCallee(msg.sender).tridentSwapCallback(data);\n    }\n\n    function _getReserves() internal view returns (uint256 _reserve0, uint256 _reserve1) {\n        (_reserve0, _reserve1) = (reserve0, reserve1);\n        _reserve0 = _toAmount(token0, _reserve0);\n        _reserve1 = _toAmount(token1, _reserve1);\n    }\n\n    function _updateReserves() internal {\n        (uint256 _reserve0, uint256 _reserve1) = _balance();\n        require(_reserve0 < type(uint128).max && _reserve1 < type(uint128).max, \"OVERFLOW\");\n        reserve0 = uint128(_reserve0);\n        reserve1 = uint128(_reserve1);\n        emit Sync(_reserve0, _reserve1);\n    }\n\n    function _balance() internal view returns (uint256 balance0, uint256 balance1) {\n        balance0 = _toAmount(token0, __balance(token0));\n        balance1 = _toAmount(token1, __balance(token1));\n    }\n\n    function __balance(address token) internal view returns (uint256 balance) {\n        // @dev balanceOf(address,address).\n        (, bytes memory ___balance) = bento.staticcall(abi.encodeWithSelector(IBentoBoxMinimal.balanceOf.selector, token, address(this)));\n        balance = abi.decode(___balance, (uint256));\n    }\n\n    function _toAmount(address token, uint256 input) internal view returns (uint256 output) {\n        // @dev toAmount(address,uint256,bool).\n        (, bytes memory _output) = bento.staticcall(abi.encodeWithSelector(IBentoBoxMinimal.toAmount.selector, token, input, false));\n        output = abi.decode(_output, (uint256));\n    }\n\n    function _toShare(address token, uint256 input) internal view returns (uint256 output) {\n        // @dev toShare(address,uint256,bool).\n        (, bytes memory _output) = bento.staticcall(abi.encodeWithSelector(IBentoBoxMinimal.toShare.selector, token, input, false));\n        output = abi.decode(_output, (uint256));\n    }\n\n    function _getAmountOut(\n        uint256 amountIn,\n        uint256 _reserve0,\n        uint256 _reserve1,\n        bool token0In\n    ) internal view returns (uint256 dy) {\n        uint256 xpIn;\n        uint256 xpOut;\n\n        if (token0In) {\n            xpIn = _reserve0 * token0PrecisionMultiplier;\n            xpOut = _reserve1 * token1PrecisionMultiplier;\n            amountIn *= token0PrecisionMultiplier;\n        } else {\n            xpIn = _reserve1 * token1PrecisionMultiplier;\n            xpOut = _reserve0 * token0PrecisionMultiplier;\n            amountIn *= token1PrecisionMultiplier;\n        }\n        uint256 d = _computeLiquidityFromAdjustedBalances(xpIn, xpOut);\n        uint256 x = xpIn + amountIn;\n        uint256 y = _getY(x, d);\n        dy = xpOut - y - 1;\n        dy /= (token0In ? token1PrecisionMultiplier : token0PrecisionMultiplier);\n    }\n\n    function _transfer(\n        address token,\n        uint256 amount,\n        address to,\n        bool unwrapBento\n    ) internal {\n        if (unwrapBento) {\n            // @dev withdraw(address,address,address,uint256,uint256).\n            (bool success, ) = bento.call(abi.encodeWithSelector(IBentoBoxMinimal.withdraw.selector, token, address(this), to, amount, 0));\n            require(success, \"WITHDRAW_FAILED\");\n        } else {\n            // @dev transfer(address,address,address,uint256).\n            (bool success, ) = bento.call(\n                abi.encodeWithSelector(IBentoBoxMinimal.transfer.selector, token, address(this), to, _toShare(token, amount))\n            );\n            require(success, \"TRANSFER_FAILED\");\n        }\n    }\n\n    /// @notice Get D, the StableSwap invariant, based on a set of balances and a particular A.\n    /// See the StableSwap paper for details.\n    /// @dev Originally https://github.com/saddle-finance/saddle-contract/blob/0b76f7fb519e34b878aa1d58cffc8d8dc0572c12/contracts/SwapUtils.sol#L319.\n    /// @return liquidity The invariant, at the precision of the pool.\n    function _computeLiquidity(uint256 _reserve0, uint256 _reserve1) internal view returns (uint256 liquidity) {\n        uint256 xp0 = _reserve0 * token0PrecisionMultiplier;\n        uint256 xp1 = _reserve1 * token1PrecisionMultiplier;\n        liquidity = _computeLiquidityFromAdjustedBalances(xp0, xp1);\n    }\n\n    function _computeLiquidityFromAdjustedBalances(uint256 xp0, uint256 xp1) internal view returns (uint256 computed) {\n        uint256 s = xp0 + xp1;\n\n        if (s == 0) {\n            computed = 0;\n        }\n        uint256 prevD;\n        uint256 D = s;\n        for (uint256 i = 0; i < MAX_LOOP_LIMIT; i++) {\n            uint256 dP = (((D * D) / xp0) * D) / xp1 / 4;\n            prevD = D;\n            D = (((N_A * s) / A_PRECISION + 2 * dP) * D) / ((N_A / A_PRECISION - 1) * D + 3 * dP);\n            if (D.within1(prevD)) {\n                break;\n            }\n        }\n        computed = D;\n    }\n\n    /// @notice Calculate the new balances of the tokens given the indexes of the token\n    /// that is swapped from (FROM) and the token that is swapped to (TO).\n    /// This function is used as a helper function to calculate how much TO token\n    /// the user should receive on swap.\n    /// @dev Originally https://github.com/saddle-finance/saddle-contract/blob/0b76f7fb519e34b878aa1d58cffc8d8dc0572c12/contracts/SwapUtils.sol#L432.\n    /// @param x The new total amount of FROM token.\n    /// @return y The amount of TO token that should remain in the pool.\n    function _getY(uint256 x, uint256 D) internal view returns (uint256 y) {\n        uint256 c = (D * D) / (x * 2);\n        c = (c * D) / ((N_A * 2) / A_PRECISION);\n        uint256 b = x + ((D * A_PRECISION) / N_A);\n        uint256 yPrev;\n        y = D;\n        // @dev Iterative approximation.\n        for (uint256 i = 0; i < MAX_LOOP_LIMIT; i++) {\n            yPrev = y;\n            y = (y * y + c) / (y * 2 + b - D);\n            if (y.within1(yPrev)) {\n                break;\n            }\n        }\n    }\n\n    /// @notice Calculate the price of a token in the pool given\n    /// precision-adjusted balances and a particular D and precision-adjusted\n    /// array of balances.\n    /// @dev This is accomplished via solving the quadratic equation iteratively.\n    /// See the StableSwap paper and Curve.fi implementation for further details.\n    /// x_1**2 + x1 * (sum' - (A*n**n - 1) * D / (A * n**n)) = D ** (n + 1) / (n ** (2 * n) * prod' * A)\n    /// x_1**2 + b*x_1 = c\n    /// x_1 = (x_1**2 + c) / (2*x_1 + b)\n    /// @dev Originally https://github.com/saddle-finance/saddle-contract/blob/0b76f7fb519e34b878aa1d58cffc8d8dc0572c12/contracts/SwapUtils.sol#L276.\n    /// @return y The price of the token, in the same precision as in xp.\n    function _getYD(\n        uint256 s, // @dev xpOut.\n        uint256 d\n    ) internal view returns (uint256 y) {\n        uint256 c = (d * d) / (s * 2);\n        c = (c * d) / ((N_A * 2) / A_PRECISION);\n\n        uint256 b = s + ((d * A_PRECISION) / N_A);\n        uint256 yPrev;\n        y = d;\n\n        for (uint256 i = 0; i < MAX_LOOP_LIMIT; i++) {\n            yPrev = y;\n            y = (y * y + c) / (y * 2 + b - d);\n            if (y.within1(yPrev)) {\n                break;\n            }\n        }\n    }\n\n    function _handleFee(address tokenIn, uint256 amountIn) internal returns (uint256 fee) {\n        fee = (amountIn * swapFee) / MAX_FEE;\n        uint256 _barFee = (fee * barFee) / MAX_FEE;\n        _transfer(tokenIn, _barFee, barFeeTo, false);\n    }\n\n    /// @dev This fee is charged to cover for `swapFee` when users add unbalanced liquidity.\n    function _nonOptimalMintFee(\n        uint256 _amount0,\n        uint256 _amount1,\n        uint256 _reserve0,\n        uint256 _reserve1\n    ) internal view returns (uint256 token0Fee, uint256 token1Fee) {\n        if (_reserve0 == 0 || _reserve1 == 0) return (0, 0);\n        uint256 amount1Optimal = (_amount0 * _reserve1) / _reserve0;\n\n        if (amount1Optimal <= _amount1) {\n            token1Fee = (swapFee * (_amount1 - amount1Optimal)) / (2 * MAX_FEE);\n        } else {\n            uint256 amount0Optimal = (_amount1 * _reserve0) / _reserve1;\n            token0Fee = (swapFee * (_amount0 - amount0Optimal)) / (2 * MAX_FEE);\n        }\n    }\n\n    function getAssets() public view override returns (address[] memory assets) {\n        assets = new address[](2);\n        assets[0] = token0;\n        assets[1] = token1;\n    }\n\n    function getAmountOut(bytes calldata data) public view override returns (uint256 finalAmountOut) {\n        (address tokenIn, uint256 amountIn) = abi.decode(data, (address, uint256));\n        (uint256 _reserve0, uint256 _reserve1) = _getReserves();\n        amountIn = _toAmount(tokenIn, amountIn);\n        amountIn -= (amountIn * swapFee) / MAX_FEE;\n\n        if (tokenIn == token0) {\n            finalAmountOut = _getAmountOut(amountIn, _reserve0, _reserve1, true);\n        } else {\n            require(tokenIn == token1, \"INVALID_INPUT_TOKEN\");\n            finalAmountOut = _getAmountOut(amountIn, _reserve0, _reserve1, false);\n        }\n    }\n\n    function getAmountIn(bytes calldata) public pure override returns (uint256) {\n        revert();\n    }\n\n    function getReserves() public view returns (uint256 _reserve0, uint256 _reserve1) {\n        (_reserve0, _reserve1) = _getReserves();\n    }\n}\n"
    },
    "contracts/pool/franchised/FranchisedHybridPoolFactory.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"./FranchisedHybridPool.sol\";\nimport \"../PoolDeployer.sol\";\n\n/// @notice Contract for deploying Trident exchange Franchised Hybrid Product Pool with configurations.\n/// @author Mudit Gupta.\ncontract FranchisedHybridPoolFactory is PoolDeployer {\n    constructor(address _masterDeployer) PoolDeployer(_masterDeployer) {}\n\n    function deployPool(bytes memory _deployData) external returns (address pool) {\n        (address tokenA, address tokenB, uint256 swapFee, uint256 a, address whiteListManager, address operator, bool level2) = abi.decode(\n            _deployData,\n            (address, address, uint256, uint256, address, address, bool)\n        );\n        if (tokenA > tokenB) {\n            (tokenA, tokenB) = (tokenB, tokenA);\n        }\n\n        // @dev Strips any extra data.\n        _deployData = abi.encode(tokenA, tokenB, swapFee, a, whiteListManager, operator, level2);\n        address[] memory tokens = new address[](2);\n        tokens[0] = tokenA;\n        tokens[1] = tokenB;\n\n        // @dev Salt is not actually needed since `_deployData` is part of creationCode and already contains the salt.\n        bytes32 salt = keccak256(_deployData);\n        pool = address(new FranchisedHybridPool{salt: salt}(_deployData, masterDeployer));\n        _registerPool(pool, tokens, salt);\n    }\n}\n"
    },
    "contracts/pool/franchised/FranchisedConstantProductPool.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"../../interfaces/IBentoBoxMinimal.sol\";\nimport \"../../interfaces/IMasterDeployer.sol\";\nimport \"../../interfaces/IPool.sol\";\nimport \"../../interfaces/ITridentCallee.sol\";\nimport \"../../libraries/TridentMath.sol\";\nimport \"./TridentFranchisedERC20.sol\";\n\n/// @notice Trident exchange franchised pool template with constant product formula for swapping between an ERC-20 token pair.\n/// @dev The reserves are stored as bento shares.\n///      The curve is applied to shares as well. This pool does not care about the underlying amounts.\ncontract FranchisedConstantProductPool is IPool, TridentFranchisedERC20 {\n    event Mint(address indexed sender, uint256 amount0, uint256 amount1, address indexed recipient, uint256 liquidity);\n    event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed recipient, uint256 liquidity);\n    event Sync(uint256 reserve0, uint256 reserve1);\n\n    uint256 internal constant MINIMUM_LIQUIDITY = 1000;\n\n    uint8 internal constant PRECISION = 112;\n    uint256 internal constant MAX_FEE = 10000; // @dev 100%.\n    uint256 internal constant MAX_FEE_SQUARE = 100000000;\n    uint256 internal constant E18 = uint256(10)**18;\n    uint256 public immutable swapFee;\n    uint256 internal immutable MAX_FEE_MINUS_SWAP_FEE;\n\n    address public immutable barFeeTo;\n    address public immutable bento;\n    address public immutable masterDeployer;\n    address public immutable token0;\n    address public immutable token1;\n\n    uint256 public barFee;\n    uint256 public price0CumulativeLast;\n    uint256 public price1CumulativeLast;\n    uint256 public kLast;\n\n    uint112 internal reserve0;\n    uint112 internal reserve1;\n    uint32 internal blockTimestampLast;\n\n    bytes32 public constant override poolIdentifier = \"Trident:FranchisedCP\";\n\n    uint256 internal unlocked;\n    modifier lock() {\n        require(unlocked == 1, \"LOCKED\");\n        unlocked = 2;\n        _;\n        unlocked = 1;\n    }\n\n    constructor(bytes memory _deployData, address _masterDeployer) {\n        (\n            address _token0,\n            address _token1,\n            uint256 _swapFee,\n            bool _twapSupport,\n            address _whiteListManager,\n            address _operator,\n            bool _level2\n        ) = abi.decode(_deployData, (address, address, uint256, bool, address, address, bool));\n\n        // @dev Factory ensures that the tokens are sorted.\n        require(_token0 != address(0), \"ZERO_ADDRESS\");\n        require(_token0 != _token1, \"IDENTICAL_ADDRESSES\");\n        require(_token0 != address(this), \"INVALID_TOKEN\");\n        require(_token1 != address(this), \"INVALID_TOKEN\");\n        require(_swapFee <= MAX_FEE, \"INVALID_SWAP_FEE\");\n\n        TridentFranchisedERC20.initialize(_whiteListManager, _operator, _level2);\n\n        (, bytes memory _barFee) = _masterDeployer.staticcall(abi.encodeWithSelector(IMasterDeployer.barFee.selector));\n        (, bytes memory _barFeeTo) = _masterDeployer.staticcall(abi.encodeWithSelector(IMasterDeployer.barFeeTo.selector));\n        (, bytes memory _bento) = _masterDeployer.staticcall(abi.encodeWithSelector(IMasterDeployer.bento.selector));\n\n        token0 = _token0;\n        token1 = _token1;\n        swapFee = _swapFee;\n        // @dev This is safe from underflow - `swapFee` cannot exceed `MAX_FEE` per previous check.\n        unchecked {\n            MAX_FEE_MINUS_SWAP_FEE = MAX_FEE - _swapFee;\n        }\n        barFee = abi.decode(_barFee, (uint256));\n        barFeeTo = abi.decode(_barFeeTo, (address));\n        bento = abi.decode(_bento, (address));\n        masterDeployer = _masterDeployer;\n        unlocked = 1;\n        if (_twapSupport) blockTimestampLast = 1;\n    }\n\n    /// @dev Mints LP tokens - should be called via the router after transferring `bento` tokens.\n    /// The router must ensure that sufficient LP tokens are minted by using the return value.\n    function mint(bytes calldata data) public override lock returns (uint256 liquidity) {\n        address recipient = abi.decode(data, (address));\n        _checkWhiteList(recipient);\n        (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) = _getReserves();\n        (uint256 balance0, uint256 balance1) = _balance();\n        uint256 _totalSupply = totalSupply;\n\n        unchecked {\n            _totalSupply += _mintFee(_reserve0, _reserve1, _totalSupply);\n        }\n\n        uint256 amount0 = balance0 - _reserve0;\n        uint256 amount1 = balance1 - _reserve1;\n        (uint256 fee0, uint256 fee1) = _nonOptimalMintFee(amount0, amount1, _reserve0, _reserve1);\n        uint256 computed = TridentMath.sqrt((balance0 - fee0) * (balance1 - fee1));\n\n        if (_totalSupply == 0) {\n            _mint(address(0), MINIMUM_LIQUIDITY);\n            liquidity = computed - MINIMUM_LIQUIDITY;\n        } else {\n            uint256 k = TridentMath.sqrt(uint256(_reserve0) * _reserve1);\n            liquidity = ((computed - k) * _totalSupply) / k;\n        }\n        require(liquidity != 0, \"INSUFFICIENT_LIQUIDITY_MINTED\");\n        _mint(recipient, liquidity);\n        _update(balance0, balance1, _reserve0, _reserve1, _blockTimestampLast);\n        kLast = TridentMath.sqrt(balance0 * balance1);\n        uint256 liquidityForEvent = liquidity;\n        emit Mint(msg.sender, amount0, amount1, recipient, liquidityForEvent);\n    }\n\n    /// @dev Burns LP tokens sent to this contract. The router must ensure that the user gets sufficient output tokens.\n    function burn(bytes calldata data) public override lock returns (IPool.TokenAmount[] memory withdrawnAmounts) {\n        (address recipient, bool unwrapBento) = abi.decode(data, (address, bool));\n        _checkWhiteList(recipient);\n        (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) = _getReserves();\n        (uint256 balance0, uint256 balance1) = _balance();\n        uint256 _totalSupply = totalSupply;\n        uint256 liquidity = balanceOf[address(this)];\n\n        unchecked {\n            _totalSupply += _mintFee(_reserve0, _reserve1, _totalSupply);\n        }\n\n        uint256 amount0 = (liquidity * balance0) / _totalSupply;\n        uint256 amount1 = (liquidity * balance1) / _totalSupply;\n\n        _burn(address(this), liquidity);\n        _transfer(token0, amount0, recipient, unwrapBento);\n        _transfer(token1, amount1, recipient, unwrapBento);\n        // @dev This is safe from underflow - amounts are lesser figures derived from balances.\n        unchecked {\n            balance0 -= amount0;\n            balance1 -= amount1;\n        }\n        _update(balance0, balance1, _reserve0, _reserve1, _blockTimestampLast);\n        kLast = TridentMath.sqrt(balance0 * balance1);\n\n        withdrawnAmounts = new TokenAmount[](2);\n        withdrawnAmounts[0] = TokenAmount({token: address(token0), amount: amount0});\n        withdrawnAmounts[1] = TokenAmount({token: address(token1), amount: amount1});\n        emit Burn(msg.sender, amount0, amount1, recipient, liquidity);\n    }\n\n    /// @dev Burns LP tokens sent to this contract and swaps one of the output tokens for another\n    /// - i.e., the user gets a single token out by burning LP tokens.\n    function burnSingle(bytes calldata data) public override lock returns (uint256 amountOut) {\n        (address tokenOut, address recipient, bool unwrapBento) = abi.decode(data, (address, address, bool));\n        _checkWhiteList(recipient);\n        (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) = _getReserves();\n        (uint256 balance0, uint256 balance1) = _balance();\n        uint256 _totalSupply = totalSupply;\n        uint256 liquidity = balanceOf[address(this)];\n\n        unchecked {\n            _totalSupply += _mintFee(_reserve0, _reserve1, _totalSupply);\n        }\n\n        uint256 amount0 = (liquidity * balance0) / _totalSupply;\n        uint256 amount1 = (liquidity * balance1) / _totalSupply;\n\n        _burn(address(this), liquidity);\n        unchecked {\n            if (tokenOut == token1) {\n                // @dev Swap `token0` for `token1`\n                // - calculate `amountOut` as if the user first withdrew balanced liquidity and then swapped `token0` for `token1`.\n                amount1 += _getAmountOut(amount0, _reserve0 - amount0, _reserve1 - amount1);\n                _transfer(token1, amount1, recipient, unwrapBento);\n                balance1 -= amount1;\n                amountOut = amount1;\n                amount0 = 0;\n            } else {\n                // @dev Swap `token1` for `token0`.\n                require(tokenOut == token0, \"INVALID_OUTPUT_TOKEN\");\n                amount0 += _getAmountOut(amount1, _reserve1 - amount1, _reserve0 - amount0);\n                _transfer(token0, amount0, recipient, unwrapBento);\n                balance0 -= amount0;\n                amountOut = amount0;\n                amount1 = 0;\n            }\n        }\n        _update(balance0, balance1, _reserve0, _reserve1, _blockTimestampLast);\n        kLast = TridentMath.sqrt(balance0 * balance1);\n        emit Burn(msg.sender, amount0, amount1, recipient, liquidity);\n    }\n\n    /// @dev Swaps one token for another. The router must prefund this contract and ensure there isn't too much slippage.\n    function swap(bytes calldata data) public override lock returns (uint256 amountOut) {\n        (address tokenIn, address recipient, bool unwrapBento) = abi.decode(data, (address, address, bool));\n        if (level2) _checkWhiteList(recipient);\n        (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) = _getReserves();\n        (uint256 balance0, uint256 balance1) = _balance();\n        uint256 amountIn;\n        address tokenOut;\n        unchecked {\n            if (tokenIn == token0) {\n                tokenOut = token1;\n                amountIn = balance0 - _reserve0;\n                amountOut = _getAmountOut(amountIn, _reserve0, _reserve1);\n                balance1 -= amountOut;\n            } else {\n                require(tokenIn == token1, \"INVALID_INPUT_TOKEN\");\n                tokenOut = token0;\n                amountIn = balance1 - reserve1;\n                amountOut = _getAmountOut(amountIn, _reserve1, _reserve0);\n                balance0 -= amountOut;\n            }\n        }\n        _transfer(tokenOut, amountOut, recipient, unwrapBento);\n        _update(balance0, balance1, _reserve0, _reserve1, _blockTimestampLast);\n        emit Swap(recipient, tokenIn, tokenOut, amountIn, amountOut);\n    }\n\n    /// @dev Swaps one token for another. The router must support swap callbacks and ensure there isn't too much slippage.\n    function flashSwap(bytes calldata data) public override lock returns (uint256 amountOut) {\n        (address tokenIn, address recipient, bool unwrapBento, uint256 amountIn, bytes memory context) = abi.decode(\n            data,\n            (address, address, bool, uint256, bytes)\n        );\n        if (level2) _checkWhiteList(recipient);\n        (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) = _getReserves();\n        unchecked {\n            if (tokenIn == token0) {\n                amountOut = _getAmountOut(amountIn, _reserve0, _reserve1);\n                _transfer(token1, amountOut, recipient, unwrapBento);\n                ITridentCallee(msg.sender).tridentSwapCallback(context);\n                (uint256 balance0, uint256 balance1) = _balance();\n                require(balance0 - _reserve0 >= amountIn, \"INSUFFICIENT_AMOUNT_IN\");\n                _update(balance0, balance1, _reserve0, _reserve1, _blockTimestampLast);\n                emit Swap(recipient, tokenIn, token1, amountIn, amountOut);\n            } else {\n                require(tokenIn == token1, \"INVALID_INPUT_TOKEN\");\n                amountOut = _getAmountOut(amountIn, _reserve1, _reserve0);\n                _transfer(token0, amountOut, recipient, unwrapBento);\n                ITridentCallee(msg.sender).tridentSwapCallback(context);\n                (uint256 balance0, uint256 balance1) = _balance();\n                require(balance1 - _reserve1 >= amountIn, \"INSUFFICIENT_AMOUNT_IN\");\n                _update(balance0, balance1, _reserve0, _reserve1, _blockTimestampLast);\n                emit Swap(recipient, tokenIn, token0, amountIn, amountOut);\n            }\n        }\n    }\n\n    /// @dev Updates `barFee` for Trident protocol.\n    function updateBarFee() public {\n        (, bytes memory _barFee) = masterDeployer.staticcall(abi.encodeWithSelector(IMasterDeployer.barFee.selector));\n        barFee = abi.decode(_barFee, (uint256));\n    }\n\n    function _getReserves()\n        internal\n        view\n        returns (\n            uint112 _reserve0,\n            uint112 _reserve1,\n            uint32 _blockTimestampLast\n        )\n    {\n        _reserve0 = reserve0;\n        _reserve1 = reserve1;\n        _blockTimestampLast = blockTimestampLast;\n    }\n\n    function _balance() internal view returns (uint256 balance0, uint256 balance1) {\n        // @dev balanceOf(address,address).\n        (, bytes memory _balance0) = bento.staticcall(abi.encodeWithSelector(0xf7888aec, token0, address(this)));\n        balance0 = abi.decode(_balance0, (uint256));\n        // @dev balanceOf(address,address).\n        (, bytes memory _balance1) = bento.staticcall(abi.encodeWithSelector(0xf7888aec, token1, address(this)));\n        balance1 = abi.decode(_balance1, (uint256));\n    }\n\n    function _update(\n        uint256 balance0,\n        uint256 balance1,\n        uint112 _reserve0,\n        uint112 _reserve1,\n        uint32 _blockTimestampLast\n    ) internal {\n        require(balance0 <= type(uint112).max && balance1 <= type(uint112).max, \"OVERFLOW\");\n        if (blockTimestampLast == 0) {\n            // @dev TWAP support is disabled for gas efficiency.\n            reserve0 = uint112(balance0);\n            reserve1 = uint112(balance1);\n        } else {\n            uint32 blockTimestamp = uint32(block.timestamp);\n            if (blockTimestamp != _blockTimestampLast && _reserve0 != 0 && _reserve1 != 0) {\n                unchecked {\n                    uint32 timeElapsed = blockTimestamp - _blockTimestampLast;\n                    uint256 price0 = (uint256(_reserve1) << PRECISION) / _reserve0;\n                    price0CumulativeLast += price0 * timeElapsed;\n                    uint256 price1 = (uint256(_reserve0) << PRECISION) / _reserve1;\n                    price1CumulativeLast += price1 * timeElapsed;\n                }\n            }\n            reserve0 = uint112(balance0);\n            reserve1 = uint112(balance1);\n            blockTimestampLast = blockTimestamp;\n        }\n        emit Sync(balance0, balance1);\n    }\n\n    function _mintFee(\n        uint112 _reserve0,\n        uint112 _reserve1,\n        uint256 _totalSupply\n    ) internal returns (uint256 liquidity) {\n        uint256 _kLast = kLast;\n        if (_kLast != 0) {\n            uint256 computed = TridentMath.sqrt(uint256(_reserve0) * _reserve1);\n            if (computed > _kLast) {\n                // @dev `barFee` % of increase in liquidity.\n                // It's going to be slightly less than `barFee` % in reality due to the math.\n                liquidity = (_totalSupply * (computed - _kLast) * barFee) / computed / MAX_FEE;\n                if (liquidity != 0) {\n                    _mint(barFeeTo, liquidity);\n                }\n            }\n        }\n    }\n\n    function _getAmountOut(\n        uint256 amountIn,\n        uint256 reserveAmountIn,\n        uint256 reserveAmountOut\n    ) internal view returns (uint256 amountOut) {\n        uint256 amountInWithFee = amountIn * MAX_FEE_MINUS_SWAP_FEE;\n        amountOut = (amountInWithFee * reserveAmountOut) / (reserveAmountIn * MAX_FEE + amountInWithFee);\n    }\n\n    function _transfer(\n        address token,\n        uint256 shares,\n        address to,\n        bool unwrapBento\n    ) internal {\n        if (unwrapBento) {\n            (bool success, ) = bento.call(abi.encodeWithSelector(IBentoBoxMinimal.withdraw.selector, token, address(this), to, 0, shares));\n            require(success, \"WITHDRAW_FAILED\");\n        } else {\n            (bool success, ) = bento.call(abi.encodeWithSelector(IBentoBoxMinimal.transfer.selector, token, address(this), to, shares));\n            require(success, \"TRANSFER_FAILED\");\n        }\n    }\n\n    /// @dev This fee is charged to cover for `swapFee` when users add unbalanced liquidity.\n    function _nonOptimalMintFee(\n        uint256 _amount0,\n        uint256 _amount1,\n        uint256 _reserve0,\n        uint256 _reserve1\n    ) internal view returns (uint256 token0Fee, uint256 token1Fee) {\n        if (_reserve0 == 0 || _reserve1 == 0) return (0, 0);\n        uint256 amount1Optimal = (_amount0 * _reserve1) / _reserve0;\n        if (amount1Optimal <= _amount1) {\n            token1Fee = (swapFee * (_amount1 - amount1Optimal)) / (2 * MAX_FEE);\n        } else {\n            uint256 amount0Optimal = (_amount1 * _reserve0) / _reserve1;\n            token0Fee = (swapFee * (_amount0 - amount0Optimal)) / (2 * MAX_FEE);\n        }\n    }\n\n    function getAssets() public view override returns (address[] memory assets) {\n        assets = new address[](2);\n        assets[0] = token0;\n        assets[1] = token1;\n    }\n\n    function getAmountOut(bytes calldata data) public view override returns (uint256 finalAmountOut) {\n        (address tokenIn, uint256 amountIn) = abi.decode(data, (address, uint256));\n        (uint112 _reserve0, uint112 _reserve1, ) = _getReserves();\n        if (tokenIn == token0) {\n            finalAmountOut = _getAmountOut(amountIn, _reserve0, _reserve1);\n        } else {\n            require(tokenIn == token1, \"INVALID_INPUT_TOKEN\");\n            finalAmountOut = _getAmountOut(amountIn, _reserve1, _reserve0);\n        }\n    }\n\n    function getAmountIn(bytes calldata) public pure override returns (uint256) {\n        revert();\n    }\n\n    function getReserves()\n        public\n        view\n        returns (\n            uint112 _reserve0,\n            uint112 _reserve1,\n            uint32 _blockTimestampLast\n        )\n    {\n        return _getReserves();\n    }\n}\n"
    },
    "contracts/libraries/TridentMath.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\n/// @notice Trident sqrt helper library.\nlibrary TridentMath {\n    /// @notice Calculate sqrt (x) rounding down, where `x` is unsigned 256-bit integer number.\n    /// @dev Adapted from https://github.com/abdk-consulting/abdk-libraries-solidity/blob/master/ABDKMath64x64.sol, \n    /// © 2019 ABDK Consulting, License-Identifier: BSD-4-Clause.\n    /// @param x Unsigned 256-bit integer number.\n    /// @return result Sqrt result.\n    function sqrt(uint256 x) internal pure returns (uint256 result) {\n        unchecked {\n            if (x == 0) result = 0;\n            else {\n                uint256 xx = x;\n                uint256 r = 1;\n                if (xx >= 0x100000000000000000000000000000000) {\n                    xx >>= 128;\n                    r <<= 64;\n                }\n                if (xx >= 0x10000000000000000) {\n                    xx >>= 64;\n                    r <<= 32;\n                }\n                if (xx >= 0x100000000) {\n                    xx >>= 32;\n                    r <<= 16;\n                }\n                if (xx >= 0x10000) {\n                    xx >>= 16;\n                    r <<= 8;\n                }\n                if (xx >= 0x100) {\n                    xx >>= 8;\n                    r <<= 4;\n                }\n                if (xx >= 0x10) {\n                    xx >>= 4;\n                    r <<= 2;\n                }\n                if (xx >= 0x8) {\n                    r <<= 1;\n                }\n                r = (r + x / r) >> 1;\n                r = (r + x / r) >> 1;\n                r = (r + x / r) >> 1;\n                r = (r + x / r) >> 1;\n                r = (r + x / r) >> 1;\n                r = (r + x / r) >> 1;\n                r = (r + x / r) >> 1; // @dev Seven iterations should be enough.\n                uint256 r1 = x / r;\n                result = r < r1 ? r : r1;\n            }\n        }\n    }\n}\n"
    },
    "contracts/pool/franchised/FranchisedConstantProductPoolFactory.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"./FranchisedConstantProductPool.sol\";\nimport \"../PoolDeployer.sol\";\n\n/// @notice Contract for deploying Trident exchange Franchised Constant Product Pool with configurations.\n/// @author Mudit Gupta.\ncontract FranchisedConstantProductPoolFactory is PoolDeployer {\n    constructor(address _masterDeployer) PoolDeployer(_masterDeployer) {}\n\n    function deployPool(bytes memory _deployData) external returns (address pool) {\n        (address tokenA, address tokenB, uint256 swapFee, bool twapSupport, address whiteListManager, address operator, bool level2) = abi\n            .decode(_deployData, (address, address, uint256, bool, address, address, bool));\n        if (tokenA > tokenB) {\n            (tokenA, tokenB) = (tokenB, tokenA);\n        }\n\n        // @dev Strips any extra data.\n        _deployData = abi.encode(tokenA, tokenB, swapFee, twapSupport, whiteListManager, operator, level2);\n\n        address[] memory tokens = new address[](2);\n        tokens[0] = tokenA;\n        tokens[1] = tokenB;\n\n        // @dev Salt is not actually needed since `_deployData` is part of creationCode and already contains the salt.\n        bytes32 salt = keccak256(_deployData);\n        pool = address(new FranchisedConstantProductPool{salt: salt}(_deployData, masterDeployer));\n        _registerPool(pool, tokens, salt);\n    }\n}\n"
    },
    "contracts/pool/ConstantProductPool.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"../interfaces/IBentoBoxMinimal.sol\";\nimport \"../interfaces/IMasterDeployer.sol\";\nimport \"../interfaces/IPool.sol\";\nimport \"../interfaces/ITridentCallee.sol\";\nimport \"../libraries/TridentMath.sol\";\nimport \"./TridentERC20.sol\";\n\n/// @notice Trident exchange pool template with constant product formula for swapping between an ERC-20 token pair.\n/// @dev The reserves are stored as bento shares.\n///      The curve is applied to shares as well. This pool does not care about the underlying amounts.\ncontract ConstantProductPool is IPool, TridentERC20 {\n    event Mint(address indexed sender, uint256 amount0, uint256 amount1, address indexed recipient, uint256 liquidity);\n    event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed recipient, uint256 liquidity);\n    event Sync(uint256 reserve0, uint256 reserve1);\n\n    uint256 internal constant MINIMUM_LIQUIDITY = 1000;\n\n    uint8 internal constant PRECISION = 112;\n    uint256 internal constant MAX_FEE = 10000; // @dev 100%.\n    uint256 internal constant MAX_FEE_SQUARE = 100000000;\n    uint256 public immutable swapFee;\n    uint256 internal immutable MAX_FEE_MINUS_SWAP_FEE;\n\n    address public immutable barFeeTo;\n    IBentoBoxMinimal public immutable bento;\n    IMasterDeployer public immutable masterDeployer;\n    address public immutable token0;\n    address public immutable token1;\n\n    uint256 public barFee;\n    uint256 public price0CumulativeLast;\n    uint256 public price1CumulativeLast;\n    uint256 public kLast;\n\n    uint112 internal reserve0;\n    uint112 internal reserve1;\n    uint32 internal blockTimestampLast;\n\n    bytes32 public constant override poolIdentifier = \"Trident:ConstantProduct\";\n\n    uint256 internal unlocked;\n    modifier lock() {\n        require(unlocked == 1, \"LOCKED\");\n        unlocked = 2;\n        _;\n        unlocked = 1;\n    }\n\n    constructor(bytes memory _deployData, address _masterDeployer) {\n        (address _token0, address _token1, uint256 _swapFee, bool _twapSupport) = abi.decode(\n            _deployData,\n            (address, address, uint256, bool)\n        );\n\n        // @dev Factory ensures that the tokens are sorted.\n        require(_token0 != address(0), \"ZERO_ADDRESS\");\n        require(_token0 != _token1, \"IDENTICAL_ADDRESSES\");\n        require(_token0 != address(this), \"INVALID_TOKEN\");\n        require(_token1 != address(this), \"INVALID_TOKEN\");\n        require(_swapFee <= MAX_FEE, \"INVALID_SWAP_FEE\");\n\n        token0 = _token0;\n        token1 = _token1;\n        swapFee = _swapFee;\n        // @dev This is safe from underflow - `swapFee` cannot exceed `MAX_FEE` per previous check.\n        unchecked {\n            MAX_FEE_MINUS_SWAP_FEE = MAX_FEE - _swapFee;\n        }\n        barFee = IMasterDeployer(_masterDeployer).barFee();\n        barFeeTo = IMasterDeployer(_masterDeployer).barFeeTo();\n        bento = IBentoBoxMinimal(IMasterDeployer(_masterDeployer).bento());\n        masterDeployer = IMasterDeployer(_masterDeployer);\n        unlocked = 1;\n        if (_twapSupport) blockTimestampLast = 1;\n    }\n\n    /// @dev Mints LP tokens - should be called via the router after transferring `bento` tokens.\n    /// The router must ensure that sufficient LP tokens are minted by using the return value.\n    function mint(bytes calldata data) public override lock returns (uint256 liquidity) {\n        address recipient = abi.decode(data, (address));\n        (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) = _getReserves();\n        (uint256 balance0, uint256 balance1) = _balance();\n\n        uint256 computed = TridentMath.sqrt(balance0 * balance1);\n        uint256 amount0 = balance0 - _reserve0;\n        uint256 amount1 = balance1 - _reserve1;\n\n        (uint256 fee0, uint256 fee1) = _nonOptimalMintFee(amount0, amount1, _reserve0, _reserve1);\n        _reserve0 += uint112(fee0);\n        _reserve1 += uint112(fee1);\n\n        (uint256 _totalSupply, uint256 k) = _mintFee(_reserve0, _reserve1);\n\n        if (_totalSupply == 0) {\n            require(amount0 > 0 && amount1 > 0, \"INVALID_AMOUNTS\");\n            liquidity = computed - MINIMUM_LIQUIDITY;\n            _mint(address(0), MINIMUM_LIQUIDITY);\n        } else {\n            uint256 kIncrease;\n            unchecked {\n                kIncrease = computed - k;\n            }\n            liquidity = (kIncrease * _totalSupply) / k;\n        }\n        require(liquidity != 0, \"INSUFFICIENT_LIQUIDITY_MINTED\");\n        _mint(recipient, liquidity);\n        _update(balance0, balance1, _reserve0, _reserve1, _blockTimestampLast);\n        kLast = computed;\n        uint256 liquidityForEvent = liquidity;\n        emit Mint(msg.sender, amount0, amount1, recipient, liquidityForEvent);\n    }\n\n    /// @dev Burns LP tokens sent to this contract. The router must ensure that the user gets sufficient output tokens.\n    function burn(bytes calldata data) public override lock returns (IPool.TokenAmount[] memory withdrawnAmounts) {\n        (address recipient, bool unwrapBento) = abi.decode(data, (address, bool));\n        (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) = _getReserves();\n        (uint256 balance0, uint256 balance1) = _balance();\n        uint256 liquidity = balanceOf[address(this)];\n\n        (uint256 _totalSupply, ) = _mintFee(_reserve0, _reserve1);\n\n        uint256 amount0 = (liquidity * balance0) / _totalSupply;\n        uint256 amount1 = (liquidity * balance1) / _totalSupply;\n\n        _burn(address(this), liquidity);\n        _transfer(token0, amount0, recipient, unwrapBento);\n        _transfer(token1, amount1, recipient, unwrapBento);\n        // @dev This is safe from underflow - amounts are lesser figures derived from balances.\n        unchecked {\n            balance0 -= amount0;\n            balance1 -= amount1;\n        }\n        _update(balance0, balance1, _reserve0, _reserve1, _blockTimestampLast);\n        kLast = TridentMath.sqrt(balance0 * balance1);\n\n        withdrawnAmounts = new TokenAmount[](2);\n        withdrawnAmounts[0] = TokenAmount({token: address(token0), amount: amount0});\n        withdrawnAmounts[1] = TokenAmount({token: address(token1), amount: amount1});\n        emit Burn(msg.sender, amount0, amount1, recipient, liquidity);\n    }\n\n    /// @dev Burns LP tokens sent to this contract and swaps one of the output tokens for another\n    /// - i.e., the user gets a single token out by burning LP tokens.\n    function burnSingle(bytes calldata data) public override lock returns (uint256 amountOut) {\n        (address tokenOut, address recipient, bool unwrapBento) = abi.decode(data, (address, address, bool));\n        (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) = _getReserves();\n        uint256 liquidity = balanceOf[address(this)];\n\n        (uint256 _totalSupply, ) = _mintFee(_reserve0, _reserve1);\n\n        uint256 amount0 = (liquidity * _reserve0) / _totalSupply;\n        uint256 amount1 = (liquidity * _reserve1) / _totalSupply;\n\n        kLast = TridentMath.sqrt((_reserve0 - amount0) * (_reserve1 - amount1));\n\n        _burn(address(this), liquidity);\n\n        // Swap one token for another\n        unchecked {\n            if (tokenOut == token1) {\n                // @dev Swap `token0` for `token1`\n                // - calculate `amountOut` as if the user first withdrew balanced liquidity and then swapped `token0` for `token1`.\n                amount1 += _getAmountOut(amount0, _reserve0 - amount0, _reserve1 - amount1);\n                _transfer(token1, amount1, recipient, unwrapBento);\n                amountOut = amount1;\n                amount0 = 0;\n            } else {\n                // @dev Swap `token1` for `token0`.\n                require(tokenOut == token0, \"INVALID_OUTPUT_TOKEN\");\n                amount0 += _getAmountOut(amount1, _reserve1 - amount1, _reserve0 - amount0);\n                _transfer(token0, amount0, recipient, unwrapBento);\n                amountOut = amount0;\n                amount1 = 0;\n            }\n        }\n\n        (uint256 balance0, uint256 balance1) = _balance();\n        _update(balance0, balance1, _reserve0, _reserve1, _blockTimestampLast);\n\n        emit Burn(msg.sender, amount0, amount1, recipient, liquidity);\n    }\n\n    /// @dev Swaps one token for another. The router must prefund this contract and ensure there isn't too much slippage.\n    function swap(bytes calldata data) public override lock returns (uint256 amountOut) {\n        (address tokenIn, address recipient, bool unwrapBento) = abi.decode(data, (address, address, bool));\n        (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) = _getReserves();\n        require(_reserve0 > 0, \"POOL_UNINITIALIZED\");\n        (uint256 balance0, uint256 balance1) = _balance();\n        uint256 amountIn;\n        address tokenOut;\n        unchecked {\n            if (tokenIn == token0) {\n                tokenOut = token1;\n                amountIn = balance0 - _reserve0;\n                amountOut = _getAmountOut(amountIn, _reserve0, _reserve1);\n                balance1 -= amountOut;\n            } else {\n                require(tokenIn == token1, \"INVALID_INPUT_TOKEN\");\n                tokenOut = token0;\n                amountIn = balance1 - reserve1;\n                amountOut = _getAmountOut(amountIn, _reserve1, _reserve0);\n                balance0 -= amountOut;\n            }\n        }\n        _transfer(tokenOut, amountOut, recipient, unwrapBento);\n        _update(balance0, balance1, _reserve0, _reserve1, _blockTimestampLast);\n        emit Swap(recipient, tokenIn, tokenOut, amountIn, amountOut);\n    }\n\n    /// @dev Swaps one token for another. The router must support swap callbacks and ensure there isn't too much slippage.\n    function flashSwap(bytes calldata data) public override lock returns (uint256 amountOut) {\n        (address tokenIn, address recipient, bool unwrapBento, uint256 amountIn, bytes memory context) = abi.decode(\n            data,\n            (address, address, bool, uint256, bytes)\n        );\n        (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) = _getReserves();\n        require(_reserve0 > 0, \"POOL_UNINITIALIZED\");\n        unchecked {\n            if (tokenIn == token0) {\n                amountOut = _getAmountOut(amountIn, _reserve0, _reserve1);\n                _transfer(token1, amountOut, recipient, unwrapBento);\n                ITridentCallee(msg.sender).tridentSwapCallback(context);\n                (uint256 balance0, uint256 balance1) = _balance();\n                require(balance0 - _reserve0 >= amountIn, \"INSUFFICIENT_AMOUNT_IN\");\n                _update(balance0, balance1, _reserve0, _reserve1, _blockTimestampLast);\n                emit Swap(recipient, tokenIn, token1, amountIn, amountOut);\n            } else {\n                require(tokenIn == token1, \"INVALID_INPUT_TOKEN\");\n                amountOut = _getAmountOut(amountIn, _reserve1, _reserve0);\n                _transfer(token0, amountOut, recipient, unwrapBento);\n                ITridentCallee(msg.sender).tridentSwapCallback(context);\n                (uint256 balance0, uint256 balance1) = _balance();\n                require(balance1 - _reserve1 >= amountIn, \"INSUFFICIENT_AMOUNT_IN\");\n                _update(balance0, balance1, _reserve0, _reserve1, _blockTimestampLast);\n                emit Swap(recipient, tokenIn, token0, amountIn, amountOut);\n            }\n        }\n    }\n\n    /// @dev Updates `barFee` for Trident protocol.\n    function updateBarFee() public {\n        barFee = IMasterDeployer(masterDeployer).barFee();\n    }\n\n    function _getReserves()\n        internal\n        view\n        returns (\n            uint112 _reserve0,\n            uint112 _reserve1,\n            uint32 _blockTimestampLast\n        )\n    {\n        _reserve0 = reserve0;\n        _reserve1 = reserve1;\n        _blockTimestampLast = blockTimestampLast;\n    }\n\n    function _balance() internal view returns (uint256 balance0, uint256 balance1) {\n        balance0 = bento.balanceOf(token0, address(this));\n        balance1 = bento.balanceOf(token1, address(this));\n    }\n\n    function _update(\n        uint256 balance0,\n        uint256 balance1,\n        uint112 _reserve0,\n        uint112 _reserve1,\n        uint32 _blockTimestampLast\n    ) internal {\n        require(balance0 <= type(uint112).max && balance1 <= type(uint112).max, \"OVERFLOW\");\n        if (_blockTimestampLast == 0) {\n            // @dev TWAP support is disabled for gas efficiency.\n            reserve0 = uint112(balance0);\n            reserve1 = uint112(balance1);\n        } else {\n            uint32 blockTimestamp = uint32(block.timestamp);\n            if (blockTimestamp != _blockTimestampLast && _reserve0 != 0 && _reserve1 != 0) {\n                unchecked {\n                    uint32 timeElapsed = blockTimestamp - _blockTimestampLast;\n                    uint256 price0 = (uint256(_reserve1) << PRECISION) / _reserve0;\n                    price0CumulativeLast += price0 * timeElapsed;\n                    uint256 price1 = (uint256(_reserve0) << PRECISION) / _reserve1;\n                    price1CumulativeLast += price1 * timeElapsed;\n                }\n            }\n            reserve0 = uint112(balance0);\n            reserve1 = uint112(balance1);\n            blockTimestampLast = blockTimestamp;\n        }\n        emit Sync(balance0, balance1);\n    }\n\n    function _mintFee(uint112 _reserve0, uint112 _reserve1) internal returns (uint256 _totalSupply, uint256 computed) {\n        _totalSupply = totalSupply;\n        uint256 _kLast = kLast;\n        if (_kLast != 0) {\n            computed = TridentMath.sqrt(uint256(_reserve0) * _reserve1);\n            if (computed > _kLast) {\n                // @dev `barFee` % of increase in liquidity.\n                // It's going to be slightly less than `barFee` % in reality due to the math.\n                uint256 liquidity = (_totalSupply * (computed - _kLast) * barFee) / computed / MAX_FEE;\n                if (liquidity != 0) {\n                    _mint(barFeeTo, liquidity);\n                    _totalSupply += liquidity;\n                }\n            }\n        }\n    }\n\n    function _getAmountOut(\n        uint256 amountIn,\n        uint256 reserveAmountIn,\n        uint256 reserveAmountOut\n    ) internal view returns (uint256 amountOut) {\n        uint256 amountInWithFee = amountIn * MAX_FEE_MINUS_SWAP_FEE;\n        amountOut = (amountInWithFee * reserveAmountOut) / (reserveAmountIn * MAX_FEE + amountInWithFee);\n    }\n\n    function _getAmountIn(\n        uint256 amountOut,\n        uint256 reserveAmountIn,\n        uint256 reserveAmountOut\n    ) internal view returns (uint256 amountIn) {\n        amountIn = (reserveAmountIn * amountOut * MAX_FEE) / ((reserveAmountOut - amountOut) * MAX_FEE_MINUS_SWAP_FEE) + 1;\n    }\n\n    function _transfer(\n        address token,\n        uint256 shares,\n        address to,\n        bool unwrapBento\n    ) internal {\n        if (unwrapBento) {\n            bento.withdraw(token, address(this), to, 0, shares);\n        } else {\n            bento.transfer(token, address(this), to, shares);\n        }\n    }\n\n    /// @dev This fee is charged to cover for `swapFee` when users add unbalanced liquidity.\n    function _nonOptimalMintFee(\n        uint256 _amount0,\n        uint256 _amount1,\n        uint256 _reserve0,\n        uint256 _reserve1\n    ) internal view returns (uint256 token0Fee, uint256 token1Fee) {\n        if (_reserve0 == 0 || _reserve1 == 0) return (0, 0);\n        uint256 amount1Optimal = (_amount0 * _reserve1) / _reserve0;\n        if (amount1Optimal <= _amount1) {\n            token1Fee = (swapFee * (_amount1 - amount1Optimal)) / (2 * MAX_FEE);\n        } else {\n            uint256 amount0Optimal = (_amount1 * _reserve0) / _reserve1;\n            token0Fee = (swapFee * (_amount0 - amount0Optimal)) / (2 * MAX_FEE);\n        }\n    }\n\n    function getAssets() public view override returns (address[] memory assets) {\n        assets = new address[](2);\n        assets[0] = token0;\n        assets[1] = token1;\n    }\n\n    function getAmountOut(bytes calldata data) public view override returns (uint256 finalAmountOut) {\n        (address tokenIn, uint256 amountIn) = abi.decode(data, (address, uint256));\n        (uint112 _reserve0, uint112 _reserve1, ) = _getReserves();\n        if (tokenIn == token0) {\n            finalAmountOut = _getAmountOut(amountIn, _reserve0, _reserve1);\n        } else {\n            require(tokenIn == token1, \"INVALID_INPUT_TOKEN\");\n            finalAmountOut = _getAmountOut(amountIn, _reserve1, _reserve0);\n        }\n    }\n\n    function getAmountIn(bytes calldata data) public view override returns (uint256 finalAmountIn) {\n        (address tokenOut, uint256 amountOut) = abi.decode(data, (address, uint256));\n        (uint112 _reserve0, uint112 _reserve1, ) = _getReserves();\n        if (tokenOut == token1) {\n            finalAmountIn = _getAmountIn(amountOut, _reserve0, _reserve1);\n        } else {\n            require(tokenOut == token0, \"INVALID_OUTPUT_TOKEN\");\n            finalAmountIn = _getAmountIn(amountOut, _reserve1, _reserve0);\n        }\n    }\n\n    /// @dev returned values are in terms of BentoBox \"shares\".\n    function getReserves()\n        public\n        view\n        returns (\n            uint112 _reserve0,\n            uint112 _reserve1,\n            uint32 _blockTimestampLast\n        )\n    {\n        return _getReserves();\n    }\n\n    /// @dev returned values are the native ERC20 token amounts.\n    function getNativeReserves()\n        public\n        view\n        returns (\n            uint256 _nativeReserve0,\n            uint256 _nativeReserve1,\n            uint32 _blockTimestampLast\n        )\n    {\n        (uint112 _reserve0, uint112 _reserve1, uint32 __blockTimestampLast) = _getReserves();\n        _nativeReserve0 = bento.toAmount(token0, _reserve0, false);\n        _nativeReserve1 = bento.toAmount(token1, _reserve1, false);\n        _blockTimestampLast = __blockTimestampLast;\n    }\n}\n"
    },
    "contracts/pool/ConstantProductPoolFactory.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"./ConstantProductPool.sol\";\nimport \"./PoolDeployer.sol\";\n\n/// @notice Contract for deploying Trident exchange Constant Product Pool with configurations.\n/// @author Mudit Gupta.\ncontract ConstantProductPoolFactory is PoolDeployer {\n    constructor(address _masterDeployer) PoolDeployer(_masterDeployer) {}\n\n    function deployPool(bytes memory _deployData) external returns (address pool) {\n        (address tokenA, address tokenB, uint256 swapFee, bool twapSupport) = abi.decode(_deployData, (address, address, uint256, bool));\n\n        if (tokenA > tokenB) {\n            (tokenA, tokenB) = (tokenB, tokenA);\n        }\n\n        // @dev Strips any extra data.\n        _deployData = abi.encode(tokenA, tokenB, swapFee, twapSupport);\n\n        address[] memory tokens = new address[](2);\n        tokens[0] = tokenA;\n        tokens[1] = tokenB;\n\n        // @dev Salt is not actually needed since `_deployData` is part of creationCode and already contains the salt.\n        bytes32 salt = keccak256(_deployData);\n        pool = address(new ConstantProductPool{salt: salt}(_deployData, masterDeployer));\n        _registerPool(pool, tokens, salt);\n    }\n}\n"
    },
    "contracts/migration/Migrator.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"./IntermediaryToken.sol\";\nimport \"../interfaces/IMasterDeployer.sol\";\nimport \"../interfaces/IBentoBoxMinimal.sol\";\nimport \"../interfaces/IPoolFactory.sol\";\nimport \"../interfaces/IPool.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../interfaces/IConstantProductPool.sol\";\nimport \"../interfaces/IUniswapV2Minimal.sol\";\n\n/// @notice Trident pool migrator contract for legacy SushiSwap.\n/** Sushiswap's master chef contracts which distribute rewards to LP token holders have the option to migrate liquidity.\n    We can set this contract as the migrator on the master chef contracts to migrate LP positions from the legacy to the new Trident\n    constant product pools. After the migrator is set anyone can call the migrate() function (once per pool) on the master chef contract.\n    Used by MasterChef / MasterChefV2 / MiniChef. */\ncontract Migrator {\n    event Migrate(address indexed oldPool, address indexed newPool, address indexed intermediaryToken);\n\n    /// @dev Intermediary token to new LP token mapping.\n    /// @dev Used to prevent subsequent calls to masterchef's migrate function with the same PID.\n    mapping(address => address) public migrated;\n\n    IBentoBoxMinimal public immutable bento;\n    IMasterDeployer public immutable masterDeployer;\n    IPoolFactory public immutable constantProductPoolFactory;\n    address public immutable masterChef;\n\n    constructor(\n        IBentoBoxMinimal _bento,\n        IMasterDeployer _masterDeployer,\n        IPoolFactory _constantProductPoolFactory,\n        address _masterChef\n    ) {\n        bento = _bento;\n        masterDeployer = _masterDeployer;\n        constantProductPoolFactory = _constantProductPoolFactory;\n        masterChef = _masterChef;\n    }\n\n    /// @notice Method to migrate MasterChef's liquidity form the legacy SushiSwap AMM to the Trident constant product pool.\n    /// @param oldPool Legacy SushiSwap pool.\n    /// @dev Since MasterChef has a requierment to receive the same amount of \"LP\" tokens back after migration we use an\n    /// intermediary token so we can mint the desired balance. Anfer unstaking users can call redeem() on the intermediary\n    /// token to receive their share of the LP tokens of the new Trident constant product pool.\n    function migrate(IUniswapV2Minimal oldPool) external returns (address) {\n        require(msg.sender == address(masterChef), \"ONLY_CHEF\");\n        require(migrated[address(oldPool)] == address(0), \"ONLY_ONCE\");\n\n        address token0 = oldPool.token0();\n        address token1 = oldPool.token1();\n\n        bytes memory deployData = abi.encode(token0, token1, 30, false);\n\n        IConstantProductPool pool = IConstantProductPool(constantProductPoolFactory.configAddress(keccak256(deployData)));\n\n        // We deploy the pool if it doesn't exist yet.\n        if (address(pool) == address(0)) {\n            pool = IConstantProductPool(masterDeployer.deployPool(address(constantProductPoolFactory), deployData));\n        }\n\n        // We are migrating all of master chef's balance.\n        uint256 lpBalance = oldPool.balanceOf(address(masterChef));\n\n        if (lpBalance == 0) {\n            return address(pool);\n        }\n\n        // Remove the liquidity and send assets to BentoBox.\n        oldPool.transferFrom(address(masterChef), address(oldPool), lpBalance);\n        (uint256 amount0, uint256 amount1) = oldPool.burn(address(bento));\n\n        bento.deposit(token0, address(bento), address(pool), amount0, 0);\n        bento.deposit(token1, address(bento), address(pool), amount1, 0);\n\n        if (pool.totalSupply() != 0) {\n            // We require the pools' prices to differ by no more than 0.5%.\n            (uint256 _nativeReserve0, uint256 _nativeReserve1, ) = pool.getNativeReserves();\n            uint256 oldPoolPrice = (1e18 * amount0) / amount1;\n            uint256 newPoolPrice = (1e18 * _nativeReserve0) / _nativeReserve1;\n            uint256 priceChange = (1e3 * oldPoolPrice) / newPoolPrice;\n            require(priceChange < 1005 && priceChange >= 995, \"PRICE_DIFFERENCE\");\n        }\n\n        // We mint the intermediary token to Master Chef.\n        address intermediaryToken = address(new IntermediaryToken(address(pool), masterChef, lpBalance));\n\n        // The new Trident pool mints liquidity to the intermediary token.\n        pool.mint(abi.encode(intermediaryToken));\n\n        migrated[intermediaryToken] = address(pool);\n\n        emit Migrate(address(oldPool), address(pool), intermediaryToken);\n\n        return intermediaryToken;\n    }\n}\n"
    },
    "contracts/migration/IntermediaryToken.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"../pool/TridentERC20.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/// @notice Intermediary token users who are staked in MasterChef will receive after migration.\n/// Can be redeemed for the LP token of the new pool.\ncontract IntermediaryToken is TridentERC20 {\n    /// @dev Liquidity token of the Trident constant product pool.\n    IERC20 public immutable lpToken;\n\n    constructor(\n        address _lpToken,\n        address _recipient,\n        uint256 _amount\n    ) {\n        lpToken = IERC20(_lpToken);\n        _mint(_recipient, _amount);\n    }\n\n    /// @dev Since we might be rewarding the intermediary token for some time we allow users to mint it.\n    function deposit(uint256 amount) public returns (uint256 minted) {\n        uint256 availableLpTokens = lpToken.balanceOf(address(this));\n        if (availableLpTokens != 0) {\n            minted = (totalSupply * amount) / availableLpTokens;\n        } else {\n            minted = amount;\n        }\n        _mint(msg.sender, minted);\n        require(lpToken.transferFrom(msg.sender, address(this), amount), \"TRANSFER_FROM_FAILED\");\n    }\n\n    function redeem(uint256 amount) public returns (uint256 claimed) {\n        uint256 availableLpTokens = lpToken.balanceOf(address(this));\n        claimed = (availableLpTokens * amount) / totalSupply;\n        _burn(msg.sender, amount);\n        require(lpToken.transfer(msg.sender, claimed), \"TRANSFER_FAILED\");\n    }\n}\n"
    },
    "contracts/interfaces/IConstantProductPool.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./IPool.sol\";\n\ninterface IConstantProductPool is IPool, IERC20 {\n    function getNativeReserves()\n        external\n        view\n        returns (\n            uint256 _nativeReserve0,\n            uint256 _nativeReserve1,\n            uint32\n        );\n}\n"
    },
    "contracts/pool/concentrated/ConcentratedLiquidityPoolStaker.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"../../interfaces/concentratedPool/IConcentratedLiquidityPool.sol\";\nimport \"../../libraries/concentratedPool/Ticks.sol\";\nimport \"../../interfaces/IBentoBoxMinimal.sol\";\nimport {IConcentratedLiquidityPoolManager as IPoolManager} from \"../../interfaces/concentratedPool/IConcentratedLiquidityPoolManager.sol\";\n\n/// @notice Trident Concentrated Liquidity Pool periphery contract that combines non-fungible position management and staking.\ncontract ConcentratedLiquidityPoolStaker {\n    event AddIncentive(IConcentratedLiquidityPool indexed pool, uint256 indexed incentiveId, address indexed rewardToken);\n    event Subscribe(uint256 indexed positionId, uint256 indexed incentiveId);\n    event ClaimReward(uint256 indexed positionId, uint256 indexed incentiveId, address indexed recipient, uint96 amount);\n    event ReclaimIncentive(IConcentratedLiquidityPool indexed pool, uint256 indexed incentiveId, uint256 amount);\n\n    struct Incentive {\n        address owner;\n        address token;\n        uint32 startTime;\n        uint32 endTime;\n        uint32 expiry;\n        uint160 secondsClaimed; // @dev x128.\n        uint96 rewardsUnclaimed;\n    }\n\n    struct Stake {\n        uint160 secondsGrowthInsideLast; // @dev x128.\n        uint32 timestamp;\n    }\n\n    IBentoBoxMinimal public immutable bento;\n    IPoolManager public poolManager;\n\n    mapping(IConcentratedLiquidityPool => uint256) public incentiveCount;\n    mapping(IConcentratedLiquidityPool => mapping(uint256 => Incentive)) public incentives;\n    /// @dev When subscribing to an incentive we take a snapshot of the position secondsGrowth accumulator.\n    /// @dev positionId to incentiveId to position's secondsGrowth snapshot mapping.\n    mapping(uint256 => mapping(uint256 => Stake)) public stakes;\n\n    constructor(IPoolManager _poolManager) {\n        poolManager = _poolManager;\n        IBentoBoxMinimal _bento = IBentoBoxMinimal(_poolManager.bento());\n        _bento.registerProtocol();\n        bento = _bento;\n    }\n\n    function addIncentive(IConcentratedLiquidityPool pool, Incentive memory incentive) public {\n        uint32 current = uint32(block.timestamp);\n        require(current <= incentive.startTime, \"ALREADY_STARTED\");\n        require(incentive.startTime < incentive.endTime, \"START_PAST_END\");\n        require(incentive.endTime + 90 days < incentive.expiry, \"END_PAST_BUFFER\");\n        require(incentive.rewardsUnclaimed != 0, \"NO_REWARDS\");\n        incentive.secondsClaimed = 0;\n        incentives[pool][incentiveCount[pool]++] = incentive;\n        _transfer(incentive.token, msg.sender, address(this), incentive.rewardsUnclaimed, false);\n        emit AddIncentive(pool, incentiveCount[pool], incentive.token);\n    }\n\n    /// @dev Withdraws any unclaimed incentive rewards.\n    function reclaimIncentive(\n        IConcentratedLiquidityPool pool,\n        uint256 incentiveId,\n        address receiver,\n        uint96 amount,\n        bool unwrapBento\n    ) public {\n        Incentive storage incentive = incentives[pool][incentiveId];\n        require(incentive.owner == msg.sender, \"NOT_OWNER\");\n        require(incentive.expiry < block.timestamp, \"EXPIRED\");\n        require(incentive.rewardsUnclaimed >= amount, \"ALREADY_CLAIMED\");\n        incentive.rewardsUnclaimed -= uint96(amount);\n        _transfer(incentive.token, address(this), receiver, amount, unwrapBento);\n        emit ReclaimIncentive(pool, incentiveId, amount);\n    }\n\n    /// @dev Subscribes a non-fungible position token to an incentive.\n    function subscribe(uint256 positionId, uint256[] calldata incentiveId) external {\n        require(poolManager.ownerOf(positionId) == msg.sender, \"NOT_OWNER\");\n        IPoolManager.Position memory position = poolManager.positions(positionId);\n        IConcentratedLiquidityPool pool = position.pool;\n        require(position.liquidity != 0, \"INACTIVE\");\n        Stake memory stakeData = Stake(uint160(rangeSecondsInside(pool, position.lower, position.upper)), uint32(block.timestamp));\n        for (uint256 i; i < incentiveId.length; i++) {\n            Incentive memory incentive = incentives[pool][incentiveId[i]];\n            Stake storage stake = stakes[positionId][incentiveId[i]];\n            require(stake.secondsGrowthInsideLast == 0, \"SUBSCRIBED\");\n            require(block.timestamp >= incentive.startTime && block.timestamp < incentive.endTime, \"INACTIVE_INCENTIVE\");\n            stakes[positionId][incentiveId[i]] = stakeData;\n            emit Subscribe(positionId, incentiveId[i]);\n        }\n    }\n\n    function claimRewards(\n        uint256 positionId,\n        uint256[] memory incentiveIds,\n        address recipient,\n        bool unwrapBento\n    ) public {\n        require(poolManager.ownerOf(positionId) == msg.sender, \"NOT_OWNER\");\n\n        IPoolManager.Position memory position = poolManager.positions(positionId);\n        IConcentratedLiquidityPool pool = position.pool;\n\n        uint256 currentSecondsGrowth = rangeSecondsInside(pool, position.lower, position.upper);\n\n        for (uint256 i = 0; i < incentiveIds.length; i++) {\n            Incentive storage incentive = incentives[pool][incentiveIds[i]];\n            Stake storage stake = stakes[positionId][incentiveIds[i]];\n\n            require(stake.timestamp >= position.latestAddition, \"MUST_RESUBSCRIBE\");\n\n            uint256 rewards;\n            uint256 secondsInside;\n\n            {\n                uint256 secondsGrowth = currentSecondsGrowth - stake.secondsGrowthInsideLast;\n                uint256 maxTime = block.timestamp < incentive.endTime ? incentive.endTime : block.timestamp;\n                uint256 secondsUnclaimed = ((maxTime - incentive.startTime) << 128) - incentive.secondsClaimed;\n                secondsInside = secondsGrowth * position.liquidity; // secondsGrowth is multiplied by 2**128\n                rewards = (incentive.rewardsUnclaimed * secondsInside) / secondsUnclaimed; // 2**128 cancels out\n            }\n\n            stake.secondsGrowthInsideLast = uint160(currentSecondsGrowth);\n            incentive.secondsClaimed += uint160(secondsInside);\n            incentive.rewardsUnclaimed -= uint96(rewards);\n\n            _transfer(incentive.token, address(this), recipient, rewards, unwrapBento);\n\n            emit ClaimReward(positionId, incentiveIds[i], recipient, uint96(rewards));\n        }\n    }\n\n    function getReward(uint256 positionId, uint256 incentiveId) public view returns (uint256 rewards, uint256 secondsInside) {\n        IPoolManager.Position memory position = poolManager.positions(positionId);\n        IConcentratedLiquidityPool pool = position.pool;\n        Incentive memory incentive = incentives[pool][positionId];\n        Stake memory stake = stakes[positionId][incentiveId];\n        if (stake.timestamp > 0) {\n            uint256 secondsGrowth = rangeSecondsInside(pool, position.lower, position.upper) - stake.secondsGrowthInsideLast;\n            secondsInside = secondsGrowth * position.liquidity;\n            uint256 maxTime = block.timestamp < incentive.endTime ? incentive.endTime : block.timestamp;\n            uint256 secondsUnclaimed = ((maxTime - incentive.startTime) << 128) - incentive.secondsClaimed;\n            rewards = (incentive.rewardsUnclaimed * secondsInside) / secondsUnclaimed;\n        }\n    }\n\n    /// @dev Calculates the \"seconds per liquidity\" accumulator for a range.\n    function rangeSecondsInside(\n        IConcentratedLiquidityPool pool,\n        int24 lowerTick,\n        int24 upperTick\n    ) public view returns (uint256 secondsInside) {\n        (, int24 currentTick) = pool.getPriceAndNearestTicks();\n\n        Ticks.Tick memory lower = pool.ticks(lowerTick);\n        Ticks.Tick memory upper = pool.ticks(upperTick);\n\n        (uint256 secondsGrowthGlobal, ) = pool.getSecondsGrowthAndLastObservation();\n        uint256 secondsBelow;\n        uint256 secondsAbove;\n\n        if (lowerTick <= currentTick) {\n            secondsBelow = lower.secondsGrowthOutside;\n        } else {\n            secondsBelow = secondsGrowthGlobal - lower.secondsGrowthOutside;\n        }\n\n        if (currentTick < upperTick) {\n            secondsAbove = upper.secondsGrowthOutside;\n        } else {\n            secondsAbove = secondsGrowthGlobal - upper.secondsGrowthOutside;\n        }\n\n        secondsInside = secondsGrowthGlobal - secondsBelow - secondsAbove;\n    }\n\n    function _transfer(\n        address token,\n        address from,\n        address to,\n        uint256 shares,\n        bool unwrapBento\n    ) internal {\n        if (unwrapBento) {\n            bento.withdraw(token, from, to, 0, shares);\n        } else {\n            bento.transfer(token, from, to, shares);\n        }\n    }\n}\n"
    },
    "contracts/pool/concentrated/ConcentratedLiquidityPoolHelper.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"../../interfaces/concentratedPool/IConcentratedLiquidityPool.sol\";\nimport \"../../libraries/concentratedPool/TickMath.sol\";\nimport \"../../libraries/concentratedPool/Ticks.sol\";\n\n/// @notice Trident Concentrated Liquidity Pool periphery contract to read state.\ncontract ConcentratedLiquidityPoolHelper {\n    struct SimpleTick {\n        int24 index;\n        uint128 liquidity;\n    }\n\n    function getTickState(IConcentratedLiquidityPool pool, uint24 tickCount) external view returns (SimpleTick[] memory) {\n        SimpleTick[] memory ticks = new SimpleTick[](tickCount); // todo save tickCount in the core contract\n\n        Ticks.Tick memory tick;\n        uint24 i;\n        int24 current = TickMath.MIN_TICK;\n\n        while (current != TickMath.MAX_TICK) {\n            tick = pool.ticks(current);\n            ticks[i++] = SimpleTick({index: current, liquidity: tick.liquidity});\n            current = tick.nextTick;\n        }\n\n        tick = pool.ticks(current);\n        ticks[i] = SimpleTick({index: TickMath.MAX_TICK, liquidity: tick.liquidity});\n\n        return ticks;\n    }\n}\n"
    },
    "contracts/test/TickMathTest.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.0;\n\nimport \"../libraries/concentratedPool/TickMath.sol\";\n\ncontract TickMathTest {\n    function getSqrtRatioAtTick(int24 tick) external pure returns (uint160) {\n        return TickMath.getSqrtRatioAtTick(tick);\n    }\n\n    function getTickAtSqrtRatio(uint160 sqrtPriceX96) external pure returns (int24) {\n        return TickMath.getTickAtSqrtRatio(sqrtPriceX96);\n    }\n}\n"
    },
    "contracts/mocks/TridentMathConsumerMock.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity ^0.8.2;\n\nimport \"../libraries/TridentMath.sol\";\n\ncontract TridentMathConsumerMock {\n    function sqrt(uint256 x) public pure returns (uint256) {\n        return TridentMath.sqrt(x);\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/ERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n    mapping(address => uint256) private _balances;\n\n    mapping(address => mapping(address => uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n\n    string private _name;\n    string private _symbol;\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * The default value of {decimals} is 18. To select a different value for\n     * {decimals} you should overload it.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    constructor(string memory name_, string memory symbol_) {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the value {ERC20} uses, unless this function is\n     * overridden;\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual override returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual override returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `recipient` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {\n        _transfer(_msgSender(), recipient, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 amount) public virtual override returns (bool) {\n        _approve(_msgSender(), spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * Requirements:\n     *\n     * - `sender` and `recipient` cannot be the zero address.\n     * - `sender` must have a balance of at least `amount`.\n     * - the caller must have allowance for ``sender``'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(\n        address sender,\n        address recipient,\n        uint256 amount\n    ) public virtual override returns (bool) {\n        _transfer(sender, recipient, amount);\n\n        uint256 currentAllowance = _allowances[sender][_msgSender()];\n        require(currentAllowance >= amount, \"ERC20: transfer amount exceeds allowance\");\n        unchecked {\n            _approve(sender, _msgSender(), currentAllowance - amount);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n        _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);\n        return true;\n    }\n\n    /**\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n        uint256 currentAllowance = _allowances[_msgSender()][spender];\n        require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n        unchecked {\n            _approve(_msgSender(), spender, currentAllowance - subtractedValue);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Moves `amount` of tokens from `sender` to `recipient`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `sender` cannot be the zero address.\n     * - `recipient` cannot be the zero address.\n     * - `sender` must have a balance of at least `amount`.\n     */\n    function _transfer(\n        address sender,\n        address recipient,\n        uint256 amount\n    ) internal virtual {\n        require(sender != address(0), \"ERC20: transfer from the zero address\");\n        require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n        _beforeTokenTransfer(sender, recipient, amount);\n\n        uint256 senderBalance = _balances[sender];\n        require(senderBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n        unchecked {\n            _balances[sender] = senderBalance - amount;\n        }\n        _balances[recipient] += amount;\n\n        emit Transfer(sender, recipient, amount);\n\n        _afterTokenTransfer(sender, recipient, amount);\n    }\n\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function _mint(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        _beforeTokenTransfer(address(0), account, amount);\n\n        _totalSupply += amount;\n        _balances[account] += amount;\n        emit Transfer(address(0), account, amount);\n\n        _afterTokenTransfer(address(0), account, amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: burn from the zero address\");\n\n        _beforeTokenTransfer(account, address(0), amount);\n\n        uint256 accountBalance = _balances[account];\n        require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n        unchecked {\n            _balances[account] = accountBalance - amount;\n        }\n        _totalSupply -= amount;\n\n        emit Transfer(account, address(0), amount);\n\n        _afterTokenTransfer(account, address(0), amount);\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(\n        address owner,\n        address spender,\n        uint256 amount\n    ) internal virtual {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual {}\n\n    /**\n     * @dev Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * has been transferred to `to`.\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual {}\n}\n"
    },
    "@openzeppelin/contracts/utils/Context.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n}\n"
    },
    "contracts/mocks/ERC20Mock.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity ^0.8.2;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract ERC20Mock is ERC20 {\n    event Deposit(address indexed dst, uint256 wad);\n    event Withdrawal(address indexed src, uint256 wad);\n\n    constructor(\n        string memory name,\n        string memory symbol,\n        uint256 supply\n    ) ERC20(name, symbol) {\n        _mint(msg.sender, supply);\n    }\n\n    receive() external payable {\n        deposit();\n    }\n\n    function deposit() public payable {\n        _mint(msg.sender, msg.value);\n        emit Deposit(msg.sender, msg.value);\n    }\n\n    function withdraw(uint256 wad) public {\n        _burn(msg.sender, wad);\n        payable(msg.sender).transfer(wad);\n        emit Withdrawal(msg.sender, wad);\n    }\n}\n"
    },
    "contracts/mocks/WETH9.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity ^0.8.2;\n\nimport \"./ERC20Mock.sol\";\n\ncontract WETH9 is ERC20Mock {\n    constructor() ERC20Mock(\"WETH9\", \"WETH9\", 0) {}\n}\n"
    },
    "contracts/examples/PoolFactory.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity ^0.8.2;\n\nimport \"../interfaces/IPoolFactory.sol\";\n\nimport \"./PoolTemplate.sol\";\n\n/**\n * @author Mudit Gupta\n */\nabstract contract PoolFactory is IPoolFactory {\n    // Consider deploying via an upgradable proxy to allow upgrading pools in the future\n\n    function deployPool(bytes memory _deployData) external override returns (address) {\n        return address(new PoolTemplate(_deployData));\n    }\n}\n"
    },
    "contracts/examples/PoolTemplate.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity ^0.8.2;\n\n/**\n * @author Mudit Gupta\n */\ncontract PoolTemplate {\n    uint256 public immutable configValue;\n    address public immutable anotherConfigValue;\n\n    constructor(bytes memory _data) {\n        (configValue, anotherConfigValue) = abi.decode(_data, (uint256, address));\n    }\n}\n"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 99999
    },
    "outputSelection": {
      "*": {
        "*": [
          "abi",
          "evm.bytecode",
          "evm.deployedBytecode",
          "evm.methodIdentifiers",
          "metadata",
          "devdoc",
          "userdoc",
          "storageLayout",
          "evm.gasEstimates"
        ],
        "": [
          "ast"
        ]
      }
    },
    "metadata": {
      "useLiteralContent": true
    },
    "libraries": {
      "": {
        "__CACHE_BREAKER__": "0x00000000d41867734bbee4c6863d9255b2b06ac1"
      }
    }
  }
}