{
  "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/TridentRouter.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"./interfaces/IBentoBoxMinimal.sol\";\nimport \"./interfaces/IPool.sol\";\nimport \"./interfaces/ITridentRouter.sol\";\nimport \"./utils/TridentHelper.sol\";\nimport \"./deployer/MasterDeployer.sol\";\n\n/// @notice Router contract that helps in swapping across Trident pools.\ncontract TridentRouter is ITridentRouter, TridentHelper {\n    /// @notice BentoBox token vault.\n    IBentoBoxMinimal public immutable bento;\n    MasterDeployer public immutable masterDeployer;\n\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        MasterDeployer _masterDeployer,\n        address _wETH\n    ) TridentHelper(_wETH) {\n        _bento.registerProtocol();\n        bento = _bento;\n        masterDeployer = _masterDeployer;\n    }\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        // @dev The pool must ensure that there's not too much slippage.\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    function deployPool(address _factory, bytes calldata _deployData) external returns (address) {\n        return masterDeployer.deployPool(_factory, _deployData);\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/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"
    },
    "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    /// @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/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; // @dev 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/utils/TridentHelper.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"../TridentRouter.sol\";\n\n/// @notice Trident router helper contract.\ncontract TridentHelper {\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(address _wETH) {\n        wETH = _wETH;\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    /// @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                // @dev 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    /// @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 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)); // @dev permit(address,address,uint256,uint256,uint8,bytes32,bytes32).\n        require(success, \"PERMIT_FAILED\");\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)); // @dev permit(address,address,uint256,uint256,bool,uint8,bytes32,bytes32).\n        require(success, \"PERMIT_FAILED\");\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/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/pool/concentrated/ConcentratedLiquidityPosition.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"../../interfaces/IBentoBoxMinimal.sol\";\nimport \"../../interfaces/IConcentratedLiquidityPool.sol\";\nimport \"../../interfaces/IMasterDeployer.sol\";\nimport \"../../interfaces/ITridentRouter.sol\";\nimport \"../../libraries/concentratedPool/FullMath.sol\";\nimport \"./TridentNFT.sol\";\n\n\n/// @notice Trident Concentrated Liquidity Pool periphery contract that combines non-fungible position management and staking.\nabstract contract ConcentratedLiquidityPosition is TridentNFT {\n    event Mint(address indexed pool, address indexed recipient, uint256 indexed positionId);\n    event Burn(address indexed pool, address indexed owner, uint256 indexed positionId);\n\n    IBentoBoxMinimal public immutable bento;\n    IMasterDeployer public immutable masterDeployer;\n\n    mapping(uint256 => Position) public positions;\n\n    struct Position {\n        IConcentratedLiquidityPool pool;\n        uint128 liquidity;\n        int24 lower;\n        int24 upper;\n        uint256 feeGrowthInside0; /// @dev Per unit of liquidity.\n        uint256 feeGrowthInside1;\n    }\n\n    constructor(address _masterDeployer) {\n        /// @dev Don't need to check _masterDeployer != address(0) as we make a call to it.\n        masterDeployer = IMasterDeployer(_masterDeployer);\n        IBentoBoxMinimal _bento = IBentoBoxMinimal(IMasterDeployer(_masterDeployer).bento());\n        _bento.registerProtocol();\n        bento = _bento;\n    }\n\n    function positionMintCallback(\n        address recipient,\n        int24 lower,\n        int24 upper,\n        uint128 amount,\n        uint256 feeGrowthInside0,\n        uint256 feeGrowthInside1\n    ) external returns (uint256 positionId) {\n        require(IMasterDeployer(masterDeployer).pools(msg.sender), \"NOT_POOL\");\n        positions[totalSupply] = Position(IConcentratedLiquidityPool(msg.sender), amount, lower, upper, feeGrowthInside0, feeGrowthInside1);\n        positionId = totalSupply;\n        _mint(recipient);\n        emit Mint(msg.sender, recipient, positionId);\n    }\n\n    function burn(\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        if (position.liquidity < amount) amount = position.liquidity;\n\n        position.pool.burn(abi.encode(position.lower, position.upper, amount, recipient, unwrapBento));\n\n        if (amount < position.liquidity) {\n            position.liquidity -= amount;\n        } else {\n            delete positions[tokenId];\n            _burn(tokenId);\n        }\n        emit Burn(address(position.pool), msg.sender, tokenId);\n    }\n\n    function collect(\n        uint256 tokenId,\n        address recipient,\n        bool unwrapBento\n    ) external returns (uint256 token0amount, uint256 token1amount) {\n        require(msg.sender == ownerOf[tokenId], \"NOT_ID_OWNER\");\n\n        Position storage position = positions[tokenId];\n\n        (address token0, address token1) = _getAssets(position.pool);\n\n        {\n            (uint256 feeGrowthInside0, uint256 feeGrowthInside1) = position.pool.rangeFeeGrowth(position.lower, position.upper);\n            token0amount = FullMath.mulDiv(\n                feeGrowthInside0 - position.feeGrowthInside0,\n                position.liquidity,\n                0x100000000000000000000000000000000\n            );\n            token1amount = FullMath.mulDiv(\n                feeGrowthInside1 - position.feeGrowthInside1,\n                position.liquidity,\n                0x100000000000000000000000000000000\n            );\n\n            position.feeGrowthInside0 = feeGrowthInside0;\n            position.feeGrowthInside1 = feeGrowthInside1;\n        }\n\n        uint256 balance0 = bento.balanceOf(token0, address(this));\n        uint256 balance1 = bento.balanceOf(token1, address(this));\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 raw\n            if (token0amount > newBalance0) token0amount = newBalance0;\n            if (token1amount > newBalance1) token1amount = newBalance1;\n        }\n        _transfer(token0, address(this), recipient, token0amount, unwrapBento);\n        _transfer(token1, address(this), recipient, token1amount, unwrapBento);\n    }\n\n    function _getAssets(IConcentratedLiquidityPool pool) internal view returns (address token0, address token1) {\n        address[] memory pair = pool.getAssets();\n        token0 = pair[0];\n        token1 = pair[1];\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/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 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 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/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/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            // @dev 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; // @dev Least significant 256 bits of the product.\n            uint256 prod1; // @dev 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            // @dev 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            // @dev 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            // @dev 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            // @dev Subtract 256 bit number from 512 bit number.\n            assembly {\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n            // @dev 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            // @dev Divide denominator by power of two.\n            assembly {\n                denominator := div(denominator, twos)\n            }\n            // @dev Divide [prod1 prod0] by the factors of two.\n            assembly {\n                prod0 := div(prod0, twos)\n            }\n            // @dev 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            // @dev 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            // @dev 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; // @dev Inverse mod 2**8.\n            inv *= 2 - denominator * inv; // @dev Inverse mod 2**16.\n            inv *= 2 - denominator * inv; // @dev Inverse mod 2**32.\n            inv *= 2 - denominator * inv; // @dev Inverse mod 2**64.\n            inv *= 2 - denominator * inv; // @dev Inverse mod 2**128.\n            inv *= 2 - denominator * inv; // @dev Inverse mod 2**256.\n            // @dev 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/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/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\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; /// @dev Per unit of liquidity.\n        uint256 feeGrowthOutside1;\n        uint160 secondsGrowthOutside;\n    }\n\n    function getMaxLiquidity(uint24 _tickSpacing) internal 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            /// @dev 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            /// @dev 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            /// @dev 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            /// @dev 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            /// @dev 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            /// @dev 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/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    /// @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        require(absTick <= uint256(uint24(MAX_TICK)), \"TICK_OUT_OF_BOUNDS\");\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            // @dev 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        // @dev Second inequality must be < because the price can never reach the price at the max tick.\n        require(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, \"R\");\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; // @dev 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/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/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\n/// @notice Trident exchange pool template with concentrated liquidity and 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 ConcentratedLiquidityPool is IPool {\n    using Ticks for mapping(int24 => Ticks.Tick);\n\n    event Mint(address indexed sender, uint256 amount0, uint256 amount1, address indexed recipient);\n    event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed recipient);\n    event Collect(address indexed sender, uint256 amount0, uint256 amount1);\n    event Sync(uint256 reserveShares0, uint256 reserveShares1);\n\n    /// @dev References for tickSpacing:\n    // 100 tickSpacing -> 2% between ticks.\n    bytes32 public constant override poolIdentifier = \"Trident:ConcentratedLiquidity\";\n\n    uint24 internal constant MAX_FEE = 100000; /// @dev Maximum `swapFee` is 10%.\n\n    uint128 internal immutable MAX_TICK_LIQUIDITY;\n    uint24 internal immutable tickSpacing;\n    uint24 internal immutable swapFee; /// @dev 1000 corresponds to 0.1% fee. Fee is measured in pips.\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    modifier lock() {\n        require(unlocked == 1, \"LOCKED\");\n        unlocked = 2;\n        _;\n        unlocked = 1;\n    }\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        /// @dev To mint an NFT the positionOwner should be set to the positionManager contract.\n        address positionOwner;\n        /// @dev When minting through the positionManager contract positionRecipient should be the NFT recipient.\n        //    It can be set to address(0) if we are not minting through the positionManager contract.\n        address positionRecipient;\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        require(_token0 != address(0), \"ZERO_ADDRESS\");\n        require(_token0 != address(this), \"INVALID_TOKEN0\");\n        require(_token1 != address(this), \"INVALID_TOKEN1\");\n        require(_swapFee <= MAX_FEE, \"INVALID_SWAP_FEE\");\n\n        token0 = _token0;\n        token1 = _token1;\n        swapFee = _swapFee;\n        price = _price;\n        tickSpacing = _tickSpacing;\n        /// @dev 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 LP tokens are minted by using the return value.\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            require(_liquidity <= MAX_TICK_LIQUIDITY, \"LIQUIDITY_OVERFLOW\");\n\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) = _getAmountsForLiquidity(priceLower, priceUpper, currentPrice, _liquidity, true);\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\n        ITridentCallee(msg.sender).tridentMintCallback(abi.encode(callbackData));\n\n        unchecked {\n            if (amount0Actual != 0) {\n                require(amount0Actual + reserve0 <= _balance(token0), \"TOKEN0_MISSING\");\n                reserve0 += amount0Actual;\n            }\n\n            if (amount1Actual != 0) {\n                require(amount1Actual + reserve1 <= _balance(token1), \"TOKEN1_MISSING\");\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            );\n        }\n\n        emit Mint(mintParams.positionOwner, amount0Actual, amount1Actual, mintParams.positionRecipient);\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        (int24 lower, int24 upper, uint128 amount, address recipient, bool unwrapBento) = abi.decode(\n            data,\n            (int24, int24, uint128, address, bool)\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        (uint256 amount0, uint256 amount1) = _getAmountsForLiquidity(\n            uint256(priceLower),\n            uint256(priceUpper),\n            uint256(currentPrice),\n            uint256(amount),\n            false\n        );\n\n        (uint256 amount0fees, uint256 amount1fees) = _updatePosition(msg.sender, lower, upper, -int128(amount));\n\n        unchecked {\n            amount0 += amount0fees;\n            amount1 += amount1fees;\n        }\n\n        withdrawnAmounts = new TokenAmount[](2);\n        withdrawnAmounts[0] = TokenAmount({token: token0, amount: amount0});\n        withdrawnAmounts[1] = TokenAmount({token: token1, amount: amount1});\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, recipient);\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); /// @dev 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                    /// @dev 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                    /// @dev 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        require(lower % int24(tickSpacing) == 0, \"INVALID_TICK\");\n        require((lower / int24(tickSpacing)) % 2 == 0, \"LOWER_EVEN\");\n\n        require(upper % int24(tickSpacing) == 0, \"INVALID_TICK\");\n        require((upper / int24(tickSpacing)) % 2 != 0, \"UPPER_ODD\"); /// @dev Can be either -1 or 1.\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            /// @dev Only supply `token1` (`token1` is Y).\n            token1amount = uint128(DyDxMath.getDy(liquidityAmount, priceLower, priceUpper, roundUp));\n        } else if (currentPrice <= priceLower) {\n            /// @dev Only supply `token0` (`token0` is X).\n            token0amount = uint128(DyDxMath.getDx(liquidityAmount, priceLower, priceUpper, roundUp));\n        } else {\n            /// @dev 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    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            require(uint256(newBalance) <= balance0, \"TOKEN0_MISSING\");\n            reserve0 = newBalance;\n            reserve1 -= uint128(amountOut);\n        } else {\n            uint256 balance1 = _balance(token1);\n            uint128 newBalance = reserve1 + inAmount;\n            require(uint256(newBalance) <= balance1, \"TOKEN1_MISSING\");\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    ) internal returns (uint256 amount0fees, uint256 amount1fees) {\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        if (amount < 0) position.liquidity -= uint128(-amount);\n        if (amount > 0) position.liquidity += uint128(amount);\n\n        require(position.liquidity < MAX_TICK_LIQUIDITY, \"MAX_TICK_LIQUIDITY\");\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        /// @dev 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    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; /// @dev 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/IPositionManager.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\n/// @notice Trident Concentrated Liquidity Pool Position manager interface.\ninterface IPositionManager {\n    function positionMintCallback(\n        address recipient,\n        int24 lower,\n        int24 upper,\n        uint128 amount,\n        uint256 feeGrowthInside0,\n        uint256 feeGrowthInside1\n    ) external returns (uint256 positionId);\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/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/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    ) internal 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"
    },
    "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\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        /// @dev Calculate `protocolFee` and convert pips to bips.\n        uint256 feeDelta = FullMath.mulDivRoundingUp(feeAmount, barFee, 1e4);\n\n        protocolFee += feeDelta;\n\n        /// @dev 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    modifier onlyMaster() {\n        require(msg.sender == masterDeployer, \"UNAUTHORIZED_DEPLOYER\");\n        _;\n    }\n\n    constructor(address _masterDeployer) {\n        require(_masterDeployer != address(0), \"ZERO_ADDRESS\");\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                require(tokens[i] < tokens[i + 1], \"INVALID_TOKEN_ORDER\");\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 endIndex\n    ) external view returns (address[] memory pairPools) {\n        pairPools = new address[](endIndex - startIndex);\n        for (uint256 i = 0; startIndex < endIndex; i++) {\n            pairPools[i] = pools[token0][token1][startIndex];\n            startIndex++;\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 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);\n    event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed recipient);\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        emit Mint(msg.sender, amount0, amount1, recipient);\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);\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);\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            finalAmountOut = bento.toShare(token0, _getAmountOut(amountIn, _reserve0, _reserve1, false), false);\n        }\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 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);\n    event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed recipient);\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        emit Mint(msg.sender, amount0, amount1, recipient);\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);\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);\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            finalAmountOut = _getAmountOut(amountIn, _reserve0, _reserve1, false);\n        }\n    }\n\n    function getReserves() public view returns (uint256 _reserve0, uint256 _reserve1) {\n        (_reserve0, _reserve1) = _getReserves();\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);\n    event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed recipient);\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        emit Mint(msg.sender, amount0, amount1, recipient);\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);\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);\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 % 2**32);\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            finalAmountOut = _getAmountOut(amountIn, _reserve1, _reserve0);\n        }\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/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);\n    event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed recipient);\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        emit Mint(msg.sender, amount0, amount1, recipient);\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);\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 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        kLast = TridentMath.sqrt((uint256(_reserve0) - amount0) * (uint256(_reserve1) - amount1));\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                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        emit Burn(msg.sender, amount0, amount1, 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 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 % 2**32);\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 _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            finalAmountOut = _getAmountOut(amountIn, _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\";\n\n/// @dev Legacy SushiSwap AMM interface\ninterface IOldPool 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    function mint(bytes calldata data) external returns (uint256 liquidity);\n}\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(IOldPool 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/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/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/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"
    },
    "contracts/pool/concentrated/ConcentratedLiquidityPoolManager.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"../../interfaces/IConcentratedLiquidityPool.sol\";\nimport \"./ConcentratedLiquidityPosition.sol\";\nimport \"../../libraries/concentratedPool/Ticks.sol\";\n\n\n/// @notice Trident Concentrated Liquidity Pool periphery contract that combines non-fungible position management and staking.\ncontract ConcentratedLiquidityPoolManager is ConcentratedLiquidityPosition {\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        uint160 secondsClaimed; // @dev x128.\n        uint96 rewardsUnclaimed;\n        uint32 startTime;\n        uint32 endTime;\n        uint32 expiry;\n    }\n\n    struct Stake {\n        uint160 secondsGrowthInsideLast; // @dev x128.\n        bool initialized;\n    }\n\n    mapping(IConcentratedLiquidityPool => uint256) public incentiveCount;\n    mapping(IConcentratedLiquidityPool => mapping(uint256 => Incentive)) public incentives;\n    mapping(uint256 => mapping(uint256 => Stake)) public stakes;\n\n    constructor(address _masterDeployer) ConcentratedLiquidityPosition(_masterDeployer) {}\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 incentiveId) public {\n        require(ownerOf[positionId] == msg.sender, \"OWNER\");\n        Position memory position = positions[positionId];\n        IConcentratedLiquidityPool pool = position.pool;\n        Incentive memory incentive = incentives[pool][incentiveId];\n        Stake storage stake = stakes[positionId][incentiveId];\n        require(position.liquidity != 0, \"INACTIVE\");\n        require(stake.secondsGrowthInsideLast == 0, \"SUBSCRIBED\");\n        require(block.timestamp > incentive.startTime && block.timestamp < incentive.endTime, \"INACTIVE_INCENTIVE\");\n        stakes[positionId][incentiveId] = Stake(uint160(rangeSecondsInside(pool, position.lower, position.upper)), true);\n        emit Subscribe(positionId, incentiveId);\n    }\n\n    function claimReward(\n        uint256 positionId,\n        uint256 incentiveId,\n        address recipient,\n        bool unwrapBento\n    ) public {\n        require(ownerOf[positionId] == msg.sender, \"OWNER\");\n        Position memory position = positions[positionId];\n        IConcentratedLiquidityPool pool = position.pool;\n        Incentive storage incentive = incentives[position.pool][incentiveId];\n        Stake storage stake = stakes[positionId][incentiveId];\n        require(stake.initialized, \"UNINITIALIZED\");\n        uint256 secondsGrowth = rangeSecondsInside(pool, position.lower, position.upper) - stake.secondsGrowthInsideLast;\n        uint256 secondsInside = secondsGrowth * position.liquidity; // x128\n        uint256 maxTime = block.timestamp < incentive.endTime ? incentive.endTime : block.timestamp;\n        uint256 secondsUnclaimed = ((maxTime - incentive.startTime) << 128) - incentive.secondsClaimed;\n        uint256 rewards = (incentive.rewardsUnclaimed * secondsInside) / secondsUnclaimed; // x128 cancels out\n        incentive.secondsClaimed += uint160(secondsInside);\n        stake.secondsGrowthInsideLast += uint160(secondsGrowth);\n        incentive.rewardsUnclaimed -= uint96(rewards);\n        _transfer(incentive.token, address(this), recipient, rewards, unwrapBento);\n        emit ClaimReward(positionId, incentiveId, recipient, uint96(rewards));\n    }\n\n    function getReward(uint256 positionId, uint256 incentiveId) public view returns (uint256 rewards, uint256 secondsInside) {\n        Position memory position = positions[positionId];\n        IConcentratedLiquidityPool pool = position.pool;\n        Incentive memory incentive = incentives[pool][positionId];\n        Stake memory stake = stakes[positionId][incentiveId];\n        if (stake.initialized) {\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    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"
    },
    "contracts/pool/concentrated/ConcentratedLiquidityPoolHelper.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.8.0;\n\nimport \"../../interfaces/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"
    }
  },
  "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"
      }
    }
  }
}