creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "src/modules/atomic-queue/AtomicSolverV2.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.21;\n\nimport {AtomicQueue, ERC20, SafeTransferLib} from \"./AtomicQueue.sol\";\nimport {IAtomicSolver} from \"./IAtomicSolver.sol\";\nimport {Auth, Authority} from \"@solmate/auth/Auth.sol\";\nimport {ERC4626} from \"@solmate/mixins/ERC4626.sol\";\nimport {IWEETH} from \"src/interfaces/external/IStaking.sol\";\nimport {FixedPointMathLib} from \"@solmate/utils/FixedPointMathLib.sol\";\n\n/**\n * @title AtomicSolverV2\n * @author crispymangoes\n */\ncontract AtomicSolverV2 is IAtomicSolver, Auth {\n    using SafeTransferLib for ERC20;\n    using FixedPointMathLib for uint256;\n    // ========================================= CONSTANTS =========================================\n\n    ERC20 internal constant eETH = ERC20(0x35fA164735182de50811E8e2E824cFb9B6118ac2);\n    ERC20 internal constant weETH = ERC20(0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee);\n\n    // ========================================= ENUMS =========================================\n\n    /**\n     * @notice The Solve Type, used in `finishSolve` to determine the logic used.\n     * @notice P2P Solver wants to swap share.asset() for user(s) shares\n     * @notice REDEEM Solver needs to redeem shares, then can cover user(s) required assets.\n     */\n    enum SolveType {\n        P2P,\n        REDEEM,\n        REDEEM_LIQUID\n    }\n\n    //============================== ERRORS ===============================\n\n    error AtomicSolverV2___WrongInitiator();\n    error AtomicSolverV2___AlreadyInSolveContext();\n    error AtomicSolverV2___FailedToSolve();\n    error AtomicSolverV2___SolveMaxAssetsExceeded(uint256 actualAssets, uint256 maxAssets);\n    error AtomicSolverV2___P2PSolveMinSharesNotMet(uint256 actualShares, uint256 minShares);\n    error AtomicSolverV2___RedeemSolveMinAssetDeltaNotMet(uint256 actualDelta, uint256 minDelta);\n\n    //============================== IMMUTABLES ===============================\n\n    constructor(address _owner, Authority _authority) Auth(_owner, _authority) {}\n\n    //============================== SOLVE FUNCTIONS ===============================\n    /**\n     * @notice Solver wants to exchange p2p share.asset() for withdraw queue shares.\n     * @dev Solver should approve this contract to spend share.asset().\n     */\n    function p2pSolve(\n        AtomicQueue queue,\n        ERC20 offer,\n        ERC20 want,\n        address[] calldata users,\n        uint256 minOfferReceived,\n        uint256 maxAssets\n    ) external requiresAuth {\n        bytes memory runData = abi.encode(SolveType.P2P, msg.sender, minOfferReceived, maxAssets);\n\n        // Solve for `users`.\n        queue.solve(offer, want, users, runData, address(this));\n    }\n\n    /**\n     * @notice Solver wants to redeem withdraw offer shares, to help cover withdraw.\n     * @dev `offer` MUST be an ERC4626 vault.\n     */\n    function redeemSolve(\n        AtomicQueue queue,\n        ERC20 offer,\n        ERC20 want,\n        address[] calldata users,\n        uint256 minAssetDelta,\n        uint256 maxAssets\n    ) external requiresAuth {\n        bytes memory runData = abi.encode(SolveType.REDEEM, msg.sender, minAssetDelta, maxAssets);\n\n        // Solve for `users`.\n        queue.solve(offer, want, users, runData, address(this));\n    }\n\n    /**\n     * @notice Solver wants to redeem withdraw offer shares, to help cover withdraw.\n     * @dev `offer` MUST be an ERC4626 vault.\n     */\n    function redeemLiquidSolve(\n        AtomicQueue queue,\n        ERC20 offer,\n        ERC20 want,\n        address[] calldata users,\n        uint256 minAssetDelta,\n        uint256 maxAssets\n    ) external requiresAuth {\n        bytes memory runData = abi.encode(SolveType.REDEEM_LIQUID, msg.sender, minAssetDelta, maxAssets);\n\n        // Solve for `users`.\n        queue.solve(offer, want, users, runData, address(this));\n    }\n\n    //============================== ISOLVER FUNCTIONS ===============================\n\n    /**\n     * @notice Implement the finishSolve function WithdrawQueue expects to call.\n     * @dev nonReentrant is not needed on this function because it is impossible to reenter,\n     *      because the above solve functions have the nonReentrant modifier.\n     *      The only way to have the first 2 checks pass is if the msg.sender is the queue,\n     *      and this contract is msg.sender of `Queue.solve()`, which is only called in the above\n     *      functions.\n     */\n    function finishSolve(\n        bytes calldata runData,\n        address initiator,\n        ERC20 offer,\n        ERC20 want,\n        uint256 offerReceived,\n        uint256 wantApprovalAmount\n    ) external requiresAuth {\n        if (initiator != address(this)) revert AtomicSolverV2___WrongInitiator();\n\n        address queue = msg.sender;\n\n        SolveType _type = abi.decode(runData, (SolveType));\n\n        if (_type == SolveType.P2P) {\n            _p2pSolve(queue, runData, offer, want, offerReceived, wantApprovalAmount);\n        } else if (_type == SolveType.REDEEM) {\n            _redeemSolve(queue, runData, offer, want, offerReceived, wantApprovalAmount);\n        } else if (_type == SolveType.REDEEM_LIQUID) {\n            _redeemLiquidSolve(queue, runData, offer, want, offerReceived, wantApprovalAmount);\n        }\n    }\n\n    //============================== HELPER FUNCTIONS ===============================\n\n    /**\n     * @notice Helper function containing the logic to handle p2p solves.\n     */\n    function _p2pSolve(\n        address queue,\n        bytes memory runData,\n        ERC20 offer,\n        ERC20 want,\n        uint256 offerReceived,\n        uint256 wantApprovalAmount\n    ) internal {\n        (, address solver, uint256 minOfferReceived, uint256 maxAssets) =\n            abi.decode(runData, (SolveType, address, uint256, uint256));\n\n        // Make sure solver is receiving the minimum amount of offer.\n        if (offerReceived < minOfferReceived) {\n            revert AtomicSolverV2___P2PSolveMinSharesNotMet(offerReceived, minOfferReceived);\n        }\n\n        // Make sure solvers `maxAssets` was not exceeded.\n        if (wantApprovalAmount > maxAssets) {\n            revert AtomicSolverV2___SolveMaxAssetsExceeded(wantApprovalAmount, maxAssets);\n        }\n\n        // Transfer required want from solver.\n        want.safeTransferFrom(solver, address(this), wantApprovalAmount);\n\n        // Transfer offer to solver.\n        offer.safeTransfer(solver, offerReceived);\n\n        // Approve queue to spend wantApprovalAmount.\n        want.safeApprove(queue, wantApprovalAmount);\n    }\n\n    /**\n     * @notice Helper function containing the logic to handle redeem solves.\n     */\n    function _redeemSolve(\n        address queue,\n        bytes memory runData,\n        ERC20 offer,\n        ERC20 want,\n        uint256 offerReceived,\n        uint256 wantApprovalAmount\n    ) internal {\n        (, address solver, uint256 minAssetDelta, uint256 maxAssets) =\n            abi.decode(runData, (SolveType, address, uint256, uint256));\n\n        // Make sure solvers `maxAssets` was not exceeded.\n        if (wantApprovalAmount > maxAssets) {\n            revert AtomicSolverV2___SolveMaxAssetsExceeded(wantApprovalAmount, maxAssets);\n        }\n\n        // Redeem the shares, sending assets to solver.\n        ERC4626 share = ERC4626(address(offer));\n        uint256 assetsFromRedeem = share.redeem(offerReceived, solver, address(this));\n\n        if (wantApprovalAmount < assetsFromRedeem) {\n            uint256 assetDelta = assetsFromRedeem - wantApprovalAmount;\n            if (assetDelta < minAssetDelta) {\n                revert AtomicSolverV2___RedeemSolveMinAssetDeltaNotMet(assetDelta, minAssetDelta);\n            }\n        }\n\n        // Transfer required assets from solver.\n        want.safeTransferFrom(solver, address(this), wantApprovalAmount);\n\n        // Approve queue to spend wantApprovalAmount.\n        want.safeApprove(queue, wantApprovalAmount);\n    }\n\n    /**\n     * @notice Helper function containing the logic to handle redeem solves.\n     */\n    function _redeemLiquidSolve(\n        address queue,\n        bytes memory runData,\n        ERC20 offer,\n        ERC20 want,\n        uint256 offerReceived,\n        uint256 wantApprovalAmount\n    ) internal {\n        (, address solver, uint256 minAssetDelta, uint256 maxAssets) =\n            abi.decode(runData, (SolveType, address, uint256, uint256));\n\n        // Make sure solvers `maxAssets` was not exceeded.\n        if (wantApprovalAmount > maxAssets) {\n            revert AtomicSolverV2___SolveMaxAssetsExceeded(wantApprovalAmount, maxAssets);\n        }\n\n        // Redeem the shares, sending assets to solver.\n        ERC4626 share = ERC4626(address(offer));\n        uint256 assetsFromRedeem = share.redeem(offerReceived, solver, address(this));\n\n        if (wantApprovalAmount < assetsFromRedeem) {\n            uint256 assetDelta = assetsFromRedeem - wantApprovalAmount;\n            if (assetDelta < minAssetDelta) {\n                revert AtomicSolverV2___RedeemSolveMinAssetDeltaNotMet(assetDelta, minAssetDelta);\n            }\n        }\n\n        // Transfer required assets from solver.\n        if (want.balanceOf(solver) < wantApprovalAmount) {\n            // Check if want is eETH, if so see if there is enough weETH to unwrap and cover withdraw.\n            if (address(want) == address(eETH)) {\n                uint256 unwrapAmount = wantApprovalAmount.mulDivDown(1e18, IWEETH(address(weETH)).getRate()) + 1;\n                if (unwrapAmount <= weETH.balanceOf(solver)) {\n                    weETH.safeTransferFrom(solver, address(this), unwrapAmount);\n                    IWEETH(address(weETH)).unwrap(unwrapAmount);\n                } else {\n                    revert AtomicSolverV2___FailedToSolve();\n                }\n            }\n            // else check if want is weETH, if so see if there is enough eETH to wrap and cover withdraw.\n            else if (address(want) == address(weETH)) {\n                uint256 wrapAmount = wantApprovalAmount.mulDivDown(IWEETH(address(weETH)).getRate(), 1e18) + 1;\n                if (wrapAmount <= eETH.balanceOf(solver)) {\n                    eETH.safeTransferFrom(solver, address(this), wrapAmount);\n                    eETH.safeApprove(address(weETH), wrapAmount);\n                    IWEETH(address(weETH)).wrap(wrapAmount);\n                } else {\n                    revert AtomicSolverV2___FailedToSolve();\n                }\n            } else {\n                revert AtomicSolverV2___FailedToSolve();\n            }\n        } else {\n            want.safeTransferFrom(solver, address(this), wantApprovalAmount);\n        }\n\n        // Approve queue to spend wantApprovalAmount.\n        want.safeApprove(queue, wantApprovalAmount);\n    }\n}\n"
      },
      "src/modules/atomic-queue/AtomicQueue.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.21;\n\nimport { Math } from \"src/utils/Math.sol\";\nimport { SafeTransferLib } from \"@solmate/utils/SafeTransferLib.sol\";\nimport { ERC20 } from \"@solmate/tokens/ERC20.sol\";\nimport { ReentrancyGuard } from \"@solmate/utils/ReentrancyGuard.sol\";\nimport { IAtomicSolver } from \"./IAtomicSolver.sol\";\n\n/**\n * @title AtomicQueue\n * @notice Allows users to create `AtomicRequests` that specify an ERC20 asset to `offer`\n *         and an ERC20 asset to `want` in return.\n * @notice Making atomic requests where the exchange rate between offer and want is not\n *         relatively stable is effectively the same as placing a limit order between\n *         those assets, so requests can be filled at a rate worse than the current market rate.\n * @notice It is possible for a user to make multiple requests that use the same offer asset.\n *         If this is done it is important that the user has approved the queue to spend the\n *         total amount of assets aggregated from all their requests, and to also have enough\n *         `offer` asset to cover the aggregate total request of `offerAmount`.\n * @author crispymangoes\n */\ncontract AtomicQueue is ReentrancyGuard {\n    using SafeTransferLib for ERC20;\n    using Math for uint256;\n\n    // ========================================= STRUCTS =========================================\n\n    /**\n     * @notice Stores request information needed to fulfill a users atomic request.\n     * @param deadline unix timestamp for when request is no longer valid\n     * @param atomicPrice the price in terms of `want` asset the user wants their `offer` assets \"sold\" at\n     * @dev atomicPrice MUST be in terms of `want` asset decimals.\n     * @param offerAmount the amount of `offer` asset the user wants converted to `want` asset\n     * @param inSolve bool used during solves to prevent duplicate users, and to prevent redoing multiple checks\n     */\n    struct AtomicRequest {\n        uint64 deadline; // deadline to fulfill request\n        uint88 atomicPrice; // In terms of want asset decimals\n        uint96 offerAmount; // The amount of offer asset the user wants to sell.\n        bool inSolve; // Indicates whether this user is currently having their request fulfilled.\n    }\n\n    /**\n     * @notice Used in `viewSolveMetaData` helper function to return data in a clean struct.\n     * @param user the address of the user\n     * @param flags 8 bits indicating the state of the user only the first 4 bits are used XXXX0000\n     *              Either all flags are false(user is solvable) or only 1 is true(an error occurred).\n     *              From right to left\n     *              - 0: indicates user deadline has passed.\n     *              - 1: indicates user request has zero offer amount.\n     *              - 2: indicates user does not have enough offer asset in wallet.\n     *              - 3: indicates user has not given AtomicQueue approval.\n     * @param assetsToOffer the amount of offer asset to solve\n     * @param assetsForWant the amount of assets users want for their offer assets\n     */\n    struct SolveMetaData {\n        address user;\n        uint8 flags;\n        uint256 assetsToOffer;\n        uint256 assetsForWant;\n    }\n\n    // ========================================= GLOBAL STATE =========================================\n\n    /**\n     * @notice Maps user address to offer asset to want asset to a AtomicRequest struct.\n     */\n    mapping(address => mapping(ERC20 => mapping(ERC20 => AtomicRequest))) public userAtomicRequest;\n\n    //============================== ERRORS ===============================\n\n    error AtomicQueue__UserRepeated(address user);\n    error AtomicQueue__RequestDeadlineExceeded(address user);\n    error AtomicQueue__UserNotInSolve(address user);\n    error AtomicQueue__ZeroOfferAmount(address user);\n\n    //============================== EVENTS ===============================\n\n    /**\n     * @notice Emitted when `updateAtomicRequest` is called.\n     */\n    event AtomicRequestUpdated(\n        address user,\n        address offerToken,\n        address wantToken,\n        uint256 amount,\n        uint256 deadline,\n        uint256 minPrice,\n        uint256 timestamp\n    );\n\n    /**\n     * @notice Emitted when `solve` exchanges a users offer asset for their want asset.\n     */\n    event AtomicRequestFulfilled(\n        address user,\n        address offerToken,\n        address wantToken,\n        uint256 offerAmountSpent,\n        uint256 wantAmountReceived,\n        uint256 timestamp\n    );\n\n    //============================== USER FUNCTIONS ===============================\n\n    /**\n     * @notice Get a users Atomic Request.\n     * @param user the address of the user to get the request for\n     * @param offer the ERC0 token they want to exchange for the want\n     * @param want the ERC20 token they want in exchange for the offer\n     */\n    function getUserAtomicRequest(address user, ERC20 offer, ERC20 want) external view returns (AtomicRequest memory) {\n        return userAtomicRequest[user][offer][want];\n    }\n\n    /**\n     * @notice Helper function that returns either\n     *         true: Withdraw request is valid.\n     *         false: Withdraw request is not valid.\n     * @dev It is possible for a withdraw request to return false from this function, but using the\n     *      request in `updateAtomicRequest` will succeed, but solvers will not be able to include\n     *      the user in `solve` unless some other state is changed.\n     * @param offer the ERC0 token they want to exchange for the want\n     * @param user the address of the user making the request\n     * @param userRequest the request struct to validate\n     */\n    function isAtomicRequestValid(\n        ERC20 offer,\n        address user,\n        AtomicRequest calldata userRequest\n    ) external view returns (bool) {\n        // Validate amount.\n        if (userRequest.offerAmount > offer.balanceOf(user)) return false;\n        // Validate deadline.\n        if (block.timestamp > userRequest.deadline) return false;\n        // Validate approval.\n        if (offer.allowance(user, address(this)) < userRequest.offerAmount) return false;\n        // Validate offerAmount is nonzero.\n        if (userRequest.offerAmount == 0) return false;\n        // Validate atomicPrice is nonzero.\n        if (userRequest.atomicPrice == 0) return false;\n\n        return true;\n    }\n\n    /**\n     * @notice Allows user to add/update their withdraw request.\n     * @notice It is possible for a withdraw request with a zero atomicPrice to be made, and solved.\n     *         If this happens, users will be selling their shares for no assets in return.\n     *         To determine a safe atomicPrice, share.previewRedeem should be used to get\n     *         a good share price, then the user can lower it from there to make their request fill faster.\n     * @param offer the ERC20 token the user is offering in exchange for the want\n     * @param want the ERC20 token the user wants in exchange for offer\n     * @param userRequest the users request\n     */\n    function updateAtomicRequest(ERC20 offer, ERC20 want, AtomicRequest calldata userRequest) external nonReentrant {\n        AtomicRequest storage request = userAtomicRequest[msg.sender][offer][want];\n\n        request.deadline = userRequest.deadline;\n        request.atomicPrice = userRequest.atomicPrice;\n        request.offerAmount = userRequest.offerAmount;\n\n        // Emit full amount user has.\n        emit AtomicRequestUpdated(\n            msg.sender,\n            address(offer),\n            address(want),\n            userRequest.offerAmount,\n            userRequest.deadline,\n            userRequest.atomicPrice,\n            block.timestamp\n        );\n    }\n\n    //============================== SOLVER FUNCTIONS ===============================\n\n    /**\n     * @notice Called by solvers in order to exchange offer asset for want asset.\n     * @notice Solvers are optimistically transferred the offer asset, then are required to\n     *         approve this contract to spend enough of want assets to cover all requests.\n     * @dev It is very likely `solve` TXs will be front run if broadcasted to public mem pools,\n     *      so solvers should use private mem pools.\n     * @param offer the ERC20 offer token to solve for\n     * @param want the ERC20 want token to solve for\n     * @param users an array of user addresses to solve for\n     * @param runData extra data that is passed back to solver when `finishSolve` is called\n     * @param solver the address to make `finishSolve` callback to\n     */\n    function solve(\n        ERC20 offer,\n        ERC20 want,\n        address[] calldata users,\n        bytes calldata runData,\n        address solver\n    ) external nonReentrant {\n        // Save offer asset decimals.\n        uint8 offerDecimals = offer.decimals();\n\n        uint256 assetsToOffer;\n        uint256 assetsForWant;\n        for (uint256 i; i < users.length; ++i) {\n            AtomicRequest storage request = userAtomicRequest[users[i]][offer][want];\n\n            if (request.inSolve) revert AtomicQueue__UserRepeated(users[i]);\n            if (block.timestamp > request.deadline) revert AtomicQueue__RequestDeadlineExceeded(users[i]);\n            if (request.offerAmount == 0) revert AtomicQueue__ZeroOfferAmount(users[i]);\n\n            // User gets whatever their atomic price * offerAmount is.\n            assetsForWant += _calculateAssetAmount(request.offerAmount, request.atomicPrice, offerDecimals);\n\n            // If all checks above passed, the users request is valid and should be fulfilled.\n            assetsToOffer += request.offerAmount;\n            request.inSolve = true;\n            // Transfer shares from user to solver.\n            offer.safeTransferFrom(users[i], solver, request.offerAmount);\n        }\n\n        IAtomicSolver(solver).finishSolve(runData, msg.sender, offer, want, assetsToOffer, assetsForWant);\n\n        for (uint256 i; i < users.length; ++i) {\n            AtomicRequest storage request = userAtomicRequest[users[i]][offer][want];\n\n            if (request.inSolve) {\n                // We know that the minimum price and deadline arguments are satisfied since this can only be true if they were.\n\n                // Send user their share of assets.\n                uint256 assetsToUser = _calculateAssetAmount(request.offerAmount, request.atomicPrice, offerDecimals);\n\n                want.safeTransferFrom(solver, users[i], assetsToUser);\n\n                emit AtomicRequestFulfilled(\n                    users[i],\n                    address(offer),\n                    address(want),\n                    request.offerAmount,\n                    assetsToUser,\n                    block.timestamp\n                );\n\n                // Set shares to withdraw to 0.\n                request.offerAmount = 0;\n                request.inSolve = false;\n            } else revert AtomicQueue__UserNotInSolve(users[i]);\n        }\n    }\n\n    /**\n     * @notice Helper function solvers can use to determine if users are solvable, and the required amounts to do so.\n     * @notice Repeated users are not accounted for in this setup, so if solvers have repeat users in their `users`\n     *         array the results can be wrong.\n     * @dev Since a user can have multiple requests with the same offer asset but different want asset, it is\n     *      possible for `viewSolveMetaData` to report no errors, but for a solve to fail, if any solves were done\n     *      between the time `viewSolveMetaData` and before `solve` is called.\n     * @param offer the ERC20 offer token to check for solvability\n     * @param want the ERC20 want token to check for solvability\n     * @param users an array of user addresses to check for solvability\n     */\n    function viewSolveMetaData(\n        ERC20 offer,\n        ERC20 want,\n        address[] calldata users\n    ) external view returns (SolveMetaData[] memory metaData, uint256 totalAssetsForWant, uint256 totalAssetsToOffer) {\n        // Save offer asset decimals.\n        uint8 offerDecimals = offer.decimals();\n\n        // Setup meta data.\n        metaData = new SolveMetaData[](users.length);\n\n        for (uint256 i; i < users.length; ++i) {\n            AtomicRequest memory request = userAtomicRequest[users[i]][offer][want];\n\n            metaData[i].user = users[i];\n\n            if (block.timestamp > request.deadline) {\n                metaData[i].flags |= uint8(1);\n            }\n            if (request.offerAmount == 0) {\n                metaData[i].flags |= uint8(1) << 1;\n            }\n            if (offer.balanceOf(users[i]) < request.offerAmount) {\n                metaData[i].flags |= uint8(1) << 2;\n            }\n            if (offer.allowance(users[i], address(this)) < request.offerAmount) {\n                metaData[i].flags |= uint8(1) << 3;\n            }\n\n            metaData[i].assetsToOffer = request.offerAmount;\n\n            // User gets whatever their execution share price is.\n            uint256 userAssets = _calculateAssetAmount(request.offerAmount, request.atomicPrice, offerDecimals);\n            metaData[i].assetsForWant = userAssets;\n\n            // If flags is zero, no errors occurred.\n            if (metaData[i].flags == 0) {\n                totalAssetsForWant += userAssets;\n                totalAssetsToOffer += request.offerAmount;\n            }\n        }\n    }\n\n    //============================== INTERNAL FUNCTIONS ===============================\n\n    /**\n     * @notice Helper function to calculate the amount of want assets a users wants in exchange for\n     *         `offerAmount` of offer asset.\n     */\n    function _calculateAssetAmount(\n        uint256 offerAmount,\n        uint256 atomicPrice,\n        uint8 offerDecimals\n    ) internal pure returns (uint256) {\n        return atomicPrice.mulDivDown(offerAmount, 10 ** offerDecimals);\n    }\n}\n"
      },
      "src/modules/atomic-queue/IAtomicSolver.sol": {
        "content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.8.0;\n\nimport { ERC20 } from \"@solmate/tokens/ERC20.sol\";\n\ninterface IAtomicSolver {\n    /**\n     * @notice This function must be implemented in order for an address to be a `solver`\n     *         for the AtomicQueue\n     * @param runData arbitrary bytes data that is dependent on how each solver is setup\n     *        it could contain swap data, or flash loan data, etc..\n     * @param initiator the address that initiated a solve\n     * @param offer the ERC20 asset sent to the solver\n     * @param want the ERC20 asset the solver must approve the queue for\n     * @param assetsToOffer the amount of `offer` sent to the solver\n     * @param assetsForWant the amount of `want` the solver must approve the queue for\n     */\n    function finishSolve(\n        bytes calldata runData,\n        address initiator,\n        ERC20 offer,\n        ERC20 want,\n        uint256 assetsToOffer,\n        uint256 assetsForWant\n    ) external;\n}\n"
      },
      "lib/solmate/src/auth/Auth.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Provides a flexible and updatable auth pattern which is completely separate from application logic.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol)\n/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)\nabstract contract Auth {\n    event OwnershipTransferred(address indexed user, address indexed newOwner);\n\n    event AuthorityUpdated(address indexed user, Authority indexed newAuthority);\n\n    address public owner;\n\n    Authority public authority;\n\n    constructor(address _owner, Authority _authority) {\n        owner = _owner;\n        authority = _authority;\n\n        emit OwnershipTransferred(msg.sender, _owner);\n        emit AuthorityUpdated(msg.sender, _authority);\n    }\n\n    modifier requiresAuth() virtual {\n        require(isAuthorized(msg.sender, msg.sig), \"UNAUTHORIZED\");\n\n        _;\n    }\n\n    function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) {\n        Authority auth = authority; // Memoizing authority saves us a warm SLOAD, around 100 gas.\n\n        // Checking if the caller is the owner only after calling the authority saves gas in most cases, but be\n        // aware that this makes protected functions uncallable even to the owner if the authority is out of order.\n        return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) || user == owner;\n    }\n\n    function setAuthority(Authority newAuthority) public virtual {\n        // We check if the caller is the owner first because we want to ensure they can\n        // always swap out the authority even if it's reverting or using up a lot of gas.\n        require(msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig));\n\n        authority = newAuthority;\n\n        emit AuthorityUpdated(msg.sender, newAuthority);\n    }\n\n    function transferOwnership(address newOwner) public virtual requiresAuth {\n        owner = newOwner;\n\n        emit OwnershipTransferred(msg.sender, newOwner);\n    }\n}\n\n/// @notice A generic interface for a contract which provides authorization data to an Auth instance.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol)\n/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)\ninterface Authority {\n    function canCall(\n        address user,\n        address target,\n        bytes4 functionSig\n    ) external view returns (bool);\n}\n"
      },
      "lib/solmate/src/mixins/ERC4626.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\nimport {ERC20} from \"../tokens/ERC20.sol\";\nimport {SafeTransferLib} from \"../utils/SafeTransferLib.sol\";\nimport {FixedPointMathLib} from \"../utils/FixedPointMathLib.sol\";\n\n/// @notice Minimal ERC4626 tokenized Vault implementation.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/mixins/ERC4626.sol)\nabstract contract ERC4626 is ERC20 {\n    using SafeTransferLib for ERC20;\n    using FixedPointMathLib for uint256;\n\n    /*//////////////////////////////////////////////////////////////\n                                 EVENTS\n    //////////////////////////////////////////////////////////////*/\n\n    event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);\n\n    event Withdraw(\n        address indexed caller,\n        address indexed receiver,\n        address indexed owner,\n        uint256 assets,\n        uint256 shares\n    );\n\n    /*//////////////////////////////////////////////////////////////\n                               IMMUTABLES\n    //////////////////////////////////////////////////////////////*/\n\n    ERC20 public immutable asset;\n\n    constructor(\n        ERC20 _asset,\n        string memory _name,\n        string memory _symbol\n    ) ERC20(_name, _symbol, _asset.decimals()) {\n        asset = _asset;\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                        DEPOSIT/WITHDRAWAL LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function deposit(uint256 assets, address receiver) public virtual returns (uint256 shares) {\n        // Check for rounding error since we round down in previewDeposit.\n        require((shares = previewDeposit(assets)) != 0, \"ZERO_SHARES\");\n\n        // Need to transfer before minting or ERC777s could reenter.\n        asset.safeTransferFrom(msg.sender, address(this), assets);\n\n        _mint(receiver, shares);\n\n        emit Deposit(msg.sender, receiver, assets, shares);\n\n        afterDeposit(assets, shares);\n    }\n\n    function mint(uint256 shares, address receiver) public virtual returns (uint256 assets) {\n        assets = previewMint(shares); // No need to check for rounding error, previewMint rounds up.\n\n        // Need to transfer before minting or ERC777s could reenter.\n        asset.safeTransferFrom(msg.sender, address(this), assets);\n\n        _mint(receiver, shares);\n\n        emit Deposit(msg.sender, receiver, assets, shares);\n\n        afterDeposit(assets, shares);\n    }\n\n    function withdraw(\n        uint256 assets,\n        address receiver,\n        address owner\n    ) public virtual returns (uint256 shares) {\n        shares = previewWithdraw(assets); // No need to check for rounding error, previewWithdraw rounds up.\n\n        if (msg.sender != owner) {\n            uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals.\n\n            if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;\n        }\n\n        beforeWithdraw(assets, shares);\n\n        _burn(owner, shares);\n\n        emit Withdraw(msg.sender, receiver, owner, assets, shares);\n\n        asset.safeTransfer(receiver, assets);\n    }\n\n    function redeem(\n        uint256 shares,\n        address receiver,\n        address owner\n    ) public virtual returns (uint256 assets) {\n        if (msg.sender != owner) {\n            uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals.\n\n            if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;\n        }\n\n        // Check for rounding error since we round down in previewRedeem.\n        require((assets = previewRedeem(shares)) != 0, \"ZERO_ASSETS\");\n\n        beforeWithdraw(assets, shares);\n\n        _burn(owner, shares);\n\n        emit Withdraw(msg.sender, receiver, owner, assets, shares);\n\n        asset.safeTransfer(receiver, assets);\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                            ACCOUNTING LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function totalAssets() public view virtual returns (uint256);\n\n    function convertToShares(uint256 assets) public view virtual returns (uint256) {\n        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.\n\n        return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets());\n    }\n\n    function convertToAssets(uint256 shares) public view virtual returns (uint256) {\n        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.\n\n        return supply == 0 ? shares : shares.mulDivDown(totalAssets(), supply);\n    }\n\n    function previewDeposit(uint256 assets) public view virtual returns (uint256) {\n        return convertToShares(assets);\n    }\n\n    function previewMint(uint256 shares) public view virtual returns (uint256) {\n        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.\n\n        return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply);\n    }\n\n    function previewWithdraw(uint256 assets) public view virtual returns (uint256) {\n        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.\n\n        return supply == 0 ? assets : assets.mulDivUp(supply, totalAssets());\n    }\n\n    function previewRedeem(uint256 shares) public view virtual returns (uint256) {\n        return convertToAssets(shares);\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                     DEPOSIT/WITHDRAWAL LIMIT LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function maxDeposit(address) public view virtual returns (uint256) {\n        return type(uint256).max;\n    }\n\n    function maxMint(address) public view virtual returns (uint256) {\n        return type(uint256).max;\n    }\n\n    function maxWithdraw(address owner) public view virtual returns (uint256) {\n        return convertToAssets(balanceOf[owner]);\n    }\n\n    function maxRedeem(address owner) public view virtual returns (uint256) {\n        return balanceOf[owner];\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                          INTERNAL HOOKS LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function beforeWithdraw(uint256 assets, uint256 shares) internal virtual {}\n\n    function afterDeposit(uint256 assets, uint256 shares) internal virtual {}\n}\n"
      },
      "src/interfaces/external/IStaking.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.21;\n\n// Swell\ninterface ISWETH {\n    function deposit() external payable;\n}\n\n// EtherFi\ninterface ILiquidityPool {\n    function deposit() external payable returns (uint256);\n\n    function requestWithdraw(address recipient, uint256 amount) external returns (uint256);\n\n    function amountForShare(uint256 shares) external view returns (uint256);\n\n    function etherFiAdminContract() external view returns (address);\n\n    function addEthAmountLockedForWithdrawal(uint128 _amount) external;\n}\n\ninterface IWithdrawRequestNft {\n    struct WithdrawRequest {\n        uint96 amountOfEEth;\n        uint96 shareOfEEth;\n        bool isValid;\n        uint32 feeGwei;\n    }\n\n    function claimWithdraw(uint256 tokenId) external;\n\n    function getRequest(uint256 requestId) external view returns (WithdrawRequest memory);\n\n    function finalizeRequests(uint256 requestId) external;\n\n    function owner() external view returns (address);\n\n    function updateAdmin(address admin, bool isAdmin) external;\n}\n\ninterface IWEETH {\n    function wrap(uint256 amount) external returns (uint256);\n\n    function unwrap(uint256 amount) external returns (uint256);\n\n    function getRate() external view returns (uint256 rate);\n}\n\n// Kelp DAO\ninterface ILRTDepositPool {\n    function depositAsset(\n        address asset,\n        uint256 depositAmount,\n        uint256 minRSETHAmountToReceive,\n        string calldata referralId\n    ) external;\n}\n\n// Lido\ninterface ISTETH {\n    function submit(address referral) external payable returns (uint256);\n}\n\ninterface IWSTETH {\n    function wrap(uint256 amount) external returns (uint256);\n\n    function unwrap(uint256 amount) external returns (uint256);\n}\n\ninterface IUNSTETH {\n    struct WithdrawalRequestStatus {\n        /// @notice stETH token amount that was locked on withdrawal queue for this request\n        uint256 amountOfStETH;\n        /// @notice amount of stETH shares locked on withdrawal queue for this request\n        uint256 amountOfShares;\n        /// @notice address that can claim or transfer this request\n        address owner;\n        /// @notice timestamp of when the request was created, in seconds\n        uint256 timestamp;\n        /// @notice true, if request is finalized\n        bool isFinalized;\n        /// @notice true, if request is claimed. Request is claimable if (isFinalized && !isClaimed)\n        bool isClaimed;\n    }\n\n    function getWithdrawalStatus(uint256[] calldata _requestIds)\n        external\n        view\n        returns (WithdrawalRequestStatus[] memory statuses);\n\n    function requestWithdrawals(uint256[] calldata _amounts, address _owner)\n        external\n        returns (uint256[] memory requestIds);\n\n    function claimWithdrawal(uint256 _requestId) external;\n\n    function claimWithdrawals(uint256[] calldata _requestIds, uint256[] calldata _hints) external;\n\n    function finalize(uint256 _lastRequestIdToBeFinalized, uint256 _maxShareRate) external payable;\n\n    function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n    function FINALIZE_ROLE() external view returns (bytes32);\n\n    function getLastFinalizedRequestId() external view returns (uint256);\n\n    function getLastCheckpointIndex() external view returns (uint256);\n\n    function findCheckpointHints(uint256[] memory requestIds, uint256 firstIndex, uint256 lastIndex)\n        external\n        view\n        returns (uint256[] memory);\n\n    function getClaimableEther(uint256[] memory requestIds, uint256[] memory hints)\n        external\n        view\n        returns (uint256[] memory);\n}\n\n// Renzo\ninterface IRestakeManager {\n    function depositETH() external payable;\n}\n\n// Stader\ninterface IStakePoolManager {\n    function deposit(address _receiver) external payable returns (uint256);\n\n    function getExchangeRate() external view returns (uint256);\n}\n\ninterface IStaderConfig {\n    function getDecimals() external view returns (uint256);\n}\n\ninterface IUserWithdrawManager {\n    struct WithdrawRequest {\n        address owner;\n        uint256 ethXAmount;\n        uint256 ethExpected;\n        uint256 ethFinalized;\n        uint256 requestTime;\n    }\n\n    function requestWithdraw(uint256 _ethXAmount, address _owner) external returns (uint256);\n\n    function claim(uint256 _requestId) external;\n\n    function userWithdrawRequests(uint256) external view returns (WithdrawRequest memory);\n\n    function finalizeUserWithdrawalRequest() external;\n}\n"
      },
      "lib/solmate/src/utils/FixedPointMathLib.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Arithmetic library with operations for fixed-point numbers.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)\n/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)\nlibrary FixedPointMathLib {\n    /*//////////////////////////////////////////////////////////////\n                    SIMPLIFIED FIXED POINT OPERATIONS\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 internal constant MAX_UINT256 = 2**256 - 1;\n\n    uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.\n\n    function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {\n        return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.\n    }\n\n    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {\n        return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.\n    }\n\n    function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {\n        return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.\n    }\n\n    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {\n        return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                    LOW LEVEL FIXED POINT OPERATIONS\n    //////////////////////////////////////////////////////////////*/\n\n    function mulDivDown(\n        uint256 x,\n        uint256 y,\n        uint256 denominator\n    ) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))\n            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {\n                revert(0, 0)\n            }\n\n            // Divide x * y by the denominator.\n            z := div(mul(x, y), denominator)\n        }\n    }\n\n    function mulDivUp(\n        uint256 x,\n        uint256 y,\n        uint256 denominator\n    ) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))\n            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {\n                revert(0, 0)\n            }\n\n            // If x * y modulo the denominator is strictly greater than 0,\n            // 1 is added to round up the division of x * y by the denominator.\n            z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))\n        }\n    }\n\n    function rpow(\n        uint256 x,\n        uint256 n,\n        uint256 scalar\n    ) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            switch x\n            case 0 {\n                switch n\n                case 0 {\n                    // 0 ** 0 = 1\n                    z := scalar\n                }\n                default {\n                    // 0 ** n = 0\n                    z := 0\n                }\n            }\n            default {\n                switch mod(n, 2)\n                case 0 {\n                    // If n is even, store scalar in z for now.\n                    z := scalar\n                }\n                default {\n                    // If n is odd, store x in z for now.\n                    z := x\n                }\n\n                // Shifting right by 1 is like dividing by 2.\n                let half := shr(1, scalar)\n\n                for {\n                    // Shift n right by 1 before looping to halve it.\n                    n := shr(1, n)\n                } n {\n                    // Shift n right by 1 each iteration to halve it.\n                    n := shr(1, n)\n                } {\n                    // Revert immediately if x ** 2 would overflow.\n                    // Equivalent to iszero(eq(div(xx, x), x)) here.\n                    if shr(128, x) {\n                        revert(0, 0)\n                    }\n\n                    // Store x squared.\n                    let xx := mul(x, x)\n\n                    // Round to the nearest number.\n                    let xxRound := add(xx, half)\n\n                    // Revert if xx + half overflowed.\n                    if lt(xxRound, xx) {\n                        revert(0, 0)\n                    }\n\n                    // Set x to scaled xxRound.\n                    x := div(xxRound, scalar)\n\n                    // If n is even:\n                    if mod(n, 2) {\n                        // Compute z * x.\n                        let zx := mul(z, x)\n\n                        // If z * x overflowed:\n                        if iszero(eq(div(zx, x), z)) {\n                            // Revert if x is non-zero.\n                            if iszero(iszero(x)) {\n                                revert(0, 0)\n                            }\n                        }\n\n                        // Round to the nearest number.\n                        let zxRound := add(zx, half)\n\n                        // Revert if zx + half overflowed.\n                        if lt(zxRound, zx) {\n                            revert(0, 0)\n                        }\n\n                        // Return properly scaled zxRound.\n                        z := div(zxRound, scalar)\n                    }\n                }\n            }\n        }\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                        GENERAL NUMBER UTILITIES\n    //////////////////////////////////////////////////////////////*/\n\n    function sqrt(uint256 x) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let y := x // We start y at x, which will help us make our initial estimate.\n\n            z := 181 // The \"correct\" value is 1, but this saves a multiplication later.\n\n            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad\n            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.\n\n            // We check y >= 2^(k + 8) but shift right by k bits\n            // each branch to ensure that if x >= 256, then y >= 256.\n            if iszero(lt(y, 0x10000000000000000000000000000000000)) {\n                y := shr(128, y)\n                z := shl(64, z)\n            }\n            if iszero(lt(y, 0x1000000000000000000)) {\n                y := shr(64, y)\n                z := shl(32, z)\n            }\n            if iszero(lt(y, 0x10000000000)) {\n                y := shr(32, y)\n                z := shl(16, z)\n            }\n            if iszero(lt(y, 0x1000000)) {\n                y := shr(16, y)\n                z := shl(8, z)\n            }\n\n            // Goal was to get z*z*y within a small factor of x. More iterations could\n            // get y in a tighter range. Currently, we will have y in [256, 256*2^16).\n            // We ensured y >= 256 so that the relative difference between y and y+1 is small.\n            // That's not possible if x < 256 but we can just verify those cases exhaustively.\n\n            // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.\n            // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.\n            // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.\n\n            // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range\n            // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.\n\n            // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate\n            // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.\n\n            // There is no overflow risk here since y < 2^136 after the first branch above.\n            z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.\n\n            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n\n            // If x+1 is a perfect square, the Babylonian method cycles between\n            // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.\n            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division\n            // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.\n            // If you don't care whether the floor or ceil square root is returned, you can remove this statement.\n            z := sub(z, lt(div(x, z), z))\n        }\n    }\n\n    function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Mod x by y. Note this will return\n            // 0 instead of reverting if y is zero.\n            z := mod(x, y)\n        }\n    }\n\n    function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Divide x by y. Note this will return\n            // 0 instead of reverting if y is zero.\n            r := div(x, y)\n        }\n    }\n\n    function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Add 1 to x * y if x % y > 0. Note this will\n            // return 0 instead of reverting if y is zero.\n            z := add(gt(mod(x, y), 0), div(x, y))\n        }\n    }\n}\n"
      },
      "src/utils/Math.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.21;\n\nlibrary Math {\n    /**\n     * @notice Substract with a floor of 0 for the result.\n     */\n    function subMinZero(uint256 x, uint256 y) internal pure returns (uint256) {\n        return x > y ? x - y : 0;\n    }\n\n    /**\n     * @notice Used to change the decimals of precision used for an amount.\n     */\n    function changeDecimals(uint256 amount, uint8 fromDecimals, uint8 toDecimals) internal pure returns (uint256) {\n        if (fromDecimals == toDecimals) {\n            return amount;\n        } else if (fromDecimals < toDecimals) {\n            return amount * 10 ** (toDecimals - fromDecimals);\n        } else {\n            return amount / 10 ** (fromDecimals - toDecimals);\n        }\n    }\n\n    // ===================================== OPENZEPPELIN'S MATH =====================================\n\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    // ================================= SOLMATE's FIXEDPOINTMATHLIB =================================\n\n    uint256 public constant WAD = 1e18; // The scalar of ETH and most ERC20s.\n\n    function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {\n        return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.\n    }\n\n    function mulDivDown(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 z) {\n        assembly {\n            // Store x * y in z for now.\n            z := mul(x, y)\n\n            // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))\n            if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {\n                revert(0, 0)\n            }\n\n            // Divide z by the denominator.\n            z := div(z, denominator)\n        }\n    }\n\n    function mulDivUp(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 z) {\n        assembly {\n            // Store x * y in z for now.\n            z := mul(x, y)\n\n            // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))\n            if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {\n                revert(0, 0)\n            }\n\n            // First, divide z - 1 by the denominator and add 1.\n            // We allow z - 1 to underflow if z is 0, because we multiply the\n            // end result by 0 if z is zero, ensuring we return 0 if z is zero.\n            z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1))\n        }\n    }\n}\n"
      },
      "lib/solmate/src/utils/SafeTransferLib.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\nimport {ERC20} from \"../tokens/ERC20.sol\";\n\n/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)\n/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.\n/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.\nlibrary SafeTransferLib {\n    /*//////////////////////////////////////////////////////////////\n                             ETH OPERATIONS\n    //////////////////////////////////////////////////////////////*/\n\n    function safeTransferETH(address to, uint256 amount) internal {\n        bool success;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Transfer the ETH and store if it succeeded or not.\n            success := call(gas(), to, amount, 0, 0, 0, 0)\n        }\n\n        require(success, \"ETH_TRANSFER_FAILED\");\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                            ERC20 OPERATIONS\n    //////////////////////////////////////////////////////////////*/\n\n    function safeTransferFrom(\n        ERC20 token,\n        address from,\n        address to,\n        uint256 amount\n    ) internal {\n        bool success;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Get a pointer to some free memory.\n            let freeMemoryPointer := mload(0x40)\n\n            // Write the abi-encoded calldata into memory, beginning with the function selector.\n            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)\n            mstore(add(freeMemoryPointer, 4), from) // Append the \"from\" argument.\n            mstore(add(freeMemoryPointer, 36), to) // Append the \"to\" argument.\n            mstore(add(freeMemoryPointer, 68), amount) // Append the \"amount\" argument.\n\n            success := and(\n                // Set success to whether the call reverted, if not we check it either\n                // returned exactly 1 (can't just be non-zero data), or had no return data.\n                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),\n                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.\n                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.\n                // Counterintuitively, this call must be positioned second to the or() call in the\n                // surrounding and() call or else returndatasize() will be zero during the computation.\n                call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)\n            )\n        }\n\n        require(success, \"TRANSFER_FROM_FAILED\");\n    }\n\n    function safeTransfer(\n        ERC20 token,\n        address to,\n        uint256 amount\n    ) internal {\n        bool success;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Get a pointer to some free memory.\n            let freeMemoryPointer := mload(0x40)\n\n            // Write the abi-encoded calldata into memory, beginning with the function selector.\n            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)\n            mstore(add(freeMemoryPointer, 4), to) // Append the \"to\" argument.\n            mstore(add(freeMemoryPointer, 36), amount) // Append the \"amount\" argument.\n\n            success := and(\n                // Set success to whether the call reverted, if not we check it either\n                // returned exactly 1 (can't just be non-zero data), or had no return data.\n                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),\n                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.\n                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.\n                // Counterintuitively, this call must be positioned second to the or() call in the\n                // surrounding and() call or else returndatasize() will be zero during the computation.\n                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)\n            )\n        }\n\n        require(success, \"TRANSFER_FAILED\");\n    }\n\n    function safeApprove(\n        ERC20 token,\n        address to,\n        uint256 amount\n    ) internal {\n        bool success;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Get a pointer to some free memory.\n            let freeMemoryPointer := mload(0x40)\n\n            // Write the abi-encoded calldata into memory, beginning with the function selector.\n            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)\n            mstore(add(freeMemoryPointer, 4), to) // Append the \"to\" argument.\n            mstore(add(freeMemoryPointer, 36), amount) // Append the \"amount\" argument.\n\n            success := and(\n                // Set success to whether the call reverted, if not we check it either\n                // returned exactly 1 (can't just be non-zero data), or had no return data.\n                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),\n                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.\n                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.\n                // Counterintuitively, this call must be positioned second to the or() call in the\n                // surrounding and() call or else returndatasize() will be zero during the computation.\n                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)\n            )\n        }\n\n        require(success, \"APPROVE_FAILED\");\n    }\n}\n"
      },
      "lib/solmate/src/tokens/ERC20.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\nabstract contract ERC20 {\n    /*//////////////////////////////////////////////////////////////\n                                 EVENTS\n    //////////////////////////////////////////////////////////////*/\n\n    event Transfer(address indexed from, address indexed to, uint256 amount);\n\n    event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n    /*//////////////////////////////////////////////////////////////\n                            METADATA STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    string public name;\n\n    string public symbol;\n\n    uint8 public immutable decimals;\n\n    /*//////////////////////////////////////////////////////////////\n                              ERC20 STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 public totalSupply;\n\n    mapping(address => uint256) public balanceOf;\n\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    /*//////////////////////////////////////////////////////////////\n                            EIP-2612 STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 internal immutable INITIAL_CHAIN_ID;\n\n    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\n\n    mapping(address => uint256) public nonces;\n\n    /*//////////////////////////////////////////////////////////////\n                               CONSTRUCTOR\n    //////////////////////////////////////////////////////////////*/\n\n    constructor(\n        string memory _name,\n        string memory _symbol,\n        uint8 _decimals\n    ) {\n        name = _name;\n        symbol = _symbol;\n        decimals = _decimals;\n\n        INITIAL_CHAIN_ID = block.chainid;\n        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                               ERC20 LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function approve(address spender, uint256 amount) public virtual returns (bool) {\n        allowance[msg.sender][spender] = amount;\n\n        emit Approval(msg.sender, spender, amount);\n\n        return true;\n    }\n\n    function transfer(address to, uint256 amount) public virtual returns (bool) {\n        balanceOf[msg.sender] -= amount;\n\n        // Cannot overflow because the sum of all user\n        // balances can't exceed the max uint256 value.\n        unchecked {\n            balanceOf[to] += amount;\n        }\n\n        emit Transfer(msg.sender, to, amount);\n\n        return true;\n    }\n\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) public virtual returns (bool) {\n        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\n\n        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\n\n        balanceOf[from] -= amount;\n\n        // Cannot overflow because the sum of all user\n        // balances can't exceed the max uint256 value.\n        unchecked {\n            balanceOf[to] += amount;\n        }\n\n        emit Transfer(from, to, amount);\n\n        return true;\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                             EIP-2612 LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) public virtual {\n        require(deadline >= block.timestamp, \"PERMIT_DEADLINE_EXPIRED\");\n\n        // Unchecked because the only math done is incrementing\n        // the owner's nonce which cannot realistically overflow.\n        unchecked {\n            address recoveredAddress = ecrecover(\n                keccak256(\n                    abi.encodePacked(\n                        \"\\x19\\x01\",\n                        DOMAIN_SEPARATOR(),\n                        keccak256(\n                            abi.encode(\n                                keccak256(\n                                    \"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\"\n                                ),\n                                owner,\n                                spender,\n                                value,\n                                nonces[owner]++,\n                                deadline\n                            )\n                        )\n                    )\n                ),\n                v,\n                r,\n                s\n            );\n\n            require(recoveredAddress != address(0) && recoveredAddress == owner, \"INVALID_SIGNER\");\n\n            allowance[recoveredAddress][spender] = value;\n        }\n\n        emit Approval(owner, spender, value);\n    }\n\n    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\n        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\n    }\n\n    function computeDomainSeparator() internal view virtual returns (bytes32) {\n        return\n            keccak256(\n                abi.encode(\n                    keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n                    keccak256(bytes(name)),\n                    keccak256(\"1\"),\n                    block.chainid,\n                    address(this)\n                )\n            );\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                        INTERNAL MINT/BURN LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function _mint(address to, uint256 amount) internal virtual {\n        totalSupply += amount;\n\n        // Cannot overflow because the sum of all user\n        // balances can't exceed the max uint256 value.\n        unchecked {\n            balanceOf[to] += amount;\n        }\n\n        emit Transfer(address(0), to, amount);\n    }\n\n    function _burn(address from, uint256 amount) internal virtual {\n        balanceOf[from] -= amount;\n\n        // Cannot underflow because a user's balance\n        // will never be larger than the total supply.\n        unchecked {\n            totalSupply -= amount;\n        }\n\n        emit Transfer(from, address(0), amount);\n    }\n}\n"
      },
      "lib/solmate/src/utils/ReentrancyGuard.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Gas optimized reentrancy protection for smart contracts.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ReentrancyGuard.sol)\n/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol)\nabstract contract ReentrancyGuard {\n    uint256 private locked = 1;\n\n    modifier nonReentrant() virtual {\n        require(locked == 1, \"REENTRANCY\");\n\n        locked = 2;\n\n        _;\n\n        locked = 1;\n    }\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "@solmate/=lib/solmate/src/",
        "@forge-std/=lib/forge-std/src/",
        "@ds-test/=lib/forge-std/lib/ds-test/src/",
        "ds-test/=lib/forge-std/lib/ds-test/src/",
        "@openzeppelin/=lib/openzeppelin-contracts/",
        "@uniswap/v3-periphery/=lib/v3-periphery/",
        "@uniswap/v3-core/=lib/v3-core/",
        "@chainlink/=lib/chainlink/",
        "@uniswapV3P/=lib/v3-periphery/contracts/",
        "@uniswapV3C/=lib/v3-core/contracts/",
        "@balancer/=lib/balancer-v2-monorepo/pkg/",
        "@ccip/=lib/ccip/",
        "@pendle/=lib/pendle-core-v2-public/",
        "@balancer-labs/=lib/balancer-v2-monorepo/../../node_modules/@balancer-labs/",
        "axelar-gmp-sdk-solidity/=lib/axelar-gmp-sdk-solidity/contracts/",
        "balancer-v2-monorepo/=lib/balancer-v2-monorepo/",
        "ccip/=lib/ccip/contracts/",
        "chainlink/=lib/chainlink/integration-tests/contracts/ethereum/src/",
        "forge-std/=lib/forge-std/src/",
        "openzeppelin-contracts/=lib/openzeppelin-contracts/",
        "pendle-core-v2-public/=lib/pendle-core-v2-public/contracts/",
        "solmate/=lib/solmate/src/",
        "v3-core/=lib/v3-core/contracts/",
        "v3-periphery/=lib/v3-periphery/contracts/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs",
        "appendCBOR": true
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "shanghai",
      "libraries": {}
    }
  }}