{"file_path":"@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/transparent/TransparentUpgradeableProxy.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC1967/ERC1967Proxy.sol\";\n\n/**\n * @dev Interface for {TransparentUpgradeableProxy}. In order to implement transparency, {TransparentUpgradeableProxy}\n * does not implement this interface directly, and some of its functions are implemented by an internal dispatch\n * mechanism. The compiler is unaware that these functions are implemented by {TransparentUpgradeableProxy} and will not\n * include them in the ABI so this interface must be used to interact with it.\n */\ninterface ITransparentUpgradeableProxy is IERC1967 {\n    function admin() external view returns (address);\n\n    function implementation() external view returns (address);\n\n    function changeAdmin(address) external;\n\n    function upgradeTo(address) external;\n\n    function upgradeToAndCall(address, bytes memory) external payable;\n}\n\n/**\n * @dev This contract implements a proxy that is upgradeable by an admin.\n *\n * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector\n * clashing], which can potentially be used in an attack, this contract uses the\n * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two\n * things that go hand in hand:\n *\n * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if\n * that call matches one of the admin functions exposed by the proxy itself.\n * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the\n * implementation. If the admin tries to call a function on the implementation it will fail with an error that says\n * \"admin cannot fallback to proxy target\".\n *\n * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing\n * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due\n * to sudden errors when trying to call a function from the proxy implementation.\n *\n * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,\n * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.\n *\n * NOTE: The real interface of this proxy is that defined in `ITransparentUpgradeableProxy`. This contract does not\n * inherit from that interface, and instead the admin functions are implicitly implemented using a custom dispatch\n * mechanism in `_fallback`. Consequently, the compiler will not produce an ABI for this contract. This is necessary to\n * fully implement transparency without decoding reverts caused by selector clashes between the proxy and the\n * implementation.\n *\n * WARNING: It is not recommended to extend this contract to add additional external functions. If you do so, the compiler\n * will not check that there are no selector conflicts, due to the note above. A selector clash between any new function\n * and the functions declared in {ITransparentUpgradeableProxy} will be resolved in favor of the new one. This could\n * render the admin operations inaccessible, which could prevent upgradeability. Transparency may also be compromised.\n */\ncontract TransparentUpgradeableProxy is ERC1967Proxy {\n    /**\n     * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and\n     * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.\n     */\n    constructor(address _logic, address admin_, bytes memory _data) payable ERC1967Proxy(_logic, _data) {\n        _changeAdmin(admin_);\n    }\n\n    /**\n     * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.\n     *\n     * CAUTION: This modifier is deprecated, as it could cause issues if the modified function has arguments, and the\n     * implementation provides a function with the same selector.\n     */\n    modifier ifAdmin() {\n        if (msg.sender == _getAdmin()) {\n            _;\n        } else {\n            _fallback();\n        }\n    }\n\n    /**\n     * @dev If caller is the admin process the call internally, otherwise transparently fallback to the proxy behavior\n     */\n    function _fallback() internal virtual override {\n        if (msg.sender == _getAdmin()) {\n            bytes memory ret;\n            bytes4 selector = msg.sig;\n            if (selector == ITransparentUpgradeableProxy.upgradeTo.selector) {\n                ret = _dispatchUpgradeTo();\n            } else if (selector == ITransparentUpgradeableProxy.upgradeToAndCall.selector) {\n                ret = _dispatchUpgradeToAndCall();\n            } else if (selector == ITransparentUpgradeableProxy.changeAdmin.selector) {\n                ret = _dispatchChangeAdmin();\n            } else if (selector == ITransparentUpgradeableProxy.admin.selector) {\n                ret = _dispatchAdmin();\n            } else if (selector == ITransparentUpgradeableProxy.implementation.selector) {\n                ret = _dispatchImplementation();\n            } else {\n                revert(\"TransparentUpgradeableProxy: admin cannot fallback to proxy target\");\n            }\n            assembly {\n                return(add(ret, 0x20), mload(ret))\n            }\n        } else {\n            super._fallback();\n        }\n    }\n\n    /**\n     * @dev Returns the current admin.\n     *\n     * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the\n     * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.\n     * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`\n     */\n    function _dispatchAdmin() private returns (bytes memory) {\n        _requireZeroValue();\n\n        address admin = _getAdmin();\n        return abi.encode(admin);\n    }\n\n    /**\n     * @dev Returns the current implementation.\n     *\n     * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the\n     * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.\n     * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`\n     */\n    function _dispatchImplementation() private returns (bytes memory) {\n        _requireZeroValue();\n\n        address implementation = _implementation();\n        return abi.encode(implementation);\n    }\n\n    /**\n     * @dev Changes the admin of the proxy.\n     *\n     * Emits an {AdminChanged} event.\n     */\n    function _dispatchChangeAdmin() private returns (bytes memory) {\n        _requireZeroValue();\n\n        address newAdmin = abi.decode(msg.data[4:], (address));\n        _changeAdmin(newAdmin);\n\n        return \"\";\n    }\n\n    /**\n     * @dev Upgrade the implementation of the proxy.\n     */\n    function _dispatchUpgradeTo() private returns (bytes memory) {\n        _requireZeroValue();\n\n        address newImplementation = abi.decode(msg.data[4:], (address));\n        _upgradeToAndCall(newImplementation, bytes(\"\"), false);\n\n        return \"\";\n    }\n\n    /**\n     * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified\n     * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the\n     * proxied contract.\n     */\n    function _dispatchUpgradeToAndCall() private returns (bytes memory) {\n        (address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes));\n        _upgradeToAndCall(newImplementation, data, true);\n\n        return \"\";\n    }\n\n    /**\n     * @dev Returns the current admin.\n     *\n     * CAUTION: This function is deprecated. Use {ERC1967Upgrade-_getAdmin} instead.\n     */\n    function _admin() internal view virtual returns (address) {\n        return _getAdmin();\n    }\n\n    /**\n     * @dev To keep this contract fully transparent, all `ifAdmin` functions must be payable. This helper is here to\n     * emulate some proxy functions being non-payable while still allowing value to pass through.\n     */\n    function _requireZeroValue() private {\n        require(msg.value == 0);\n    }\n}\n","deployed_bytecode":"0x60806040523661001357610011610017565b005b6100115b61001f610168565b6001600160a01b0316330361015e5760606001600160e01b03195f35166364d3180d60e11b81016100595761005261019a565b9150610156565b63587086bd60e11b6001600160e01b0319821601610079576100526101ed565b63070d7c6960e41b6001600160e01b031982160161009957610052610231565b621eb96f60e61b6001600160e01b03198216016100b857610052610261565b63a39f25e560e01b6001600160e01b03198216016100d8576100526102a0565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b6101666102b3565b565b5f7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101a46102c3565b5f6101b23660048184610668565b8101906101bf91906106aa565b90506101da8160405180602001604052805f8152505f6102cd565b505060408051602081019091525f815290565b60605f806101fe3660048184610668565b81019061020b91906106d7565b9150915061021b828260016102cd565b60405180602001604052805f8152509250505090565b606061023b6102c3565b5f6102493660048184610668565b81019061025691906106aa565b90506101da816102f8565b606061026b6102c3565b5f610274610168565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b60606102aa6102c3565b5f61027461034f565b6101666102be61034f565b61035d565b3415610166575f80fd5b6102d68361037b565b5f825111806102e25750805b156102f3576102f183836103ba565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f610321610168565b604080516001600160a01b03928316815291841660208301520160405180910390a161034c816103e6565b50565b5f61035861048f565b905090565b365f80375f80365f845af43d5f803e808015610377573d5ff35b3d5ffd5b610384816104b6565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606103df83836040518060600160405280602781526020016107e76027913961054a565b9392505050565b6001600160a01b03811661044b5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161014d565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b5f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61018b565b6001600160a01b0381163b6105235760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161014d565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61046e565b60605f80856001600160a01b031685604051610566919061079b565b5f60405180830381855af49150503d805f811461059e576040519150601f19603f3d011682016040523d82523d5f602084013e6105a3565b606091505b50915091506105b4868383876105be565b9695505050505050565b6060831561062c5782515f03610625576001600160a01b0385163b6106255760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161014d565b5081610636565b610636838361063e565b949350505050565b81511561064e5781518083602001fd5b8060405162461bcd60e51b815260040161014d91906107b1565b5f8085851115610676575f80fd5b83861115610682575f80fd5b5050820193919092039150565b80356001600160a01b03811681146106a5575f80fd5b919050565b5f602082840312156106ba575f80fd5b6103df8261068f565b634e487b7160e01b5f52604160045260245ffd5b5f80604083850312156106e8575f80fd5b6106f18361068f565b9150602083013567ffffffffffffffff81111561070c575f80fd5b8301601f8101851361071c575f80fd5b803567ffffffffffffffff811115610736576107366106c3565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610765576107656106c3565b60405281815282820160200187101561077c575f80fd5b816020840160208301375f602083830101528093505050509250929050565b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220eb083688b567a966712fc62205d8c7edb3629908943ecb7d2d4098a15b037a7564736f6c634300081a0033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"cancun","libraries":{},"optimizer":{"enabled":true,"runs":200},"outputSelection":{"*":{"":["*"],"*":["*"]}}},"optimization_runs":200,"sourcify_repo_url":null,"decoded_constructor_args":[["0x387568e1ea4Ff4D003B8147739dB69D87325E206",{"internalType":"address","name":"_logic","type":"address"}],["0xd41d29fc53fE5Ce9f0fB2328E54d35A2a03a324B",{"internalType":"address","name":"admin_","type":"address"}],["0x",{"internalType":"bytes","name":"_data","type":"bytes"}]],"compiler_version":"v0.8.26+commit.8a97fa7a","is_verified_via_verifier_alliance":false,"verified_at":"2025-05-01T13:12:59.341988Z","implementations":[{"address_hash":"0xE4031e271809d20074E4bef1caeEfEc5f710e8A6","name":"SavingFxUSD"}],"proxy_type":"eip1967","external_libraries":[],"creation_bytecode":"0x6080604052604051610d76380380610d76833981016040819052610022916103c3565b828161002f82825f610043565b5061003b90508261006e565b5050506104df565b61004c836100db565b5f825111806100585750805b1561006957610067838361011a565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6100ad5f80516020610d2f833981519152546001600160a01b031690565b604080516001600160a01b03928316815291841660208301520160405180910390a16100d881610146565b50565b6100e4816101e1565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b606061013f8383604051806060016040528060278152602001610d4f60279139610275565b9392505050565b6001600160a01b0381166101b05760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b805f80516020610d2f8339815191525b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b61024e5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016101a7565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6101c0565b60605f80856001600160a01b0316856040516102919190610494565b5f60405180830381855af49150503d805f81146102c9576040519150601f19603f3d011682016040523d82523d5f602084013e6102ce565b606091505b5090925090506102e0868383876102ea565b9695505050505050565b606083156103585782515f03610351576001600160a01b0385163b6103515760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016101a7565b5081610362565b610362838361036a565b949350505050565b81511561037a5781518083602001fd5b8060405162461bcd60e51b81526004016101a791906104aa565b80516001600160a01b03811681146103aa575f80fd5b919050565b634e487b7160e01b5f52604160045260245ffd5b5f805f606084860312156103d5575f80fd5b6103de84610394565b92506103ec60208501610394565b60408501519092506001600160401b03811115610407575f80fd5b8401601f81018613610417575f80fd5b80516001600160401b03811115610430576104306103af565b604051601f8201601f19908116603f011681016001600160401b038111828210171561045e5761045e6103af565b604052818152828201602001881015610475575f80fd5b8160208401602083015e5f602083830101528093505050509250925092565b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b610843806104ec5f395ff3fe60806040523661001357610011610017565b005b6100115b61001f610168565b6001600160a01b0316330361015e5760606001600160e01b03195f35166364d3180d60e11b81016100595761005261019a565b9150610156565b63587086bd60e11b6001600160e01b0319821601610079576100526101ed565b63070d7c6960e41b6001600160e01b031982160161009957610052610231565b621eb96f60e61b6001600160e01b03198216016100b857610052610261565b63a39f25e560e01b6001600160e01b03198216016100d8576100526102a0565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b6101666102b3565b565b5f7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101a46102c3565b5f6101b23660048184610668565b8101906101bf91906106aa565b90506101da8160405180602001604052805f8152505f6102cd565b505060408051602081019091525f815290565b60605f806101fe3660048184610668565b81019061020b91906106d7565b9150915061021b828260016102cd565b60405180602001604052805f8152509250505090565b606061023b6102c3565b5f6102493660048184610668565b81019061025691906106aa565b90506101da816102f8565b606061026b6102c3565b5f610274610168565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b60606102aa6102c3565b5f61027461034f565b6101666102be61034f565b61035d565b3415610166575f80fd5b6102d68361037b565b5f825111806102e25750805b156102f3576102f183836103ba565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f610321610168565b604080516001600160a01b03928316815291841660208301520160405180910390a161034c816103e6565b50565b5f61035861048f565b905090565b365f80375f80365f845af43d5f803e808015610377573d5ff35b3d5ffd5b610384816104b6565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606103df83836040518060600160405280602781526020016107e76027913961054a565b9392505050565b6001600160a01b03811661044b5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161014d565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b5f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61018b565b6001600160a01b0381163b6105235760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161014d565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61046e565b60605f80856001600160a01b031685604051610566919061079b565b5f60405180830381855af49150503d805f811461059e576040519150601f19603f3d011682016040523d82523d5f602084013e6105a3565b606091505b50915091506105b4868383876105be565b9695505050505050565b6060831561062c5782515f03610625576001600160a01b0385163b6106255760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161014d565b5081610636565b610636838361063e565b949350505050565b81511561064e5781518083602001fd5b8060405162461bcd60e51b815260040161014d91906107b1565b5f8085851115610676575f80fd5b83861115610682575f80fd5b5050820193919092039150565b80356001600160a01b03811681146106a5575f80fd5b919050565b5f602082840312156106ba575f80fd5b6103df8261068f565b634e487b7160e01b5f52604160045260245ffd5b5f80604083850312156106e8575f80fd5b6106f18361068f565b9150602083013567ffffffffffffffff81111561070c575f80fd5b8301601f8101851361071c575f80fd5b803567ffffffffffffffff811115610736576107366106c3565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610765576107656106c3565b60405281815282820160200187101561077c575f80fd5b816020840160208301375f602083830101528093505050509250929050565b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220eb083688b567a966712fc62205d8c7edb3629908943ecb7d2d4098a15b037a7564736f6c634300081a0033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564000000000000000000000000387568e1ea4ff4d003b8147739db69d87325e206000000000000000000000000d41d29fc53fe5ce9f0fb2328e54d35a2a03a324b00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000","name":"TransparentUpgradeableProxy","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"cancun","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"@openzeppelin/contracts/utils/structs/EnumerableSet.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n *     // Add the library methods\n *     using EnumerableSet for EnumerableSet.AddressSet;\n *\n *     // Declare a set state variable\n *     EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position is the index of the value in the `values` array plus 1.\n        // Position 0 is used to mean a value is not in the set.\n        mapping(bytes32 value => uint256) _positions;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._positions[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We cache the value's position to prevent multiple reads from the same storage slot\n        uint256 position = set._positions[value];\n\n        if (position != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 valueIndex = position - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (valueIndex != lastIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the lastValue to the index where the value to delete is\n                set._values[valueIndex] = lastValue;\n                // Update the tracked position of the lastValue (that was just moved)\n                set._positions[lastValue] = position;\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the tracked position for the deleted slot\n            delete set._positions[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._positions[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        bytes32[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n"},{"file_path":"contracts/common/EIP2535/interfaces/IDiamondCut.sol","source_code":"// SPDX-License-Identifier: CC0-1.0\npragma solidity ^0.8.0;\n\n/******************************************************************************\\\n* Author: Nick Mudge <nick@perfectabstractions.com>, Twitter/Github: @mudgen\n* EIP-2535 Diamonds\n/******************************************************************************/\n\nimport { IDiamond } from \"./IDiamond.sol\";\n\ninterface IDiamondCut is IDiamond {\n  /// @notice Add/replace/remove any number of functions and optionally execute\n  ///         a function with delegatecall\n  /// @param _diamondCut Contains the facet addresses and function selectors\n  /// @param _init The address of the contract or facet to execute _calldata\n  /// @param _calldata A function call, including function selector and arguments\n  ///                  _calldata is executed with delegatecall on _init\n  function diamondCut(\n    FacetCut[] calldata _diamondCut,\n    address _init,\n    bytes calldata _calldata\n  ) external;\n}\n"},{"file_path":"@openzeppelin/contracts/access/Ownable2Step.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.20;\n\nimport {Ownable} from \"./Ownable.sol\";\n\n/**\n * @dev Contract module which provides access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is specified at deployment time in the constructor for `Ownable`. This\n * can later be changed with {transferOwnership} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2Step is Ownable {\n    address private _pendingOwner;\n\n    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Returns the address of the pending owner.\n     */\n    function pendingOwner() public view virtual returns (address) {\n        return _pendingOwner;\n    }\n\n    /**\n     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual override onlyOwner {\n        _pendingOwner = newOwner;\n        emit OwnershipTransferStarted(owner(), newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual override {\n        delete _pendingOwner;\n        super._transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev The new owner accepts the ownership transfer.\n     */\n    function acceptOwnership() public virtual {\n        address sender = _msgSender();\n        if (pendingOwner() != sender) {\n            revert OwnableUnauthorizedAccount(sender);\n        }\n        _transferOwnership(sender);\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/utils/introspection/ERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n        return interfaceId == type(IERC165).interfaceId;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC721} from \"../IERC721.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721Metadata is IERC721 {\n    /**\n     * @dev Returns the token collection name.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the token collection symbol.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n     */\n    function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)\n\npragma solidity ^0.8.20;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant NOT_ENTERED = 1;\n    uint256 private constant ENTERED = 2;\n\n    /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard\n    struct ReentrancyGuardStorage {\n        uint256 _status;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.ReentrancyGuard\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;\n\n    function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {\n        assembly {\n            $.slot := ReentrancyGuardStorageLocation\n        }\n    }\n\n    /**\n     * @dev Unauthorized reentrant call.\n     */\n    error ReentrancyGuardReentrantCall();\n\n    function __ReentrancyGuard_init() internal onlyInitializing {\n        __ReentrancyGuard_init_unchained();\n    }\n\n    function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n        $._status = NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n        // On the first call to nonReentrant, _status will be NOT_ENTERED\n        if ($._status == ENTERED) {\n            revert ReentrancyGuardReentrantCall();\n        }\n\n        // Any calls to nonReentrant after this point will fail\n        $._status = ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        $._status = NOT_ENTERED;\n    }\n\n    /**\n     * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n     * `nonReentrant` function in the call stack.\n     */\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n        return $._status == ENTERED;\n    }\n}\n"},{"file_path":"contracts/periphery/facets/RouterManagementFacet.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\n\nimport { LibDiamond } from \"../../common/EIP2535/libraries/LibDiamond.sol\";\nimport { LibRouter } from \"../libraries/LibRouter.sol\";\n\ncontract RouterManagementFacet {\n  using EnumerableSet for EnumerableSet.AddressSet;\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the token approve spender for the given target.\n  function getSpender(address target) external view returns (address _spender) {\n    LibRouter.RouterStorage storage $ = LibRouter.routerStorage();\n    _spender = $.spenders[target];\n    if (_spender == address(0)) _spender = target;\n  }\n\n  /// @notice Return the list of approved targets.\n  function getApprovedTargets() external view returns (address[] memory _accounts) {\n    LibRouter.RouterStorage storage $ = LibRouter.routerStorage();\n    uint256 _numAccount = $.approvedTargets.length();\n    _accounts = new address[](_numAccount);\n    for (uint256 i = 0; i < _numAccount; i++) {\n      _accounts[i] = $.approvedTargets.at(i);\n    }\n  }\n\n  /// @notice Return the whitelist kind for the given target.\n  function getWhitelisted() external view returns (address[] memory _accounts) {\n    LibRouter.RouterStorage storage $ = LibRouter.routerStorage();\n    uint256 _numAccount = $.whitelisted.length();\n    _accounts = new address[](_numAccount);\n    for (uint256 i = 0; i < _numAccount; i++) {\n      _accounts[i] = $.whitelisted.at(i);\n    }\n  }\n\n  function getRevenuePool() external view returns (address) {\n    LibRouter.RouterStorage storage $ = LibRouter.routerStorage();\n    return $.revenuePool;\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Approve contract to be used in token converting.\n  function approveTarget(address target, address spender) external {\n    LibDiamond.enforceIsContractOwner();\n    LibRouter.approveTarget(target, spender);\n  }\n\n  /// @notice Remove approve contract in token converting.\n  function removeTarget(address target) external {\n    LibDiamond.enforceIsContractOwner();\n    LibRouter.removeTarget(target);\n  }\n\n  /// @notice Update whitelist status of the given contract.\n  function updateWhitelist(address target, bool status) external {\n    LibDiamond.enforceIsContractOwner();\n    LibRouter.updateWhitelist(target, status);\n  }\n\n  /// @notice Update revenue pool.\n  function updateRevenuePool(address revenuePool) external {\n    LibDiamond.enforceIsContractOwner();\n    LibRouter.updateRevenuePool(revenuePool);\n  }\n}\n"},{"file_path":"contracts/interfaces/IRewardSplitter.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IRewardSplitter {\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Split token to different RebalancePool.\n  /// @param token The address of token to split.\n  function split(address token) external;\n\n  /// @notice Deposit new rewards to this contract.\n  ///\n  /// @param token The address of reward token.\n  /// @param amount The amount of new rewards.\n  function depositReward(address token, uint256 amount) external;\n}\n"},{"file_path":"@openzeppelin/contracts-v4/utils/Address.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     *\n     * Furthermore, `isContract` will also return true if the target contract within\n     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n     * which only has an effect at the end of a transaction.\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n     *\n     * _Available since v4.8._\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        if (success) {\n            if (returndata.length == 0) {\n                // only check isContract if the call was successful and the return data is empty\n                // otherwise we already know that it was a contract\n                require(isContract(target), \"Address: call to non-contract\");\n            }\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason or using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    function _revert(bytes memory returndata, string memory errorMessage) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            /// @solidity memory-safe-assembly\n            assembly {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert(errorMessage);\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/utils/Context.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/token/ERC20/ERC20Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20Upgradeable.sol\";\nimport \"./extensions/IERC20MetadataUpgradeable.sol\";\nimport \"../../utils/ContextUpgradeable.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {\n    mapping(address => uint256) private _balances;\n\n    mapping(address => mapping(address => uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n\n    string private _name;\n    string private _symbol;\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {\n        __ERC20_init_unchained(name_, symbol_);\n    }\n\n    function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the default value returned by this function, unless\n     * it's overridden.\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual override returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual override returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function transfer(address to, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _transfer(owner, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n     * `transferFrom`. This is semantically equivalent to an infinite approval.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * NOTE: Does not update the allowance if the current allowance\n     * is the maximum `uint256`.\n     *\n     * Requirements:\n     *\n     * - `from` and `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     * - the caller must have allowance for ``from``'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {\n        address spender = _msgSender();\n        _spendAllowance(from, spender, amount);\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, allowance(owner, spender) + addedValue);\n        return true;\n    }\n\n    /**\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        uint256 currentAllowance = allowance(owner, spender);\n        require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n        unchecked {\n            _approve(owner, spender, currentAllowance - subtractedValue);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Moves `amount` of tokens from `from` to `to`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     */\n    function _transfer(address from, address to, uint256 amount) internal virtual {\n        require(from != address(0), \"ERC20: transfer from the zero address\");\n        require(to != address(0), \"ERC20: transfer to the zero address\");\n\n        _beforeTokenTransfer(from, to, amount);\n\n        uint256 fromBalance = _balances[from];\n        require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n        unchecked {\n            _balances[from] = fromBalance - amount;\n            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n            // decrementing then incrementing.\n            _balances[to] += amount;\n        }\n\n        emit Transfer(from, to, amount);\n\n        _afterTokenTransfer(from, to, amount);\n    }\n\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function _mint(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        _beforeTokenTransfer(address(0), account, amount);\n\n        _totalSupply += amount;\n        unchecked {\n            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n            _balances[account] += amount;\n        }\n        emit Transfer(address(0), account, amount);\n\n        _afterTokenTransfer(address(0), account, amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: burn from the zero address\");\n\n        _beforeTokenTransfer(account, address(0), amount);\n\n        uint256 accountBalance = _balances[account];\n        require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n        unchecked {\n            _balances[account] = accountBalance - amount;\n            // Overflow not possible: amount <= accountBalance <= totalSupply.\n            _totalSupply -= amount;\n        }\n\n        emit Transfer(account, address(0), amount);\n\n        _afterTokenTransfer(account, address(0), amount);\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(address owner, address spender, uint256 amount) internal virtual {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n     *\n     * Does not update the allowance amount in case of infinite allowance.\n     * Revert if not enough allowance is available.\n     *\n     * Might emit an {Approval} event.\n     */\n    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n            unchecked {\n                _approve(owner, spender, currentAllowance - amount);\n            }\n        }\n    }\n\n    /**\n     * @dev Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n    /**\n     * @dev Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * has been transferred to `to`.\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[45] private __gap;\n}\n"},{"file_path":"contracts/core/FxUSDRegeneracy.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { AccessControlUpgradeable } from \"@openzeppelin/contracts-upgradeable-v4/access/AccessControlUpgradeable.sol\";\nimport { ERC20PermitUpgradeable } from \"@openzeppelin/contracts-upgradeable-v4/token/ERC20/extensions/ERC20PermitUpgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable-v4/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable-v4/token/ERC20/IERC20Upgradeable.sol\";\nimport { EnumerableSetUpgradeable } from \"@openzeppelin/contracts-upgradeable-v4/utils/structs/EnumerableSetUpgradeable.sol\";\n\nimport { IFxFractionalTokenV2 } from \"../v2/interfaces/IFxFractionalTokenV2.sol\";\nimport { IFxMarketV2 } from \"../v2/interfaces/IFxMarketV2.sol\";\nimport { IFxTreasuryV2 } from \"../v2/interfaces/IFxTreasuryV2.sol\";\nimport { IFxUSD } from \"../v2/interfaces/IFxUSD.sol\";\nimport { IFxShareableRebalancePool } from \"../v2/interfaces/IFxShareableRebalancePool.sol\";\nimport { IFxUSDRegeneracy } from \"../interfaces/IFxUSDRegeneracy.sol\";\nimport { IPegKeeper } from \"../interfaces/IPegKeeper.sol\";\n\nimport { Math } from \"../libraries/Math.sol\";\n\n/// @dev It has the same storage layout with `https://github.com/AladdinDAO/aladdin-v3-contracts/contracts/f(x)/v2/FxUSD.sol`.\ncontract FxUSDRegeneracy is AccessControlUpgradeable, ERC20PermitUpgradeable, IFxUSD, IFxUSDRegeneracy {\n  using SafeERC20Upgradeable for IERC20Upgradeable;\n  using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;\n\n  /**********\n   * Errors *\n   **********/\n\n  error ErrorCallerNotPoolManager();\n\n  error ErrorCallerNotPegKeeper();\n\n  error ErrorExceedStableReserve();\n\n  error ErrorInsufficientOutput();\n\n  error ErrorInsufficientBuyBack();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @notice The role for migrator.\n  bytes32 public constant MIGRATOR_ROLE = keccak256(\"MIGRATOR_ROLE\");\n\n  /// @dev The precision used to compute nav.\n  uint256 private constant PRECISION = 1e18;\n\n  /***********\n   * Structs *\n   ***********/\n\n  /// @param fToken The address of Fractional Token.\n  /// @param treasury The address of treasury contract.\n  /// @param market The address of market contract.\n  /// @param mintCap The maximum amount of fToken can be minted.\n  /// @param managed The amount of fToken managed in this contract.\n  struct FxMarketStruct {\n    address fToken;\n    address treasury;\n    address market;\n    uint256 mintCap;\n    uint256 managed;\n  }\n\n  /// @dev The struct for stable token reserve.\n  /// @param owned The number of stable coins owned in this contract.\n  /// @param managed The amount of fxUSD managed under this stable coin.\n  /// @param enabled Whether this stable coin is enabled, currently always true\n  /// @param decimals The decimal for the stable coin.\n  /// @param reserved Reserved slots for future usage.\n  struct StableReserveStruct {\n    uint96 owned;\n    uint96 managed;\n    uint8 decimals;\n  }\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @inheritdoc IFxUSDRegeneracy\n  address public immutable poolManager;\n\n  /// @inheritdoc IFxUSDRegeneracy\n  address public immutable stableToken;\n\n  /// @inheritdoc IFxUSDRegeneracy\n  address public immutable pegKeeper;\n\n  /*********************\n   * Storage Variables *\n   *********************/\n\n  /// @notice Mapping from base token address to metadata.\n  mapping(address => FxMarketStruct) public markets;\n\n  /// @dev The list of supported base tokens.\n  EnumerableSetUpgradeable.AddressSet private supportedTokens;\n\n  /// @dev The list of supported rebalance pools.\n  EnumerableSetUpgradeable.AddressSet private supportedPools;\n\n  /// @notice The total supply for legacy 2.0 pools.\n  uint256 public legacyTotalSupply;\n\n  /// @notice The reserve struct for stable token.\n  StableReserveStruct public stableReserve;\n\n  /*************\n   * Modifiers *\n   *************/\n\n  modifier onlySupportedMarket(address _baseToken) {\n    _checkBaseToken(_baseToken);\n    _;\n  }\n\n  modifier onlySupportedPool(address _pool) {\n    if (!supportedPools.contains(_pool)) revert ErrorUnsupportedRebalancePool();\n    _;\n  }\n\n  modifier onlyMintableMarket(address _baseToken, bool isMint) {\n    _checkMarketMintable(_baseToken, isMint);\n    _;\n  }\n\n  modifier onlyPoolManager() {\n    if (_msgSender() != poolManager) revert ErrorCallerNotPoolManager();\n    _;\n  }\n\n  modifier onlyPegKeeper() {\n    if (_msgSender() != pegKeeper) revert ErrorCallerNotPegKeeper();\n    _;\n  }\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _poolManager, address _stableToken, address _pegKeeper) {\n    poolManager = _poolManager;\n    stableToken = _stableToken;\n    pegKeeper = _pegKeeper;\n  }\n\n  function initialize(string memory _name, string memory _symbol) external initializer {\n    __Context_init();\n    __ERC165_init();\n    __AccessControl_init();\n    __ERC20_init(_name, _symbol);\n    __ERC20Permit_init(_name);\n\n    _grantRole(DEFAULT_ADMIN_ROLE, _msgSender());\n  }\n\n  function initializeV2() external reinitializer(2) {\n    stableReserve.decimals = FxUSDRegeneracy(stableToken).decimals();\n    legacyTotalSupply = totalSupply();\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @inheritdoc IFxUSD\n  function getMarkets() external view override returns (address[] memory _tokens) {\n    uint256 _numMarkets = supportedTokens.length();\n    _tokens = new address[](_numMarkets);\n    for (uint256 i = 0; i < _numMarkets; ++i) {\n      _tokens[i] = supportedTokens.at(i);\n    }\n  }\n\n  /// @inheritdoc IFxUSD\n  function getRebalancePools() external view override returns (address[] memory _pools) {\n    uint256 _numPools = supportedPools.length();\n    _pools = new address[](_numPools);\n    for (uint256 i = 0; i < _numPools; ++i) {\n      _pools[i] = supportedPools.at(i);\n    }\n  }\n\n  /// @inheritdoc IFxUSD\n  function nav() external view override returns (uint256 _nav) {\n    uint256 _numMarkets = supportedTokens.length();\n    uint256 _supply = legacyTotalSupply;\n    if (_supply == 0) return PRECISION;\n\n    for (uint256 i = 0; i < _numMarkets; i++) {\n      address _baseToken = supportedTokens.at(i);\n      address _fToken = markets[_baseToken].fToken;\n      uint256 _fnav = IFxFractionalTokenV2(_fToken).nav();\n      _nav += _fnav * markets[_baseToken].managed;\n    }\n    _nav /= _supply;\n  }\n\n  /// @inheritdoc IFxUSD\n  function isUnderCollateral() public view override returns (bool) {\n    uint256 _numMarkets = supportedTokens.length();\n    for (uint256 i = 0; i < _numMarkets; i++) {\n      address _baseToken = supportedTokens.at(i);\n      address _treasury = markets[_baseToken].treasury;\n      if (IFxTreasuryV2(_treasury).isUnderCollateral()) return true;\n    }\n    return false;\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc IFxUSD\n  function wrap(\n    address _baseToken,\n    uint256 _amount,\n    address _receiver\n  ) external override onlySupportedMarket(_baseToken) onlyMintableMarket(_baseToken, false) {\n    if (isUnderCollateral()) revert ErrorUnderCollateral();\n\n    address _fToken = markets[_baseToken].fToken;\n    IERC20Upgradeable(_fToken).safeTransferFrom(_msgSender(), address(this), _amount);\n\n    _mintShares(_baseToken, _receiver, _amount);\n\n    emit Wrap(_baseToken, _msgSender(), _receiver, _amount);\n  }\n\n  /// @inheritdoc IFxUSD\n  function unwrap(\n    address _baseToken,\n    uint256 _amount,\n    address _receiver\n  ) external onlyRole(MIGRATOR_ROLE) onlySupportedMarket(_baseToken) {\n    if (isUnderCollateral()) revert ErrorUnderCollateral();\n\n    _burnShares(_baseToken, _msgSender(), _amount);\n\n    address _fToken = markets[_baseToken].fToken;\n    IERC20Upgradeable(_fToken).safeTransfer(_receiver, _amount);\n\n    emit Unwrap(_baseToken, _msgSender(), _receiver, _amount);\n  }\n\n  /// @inheritdoc IFxUSD\n  function wrapFrom(address _pool, uint256 _amount, address _receiver) external override onlySupportedPool(_pool) {\n    if (isUnderCollateral()) revert ErrorUnderCollateral();\n\n    address _baseToken = IFxShareableRebalancePool(_pool).baseToken();\n    _checkBaseToken(_baseToken);\n    _checkMarketMintable(_baseToken, false);\n\n    IFxShareableRebalancePool(_pool).withdrawFrom(_msgSender(), _amount, address(this));\n    _mintShares(_baseToken, _receiver, _amount);\n\n    emit Wrap(_baseToken, _msgSender(), _receiver, _amount);\n  }\n\n  /// @inheritdoc IFxUSD\n  function mint(address, uint256, address, uint256) external virtual override returns (uint256) {\n    revert(\"mint paused\");\n  }\n\n  /// @inheritdoc IFxUSD\n  function earn(address, uint256, address) external virtual override {\n    revert(\"earn paused\");\n  }\n\n  /// @inheritdoc IFxUSD\n  function mintAndEarn(address, uint256, address, uint256) external virtual override returns (uint256) {\n    revert(\"mint and earn paused\");\n  }\n\n  /// @inheritdoc IFxUSD\n  function redeem(\n    address _baseToken,\n    uint256 _amountIn,\n    address _receiver,\n    uint256 _minOut\n  ) external override onlySupportedMarket(_baseToken) returns (uint256 _amountOut, uint256 _bonusOut) {\n    if (isUnderCollateral()) revert ErrorUnderCollateral();\n\n    address _market = markets[_baseToken].market;\n    address _fToken = markets[_baseToken].fToken;\n\n    uint256 _balance = IERC20Upgradeable(_fToken).balanceOf(address(this));\n    (_amountOut, _bonusOut) = IFxMarketV2(_market).redeemFToken(_amountIn, _receiver, _minOut);\n    // the real amount of fToken redeemed\n    _amountIn = _balance - IERC20Upgradeable(_fToken).balanceOf(address(this));\n\n    _burnShares(_baseToken, _msgSender(), _amountIn);\n    emit Unwrap(_baseToken, _msgSender(), _receiver, _amountIn);\n  }\n\n  /// @inheritdoc IFxUSD\n  function redeemFrom(\n    address _pool,\n    uint256 _amountIn,\n    address _receiver,\n    uint256 _minOut\n  ) external override onlySupportedPool(_pool) returns (uint256 _amountOut, uint256 _bonusOut) {\n    address _baseToken = IFxShareableRebalancePool(_pool).baseToken();\n    address _market = markets[_baseToken].market;\n    address _fToken = markets[_baseToken].fToken;\n\n    // calculate the actual amount of fToken withdrawn from rebalance pool.\n    _amountOut = IERC20Upgradeable(_fToken).balanceOf(address(this));\n    IFxShareableRebalancePool(_pool).withdrawFrom(_msgSender(), _amountIn, address(this));\n    _amountOut = IERC20Upgradeable(_fToken).balanceOf(address(this)) - _amountOut;\n\n    // redeem fToken as base token\n    // assume all fToken will be redeem for simplicity\n    (_amountOut, _bonusOut) = IFxMarketV2(_market).redeemFToken(_amountOut, _receiver, _minOut);\n  }\n\n  /// @inheritdoc IFxUSD\n  function autoRedeem(\n    uint256 _amountIn,\n    address _receiver,\n    uint256[] memory _minOuts\n  )\n    external\n    override\n    returns (address[] memory _baseTokens, uint256[] memory _amountOuts, uint256[] memory _bonusOuts)\n  {\n    uint256 _numMarkets = supportedTokens.length();\n    if (_minOuts.length != _numMarkets) revert ErrorLengthMismatch();\n\n    _baseTokens = new address[](_numMarkets);\n    _amountOuts = new uint256[](_numMarkets);\n    _bonusOuts = new uint256[](_numMarkets);\n    uint256[] memory _supplies = new uint256[](_numMarkets);\n\n    bool _isUnderCollateral = false;\n    for (uint256 i = 0; i < _numMarkets; i++) {\n      _baseTokens[i] = supportedTokens.at(i);\n      _supplies[i] = markets[_baseTokens[i]].managed;\n      address _treasury = markets[_baseTokens[i]].treasury;\n      if (IFxTreasuryV2(_treasury).isUnderCollateral()) _isUnderCollateral = true;\n    }\n\n    uint256 _supply = legacyTotalSupply;\n    if (_amountIn > _supply) revert(\"redeem exceed supply\");\n    unchecked {\n      legacyTotalSupply = _supply - _amountIn;\n    }\n    _burn(_msgSender(), _amountIn);\n\n    if (_isUnderCollateral) {\n      // redeem proportionally\n      for (uint256 i = 0; i < _numMarkets; i++) {\n        _amountOuts[i] = (_supplies[i] * _amountIn) / _supply;\n      }\n    } else {\n      // redeem by sorted fToken amounts\n      while (_amountIn > 0) {\n        unchecked {\n          uint256 maxSupply = _supplies[0];\n          uint256 maxIndex = 0;\n          for (uint256 i = 1; i < _numMarkets; i++) {\n            if (_supplies[i] > maxSupply) {\n              maxSupply = _supplies[i];\n              maxIndex = i;\n            }\n          }\n          if (_amountIn > maxSupply) _amountOuts[maxIndex] = maxSupply;\n          else _amountOuts[maxIndex] = _amountIn;\n          _supplies[maxIndex] -= _amountOuts[maxIndex];\n          _amountIn -= _amountOuts[maxIndex];\n        }\n      }\n    }\n\n    for (uint256 i = 0; i < _numMarkets; i++) {\n      if (_amountOuts[i] == 0) continue;\n      emit Unwrap(_baseTokens[i], _msgSender(), _receiver, _amountOuts[i]);\n\n      markets[_baseTokens[i]].managed -= _amountOuts[i];\n      address _market = markets[_baseTokens[i]].market;\n      (_amountOuts[i], _bonusOuts[i]) = IFxMarketV2(_market).redeemFToken(_amountOuts[i], _receiver, _minOuts[i]);\n    }\n  }\n\n  /// @inheritdoc IFxUSDRegeneracy\n  function mint(address to, uint256 amount) external onlyPoolManager {\n    _mint(to, amount);\n  }\n\n  /// @inheritdoc IFxUSDRegeneracy\n  function burn(address from, uint256 amount) external onlyPoolManager {\n    _burn(from, amount);\n  }\n\n  /// @inheritdoc IFxUSDRegeneracy\n  function onRebalanceWithStable(uint256 amountStableToken, uint256 amountFxUSD) external onlyPoolManager {\n    stableReserve.owned += uint96(amountStableToken);\n    stableReserve.managed += uint96(amountFxUSD);\n\n    emit RebalanceWithStable(amountStableToken, amountFxUSD);\n  }\n\n  /// @inheritdoc IFxUSDRegeneracy\n  function buyback(\n    uint256 amountIn,\n    address receiver,\n    bytes calldata data\n  ) external onlyPegKeeper returns (uint256 amountOut, uint256 bonusOut) {\n    StableReserveStruct memory cachedStableReserve = stableReserve;\n    if (amountIn > cachedStableReserve.owned) revert ErrorExceedStableReserve();\n\n    // rounding up\n    uint256 expectedFxUSD = Math.mulDivUp(amountIn, cachedStableReserve.managed, cachedStableReserve.owned);\n\n    // convert USDC to fxUSD\n    IERC20Upgradeable(stableToken).safeTransfer(pegKeeper, amountIn);\n    uint256 actualOut = balanceOf(address(this));\n    amountOut = IPegKeeper(pegKeeper).onSwap(stableToken, address(this), amountIn, data);\n    actualOut = balanceOf(address(this)) - actualOut;\n\n    // check actual fxUSD swapped in case peg keeper is hacked.\n    if (amountOut > actualOut) revert ErrorInsufficientOutput();\n\n    // check fxUSD swapped can cover debts\n    if (amountOut < expectedFxUSD) revert ErrorInsufficientBuyBack();\n    bonusOut = amountOut - expectedFxUSD;\n\n    _burn(address(this), expectedFxUSD);\n    unchecked {\n      cachedStableReserve.owned -= uint96(amountIn);\n      if (cachedStableReserve.managed > expectedFxUSD) {\n        cachedStableReserve.managed -= uint96(expectedFxUSD);\n      } else {\n        cachedStableReserve.managed = 0;\n      }\n      stableReserve = cachedStableReserve;\n    }\n\n    if (bonusOut > 0) {\n      _transfer(address(this), receiver, bonusOut);\n    }\n\n    emit Buyback(amountIn, amountOut, bonusOut);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to check base token.\n  /// @param _baseToken The address of the base token.\n  function _checkBaseToken(address _baseToken) private view {\n    if (!supportedTokens.contains(_baseToken)) revert ErrorUnsupportedMarket();\n  }\n\n  /// @dev Internal function to check market.\n  /// @param _baseToken The address of the base token.\n  /// @param _checkCollateralRatio Whether to check collateral ratio.\n  function _checkMarketMintable(address _baseToken, bool _checkCollateralRatio) private view {\n    address _treasury = markets[_baseToken].treasury;\n    if (_checkCollateralRatio) {\n      uint256 _collateralRatio = IFxTreasuryV2(_treasury).collateralRatio();\n      uint256 _stabilityRatio = IFxMarketV2(markets[_baseToken].market).stabilityRatio();\n      // not allow to mint when collateral ratio <= stability ratio\n      if (_collateralRatio <= _stabilityRatio) revert ErrorMarketInStabilityMode();\n    }\n    // not allow to mint when price is invalid\n    if (!IFxTreasuryV2(_treasury).isBaseTokenPriceValid()) revert ErrorMarketWithInvalidPrice();\n  }\n\n  /// @dev Internal function to mint fxUSD.\n  /// @param _baseToken The address of the base token.\n  /// @param _receiver The address of fxUSD recipient.\n  /// @param _amount The amount of fxUSD to mint.\n  function _mintShares(address _baseToken, address _receiver, uint256 _amount) private {\n    unchecked {\n      markets[_baseToken].managed += _amount;\n      legacyTotalSupply += _amount;\n    }\n\n    _mint(_receiver, _amount);\n  }\n\n  /// @dev Internal function to burn fxUSD.\n  /// @param _baseToken The address of the base token.\n  /// @param _owner The address of fxUSD owner.\n  /// @param _amount The amount of fxUSD to burn.\n  function _burnShares(address _baseToken, address _owner, uint256 _amount) private {\n    uint256 _managed = markets[_baseToken].managed;\n    if (_amount > _managed) revert ErrorInsufficientLiquidity();\n    unchecked {\n      markets[_baseToken].managed -= _amount;\n      legacyTotalSupply -= _amount;\n    }\n\n    _burn(_owner, _amount);\n  }\n}\n"},{"file_path":"contracts/interfaces/IProtocolFees.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IProtocolFees {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when the reserve pool contract is updated.\n  /// @param oldReservePool The address of previous reserve pool.\n  /// @param newReservePool The address of current reserve pool.\n  event UpdateReservePool(address indexed oldReservePool, address indexed newReservePool);\n\n  /// @notice Emitted when the treasury contract is updated.\n  /// @param oldTreasury The address of previous treasury contract.\n  /// @param newTreasury The address of current treasury contract.\n  event UpdateTreasury(address indexed oldTreasury, address indexed newTreasury);\n\n  /// @notice Emitted when the revenue pool contract is updated.\n  /// @param oldPool The address of previous revenue pool contract.\n  /// @param newPool The address of current revenue pool contract.\n  event UpdateRevenuePool(address indexed oldPool, address indexed newPool);\n\n  /// @notice Emitted when the ratio for treasury is updated.\n  /// @param oldRatio The value of the previous ratio, multiplied by 1e9.\n  /// @param newRatio The value of the current ratio, multiplied by 1e9.\n  event UpdateRewardsExpenseRatio(uint256 oldRatio, uint256 newRatio);\n\n  /// @notice Emitted when the ratio for treasury is updated.\n  /// @param oldRatio The value of the previous ratio, multiplied by 1e9.\n  /// @param newRatio The value of the current ratio, multiplied by 1e9.\n  event UpdateFundingExpenseRatio(uint256 oldRatio, uint256 newRatio);\n\n  /// @notice Emitted when the ratio for treasury is updated.\n  /// @param oldRatio The value of the previous ratio, multiplied by 1e9.\n  /// @param newRatio The value of the current ratio, multiplied by 1e9.\n  event UpdateLiquidationExpenseRatio(uint256 oldRatio, uint256 newRatio);\n\n  /// @notice Emitted when the ratio for harvester is updated.\n  /// @param oldRatio The value of the previous ratio, multiplied by 1e9.\n  /// @param newRatio The value of the current ratio, multiplied by 1e9.\n  event UpdateHarvesterRatio(uint256 oldRatio, uint256 newRatio);\n\n  /// @notice Emitted when the flash loan fee ratio is updated.\n  /// @param oldRatio The value of the previous ratio, multiplied by 1e9.\n  /// @param newRatio The value of the current ratio, multiplied by 1e9.\n  event UpdateFlashLoanFeeRatio(uint256 oldRatio, uint256 newRatio);\n\n  /// @notice Emitted when the redeem fee ratio is updated.\n  /// @param oldRatio The value of the previous ratio, multiplied by 1e9.\n  /// @param newRatio The value of the current ratio, multiplied by 1e9.\n  event UpdateRedeemFeeRatio(uint256 oldRatio, uint256 newRatio);\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the fee ratio distributed as protocol revenue in funding costs, multiplied by 1e9.\n  function getFundingExpenseRatio() external view returns (uint256);\n\n  /// @notice Return the fee ratio distributed as protocol revenue in general rewards, multiplied by 1e9.\n  function getRewardsExpenseRatio() external view returns (uint256);\n\n  /// @notice Return the fee ratio distributed as protocol revenue in liquidation/rebalance, multiplied by 1e9.\n  function getLiquidationExpenseRatio() external view returns (uint256);\n\n  /// @notice Return the fee ratio distributed to fxBASE in funding costs, multiplied by 1e9.\n  function getFundingFxSaveRatio() external view returns (uint256);\n\n  /// @notice Return the fee ratio distributed to fxBASE in general rewards, multiplied by 1e9.\n  function getRewardsFxSaveRatio() external view returns (uint256);\n\n  /// @notice Return the fee ratio distributed ad harvester bounty, multiplied by 1e9.\n  function getHarvesterRatio() external view returns (uint256);\n\n  /// @notice Return the flash loan fee ratio, multiplied by 1e9.\n  function getFlashLoanFeeRatio() external view returns (uint256);\n\n  /// @notice Return the redeem fee ratio, multiplied by 1e9.\n  function getRedeemFeeRatio() external view returns (uint256);\n\n  /// @notice Return the address of reserve pool.\n  function reservePool() external view returns (address);\n\n  /// @notice Return the address of protocol treasury.\n  function treasury() external view returns (address);\n\n  /// @notice Return the address of protocol revenue pool.\n  function revenuePool() external view returns (address);\n\n  /// @notice Return the amount of protocol fees accumulated by the given pool.\n  function accumulatedPoolFees(address pool) external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Withdraw accumulated pool fee for the given pool lists.\n  /// @param pools The list of pool addresses to withdraw.\n  function withdrawAccumulatedPoolFee(address[] memory pools) external;\n}\n"},{"file_path":"contracts/interfaces/IPoolManager.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IPoolManager {\n  /**********\n   * Events *\n   **********/\n  \n  /// @notice Register a new pool.\n  /// @param pool The address of fx pool.\n  event RegisterPool(address indexed pool);\n\n  /// @notice Emitted when the reward splitter contract is updated.\n  /// @param pool The address of fx pool.\n  /// @param oldSplitter The address of previous reward splitter contract.\n  /// @param newSplitter The address of current reward splitter contract.\n  event UpdateRewardSplitter(address indexed pool, address indexed oldSplitter, address indexed newSplitter);\n\n  /// @notice Emitted when the threshold for permissionless liquidate/rebalance is updated.\n  /// @param oldThreshold The value of previous threshold.\n  /// @param newThreshold The value of current threshold.\n  event UpdatePermissionedLiquidationThreshold(uint256 oldThreshold, uint256 newThreshold);\n\n  /// @notice Emitted when token rate is updated.\n  /// @param scalar The token scalar to reach 18 decimals.\n  /// @param provider The address of token rate provider.\n  event UpdateTokenRate(address indexed token, uint256 scalar, address provider);\n\n  /// @notice Emitted when pool capacity is updated.\n  /// @param pool The address of fx pool.\n  /// @param collateralCapacity The capacity for collateral token.\n  /// @param debtCapacity The capacity for debt token.\n  event UpdatePoolCapacity(address indexed pool, uint256 collateralCapacity, uint256 debtCapacity);\n\n  /// @notice Emitted when position is updated.\n  /// @param pool The address of pool where the position belongs to.\n  /// @param position The id of the position.\n  /// @param deltaColls The amount of collateral token changes.\n  /// @param deltaDebts The amount of debt token changes.\n  /// @param protocolFees The amount of protocol fees charges.\n  event Operate(\n    address indexed pool,\n    uint256 indexed position,\n    int256 deltaColls,\n    int256 deltaDebts,\n    uint256 protocolFees\n  );\n  \n  /// @notice Emitted when redeem happened.\n  /// @param pool The address of pool redeemed.\n  /// @param colls The amount of collateral tokens redeemed.\n  /// @param debts The amount of debt tokens redeemed.\n  /// @param protocolFees The amount of protocol fees charges.\n  event Redeem(address indexed pool, uint256 colls, uint256 debts, uint256 protocolFees);\n\n  /// @notice Emitted when rebalance for a tick happened.\n  /// @param pool The address of pool rebalanced.\n  /// @param tick The index of tick rebalanced.\n  /// @param colls The amount of collateral tokens rebalanced.\n  /// @param fxUSDDebts The amount of fxUSD rebalanced.\n  /// @param stableDebts The amount of stable token (a.k.a USDC) rebalanced.\n  event RebalanceTick(address indexed pool, int16 indexed tick, uint256 colls, uint256 fxUSDDebts, uint256 stableDebts);\n\n  /// @notice Emitted when rebalance for a position happened.\n  /// @param pool The address of pool rebalanced.\n  /// @param position The index of position rebalanced.\n  /// @param colls The amount of collateral tokens rebalanced.\n  /// @param fxUSDDebts The amount of fxUSD rebalanced.\n  /// @param stableDebts The amount of stable token (a.k.a USDC) rebalanced.\n  event RebalancePosition(address indexed pool, uint256 indexed position, uint256 colls, uint256 fxUSDDebts, uint256 stableDebts);\n\n  /// @notice Emitted when liquidate for a position happened.\n  /// @param pool The address of pool liquidated.\n  /// @param position The index of position liquidated.\n  /// @param colls The amount of collateral tokens liquidated.\n  /// @param fxUSDDebts The amount of fxUSD liquidated.\n  /// @param stableDebts The amount of stable token (a.k.a USDC) liquidated.\n  event LiquidatePosition(address indexed pool, uint256 indexed position, uint256 colls, uint256 fxUSDDebts, uint256 stableDebts);\n\n  /// @notice Emitted when someone harvest pending rewards.\n  /// @param caller The address of caller.\n  /// @param amountRewards The amount of total harvested rewards.\n  /// @param amountFunding The amount of total harvested funding.\n  /// @param performanceFee The amount of harvested rewards distributed to protocol revenue.\n  /// @param harvestBounty The amount of harvested rewards distributed to caller as harvest bounty.\n  event Harvest(\n    address indexed caller,\n    address indexed pool,\n    uint256 amountRewards,\n    uint256 amountFunding,\n    uint256 performanceFee,\n    uint256 harvestBounty\n  );\n\n  /*************************\n   * Public View Functions *\n   *************************/\n  \n  /// @notice The address of fxUSD.\n  function fxUSD() external view returns (address);\n\n  /// @notice The address of FxUSDSave.\n  function fxBASE() external view returns (address);\n\n  /// @notice The address of `PegKeeper`.\n  function pegKeeper() external view returns (address);\n\n  /// @notice The address of reward splitter.\n  function rewardSplitter(address pool) external view returns (address);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n  \n  /// @notice Open a new position or operate on an old position.\n  /// @param pool The address of pool to operate.\n  /// @param positionId The id of the position. If `positionId=0`, it means we need to open a new position.\n  /// @param newColl The amount of collateral token to supply (positive value) or withdraw (negative value).\n  /// @param newDebt The amount of debt token to borrow (positive value) or repay (negative value).\n  /// @return actualPositionId The id of this position.\n  function operate(\n    address pool,\n    uint256 positionId,\n    int256 newColl,\n    int256 newDebt\n  ) external returns (uint256 actualPositionId);\n\n  /// @notice Redeem debt tokens to get collateral tokens.\n  /// @param pool The address of pool to redeem.\n  /// @param debts The amount of debt tokens to redeem.\n  /// @param minColls The minimum amount of collateral tokens should redeem.\n  /// @return colls The amount of collateral tokens redeemed.\n  function redeem(address pool, uint256 debts, uint256 minColls) external returns (uint256 colls);\n\n  /// @notice Rebalance all positions in the given tick.\n  /// @param pool The address of pool to rebalance.\n  /// @param receiver The address of recipient for rebalanced tokens.\n  /// @param tick The index of tick to rebalance.\n  /// @param maxFxUSD The maximum amount of fxUSD to rebalance.\n  /// @param maxStable The maximum amount of stable token (a.k.a USDC) to rebalance.\n  /// @return colls The amount of collateral tokens rebalanced.\n  /// @return fxUSDUsed The amount of fxUSD used to rebalance.\n  /// @return stableUsed The amount of stable token used to rebalance.\n  function rebalance(\n    address pool,\n    address receiver,\n    int16 tick,\n    uint256 maxFxUSD,\n    uint256 maxStable\n  ) external returns (uint256 colls, uint256 fxUSDUsed, uint256 stableUsed);\n\n  /// @notice Rebalance a given position.\n  /// @param pool The address of pool to rebalance.\n  /// @param receiver The address of recipient for rebalanced tokens.\n  /// @param positionId The id of position to rebalance.\n  /// @param maxFxUSD The maximum amount of fxUSD to rebalance.\n  /// @param maxStable The maximum amount of stable token (a.k.a USDC) to rebalance.\n  /// @return colls The amount of collateral tokens rebalanced.\n  /// @return fxUSDUsed The amount of fxUSD used to rebalance.\n  /// @return stableUsed The amount of stable token used to rebalance.\n  function rebalance(\n    address pool,\n    address receiver,\n    uint32 positionId,\n    uint256 maxFxUSD,\n    uint256 maxStable\n  ) external returns (uint256 colls, uint256 fxUSDUsed, uint256 stableUsed);\n\n  /// @notice Liquidate a given position.\n  /// @param pool The address of pool to liquidate.\n  /// @param receiver The address of recipient for liquidated tokens.\n  /// @param positionId The id of position to liquidate.\n  /// @param maxFxUSD The maximum amount of fxUSD to liquidate.\n  /// @param maxStable The maximum amount of stable token (a.k.a USDC) to liquidate.\n  /// @return colls The amount of collateral tokens liquidated.\n  /// @return fxUSDUsed The amount of fxUSD used to liquidate.\n  /// @return stableUsed The amount of stable token used to liquidate.\n  function liquidate(\n    address pool,\n    address receiver,\n    uint32 positionId,\n    uint256 maxFxUSD,\n    uint256 maxStable\n  ) external returns (uint256 colls, uint256 fxUSDUsed, uint256 stableUsed);\n\n  /// @notice Harvest pending rewards of the given pool.\n  /// @param pool The address of pool to harvest.\n  /// @return amountRewards The amount of rewards harvested.\n  /// @return amountFunding The amount of funding harvested.\n  function harvest(address pool) external returns (uint256 amountRewards, uint256 amountFunding);\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/utils/introspection/IERC165Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165Upgradeable {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},{"file_path":"contracts/interfaces/IPegKeeper.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IPegKeeper {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when the converter contract is updated.\n  /// @param oldConverter The address of previous converter contract.\n  /// @param newConverter The address of current converter contract.\n  event UpdateConverter(address indexed oldConverter, address indexed newConverter);\n\n  /// @notice Emitted when the curve pool contract is updated.\n  /// @param oldPool The address of previous curve pool contract.\n  /// @param newPool The address of current curve pool contract.\n  event UpdateCurvePool(address indexed oldPool, address indexed newPool);\n\n  /// @notice Emitted when the price threshold is updated.\n  /// @param oldThreshold The value of previous price threshold\n  /// @param newThreshold The value of current price threshold\n  event UpdatePriceThreshold(uint256 oldThreshold, uint256 newThreshold);\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return whether borrow for fxUSD is allowed.\n  function isBorrowAllowed() external view returns (bool);\n\n  /// @notice Return whether funding costs is enabled.\n  function isFundingEnabled() external view returns (bool);\n  \n  /// @notice Return the price of fxUSD, multiplied by 1e18\n  function getFxUSDPrice() external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Buyback fxUSD with stable reserve in FxUSDSave.\n  /// @param amountIn the amount of stable token to use.\n  /// @param data The hook data to `onSwap`.\n  /// @return amountOut The amount of fxUSD swapped.\n  /// @return bonusOut The amount of bonus fxUSD.\n  function buyback(uint256 amountIn, bytes calldata data) external returns (uint256 amountOut, uint256 bonusOut);\n\n  /// @notice Stabilize the fxUSD price in curve pool.\n  /// @param srcToken The address of source token (fxUSD or stable token).\n  /// @param amountIn the amount of source token to use.\n  /// @param data The hook data to `onSwap`.\n  /// @return amountOut The amount of target token swapped.\n  /// @return bonusOut The amount of bonus token.\n  function stabilize(\n    address srcToken,\n    uint256 amountIn,\n    bytes calldata data\n  ) external returns (uint256 amountOut, uint256 bonusOut);\n\n  /// @notice Swap callback from `buyback` and `stabilize`.\n  /// @param srcToken The address of source token.\n  /// @param srcToken The address of target token.\n  /// @param amountIn the amount of source token to use.\n  /// @param data The callback data.\n  /// @return amountOut The amount of target token swapped.\n  function onSwap(\n    address srcToken,\n    address targetToken,\n    uint256 amountIn,\n    bytes calldata data\n  ) external returns (uint256 amountOut);\n}\n"},{"file_path":"contracts/helpers/interfaces/IMultiPathConverter.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IMultiPathConverter {\n  function queryConvert(\n    uint256 _amount,\n    uint256 _encoding,\n    uint256[] calldata _routes\n  ) external returns (uint256 amountOut);\n\n  function convert(\n    address _tokenIn,\n    uint256 _amount,\n    uint256 _encoding,\n    uint256[] calldata _routes\n  ) external payable returns (uint256 amountOut);\n}\n"},{"file_path":"contracts/periphery/facets/MigrateFacet.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC721 } from \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\n\nimport { IMultiPathConverter } from \"../../helpers/interfaces/IMultiPathConverter.sol\";\nimport { IBalancerVault } from \"../../interfaces/Balancer/IBalancerVault.sol\";\nimport { IPool } from \"../../interfaces/IPool.sol\";\nimport { IPoolManager } from \"../../interfaces/IPoolManager.sol\";\nimport { IFxMarketV2 } from \"../../v2/interfaces/IFxMarketV2.sol\";\nimport { IFxUSD } from \"../../v2/interfaces/IFxUSD.sol\";\n\nimport { WordCodec } from \"../../common/codec/WordCodec.sol\";\nimport { LibRouter } from \"../libraries/LibRouter.sol\";\nimport { FlashLoanFacetBase } from \"./FlashLoanFacetBase.sol\";\n\ncontract MigrateFacet is FlashLoanFacetBase {\n  using SafeERC20 for IERC20;\n  using WordCodec for bytes32;\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the amount of tokens swapped are not enough.\n  error ErrorInsufficientAmountSwapped();\n\n  /// @dev Thrown when debt ratio out of range.\n  error ErrorDebtRatioOutOfRange();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The address of USDC token.\n  address private constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;\n\n  /// @dev The address of fxUSD token.\n  address private constant fxUSD = 0x085780639CC2cACd35E474e71f4d000e2405d8f6;\n\n  /// @dev The address of wstETH market contract.\n  address private constant wstETHMarket = 0xAD9A0E7C08bc9F747dF97a3E7E7f620632CB6155;\n\n  /// @dev The address of wstETH token.\n  address private constant wstETH = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0;\n\n  /// @dev The address of fstETH token.\n  address private constant fstETH = 0xD6B8162e2fb9F3EFf09bb8598ca0C8958E33A23D;\n\n  /// @dev The address of xstETH token.\n  address private constant xstETH = 0x5a097b014C547718e79030a077A91Ae37679EfF5;\n\n  /// @dev The address of sfrxETH market contract.\n  address private constant sfrxETHMarket = 0x714B853b3bA73E439c652CfE79660F329E6ebB42;\n\n  /// @dev The address of sfrxETH token.\n  address private constant sfrxETH = 0xac3E018457B222d93114458476f3E3416Abbe38F;\n\n  /// @dev The address of ffrxETH token.\n  address private constant ffrxETH = 0xa87F04c9743Fd1933F82bdDec9692e9D97673769;\n\n  /// @dev The address of xfrxETH token.\n  address private constant xfrxETH = 0x2bb0C32101456F5960d4e994Bac183Fe0dc6C82c;\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @dev The address of `PoolManager` contract.\n  address private immutable poolManager;\n\n  /// @dev The address of `MultiPathConverter` contract.\n  address private immutable converter;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _balancer, address _poolManager, address _converter) FlashLoanFacetBase(_balancer) {\n    poolManager = _poolManager;\n    converter = _converter;\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Migrate xstETH to fx position.\n  /// @param pool The address of fx position pool.\n  /// @param positionId The index of position.\n  /// @param xTokenAmount The amount of xstETH to migrate.\n  /// @param borrowAmount The amount of USDC to borrow.\n  /// @param data The calldata passing to `onMigrateXstETHPosition` hook function.\n  function migrateXstETHPosition(\n    address pool,\n    uint256 positionId,\n    uint256 xTokenAmount,\n    uint256 borrowAmount,\n    bytes calldata data\n  ) external nonReentrant {\n    IERC20(xstETH).safeTransferFrom(msg.sender, address(this), xTokenAmount);\n    if (positionId > 0) {\n      IERC721(pool).transferFrom(msg.sender, address(this), positionId);\n    }\n\n    _invokeFlashLoan(\n      USDC,\n      borrowAmount,\n      abi.encodeCall(\n        MigrateFacet.onMigrateXstETHPosition,\n        (pool, positionId, xTokenAmount, borrowAmount, msg.sender, data)\n      )\n    );\n\n    // refund USDC to caller\n    LibRouter.refundERC20(USDC, LibRouter.routerStorage().revenuePool);\n  }\n\n  /// @notice Migrate xfrxETH to fx position.\n  /// @param pool The address of fx position pool.\n  /// @param positionId The index of position.\n  /// @param xTokenAmount The amount of xfrxETH to migrate.\n  /// @param borrowAmount The amount of USDC to borrow.\n  /// @param data The calldata passing to `onMigrateXfrxETHPosition` hook function.\n  function migrateXfrxETHPosition(\n    address pool,\n    uint256 positionId,\n    uint256 xTokenAmount,\n    uint256 borrowAmount,\n    bytes calldata data\n  ) external nonReentrant {\n    IERC20(xfrxETH).safeTransferFrom(msg.sender, address(this), xTokenAmount);\n    if (positionId > 0) {\n      IERC721(pool).transferFrom(msg.sender, address(this), positionId);\n    }\n\n    _invokeFlashLoan(\n      USDC,\n      borrowAmount,\n      abi.encodeCall(\n        MigrateFacet.onMigrateXfrxETHPosition,\n        (pool, positionId, xTokenAmount, borrowAmount, msg.sender, data)\n      )\n    );\n\n    // refund USDC to caller\n    LibRouter.refundERC20(USDC, LibRouter.routerStorage().revenuePool);\n  }\n\n  /// @notice Hook for `migrateXstETHPosition`.\n  /// @param pool The address of fx position pool.\n  /// @param positionId The index of position.\n  /// @param xTokenAmount The amount of xstETH to migrate.\n  /// @param borrowAmount The amount of USDC to borrow.\n  /// @param recipient The address of position holder.\n  /// @param data Hook data.\n  function onMigrateXstETHPosition(\n    address pool,\n    uint256 positionId,\n    uint256 xTokenAmount,\n    uint256 borrowAmount,\n    address recipient,\n    bytes memory data\n  ) external onlySelf {\n    uint256 fTokenAmount = (xTokenAmount * IERC20(fstETH).totalSupply()) / IERC20(xstETH).totalSupply();\n\n    // swap USDC to fxUSD\n    fTokenAmount = _swapUSDCToFxUSD(borrowAmount, fTokenAmount, data);\n\n    // unwrap fxUSD as fToken\n    IFxUSD(fxUSD).unwrap(wstETH, fTokenAmount, address(this));\n\n    uint256 wstETHAmount;\n    {\n      wstETHAmount = IFxMarketV2(wstETHMarket).redeemXToken(xTokenAmount, address(this), 0);\n      (uint256 baseOut, uint256 bonus) = IFxMarketV2(wstETHMarket).redeemFToken(fTokenAmount, address(this), 0);\n      wstETHAmount += baseOut + bonus;\n    }\n\n    // since we need to swap back to USDC, mint 0.1% more fxUSD to cover slippage.\n    fTokenAmount = (fTokenAmount * 1001) / 1000;\n\n    LibRouter.approve(wstETH, poolManager, wstETHAmount);\n    positionId = IPoolManager(poolManager).operate(pool, positionId, int256(wstETHAmount), int256(fTokenAmount));\n    _checkPositionDebtRatio(pool, positionId, abi.decode(data, (bytes32)));\n    IERC721(pool).transferFrom(address(this), recipient, positionId);\n\n    // swap fxUSD to USDC and pay debts\n    _swapFxUSDToUSDC(IERC20(fxUSD).balanceOf(address(this)), borrowAmount, data);\n  }\n\n  /// @notice Hook for `migrateXfrxETHPosition`.\n  /// @param pool The address of fx position pool.\n  /// @param positionId The index of position.\n  /// @param xTokenAmount The amount of xstETH to migrate.\n  /// @param borrowAmount The amount of USDC to borrow.\n  /// @param recipient The address of position holder.\n  /// @param data Hook data.\n  function onMigrateXfrxETHPosition(\n    address pool,\n    uint256 positionId,\n    uint256 xTokenAmount,\n    uint256 borrowAmount,\n    address recipient,\n    bytes memory data\n  ) external onlySelf {\n    uint256 fTokenAmount = (xTokenAmount * IERC20(ffrxETH).totalSupply()) / IERC20(xfrxETH).totalSupply();\n\n    // swap USDC to fxUSD\n    fTokenAmount = _swapUSDCToFxUSD(borrowAmount, fTokenAmount, data);\n\n    // unwrap fxUSD as fToken\n    IFxUSD(fxUSD).unwrap(sfrxETH, fTokenAmount, address(this));\n\n    uint256 wstETHAmount;\n    {\n      // redeem\n      wstETHAmount = IFxMarketV2(sfrxETHMarket).redeemXToken(xTokenAmount, address(this), 0);\n      (uint256 baseOut, uint256 bonus) = IFxMarketV2(sfrxETHMarket).redeemFToken(fTokenAmount, address(this), 0);\n      wstETHAmount += baseOut + bonus;\n      // swap sfrxETH to wstETH\n      wstETHAmount = _swapSfrxETHToWstETH(wstETHAmount, 0, data);\n    }\n\n    // since we need to swap back to USDC, mint 0.1% more fxUSD to cover slippage.\n    fTokenAmount = (fTokenAmount * 1001) / 1000;\n\n    LibRouter.approve(wstETH, poolManager, wstETHAmount);\n    positionId = IPoolManager(poolManager).operate(pool, positionId, int256(wstETHAmount), int256(fTokenAmount));\n    _checkPositionDebtRatio(pool, positionId, abi.decode(data, (bytes32)));\n    IERC721(pool).transferFrom(address(this), recipient, positionId);\n\n    // swap fxUSD to USDC and pay debts\n    _swapFxUSDToUSDC(IERC20(fxUSD).balanceOf(address(this)), borrowAmount, data);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to swap USDC to fxUSD.\n  /// @param amountUSDC The amount of USDC to use.\n  /// @param minFxUSD The minimum amount of fxUSD should receive.\n  /// @param data The swap route encoding.\n  /// @return amountFxUSD The amount of fxUSD received.\n  function _swapUSDCToFxUSD(\n    uint256 amountUSDC,\n    uint256 minFxUSD,\n    bytes memory data\n  ) internal returns (uint256 amountFxUSD) {\n    (, uint256 swapEncoding, uint256[] memory swapRoutes) = abi.decode(data, (bytes32, uint256, uint256[]));\n    return _swap(USDC, amountUSDC, minFxUSD, swapEncoding, swapRoutes);\n  }\n\n  /// @dev Internal function to swap fxUSD to USDC.\n  /// @param amountFxUSD The amount of fxUSD to use.\n  /// @param minUSDC The minimum amount of USDC should receive.\n  /// @param data The swap route encoding.\n  /// @return amountUSDC The amount of USDC received.\n  function _swapFxUSDToUSDC(\n    uint256 amountFxUSD,\n    uint256 minUSDC,\n    bytes memory data\n  ) internal returns (uint256 amountUSDC) {\n    (, , , uint256 swapEncoding, uint256[] memory swapRoutes) = abi.decode(\n      data,\n      (bytes32, uint256, uint256[], uint256, uint256[])\n    );\n    return _swap(fxUSD, amountFxUSD, minUSDC, swapEncoding, swapRoutes);\n  }\n\n  /// @dev Internal function to swap sfrxETH to wstETH.\n  /// @param amountSfrxETH The amount of sfrxETH to use.\n  /// @param minWstETH The minimum amount of wstETH should receive.\n  /// @param data The swap route encoding.\n  /// @return amountWstETH The amount of wstETH received.\n  function _swapSfrxETHToWstETH(\n    uint256 amountSfrxETH,\n    uint256 minWstETH,\n    bytes memory data\n  ) internal returns (uint256 amountWstETH) {\n    (, , , , , uint256 swapEncoding, uint256[] memory swapRoutes) = abi.decode(\n      data,\n      (bytes32, uint256, uint256[], uint256, uint256[], uint256, uint256[])\n    );\n    return _swap(sfrxETH, amountSfrxETH, minWstETH, swapEncoding, swapRoutes);\n  }\n\n  /// @dev Internal function to do swap.\n  /// @param token The address of input token.\n  /// @param amountIn The amount of input token.\n  /// @param minOut The minimum amount of output tokens should receive.\n  /// @param encoding The encoding for swap routes.\n  /// @param routes The swap routes to `MultiPathConverter`.\n  /// @return amountOut The amount of output tokens received.\n  function _swap(\n    address token,\n    uint256 amountIn,\n    uint256 minOut,\n    uint256 encoding,\n    uint256[] memory routes\n  ) internal returns (uint256 amountOut) {\n    LibRouter.approve(token, converter, amountIn);\n    amountOut = IMultiPathConverter(converter).convert(token, amountIn, encoding, routes);\n    if (amountOut < minOut) revert ErrorInsufficientAmountSwapped();\n  }\n\n  /// @dev Internal function to check debt ratio for the position.\n  /// @param pool The address of fx position pool.\n  /// @param positionId The index of the position.\n  /// @param miscData The encoded data for debt ratio range.\n  function _checkPositionDebtRatio(address pool, uint256 positionId, bytes32 miscData) internal view {\n    uint256 debtRatio = IPool(pool).getPositionDebtRatio(positionId);\n    uint256 minDebtRatio = miscData.decodeUint(0, 60);\n    uint256 maxDebtRatio = miscData.decodeUint(60, 60);\n    if (debtRatio < minDebtRatio || debtRatio > maxDebtRatio) {\n      revert ErrorDebtRatioOutOfRange();\n    }\n  }\n}\n"},{"file_path":"contracts/fund/AssetManagement.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { AccessControlUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\";\n\nabstract contract AssetManagement is AccessControlUpgradeable {\n  /**\n   * @dev This empty reserved space is put in place to allow future versions to add new\n   * variables without shifting down storage in the inheritance chain.\n   */\n  uint256[50] private __gap;\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/utils/StringsUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/MathUpgradeable.sol\";\nimport \"./math/SignedMathUpgradeable.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary StringsUpgradeable {\n    bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            uint256 length = MathUpgradeable.log10(value) + 1;\n            string memory buffer = new string(length);\n            uint256 ptr;\n            /// @solidity memory-safe-assembly\n            assembly {\n                ptr := add(buffer, add(32, length))\n            }\n            while (true) {\n                ptr--;\n                /// @solidity memory-safe-assembly\n                assembly {\n                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n                }\n                value /= 10;\n                if (value == 0) break;\n            }\n            return buffer;\n        }\n    }\n\n    /**\n     * @dev Converts a `int256` to its ASCII `string` decimal representation.\n     */\n    function toString(int256 value) internal pure returns (string memory) {\n        return string(abi.encodePacked(value < 0 ? \"-\" : \"\", toString(SignedMathUpgradeable.abs(value))));\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            return toHexString(value, MathUpgradeable.log256(value) + 1);\n        }\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i > 1; --i) {\n            buffer[i] = _SYMBOLS[value & 0xf];\n            value >>= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n\n    /**\n     * @dev Returns true if the two strings are equal.\n     */\n    function equal(string memory a, string memory b) internal pure returns (bool) {\n        return keccak256(bytes(a)) == keccak256(bytes(b));\n    }\n}\n"},{"file_path":"contracts/common/EIP2535/facets/OwnershipFacet.sol","source_code":"// SPDX-License-Identifier: CC0-1.0\npragma solidity ^0.8.0;\n\n/******************************************************************************\\\n* Author: Nick Mudge <nick@perfectabstractions.com>, Twitter/Github: @mudgen\n* EIP-2535 Diamonds\n/******************************************************************************/\n\nimport { LibDiamond } from \"../libraries/LibDiamond.sol\";\nimport { IERC173 } from \"../interfaces/IERC173.sol\";\n\ncontract OwnershipFacet is IERC173 {\n  function transferOwnership(address _newOwner) external override {\n    LibDiamond.enforceIsContractOwner();\n    LibDiamond.setContractOwner(_newOwner);\n  }\n\n  function owner() external view override returns (address owner_) {\n    owner_ = LibDiamond.contractOwner();\n  }\n}\n"},{"file_path":"contracts/common/rewards/distributor/LinearMultipleRewardDistributor.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { AccessControlUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\n\nimport { IMultipleRewardDistributor } from \"./IMultipleRewardDistributor.sol\";\nimport { LinearReward } from \"./LinearReward.sol\";\n\n// solhint-disable no-empty-blocks\n// solhint-disable not-rely-on-time\n\nabstract contract LinearMultipleRewardDistributor is AccessControlUpgradeable, IMultipleRewardDistributor {\n  using EnumerableSet for EnumerableSet.AddressSet;\n  using SafeERC20 for IERC20;\n\n  using LinearReward for LinearReward.RewardData;\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @notice The role used to manage rewards.\n  bytes32 public constant REWARD_MANAGER_ROLE = keccak256(\"REWARD_MANAGER_ROLE\");\n\n  /// @notice The length of reward period in seconds.\n  /// @dev If the value is zero, the reward will be distributed immediately.\n  /// @dev It is either zero or at least 1 day (which is 86400).\n  uint40 public immutable periodLength;\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @inheritdoc IMultipleRewardDistributor\n  mapping(address => address) public override distributors;\n\n  /// @notice Mapping from reward token address to linear distribution reward data.\n  mapping(address => LinearReward.RewardData) public rewardData;\n\n  /// @dev The list of active reward tokens.\n  EnumerableSet.AddressSet internal activeRewardTokens;\n\n  /// @dev The list of historical reward tokens.\n  EnumerableSet.AddressSet private historicalRewardTokens;\n\n  /// @dev reserved slots.\n  uint256[46] private __gap;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(uint40 _periodLength) {\n    require(_periodLength == 0 || (_periodLength >= 1 days && _periodLength <= 28 days), \"invalid period length\");\n\n    periodLength = _periodLength;\n  }\n\n  // solhint-disable-next-line func-name-mixedcase\n  function __LinearMultipleRewardDistributor_init() internal onlyInitializing {}\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @inheritdoc IMultipleRewardDistributor\n  function getActiveRewardTokens() public view override returns (address[] memory _rewardTokens) {\n    uint256 _length = activeRewardTokens.length();\n    _rewardTokens = new address[](_length);\n\n    for (uint256 i = 0; i < _length; i++) {\n      _rewardTokens[i] = activeRewardTokens.at(i);\n    }\n  }\n\n  /// @inheritdoc IMultipleRewardDistributor\n  function getHistoricalRewardTokens() public view override returns (address[] memory _rewardTokens) {\n    uint256 _length = historicalRewardTokens.length();\n    _rewardTokens = new address[](_length);\n\n    for (uint256 i = 0; i < _length; i++) {\n      _rewardTokens[i] = historicalRewardTokens.at(i);\n    }\n  }\n\n  /// @inheritdoc IMultipleRewardDistributor\n  function pendingRewards(address _token) external view override returns (uint256, uint256) {\n    return rewardData[_token].pending();\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc IMultipleRewardDistributor\n  function depositReward(address _token, uint256 _amount) external override {\n    address _distributor = _msgSender();\n    if (!activeRewardTokens.contains(_token)) revert NotActiveRewardToken();\n    if (distributors[_token] != _distributor) revert NotRewardDistributor();\n\n    if (_amount > 0) {\n      IERC20(_token).safeTransferFrom(_distributor, address(this), _amount);\n    }\n\n    _distributePendingReward();\n\n    _notifyReward(_token, _amount);\n\n    emit DepositReward(_token, _amount);\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Register a new reward token.\n  /// @dev Make sure no fee on transfer token is added as reward token.\n  ///\n  /// @param _token The address of reward token.\n  /// @param _distributor The address of reward distributor.\n  function registerRewardToken(address _token, address _distributor) external onlyRole(REWARD_MANAGER_ROLE) {\n    if (_distributor == address(0)) revert RewardDistributorIsZero();\n    if (activeRewardTokens.contains(_token)) revert DuplicatedRewardToken();\n\n    activeRewardTokens.add(_token);\n    distributors[_token] = _distributor;\n    historicalRewardTokens.remove(_token);\n\n    emit RegisterRewardToken(_token, _distributor);\n  }\n\n  /// @notice Update the distributor for reward token.\n  ///\n  /// @param _token The address of reward token.\n  /// @param _newDistributor The address of new reward distributor.\n  function updateRewardDistributor(address _token, address _newDistributor) external onlyRole(REWARD_MANAGER_ROLE) {\n    if (_newDistributor == address(0)) revert RewardDistributorIsZero();\n    if (!activeRewardTokens.contains(_token)) revert NotActiveRewardToken();\n\n    address _oldDistributor = distributors[_token];\n    distributors[_token] = _newDistributor;\n\n    emit UpdateRewardDistributor(_token, _oldDistributor, _newDistributor);\n  }\n\n  /// @notice Unregister an existing reward token.\n  ///\n  /// @param _token The address of reward token.\n  function unregisterRewardToken(address _token) external onlyRole(REWARD_MANAGER_ROLE) {\n    if (!activeRewardTokens.contains(_token)) revert NotActiveRewardToken();\n\n    LinearReward.RewardData memory _data = rewardData[_token];\n    unchecked {\n      (uint256 _distributable, uint256 _undistributed) = _data.pending();\n      if (_data.queued < periodLength) _data.queued = 0; // ignore round error\n      if (_data.queued + _distributable + _undistributed > 0) revert RewardDistributionNotFinished();\n    }\n\n    activeRewardTokens.remove(_token);\n    distributors[_token] = address(0);\n    historicalRewardTokens.add(_token);\n\n    emit UnregisterRewardToken(_token);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to notify new rewards.\n  ///\n  /// @param _token The address of token.\n  /// @param _amount The amount of new rewards.\n  function _notifyReward(address _token, uint256 _amount) internal {\n    if (periodLength == 0) {\n      _accumulateReward(_token, _amount);\n    } else {\n      LinearReward.RewardData memory _data = rewardData[_token];\n      _data.increase(periodLength, _amount);\n      rewardData[_token] = _data;\n    }\n  }\n\n  /// @dev Internal function to distribute all pending reward tokens.\n  function _distributePendingReward() internal {\n    if (periodLength == 0 || activeRewardTokens.length() == 0) return;\n\n    address[] memory _activeRewardTokens = getActiveRewardTokens();\n    for (uint256 i = 0; i < _activeRewardTokens.length; i++) {\n      address _token = _activeRewardTokens[i];\n      (uint256 _pending, ) = rewardData[_token].pending();\n      rewardData[_token].lastUpdate = uint40(block.timestamp);\n\n      if (_pending > 0) {\n        _accumulateReward(_token, _pending);\n      }\n    }\n  }\n\n  /// @dev Internal function to accumulate distributed rewards.\n  ///\n  /// @param _token The address of token.\n  /// @param _amount The amount of rewards to accumulate.\n  function _accumulateReward(address _token, uint256 _amount) internal virtual;\n}\n"},{"file_path":"contracts/interfaces/Chainlink/AggregatorV3Interface.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n  function decimals() external view returns (uint8);\n\n  function description() external view returns (string memory);\n\n  function version() external view returns (uint256);\n\n  function latestAnswer() external view returns (uint256);\n\n  function getRoundData(uint80 _roundId)\n    external\n    view\n    returns (\n      uint80 roundId,\n      int256 answer,\n      uint256 startedAt,\n      uint256 updatedAt,\n      uint80 answeredInRound\n    );\n\n  function latestRoundData()\n    external\n    view\n    returns (\n      uint80 roundId,\n      int256 answer,\n      uint256 startedAt,\n      uint256 updatedAt,\n      uint80 answeredInRound\n    );\n}\n"},{"file_path":"contracts/v2/interfaces/IFxShareableRebalancePool.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IFxBoostableRebalancePool } from \"./IFxBoostableRebalancePool.sol\";\n\ninterface IFxShareableRebalancePool is IFxBoostableRebalancePool {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when one user share votes to another user.\n  /// @param owner The address of votes owner.\n  /// @param staker The address of staker to share votes.\n  event ShareVote(address indexed owner, address indexed staker);\n\n  /// @notice Emitted when the owner cancel sharing to some staker.\n  /// @param owner The address of votes owner.\n  /// @param staker The address of staker to cancel votes share.\n  event CancelShareVote(address indexed owner, address indexed staker);\n\n  /// @notice Emitted when staker accept the vote sharing.\n  /// @param staker The address of the staker.\n  /// @param oldOwner The address of the previous vote sharing owner.\n  /// @param newOwner The address of the current vote sharing owner.\n  event AcceptSharedVote(address indexed staker, address indexed oldOwner, address indexed newOwner);\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when caller shares votes to self.\n  error ErrorSelfSharingIsNotAllowed();\n\n  /// @dev Thrown when a staker with shared votes try to share its votes to others.\n  error ErrorCascadedSharingIsNotAllowed();\n\n  /// @dev Thrown when staker try to accept non-allowed vote sharing.\n  error ErrorVoteShareNotAllowed();\n\n  /// @dev Thrown when staker try to reject a non-existed vote sharing.\n  error ErrorNoAcceptedSharedVote();\n\n  /// @dev Thrown when the staker has ability to share ve balance.\n  error ErrorVoteOwnerCannotStake();\n\n  /// @dev Thrown when staker try to accept twice.\n  error ErrorRepeatAcceptSharedVote();\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the owner of votes of some staker.\n  /// @param account The address of user to query.\n  function getStakerVoteOwner(address account) external view returns (address);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Withdraw asset from this contract on behalf of someone\n  function withdrawFrom(\n    address owner,\n    uint256 amount,\n    address receiver\n  ) external;\n\n  /// @notice Owner changes the vote sharing state for some user.\n  /// @param staker The address of user to change.\n  function toggleVoteSharing(address staker) external;\n\n  /// @notice Staker accepts the vote sharing.\n  /// @param newOwner The address of the owner of the votes.\n  function acceptSharedVote(address newOwner) external;\n\n  /// @notice Staker reject the current vote sharing.\n  function rejectSharedVote() external;\n}\n"},{"file_path":"contracts/libraries/TickBitmap.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { BitMath } from \"./BitMath.sol\";\n\nlibrary TickBitmap {\n  function position(int16 tick) private pure returns (int8 wordPos, uint8 bitPos) {\n    assembly {\n      wordPos := shr(8, tick)\n      bitPos := and(tick, 255)\n    }\n  }\n\n  function flipTick(mapping(int8 => uint256) storage self, int16 tick) internal {\n    (int8 wordPos, uint8 bitPos) = position(tick);\n    uint256 mask = 1 << bitPos;\n    self[wordPos] ^= mask;\n  }\n\n  function isBitSet(mapping(int8 => uint256) storage self, int16 tick) internal view returns (bool) {\n    (int8 wordPos, uint8 bitPos) = position(tick);\n    uint256 mask = 1 << bitPos;\n    return (self[wordPos] & mask) > 0;\n  }\n\n  /// @notice Returns the next initialized tick contained in the same word (or adjacent word) as the tick that is\n  /// to the left (less than or equal to).\n  function nextDebtPositionWithinOneWord(\n    mapping(int8 => uint256) storage self,\n    int16 tick\n  ) internal view returns (int16 next, bool hasDebt) {\n    unchecked {\n      // start from the word of the next tick, since the current tick state doesn't matter\n      (int8 wordPos, uint8 bitPos) = position(tick);\n      // all the 1s at or to the right of the current bitPos\n      uint256 mask = (1 << bitPos) - 1 + (1 << bitPos);\n      uint256 masked = self[wordPos] & mask;\n\n      // if there are no initialized ticks to the left of the current tick, return leftmost in the word\n      hasDebt = masked != 0;\n      // overflow/underflow is possible, but prevented externally by limiting tick\n      next = hasDebt\n        ? (tick - int16(uint16(bitPos - BitMath.mostSignificantBit(masked))))\n        : (tick - int16(uint16(bitPos)));\n    }\n  }\n}\n"},{"file_path":"contracts/common/ERC3156/IERC3156FlashLender.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IERC3156FlashBorrower } from \"./IERC3156FlashBorrower.sol\";\n\ninterface IERC3156FlashLender {\n  /**\n   * @dev The amount of currency available to be lent.\n   * @param token The loan currency.\n   * @return The amount of `token` that can be borrowed.\n   */\n  function maxFlashLoan(address token) external view returns (uint256);\n\n  /**\n   * @dev The fee to be charged for a given loan.\n   * @param token The loan currency.\n   * @param amount The amount of tokens lent.\n   * @return The amount of `token` to be charged for the loan, on top of the returned principal.\n   */\n  function flashFee(address token, uint256 amount) external view returns (uint256);\n\n  /**\n   * @dev Initiate a flash loan.\n   * @param receiver The receiver of the tokens in the loan, and the receiver of the callback.\n   * @param token The loan currency.\n   * @param amount The amount of tokens lent.\n   * @param data Arbitrary data structure, intended to contain user-defined parameters.\n   */\n  function flashLoan(\n    IERC3156FlashBorrower receiver,\n    address token,\n    uint256 amount,\n    bytes calldata data\n  ) external returns (bool);\n}\n"},{"file_path":"contracts/core/pool/BasePool.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IPegKeeper } from \"../../interfaces/IPegKeeper.sol\";\nimport { IPool } from \"../../interfaces/IPool.sol\";\nimport { IPoolManager } from \"../../interfaces/IPoolManager.sol\";\nimport { IPriceOracle } from \"../../price-oracle/interfaces/IPriceOracle.sol\";\n\nimport { WordCodec } from \"../../common/codec/WordCodec.sol\";\nimport { Math } from \"../../libraries/Math.sol\";\nimport { TickBitmap } from \"../../libraries/TickBitmap.sol\";\nimport { PositionLogic } from \"./PositionLogic.sol\";\nimport { TickLogic } from \"./TickLogic.sol\";\n\nabstract contract BasePool is TickLogic, PositionLogic {\n  using TickBitmap for mapping(int8 => uint256);\n  using WordCodec for bytes32;\n\n  /***********\n   * Structs *\n   ***********/\n\n  struct OperationMemoryVar {\n    int256 tick;\n    uint48 node;\n    uint256 positionColl;\n    uint256 positionDebt;\n    int256 newColl;\n    int256 newDebt;\n    uint256 collIndex;\n    uint256 debtIndex;\n    uint256 globalColl;\n    uint256 globalDebt;\n    uint256 price;\n  }\n\n  /*************\n   * Modifiers *\n   *************/\n\n  modifier onlyPoolManager() {\n    if (_msgSender() != poolManager) {\n      revert ErrorCallerNotPoolManager();\n    }\n    _;\n  }\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _poolManager) {\n    _checkAddressNotZero(_poolManager);\n\n    poolManager = _poolManager;\n    fxUSD = IPoolManager(_poolManager).fxUSD();\n    pegKeeper = IPoolManager(_poolManager).pegKeeper();\n  }\n\n  function __BasePool_init() internal onlyInitializing {\n    _updateDebtIndex(E96);\n    _updateCollateralIndex(E96);\n    _updateDebtRatioRange(500000000000000000, 857142857142857142); // 1/2 ~ 6/7\n    _updateMaxRedeemRatioPerTick(200000000); // 20%\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc IPool\n  function operate(\n    uint256 positionId,\n    int256 newRawColl,\n    int256 newRawDebt,\n    address owner\n  ) external onlyPoolManager returns (uint256, int256, int256, uint256) {\n    if (newRawColl == 0 && newRawDebt == 0) revert ErrorNoSupplyAndNoBorrow();\n    if (newRawColl != 0 && (newRawColl > -MIN_COLLATERAL && newRawColl < MIN_COLLATERAL)) {\n      revert ErrorCollateralTooSmall();\n    }\n    if (newRawDebt != 0 && (newRawDebt > -MIN_DEBT && newRawDebt < MIN_DEBT)) {\n      revert ErrorDebtTooSmall();\n    }\n    if (newRawDebt > 0 && (_isBorrowPaused() || !IPegKeeper(pegKeeper).isBorrowAllowed())) {\n      revert ErrorBorrowPaused();\n    }\n\n    OperationMemoryVar memory op;\n    // price precision and ratio precision are both 1e18, use min price here\n    (, op.price, ) = IPriceOracle(priceOracle).getPrice();\n    (op.globalDebt, op.globalColl) = _getDebtAndCollateralShares();\n    (op.collIndex, op.debtIndex) = _updateCollAndDebtIndex();\n    if (positionId == 0) {\n      positionId = _mintPosition(owner);\n    } else {\n      // make sure position is owned and check owner only in case of withdraw or borrow\n      if (ownerOf(positionId) != owner && (newRawColl < 0 || newRawDebt > 0)) {\n        revert ErrorNotPositionOwner();\n      }\n      PositionInfo memory position = _getAndUpdatePosition(positionId);\n      // temporarily remove position from tick tree for simplicity\n      _removePositionFromTick(position);\n      op.tick = position.tick;\n      op.node = position.nodeId;\n      op.positionDebt = position.debts;\n      op.positionColl = position.colls;\n\n      // cannot withdraw or borrow when the position is above liquidation ratio\n      if (newRawColl < 0 || newRawDebt > 0) {\n        uint256 rawColls = _convertToRawColl(op.positionColl, op.collIndex, Math.Rounding.Down);\n        uint256 rawDebts = _convertToRawDebt(op.positionDebt, op.debtIndex, Math.Rounding.Down);\n        (uint256 debtRatio, ) = _getLiquidateRatios();\n        if (rawDebts * PRECISION * PRECISION > debtRatio * rawColls * op.price) revert ErrorPositionInLiquidationMode();\n      }\n    }\n\n    uint256 protocolFees;\n    // supply or withdraw\n    if (newRawColl > 0) {\n      protocolFees = _deductProtocolFees(newRawColl);\n      newRawColl -= int256(protocolFees);\n      op.newColl = int256(_convertToCollShares(uint256(newRawColl), op.collIndex, Math.Rounding.Down));\n      op.positionColl += uint256(op.newColl);\n      op.globalColl += uint256(op.newColl);\n    } else if (newRawColl < 0) {\n      if (newRawColl == type(int256).min) {\n        // this is max withdraw\n        newRawColl = -int256(_convertToRawColl(op.positionColl, op.collIndex, Math.Rounding.Down));\n        op.newColl = -int256(op.positionColl);\n      } else {\n        // this is partial withdraw, rounding up removing extra wei from collateral\n        op.newColl = -int256(_convertToCollShares(uint256(-newRawColl), op.collIndex, Math.Rounding.Up));\n        if (uint256(-op.newColl) > op.positionColl) revert ErrorWithdrawExceedSupply();\n      }\n      unchecked {\n        op.positionColl -= uint256(-op.newColl);\n        op.globalColl -= uint256(-op.newColl);\n      }\n      protocolFees = _deductProtocolFees(newRawColl);\n      newRawColl += int256(protocolFees);\n    }\n\n    // borrow or repay\n    if (newRawDebt > 0) {\n      // rounding up adding extra wei in debt\n      op.newDebt = int256(_convertToDebtShares(uint256(newRawDebt), op.debtIndex, Math.Rounding.Up));\n      op.positionDebt += uint256(op.newDebt);\n      op.globalDebt += uint256(op.newDebt);\n    } else if (newRawDebt < 0) {\n      if (newRawDebt == type(int256).min) {\n        // this is max repay, rounding up amount that will be transferred in to pay back full debt:\n        // subtracting -1 of negative debtAmount newDebt_ for safe rounding (increasing payback)\n        newRawDebt = -int256(_convertToRawDebt(op.positionDebt, op.debtIndex, Math.Rounding.Up));\n        op.newDebt = -int256(op.positionDebt);\n      } else {\n        // this is partial repay, safe rounding up negative amount to rounding reduce payback\n        op.newDebt = -int256(_convertToDebtShares(uint256(-newRawDebt), op.debtIndex, Math.Rounding.Up));\n      }\n      op.positionDebt -= uint256(-op.newDebt);\n      op.globalDebt -= uint256(-op.newDebt);\n    }\n\n    // final debt ratio check\n    {\n      // check position debt ratio is between `minDebtRatio` and `maxDebtRatio`.\n      uint256 rawColls = _convertToRawColl(op.positionColl, op.collIndex, Math.Rounding.Down);\n      uint256 rawDebts = _convertToRawDebt(op.positionDebt, op.debtIndex, Math.Rounding.Down);\n      (uint256 minDebtRatio, uint256 maxDebtRatio) = _getDebtRatioRange();\n      if (rawDebts * PRECISION * PRECISION > maxDebtRatio * rawColls * op.price) revert ErrorDebtRatioTooLarge();\n      if (rawDebts * PRECISION * PRECISION < minDebtRatio * rawColls * op.price) revert ErrorDebtRatioTooSmall();\n    }\n\n    // update position state to storage\n    (op.tick, op.node) = _addPositionToTick(op.positionColl, op.positionDebt, true);\n\n    if (op.positionColl > type(uint96).max) revert ErrorOverflow();\n    if (op.positionDebt > type(uint96).max) revert ErrorOverflow();\n    positionData[positionId] = PositionInfo(int16(op.tick), op.node, uint96(op.positionColl), uint96(op.positionDebt));\n\n    // update global state to storage\n    _updateDebtAndCollateralShares(op.globalDebt, op.globalColl);\n\n    emit PositionSnapshot(positionId, int16(op.tick), op.positionColl, op.positionDebt, op.price);\n\n    return (positionId, newRawColl, newRawDebt, protocolFees);\n  }\n\n  /// @inheritdoc IPool\n  function redeem(uint256 rawDebts) external onlyPoolManager returns (uint256 rawColls) {\n    if (_isRedeemPaused()) revert ErrorRedeemPaused();\n\n    (uint256 cachedCollIndex, uint256 cachedDebtIndex) = _updateCollAndDebtIndex();\n    (uint256 cachedTotalDebts, uint256 cachedTotalColls) = _getDebtAndCollateralShares();\n    (, , uint256 price) = IPriceOracle(priceOracle).getPrice(); // use max price\n    // check global debt ratio, if global debt ratio >= 1, disable redeem\n    {\n      uint256 totalRawColls = _convertToRawColl(cachedTotalColls, cachedCollIndex, Math.Rounding.Down);\n      uint256 totalRawDebts = _convertToRawDebt(cachedTotalDebts, cachedDebtIndex, Math.Rounding.Down);\n      if (totalRawDebts * PRECISION >= totalRawColls * price) revert ErrorPoolUnderCollateral();\n    }\n\n    int16 tick = _getTopTick();\n    bool hasDebt = true;\n    uint256 debtShare = _convertToDebtShares(rawDebts, cachedDebtIndex, Math.Rounding.Down);\n    while (debtShare > 0) {\n      if (!hasDebt) {\n        (tick, hasDebt) = tickBitmap.nextDebtPositionWithinOneWord(tick - 1);\n      } else {\n        uint256 node = tickData[tick];\n        bytes32 value = tickTreeData[node].value;\n        uint256 tickDebtShare = value.decodeUint(DEBT_SHARE_OFFSET, 128);\n        // skip bad debt\n        {\n          uint256 tickCollShare = value.decodeUint(COLL_SHARE_OFFSET, 128);\n          if (\n            _convertToRawDebt(tickDebtShare, cachedDebtIndex, Math.Rounding.Down) * PRECISION >\n            _convertToRawColl(tickCollShare, cachedCollIndex, Math.Rounding.Down) * price\n          ) {\n            hasDebt = false;\n            tick = tick;\n            continue;\n          }\n        }\n\n        // redeem at most `maxRedeemRatioPerTick`\n        uint256 debtShareToRedeem = (tickDebtShare * _getMaxRedeemRatioPerTick()) / FEE_PRECISION;\n        if (debtShareToRedeem > debtShare) debtShareToRedeem = debtShare;\n        uint256 rawCollRedeemed = (_convertToRawDebt(debtShareToRedeem, cachedDebtIndex, Math.Rounding.Down) *\n          PRECISION) / price;\n        uint256 collShareRedeemed = _convertToCollShares(rawCollRedeemed, cachedCollIndex, Math.Rounding.Down);\n        _liquidateTick(tick, collShareRedeemed, debtShareToRedeem, price);\n        debtShare -= debtShareToRedeem;\n        rawColls += rawCollRedeemed;\n\n        cachedTotalColls -= collShareRedeemed;\n        cachedTotalDebts -= debtShareToRedeem;\n\n        (tick, hasDebt) = tickBitmap.nextDebtPositionWithinOneWord(tick - 1);\n      }\n      if (tick == type(int16).min) break;\n    }\n    _updateDebtAndCollateralShares(cachedTotalDebts, cachedTotalColls);\n  }\n\n  /// @inheritdoc IPool\n  function rebalance(int16 tick, uint256 maxRawDebts) external onlyPoolManager returns (RebalanceResult memory result) {\n    (uint256 cachedCollIndex, uint256 cachedDebtIndex) = _updateCollAndDebtIndex();\n    (, uint256 price, ) = IPriceOracle(priceOracle).getPrice(); // use min price\n    uint256 node = tickData[tick];\n    bytes32 value = tickTreeData[node].value;\n    uint256 tickRawColl = _convertToRawColl(\n      value.decodeUint(COLL_SHARE_OFFSET, 128),\n      cachedCollIndex,\n      Math.Rounding.Down\n    );\n    uint256 tickRawDebt = _convertToRawDebt(\n      value.decodeUint(DEBT_SHARE_OFFSET, 128),\n      cachedDebtIndex,\n      Math.Rounding.Down\n    );\n    (uint256 rebalanceDebtRatio, uint256 rebalanceBonusRatio) = _getRebalanceRatios();\n    (uint256 liquidateDebtRatio, ) = _getLiquidateRatios();\n    // rebalance only debt ratio >= `rebalanceDebtRatio` and ratio < `liquidateDebtRatio`\n    if (tickRawDebt * PRECISION * PRECISION < rebalanceDebtRatio * tickRawColl * price) {\n      revert ErrorRebalanceDebtRatioNotReached();\n    }\n    if (tickRawDebt * PRECISION * PRECISION >= liquidateDebtRatio * tickRawColl * price) {\n      revert ErrorRebalanceOnLiquidatableTick();\n    }\n\n    // compute debts to rebalance to make debt ratio to `rebalanceDebtRatio`\n    result.rawDebts = _getRawDebtToRebalance(tickRawColl, tickRawDebt, price, rebalanceDebtRatio, rebalanceBonusRatio);\n    if (maxRawDebts < result.rawDebts) result.rawDebts = maxRawDebts;\n\n    uint256 debtShareToRebalance = _convertToDebtShares(result.rawDebts, cachedDebtIndex, Math.Rounding.Down);\n    result.rawColls = (result.rawDebts * PRECISION) / price;\n    result.bonusRawColls = (result.rawColls * rebalanceBonusRatio) / FEE_PRECISION;\n    if (result.bonusRawColls > tickRawColl - result.rawColls) {\n      result.bonusRawColls = tickRawColl - result.rawColls;\n    }\n    uint256 collShareToRebalance = _convertToCollShares(\n      result.rawColls + result.bonusRawColls,\n      cachedCollIndex,\n      Math.Rounding.Down\n    );\n\n    _liquidateTick(tick, collShareToRebalance, debtShareToRebalance, price);\n    unchecked {\n      (uint256 totalDebts, uint256 totalColls) = _getDebtAndCollateralShares();\n      _updateDebtAndCollateralShares(totalDebts - debtShareToRebalance, totalColls - collShareToRebalance);\n    }\n  }\n\n  /// @inheritdoc IPool\n  function rebalance(\n    uint32 positionId,\n    uint256 maxRawDebts\n  ) external onlyPoolManager returns (RebalanceResult memory result) {\n    _requireOwned(positionId);\n\n    (uint256 cachedCollIndex, uint256 cachedDebtIndex) = _updateCollAndDebtIndex();\n    (, uint256 price, ) = IPriceOracle(priceOracle).getPrice(); // use min price\n    PositionInfo memory position = _getAndUpdatePosition(positionId);\n    uint256 positionRawColl = _convertToRawColl(position.colls, cachedCollIndex, Math.Rounding.Down);\n    uint256 positionRawDebt = _convertToRawDebt(position.debts, cachedDebtIndex, Math.Rounding.Down);\n    (uint256 rebalanceDebtRatio, uint256 rebalanceBonusRatio) = _getRebalanceRatios();\n    // rebalance only debt ratio >= `rebalanceDebtRatio` and ratio < `liquidateDebtRatio`\n    if (positionRawDebt * PRECISION * PRECISION < rebalanceDebtRatio * positionRawColl * price) {\n      revert ErrorRebalanceDebtRatioNotReached();\n    }\n    {\n      (uint256 liquidateDebtRatio, ) = _getLiquidateRatios();\n      if (positionRawDebt * PRECISION * PRECISION >= liquidateDebtRatio * positionRawColl * price) {\n        revert ErrorRebalanceOnLiquidatableTick();\n      }\n    }\n    _removePositionFromTick(position);\n\n    // compute debts to rebalance to make debt ratio to `rebalanceDebtRatio`\n    result.rawDebts = _getRawDebtToRebalance(\n      positionRawColl,\n      positionRawDebt,\n      price,\n      rebalanceDebtRatio,\n      rebalanceBonusRatio\n    );\n    if (maxRawDebts < result.rawDebts) result.rawDebts = maxRawDebts;\n\n    uint256 debtShareToRebalance = _convertToDebtShares(result.rawDebts, cachedDebtIndex, Math.Rounding.Down);\n    result.rawColls = (result.rawDebts * PRECISION) / price;\n    result.bonusRawColls = (result.rawColls * rebalanceBonusRatio) / FEE_PRECISION;\n    if (result.bonusRawColls > positionRawColl - result.rawColls) {\n      result.bonusRawColls = positionRawColl - result.rawColls;\n    }\n    uint256 collShareToRebalance = _convertToCollShares(\n      result.rawColls + result.bonusRawColls,\n      cachedCollIndex,\n      Math.Rounding.Down\n    );\n    position.debts -= uint96(debtShareToRebalance);\n    position.colls -= uint96(collShareToRebalance);\n\n    {\n      int256 tick;\n      (tick, position.nodeId) = _addPositionToTick(position.colls, position.debts, false);\n      position.tick = int16(tick);\n    }\n    positionData[positionId] = position;\n    unchecked {\n      (uint256 totalDebts, uint256 totalColls) = _getDebtAndCollateralShares();\n      _updateDebtAndCollateralShares(totalDebts - debtShareToRebalance, totalColls - collShareToRebalance);\n    }\n\n    emit PositionSnapshot(positionId, position.tick, position.colls, position.debts, price);\n  }\n\n  /// @inheritdoc IPool\n  function liquidate(\n    uint256 positionId,\n    uint256 maxRawDebts,\n    uint256 reservedRawColls\n  ) external onlyPoolManager returns (LiquidateResult memory result) {\n    _requireOwned(positionId);\n\n    (uint256 cachedCollIndex, uint256 cachedDebtIndex) = _updateCollAndDebtIndex();\n    (, uint256 price, ) = IPriceOracle(priceOracle).getPrice(); // use min price\n    PositionInfo memory position = _getAndUpdatePosition(positionId);\n    uint256 positionRawColl = _convertToRawColl(position.colls, cachedCollIndex, Math.Rounding.Down);\n    uint256 positionRawDebt = _convertToRawDebt(position.debts, cachedDebtIndex, Math.Rounding.Down);\n    uint256 liquidateBonusRatio;\n    // liquidate only debt ratio >= `liquidateDebtRatio`\n    {\n      uint256 liquidateDebtRatio;\n      (liquidateDebtRatio, liquidateBonusRatio) = _getLiquidateRatios();\n      if (positionRawDebt * PRECISION * PRECISION < liquidateDebtRatio * positionRawColl * price) {\n        revert ErrorLiquidateDebtRatioNotReached();\n      }\n    }\n\n    _removePositionFromTick(position);\n\n    result.rawDebts = positionRawDebt;\n    if (result.rawDebts > maxRawDebts) result.rawDebts = maxRawDebts;\n    uint256 debtShareToLiquidate = result.rawDebts == positionRawDebt\n      ? position.debts\n      : _convertToDebtShares(result.rawDebts, cachedDebtIndex, Math.Rounding.Down);\n    uint256 collShareToLiquidate;\n    result.rawColls = (result.rawDebts * PRECISION) / price;\n    if (positionRawColl < result.rawColls) {\n      // adjust result.rawColls, result.rawDebts and debtShareToLiquidate\n      result.rawColls = positionRawColl;\n      result.rawDebts = (positionRawColl * price) / PRECISION;\n      if (result.rawDebts > positionRawDebt) result.rawDebts = positionRawDebt;\n      debtShareToLiquidate = result.rawDebts == positionRawDebt\n        ? position.debts\n        : _convertToDebtShares(result.rawDebts, cachedDebtIndex, Math.Rounding.Down);\n    }\n\n    result.bonusRawColls = (result.rawColls * liquidateBonusRatio) / FEE_PRECISION;\n    if (result.bonusRawColls > positionRawColl - result.rawColls) {\n      uint256 diff = result.bonusRawColls - (positionRawColl - result.rawColls);\n      if (diff < reservedRawColls) result.bonusFromReserve = diff;\n      else result.bonusFromReserve = reservedRawColls;\n      result.bonusRawColls = positionRawColl - result.rawColls + result.bonusFromReserve;\n\n      collShareToLiquidate = position.colls;\n    } else {\n      collShareToLiquidate = _convertToCollShares(\n        result.rawColls + result.bonusRawColls,\n        cachedCollIndex,\n        Math.Rounding.Down\n      );\n    }\n    position.debts -= uint96(debtShareToLiquidate);\n    position.colls -= uint96(collShareToLiquidate);\n\n    unchecked {\n      (uint256 totalDebts, uint256 totalColls) = _getDebtAndCollateralShares();\n      _updateDebtAndCollateralShares(totalDebts - debtShareToLiquidate, totalColls - collShareToLiquidate);\n    }\n\n    // try distribute bad debts\n    if (position.colls == 0 && position.debts > 0) {\n      (uint256 totalDebts, ) = _getDebtAndCollateralShares();\n      totalDebts -= position.debts;\n      _updateDebtShares(totalDebts);\n      uint256 rawBadDebt = _convertToRawDebt(position.debts, cachedDebtIndex, Math.Rounding.Down);\n      _updateDebtIndex(cachedDebtIndex + (rawBadDebt * E96) / totalDebts);\n      position.debts = 0;\n    }\n    {\n      int256 tick;\n      (tick, position.nodeId) = _addPositionToTick(position.colls, position.debts, false);\n      position.tick = int16(tick);\n    }\n    positionData[positionId] = position;\n\n    emit PositionSnapshot(positionId, position.tick, position.colls, position.debts, price);\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Update the borrow and redeem status.\n  /// @param borrowStatus The new borrow status.\n  /// @param redeemStatus The new redeem status.\n  function updateBorrowAndRedeemStatus(bool borrowStatus, bool redeemStatus) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateBorrowStatus(borrowStatus);\n    _updateRedeemStatus(redeemStatus);\n  }\n\n  /// @notice Update debt ratio range.\n  /// @param minRatio The minimum allowed debt ratio to update, multiplied by 1e18.\n  /// @param maxRatio The maximum allowed debt ratio to update, multiplied by 1e18.\n  function updateDebtRatioRange(uint256 minRatio, uint256 maxRatio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateDebtRatioRange(minRatio, maxRatio);\n  }\n\n  /// @notice Update maximum redeem ratio per tick.\n  /// @param ratio The ratio to update, multiplied by 1e9.\n  function updateMaxRedeemRatioPerTick(uint256 ratio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateMaxRedeemRatioPerTick(ratio);\n  }\n\n  /// @notice Update ratio for rebalance.\n  /// @param debtRatio The minimum debt ratio to start rebalance, multiplied by 1e18.\n  /// @param bonusRatio The bonus ratio during rebalance, multiplied by 1e9.\n  function updateRebalanceRatios(uint256 debtRatio, uint256 bonusRatio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateRebalanceRatios(debtRatio, bonusRatio);\n  }\n\n  /// @notice Update ratio for liquidate.\n  /// @param debtRatio The minimum debt ratio to start liquidate, multiplied by 1e18.\n  /// @param bonusRatio The bonus ratio during liquidate, multiplied by 1e9.\n  function updateLiquidateRatios(uint256 debtRatio, uint256 bonusRatio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateLiquidateRatios(debtRatio, bonusRatio);\n  }\n\n  /// @notice Update the address of price oracle.\n  /// @param newOracle The address of new price oracle.\n  function updatePriceOracle(address newOracle) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updatePriceOracle(newOracle);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to compute the amount of debt to rebalance to reach certain debt ratio.\n  /// @param coll The amount of collateral tokens.\n  /// @param debt The amount of debt tokens.\n  /// @param price The price of the collateral token.\n  /// @param targetDebtRatio The target debt ratio, multiplied by 1e18.\n  /// @param incentiveRatio The bonus ratio, multiplied by 1e9.\n  /// @return rawDebts The amount of debt tokens to rebalance.\n  function _getRawDebtToRebalance(\n    uint256 coll,\n    uint256 debt,\n    uint256 price,\n    uint256 targetDebtRatio,\n    uint256 incentiveRatio\n  ) internal pure returns (uint256 rawDebts) {\n    // we have\n    //   1. (debt - x) / (price * (coll - y * (1 + incentive))) <= target_ratio\n    //   2. debt / (price * coll) >= target_ratio\n    // then\n    // => debt - x <= target * price * (coll - y * (1 + incentive)) and y = x / price\n    // => debt - target_ratio * price * coll <= (1 - (1 + incentive) * target) * x\n    // => x >= (debt - target_ratio * price * coll) / (1 - (1 + incentive) * target)\n    rawDebts =\n      (debt * PRECISION * PRECISION - targetDebtRatio * price * coll) /\n      (PRECISION * PRECISION - (PRECISION * targetDebtRatio * (FEE_PRECISION + incentiveRatio)) / FEE_PRECISION);\n  }\n\n  /// @dev Internal function to update collateral and debt index.\n  /// @return newCollIndex The updated collateral index.\n  /// @return newDebtIndex The updated debt index.\n  function _updateCollAndDebtIndex() internal virtual returns (uint256 newCollIndex, uint256 newDebtIndex);\n\n  /// @dev Internal function to compute the protocol fees.\n  /// @param rawColl The amount of collateral tokens involved.\n  /// @return fees The expected protocol fees.\n  function _deductProtocolFees(int256 rawColl) internal view virtual returns (uint256 fees);\n\n  /**\n   * @dev This empty reserved space is put in place to allow future versions to add new\n   * variables without shifting down storage in the inheritance chain.\n   */\n  uint256[50] private __gap;\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/token/ERC20/IERC20Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20Upgradeable {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/utils/structs/EnumerableSetUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n *     // Add the library methods\n *     using EnumerableSet for EnumerableSet.AddressSet;\n *\n *     // Declare a set state variable\n *     EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSetUpgradeable {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 => uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        bytes32[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/token/ERC20/extensions/IERC20PermitUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n *     doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n *     token.safeTransferFrom(msg.sender, address(this), value);\n *     ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20PermitUpgradeable {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     *\n     * CAUTION: See Security Considerations above.\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    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol)\n\npragma solidity ^0.8.20;\n\nimport {MessageHashUtils} from \"@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol\";\nimport {IERC5267} from \"@openzeppelin/contracts/interfaces/IERC5267.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose\n * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract\n * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to\n * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain\n * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the\n * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.\n */\nabstract contract EIP712Upgradeable is Initializable, IERC5267 {\n    bytes32 private constant TYPE_HASH =\n        keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\");\n\n    /// @custom:storage-location erc7201:openzeppelin.storage.EIP712\n    struct EIP712Storage {\n        /// @custom:oz-renamed-from _HASHED_NAME\n        bytes32 _hashedName;\n        /// @custom:oz-renamed-from _HASHED_VERSION\n        bytes32 _hashedVersion;\n\n        string _name;\n        string _version;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.EIP712\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant EIP712StorageLocation = 0xa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100;\n\n    function _getEIP712Storage() private pure returns (EIP712Storage storage $) {\n        assembly {\n            $.slot := EIP712StorageLocation\n        }\n    }\n\n    /**\n     * @dev Initializes the domain separator and parameter caches.\n     *\n     * The meaning of `name` and `version` is specified in\n     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n     *\n     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n     * - `version`: the current major version of the signing domain.\n     *\n     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n     * contract upgrade].\n     */\n    function __EIP712_init(string memory name, string memory version) internal onlyInitializing {\n        __EIP712_init_unchained(name, version);\n    }\n\n    function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {\n        EIP712Storage storage $ = _getEIP712Storage();\n        $._name = name;\n        $._version = version;\n\n        // Reset prior values in storage if upgrading\n        $._hashedName = 0;\n        $._hashedVersion = 0;\n    }\n\n    /**\n     * @dev Returns the domain separator for the current chain.\n     */\n    function _domainSeparatorV4() internal view returns (bytes32) {\n        return _buildDomainSeparator();\n    }\n\n    function _buildDomainSeparator() private view returns (bytes32) {\n        return keccak256(abi.encode(TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(this)));\n    }\n\n    /**\n     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n     * function returns the hash of the fully encoded EIP712 message for this domain.\n     *\n     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n     *\n     * ```solidity\n     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n     *     keccak256(\"Mail(address to,string contents)\"),\n     *     mailTo,\n     *     keccak256(bytes(mailContents))\n     * )));\n     * address signer = ECDSA.recover(digest, signature);\n     * ```\n     */\n    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n        return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);\n    }\n\n    /**\n     * @dev See {IERC-5267}.\n     */\n    function eip712Domain()\n        public\n        view\n        virtual\n        returns (\n            bytes1 fields,\n            string memory name,\n            string memory version,\n            uint256 chainId,\n            address verifyingContract,\n            bytes32 salt,\n            uint256[] memory extensions\n        )\n    {\n        EIP712Storage storage $ = _getEIP712Storage();\n        // If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized\n        // and the EIP712 domain is not reliable, as it will be missing name and version.\n        require($._hashedName == 0 && $._hashedVersion == 0, \"EIP712: Uninitialized\");\n\n        return (\n            hex\"0f\", // 01111\n            _EIP712Name(),\n            _EIP712Version(),\n            block.chainid,\n            address(this),\n            bytes32(0),\n            new uint256[](0)\n        );\n    }\n\n    /**\n     * @dev The name parameter for the EIP712 domain.\n     *\n     * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs\n     * are a concern.\n     */\n    function _EIP712Name() internal view virtual returns (string memory) {\n        EIP712Storage storage $ = _getEIP712Storage();\n        return $._name;\n    }\n\n    /**\n     * @dev The version parameter for the EIP712 domain.\n     *\n     * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs\n     * are a concern.\n     */\n    function _EIP712Version() internal view virtual returns (string memory) {\n        EIP712Storage storage $ = _getEIP712Storage();\n        return $._version;\n    }\n\n    /**\n     * @dev The hash of the name parameter for the EIP712 domain.\n     *\n     * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead.\n     */\n    function _EIP712NameHash() internal view returns (bytes32) {\n        EIP712Storage storage $ = _getEIP712Storage();\n        string memory name = _EIP712Name();\n        if (bytes(name).length > 0) {\n            return keccak256(bytes(name));\n        } else {\n            // If the name is empty, the contract may have been upgraded without initializing the new storage.\n            // We return the name hash in storage if non-zero, otherwise we assume the name is empty by design.\n            bytes32 hashedName = $._hashedName;\n            if (hashedName != 0) {\n                return hashedName;\n            } else {\n                return keccak256(\"\");\n            }\n        }\n    }\n\n    /**\n     * @dev The hash of the version parameter for the EIP712 domain.\n     *\n     * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead.\n     */\n    function _EIP712VersionHash() internal view returns (bytes32) {\n        EIP712Storage storage $ = _getEIP712Storage();\n        string memory version = _EIP712Version();\n        if (bytes(version).length > 0) {\n            return keccak256(bytes(version));\n        } else {\n            // If the version is empty, the contract may have been upgraded without initializing the new storage.\n            // We return the version hash in storage if non-zero, otherwise we assume the version is empty by design.\n            bytes32 hashedVersion = $._hashedVersion;\n            if (hashedVersion != 0) {\n                return hashedVersion;\n            } else {\n                return keccak256(\"\");\n            }\n        }\n    }\n}\n"},{"file_path":"contracts/core/ProtocolFees.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { AccessControlUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\";\n\nimport { IPool } from \"../interfaces/IPool.sol\";\nimport { IProtocolFees } from \"../interfaces/IProtocolFees.sol\";\n\nimport { WordCodec } from \"../common/codec/WordCodec.sol\";\n\nabstract contract ProtocolFees is AccessControlUpgradeable, IProtocolFees {\n  using SafeERC20 for IERC20;\n  using WordCodec for bytes32;\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the given address is zero.\n  error ErrorZeroAddress();\n\n  /// @dev Thrown when the expense ratio exceeds `MAX_EXPENSE_RATIO`.\n  error ErrorExpenseRatioTooLarge();\n\n  /// @dev Thrown when the harvester ratio exceeds `MAX_HARVESTER_RATIO`.\n  error ErrorHarvesterRatioTooLarge();\n\n  /// @dev Thrown when the flash loan fee ratio exceeds `MAX_FLASH_LOAN_FEE_RATIO`.\n  error ErrorFlashLoanFeeRatioTooLarge();\n\n  /// @dev Thrown when the redeem fee ratio exceeds `MAX_REDEEM_FEE_RATIO`.\n  error ErrorRedeemFeeRatioTooLarge();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The maximum expense ratio.\n  uint256 private constant MAX_EXPENSE_RATIO = 5e8; // 50%\n\n  /// @dev The maximum harvester ratio.\n  uint256 private constant MAX_HARVESTER_RATIO = 2e8; // 20%\n\n  /// @dev The maximum flash loan fee ratio.\n  uint256 private constant MAX_FLASH_LOAN_FEE_RATIO = 1e8; // 10%\n\n  /// @dev The maximum redeem fee ratio.\n  uint256 private constant MAX_REDEEM_FEE_RATIO = 1e8; // 10%\n\n  /// @dev The offset of general expense ratio in `_miscData`.\n  uint256 private constant REWARDS_EXPENSE_RATIO_OFFSET = 0;\n\n  /// @dev The offset of harvester ratio in `_miscData`.\n  uint256 private constant HARVESTER_RATIO_OFFSET = 30;\n\n  /// @dev The offset of flash loan ratio in `_miscData`.\n  uint256 private constant FLASH_LOAN_RATIO_OFFSET = 60;\n\n  /// @dev The offset of redeem fee ratio in `_miscData`.\n  uint256 private constant REDEEM_FEE_RATIO_OFFSET = 90;\n\n  /// @dev The offset of funding expense ratio in `_miscData`.\n  uint256 private constant FUNDING_EXPENSE_RATIO_OFFSET = 120;\n\n  /// @dev The offset of liquidation expense ratio in `_miscData`.\n  uint256 private constant LIQUIDATION_EXPENSE_RATIO_OFFSET = 150;\n\n  /// @dev The precision used to compute fees.\n  uint256 internal constant FEE_PRECISION = 1e9;\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @dev `_miscData` is a storage slot that can be used to store unrelated pieces of information.\n  /// All pools store the *expense ratio*, *harvester ratio* and *withdraw fee percentage*, but\n  /// the `miscData`can be extended to store more pieces of information.\n  ///\n  /// The *expense ratio* is stored in the first most significant 32 bits, and the *harvester ratio* is\n  /// stored in the next most significant 32 bits, and the *withdraw fee percentage* is stored in the\n  /// next most significant 32 bits, leaving the remaining 160 bits free to store any other information\n  /// derived pools might need.\n  ///\n  /// - The *expense ratio* and *harvester ratio* are charged each time when harvester harvest the pool revenue.\n  /// - The *withdraw fee percentage* is charged each time when user try to withdraw assets from the pool.\n  ///\n  /// [ rewards expense ratio | harvester ratio | flash loan ratio | redeem ratio | funding expense ratio | liquidation expense ratio | available ]\n  /// [        30 bits        |     30 bits     |     30  bits     |   30  bits   |        30 bits        |          30 bits          |  76 bits  ]\n  /// [ MSB                                                                                                                                   LSB ]\n  bytes32 internal _miscData;\n\n  /// @inheritdoc IProtocolFees\n  address public treasury;\n\n  /// @inheritdoc IProtocolFees\n  /// @dev Hold fees including open, close, redeem, liquidation and rebalance.\n  address public revenuePool;\n\n  /// @inheritdoc IProtocolFees\n  address public reservePool;\n\n  /// @inheritdoc IProtocolFees\n  mapping(address => uint256) public accumulatedPoolFees;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  function __ProtocolFees_init(\n    uint256 _expenseRatio,\n    uint256 _harvesterRatio,\n    uint256 _flashLoanFeeRatio,\n    address _treasury,\n    address _revenuePool,\n    address _reservePool\n  ) internal onlyInitializing {\n    _updateFundingExpenseRatio(_expenseRatio);\n    _updateRewardsExpenseRatio(_expenseRatio);\n    _updateLiquidationExpenseRatio(_expenseRatio);\n    _updateHarvesterRatio(_harvesterRatio);\n    _updateFlashLoanFeeRatio(_flashLoanFeeRatio);\n    _updateTreasury(_treasury);\n    _updateRevenuePool(_revenuePool);\n    _updateReservePool(_reservePool);\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @inheritdoc IProtocolFees\n  function getFundingExpenseRatio() public view returns (uint256) {\n    return _miscData.decodeUint(FUNDING_EXPENSE_RATIO_OFFSET, 30);\n  }\n\n  /// @inheritdoc IProtocolFees\n  function getRewardsExpenseRatio() public view returns (uint256) {\n    return _miscData.decodeUint(REWARDS_EXPENSE_RATIO_OFFSET, 30);\n  }\n\n  /// @inheritdoc IProtocolFees\n  function getLiquidationExpenseRatio() public view returns (uint256) {\n    return _miscData.decodeUint(LIQUIDATION_EXPENSE_RATIO_OFFSET, 30);\n  }\n\n  /// @inheritdoc IProtocolFees\n  function getHarvesterRatio() public view returns (uint256) {\n    return _miscData.decodeUint(HARVESTER_RATIO_OFFSET, 30);\n  }\n\n  /// @inheritdoc IProtocolFees\n  function getFundingFxSaveRatio() external view returns (uint256) {\n    return FEE_PRECISION - getFundingExpenseRatio() - getHarvesterRatio();\n  }\n\n  /// @inheritdoc IProtocolFees\n  function getRewardsFxSaveRatio() external view returns (uint256) {\n    return FEE_PRECISION - getRewardsExpenseRatio() - getHarvesterRatio();\n  }\n\n  /// @inheritdoc IProtocolFees\n  function getFlashLoanFeeRatio() public view returns (uint256) {\n    return _miscData.decodeUint(FLASH_LOAN_RATIO_OFFSET, 30);\n  }\n\n  /// @inheritdoc IProtocolFees\n  function getRedeemFeeRatio() public view returns (uint256) {\n    return _miscData.decodeUint(REDEEM_FEE_RATIO_OFFSET, 30);\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc IProtocolFees\n  function withdrawAccumulatedPoolFee(address[] memory pools) external {\n    for (uint256 i = 0; i < pools.length; ++i) {\n      _takeAccumulatedPoolFee(pools[i]);\n    }\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Change address of reserve pool contract.\n  /// @param _newReservePool The new address of reserve pool contract.\n  function updateReservePool(address _newReservePool) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateReservePool(_newReservePool);\n  }\n\n  /// @notice Change address of treasury contract.\n  /// @param _newTreasury The new address of treasury contract.\n  function updateTreasury(address _newTreasury) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateTreasury(_newTreasury);\n  }\n\n  /// @notice Change address of revenue pool contract.\n  /// @param _newPool The new address of revenue pool contract.\n  function updateRevenuePool(address _newPool) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateRevenuePool(_newPool);\n  }\n\n  /// @notice Update the fee ratio distributed to treasury.\n  /// @param newRewardsRatio The new ratio for rewards to update, multiplied by 1e9.\n  /// @param newFundingRatio The new ratio for funding to update, multiplied by 1e9.\n  /// @param newLiquidationRatio The new ratio for liquidation/rebalance to update, multiplied by 1e9.\n  function updateExpenseRatio(\n    uint32 newRewardsRatio,\n    uint32 newFundingRatio,\n    uint32 newLiquidationRatio\n  ) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateRewardsExpenseRatio(newRewardsRatio);\n    _updateFundingExpenseRatio(newFundingRatio);\n    _updateLiquidationExpenseRatio(newLiquidationRatio);\n  }\n\n  /// @notice Update the fee ratio distributed to harvester.\n  /// @param newRatio The new ratio to update, multiplied by 1e9.\n  function updateHarvesterRatio(uint32 newRatio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateHarvesterRatio(newRatio);\n  }\n\n  /// @notice Update the flash loan fee ratio.\n  /// @param newRatio The new ratio to update, multiplied by 1e9.\n  function updateFlashLoanFeeRatio(uint32 newRatio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateFlashLoanFeeRatio(newRatio);\n  }\n\n  /// @notice Update the redeem fee ratio.\n  /// @param newRatio The new ratio to update, multiplied by 1e9.\n  function updateRedeemFeeRatio(uint32 newRatio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateRedeemFeeRatio(newRatio);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to change address of treasury contract.\n  /// @param _newTreasury The new address of treasury contract.\n  function _updateTreasury(address _newTreasury) private {\n    if (_newTreasury == address(0)) revert ErrorZeroAddress();\n\n    address _oldTreasury = treasury;\n    treasury = _newTreasury;\n\n    emit UpdateTreasury(_oldTreasury, _newTreasury);\n  }\n\n  /// @dev Internal function to change address of revenue pool contract.\n  /// @param _newPool The new address of revenue pool contract.\n  function _updateRevenuePool(address _newPool) private {\n    if (_newPool == address(0)) revert ErrorZeroAddress();\n\n    address _oldPool = revenuePool;\n    revenuePool = _newPool;\n\n    emit UpdateRevenuePool(_oldPool, _newPool);\n  }\n\n  /// @dev Internal function to change the address of reserve pool contract.\n  /// @param newReservePool The new address of reserve pool contract.\n  function _updateReservePool(address newReservePool) private {\n    if (newReservePool == address(0)) revert ErrorZeroAddress();\n\n    address oldReservePool = reservePool;\n    reservePool = newReservePool;\n\n    emit UpdateReservePool(oldReservePool, newReservePool);\n  }\n\n  /// @dev Internal function to update the fee ratio distributed to treasury.\n  /// @param newRatio The new ratio to update, multiplied by 1e9.\n  function _updateRewardsExpenseRatio(uint256 newRatio) private {\n    if (uint256(newRatio) > MAX_EXPENSE_RATIO) {\n      revert ErrorExpenseRatioTooLarge();\n    }\n\n    bytes32 _data = _miscData;\n    uint256 _oldRatio = _miscData.decodeUint(REWARDS_EXPENSE_RATIO_OFFSET, 30);\n    _miscData = _data.insertUint(newRatio, REWARDS_EXPENSE_RATIO_OFFSET, 30);\n\n    emit UpdateRewardsExpenseRatio(_oldRatio, newRatio);\n  }\n\n  /// @dev Internal function to update the fee ratio distributed to treasury.\n  /// @param newRatio The new ratio to update, multiplied by 1e9.\n  function _updateLiquidationExpenseRatio(uint256 newRatio) private {\n    if (uint256(newRatio) > MAX_EXPENSE_RATIO) {\n      revert ErrorExpenseRatioTooLarge();\n    }\n\n    bytes32 _data = _miscData;\n    uint256 _oldRatio = _miscData.decodeUint(LIQUIDATION_EXPENSE_RATIO_OFFSET, 30);\n    _miscData = _data.insertUint(newRatio, LIQUIDATION_EXPENSE_RATIO_OFFSET, 30);\n\n    emit UpdateLiquidationExpenseRatio(_oldRatio, newRatio);\n  }\n\n  /// @dev Internal function to update the fee ratio distributed to treasury.\n  /// @param newRatio The new ratio to update, multiplied by 1e9.\n  function _updateFundingExpenseRatio(uint256 newRatio) private {\n    if (uint256(newRatio) > MAX_EXPENSE_RATIO) {\n      revert ErrorExpenseRatioTooLarge();\n    }\n\n    bytes32 _data = _miscData;\n    uint256 _oldRatio = _miscData.decodeUint(FUNDING_EXPENSE_RATIO_OFFSET, 30);\n    _miscData = _data.insertUint(newRatio, FUNDING_EXPENSE_RATIO_OFFSET, 30);\n\n    emit UpdateFundingExpenseRatio(_oldRatio, newRatio);\n  }\n\n  /// @dev Internal function to update the fee ratio distributed to harvester.\n  /// @param newRatio The new ratio to update, multiplied by 1e9.\n  function _updateHarvesterRatio(uint256 newRatio) private {\n    if (uint256(newRatio) > MAX_HARVESTER_RATIO) {\n      revert ErrorHarvesterRatioTooLarge();\n    }\n\n    bytes32 _data = _miscData;\n    uint256 _oldRatio = _miscData.decodeUint(HARVESTER_RATIO_OFFSET, 30);\n    _miscData = _data.insertUint(newRatio, HARVESTER_RATIO_OFFSET, 30);\n\n    emit UpdateHarvesterRatio(_oldRatio, newRatio);\n  }\n\n  /// @dev Internal function to update the flash loan fee ratio.\n  /// @param newRatio The new ratio to update, multiplied by 1e9.\n  function _updateFlashLoanFeeRatio(uint256 newRatio) private {\n    if (uint256(newRatio) > MAX_FLASH_LOAN_FEE_RATIO) {\n      revert ErrorFlashLoanFeeRatioTooLarge();\n    }\n\n    bytes32 _data = _miscData;\n    uint256 _oldRatio = _miscData.decodeUint(FLASH_LOAN_RATIO_OFFSET, 30);\n    _miscData = _data.insertUint(newRatio, FLASH_LOAN_RATIO_OFFSET, 30);\n\n    emit UpdateFlashLoanFeeRatio(_oldRatio, newRatio);\n  }\n\n  /// @dev Internal function to update the redeem fee ratio.\n  /// @param newRatio The new ratio to update, multiplied by 1e9.\n  function _updateRedeemFeeRatio(uint256 newRatio) private {\n    if (uint256(newRatio) > MAX_REDEEM_FEE_RATIO) {\n      revert ErrorRedeemFeeRatioTooLarge();\n    }\n\n    bytes32 _data = _miscData;\n    uint256 _oldRatio = _miscData.decodeUint(REDEEM_FEE_RATIO_OFFSET, 30);\n    _miscData = _data.insertUint(newRatio, REDEEM_FEE_RATIO_OFFSET, 30);\n\n    emit UpdateRedeemFeeRatio(_oldRatio, newRatio);\n  }\n\n  /// @dev Internal function to accumulate protocol fee for the given pool.\n  /// @param pool The address of pool.\n  /// @param amount The amount of protocol fee.\n  function _accumulatePoolFee(address pool, uint256 amount) internal {\n    if (amount > 0) {\n      accumulatedPoolFees[pool] += amount;\n    }\n  }\n\n  /// @dev Internal function to withdraw accumulated protocol fee for the given pool.\n  /// @param pool The address of pool.\n  function _takeAccumulatedPoolFee(address pool) internal returns (uint256 fees) {\n    fees = accumulatedPoolFees[pool];\n    if (fees > 0) {\n      address collateralToken = IPool(pool).collateralToken();\n      IERC20(collateralToken).safeTransfer(revenuePool, fees);\n\n      accumulatedPoolFees[pool] = 0;\n    }\n  }\n\n  /**\n   * @dev This empty reserved space is put in place to allow future versions to add new\n   * variables without shifting down storage in the inheritance chain.\n   */\n  uint256[45] private __gap;\n}\n"},{"file_path":"contracts/interfaces/Curve/ICurveStableSwapNG.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface ICurveStableSwapNG {\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  function coins(uint256 index) external view returns (address);\n\n  function last_price(uint256 index) external view returns (uint256);\n\n  function ema_price(uint256 index) external view returns (uint256);\n\n  /// @notice Returns the AMM State price of token\n  /// @dev if i = 0, it will return the state price of coin[1].\n  /// @param i index of state price (0 for coin[1], 1 for coin[2], ...)\n  /// @return uint256 The state price quoted by the AMM for coin[i+1]\n  function get_p(uint256 i) external view returns (uint256);\n\n  function price_oracle(uint256 index) external view returns (uint256);\n\n  function D_oracle() external view returns (uint256);\n\n  function A() external view returns (uint256);\n\n  function A_precise() external view returns (uint256);\n\n  /// @notice Calculate the current input dx given output dy\n  /// @dev Index values can be found via the `coins` public getter method\n  /// @param i Index value for the coin to send\n  /// @param j Index value of the coin to receive\n  /// @param dy Amount of `j` being received after exchange\n  /// @return Amount of `i` predicted\n  function get_dx(\n    int128 i,\n    int128 j,\n    uint256 dy\n  ) external view returns (uint256);\n\n  /// @notice Calculate the current output dy given input dx\n  /// @dev Index values can be found via the `coins` public getter method\n  /// @param i Index value for the coin to send\n  /// @param j Index value of the coin to receive\n  /// @param dx Amount of `i` being exchanged\n  /// @return Amount of `j` predicted\n  function get_dy(\n    int128 i,\n    int128 j,\n    uint256 dx\n  ) external view returns (uint256);\n\n  /// @notice Calculate the amount received when withdrawing a single coin\n  /// @param burn_amount Amount of LP tokens to burn in the withdrawal\n  /// @param i Index value of the coin to withdraw\n  /// @return Amount of coin received\n  function calc_withdraw_one_coin(uint256 burn_amount, int128 i) external view returns (uint256);\n\n  /// @notice The current virtual price of the pool LP token\n  /// @dev Useful for calculating profits.\n  ///      The method may be vulnerable to donation-style attacks if implementation\n  ///      contains rebasing tokens. For integrators, caution is advised.\n  /// @return LP token virtual price normalized to 1e18\n  function get_virtual_price() external view returns (uint256);\n\n  /// @notice Calculate addition or reduction in token supply from a deposit or withdrawal\n  /// @param amounts Amount of each coin being deposited\n  /// @param is_deposit set True for deposits, False for withdrawals\n  /// @return Expected amount of LP tokens received\n  function calc_token_amount(uint256[] calldata amounts, bool is_deposit) external view returns (uint256);\n\n  /// @notice Get the current balance of a coin within the\n  ///         pool, less the accrued admin fees\n  /// @param i Index value for the coin to query balance of\n  /// @return Token balance\n  function balances(uint256 i) external view returns (uint256);\n\n  function get_balances() external view returns (uint256[] memory);\n\n  function stored_rates() external view returns (uint256[] memory);\n\n  /// @notice Return the fee for swapping between `i` and `j`\n  /// @param i Index value for the coin to send\n  /// @param j Index value of the coin to receive\n  /// @return Swap fee expressed as an integer with 1e10 precision\n  function dynamic_fee(int128 i, int128 j) external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Perform an exchange between two coins\n  /// @dev Index values can be found via the `coins` public getter method\n  /// @param i Index value for the coin to send\n  /// @param j Index value of the coin to receive\n  /// @param dx Amount of `i` being exchanged\n  /// @param min_dy Minimum amount of `j` to receive\n  /// @return Actual amount of `j` received\n  function exchange(\n    int128 i,\n    int128 j,\n    uint256 dx,\n    uint256 min_dy\n  ) external returns (uint256);\n\n  /// @notice Perform an exchange between two coins\n  /// @dev Index values can be found via the `coins` public getter method\n  /// @param i Index value for the coin to send\n  /// @param j Index value of the coin to receive\n  /// @param dx Amount of `i` being exchanged\n  /// @param min_dy Minimum amount of `j` to receive\n  /// @param receiver Address that receives `j`\n  /// @return Actual amount of `j` received\n  function exchange(\n    int128 i,\n    int128 j,\n    uint256 dx,\n    uint256 min_dy,\n    address receiver\n  ) external returns (uint256);\n\n  /// @notice Perform an exchange between two coins without transferring token in\n  /// @dev The contract swaps tokens based on a change in balance of coin[i]. The\n  ///      dx = ERC20(coin[i]).balanceOf(self) - self.stored_balances[i]. Users of\n  ///      this method are dex aggregators, arbitrageurs, or other users who do not\n  ///      wish to grant approvals to the contract: they would instead send tokens\n  ///      directly to the contract and call `exchange_received`.\n  ///      Note: This is disabled if pool contains rebasing tokens.\n  /// @param i Index value for the coin to send\n  /// @param j Index value of the coin to receive\n  /// @param dx Amount of `i` being exchanged\n  /// @param min_dy Minimum amount of `j` to receive\n  /// @return Actual amount of `j` received\n  function exchange_received(\n    int128 i,\n    int128 j,\n    uint256 dx,\n    uint256 min_dy\n  ) external returns (uint256);\n\n  /// @notice Perform an exchange between two coins without transferring token in\n  /// @dev The contract swaps tokens based on a change in balance of coin[i]. The\n  ///      dx = ERC20(coin[i]).balanceOf(self) - self.stored_balances[i]. Users of\n  ///      this method are dex aggregators, arbitrageurs, or other users who do not\n  ///      wish to grant approvals to the contract: they would instead send tokens\n  ///      directly to the contract and call `exchange_received`.\n  ///      Note: This is disabled if pool contains rebasing tokens.\n  /// @param i Index value for the coin to send\n  /// @param j Index value of the coin to receive\n  /// @param dx Amount of `i` being exchanged\n  /// @param min_dy Minimum amount of `j` to receive\n  /// @param receiver Address that receives `j`\n  /// @return Actual amount of `j` received\n  function exchange_received(\n    int128 i,\n    int128 j,\n    uint256 dx,\n    uint256 min_dy,\n    address receiver\n  ) external returns (uint256);\n\n  /// @notice Deposit coins into the pool\n  /// @param amounts List of amounts of coins to deposit\n  /// @param min_mint_amount Minimum amount of LP tokens to mint from the deposit\n  /// @return Amount of LP tokens received by depositing\n  function add_liquidity(uint256[] calldata amounts, uint256 min_mint_amount) external returns (uint256);\n\n  /// @notice Deposit coins into the pool\n  /// @param amounts List of amounts of coins to deposit\n  /// @param min_mint_amount Minimum amount of LP tokens to mint from the deposit\n  /// @param receiver Address that owns the minted LP tokens\n  /// @return Amount of LP tokens received by depositing\n  function add_liquidity(\n    uint256[] calldata amounts,\n    uint256 min_mint_amount,\n    address receiver\n  ) external returns (uint256);\n\n  /// @notice Withdraw a single coin from the pool\n  /// @param burn_amount Amount of LP tokens to burn in the withdrawal\n  /// @param i Index value of the coin to withdraw\n  /// @param min_received Minimum amount of coin to receive\n  /// @return Amount of coin received\n  function remove_liquidity_one_coin(\n    uint256 burn_amount,\n    int128 i,\n    uint256 min_received\n  ) external returns (uint256);\n\n  /// @notice Withdraw a single coin from the pool\n  /// @param burn_amount Amount of LP tokens to burn in the withdrawal\n  /// @param i Index value of the coin to withdraw\n  /// @param min_received Minimum amount of coin to receive\n  /// @param receiver Address that receives the withdrawn coins\n  /// @return Amount of coin received\n  function remove_liquidity_one_coin(\n    uint256 burn_amount,\n    int128 i,\n    uint256 min_received,\n    address receiver\n  ) external returns (uint256);\n\n  /// @notice Withdraw coins from the pool in an imbalanced amount\n  /// @param amounts List of amounts of underlying coins to withdraw\n  /// @param max_burn_amount Maximum amount of LP token to burn in the withdrawal\n  /// @return Actual amount of the LP token burned in the withdrawal\n  function remove_liquidity_imbalance(uint256[] calldata amounts, uint256 max_burn_amount) external returns (uint256);\n\n  /// @notice Withdraw coins from the pool in an imbalanced amount\n  /// @param amounts List of amounts of underlying coins to withdraw\n  /// @param max_burn_amount Maximum amount of LP token to burn in the withdrawal\n  /// @param receiver Address that receives the withdrawn coins\n  /// @return Actual amount of the LP token burned in the withdrawal\n  function remove_liquidity_imbalance(\n    uint256[] calldata amounts,\n    uint256 max_burn_amount,\n    address receiver\n  ) external returns (uint256);\n\n  /// @notice Withdraw coins from the pool\n  /// @dev Withdrawal amounts are based on current deposit ratios\n  /// @param burn_amount Quantity of LP tokens to burn in the withdrawal\n  /// @param min_amounts Minimum amounts of underlying coins to receive\n  /// @return List of amounts of coins that were withdrawn\n  function remove_liquidity(uint256 burn_amount, uint256[] calldata min_amounts) external returns (uint256[] memory);\n\n  /// @notice Withdraw coins from the pool\n  /// @dev Withdrawal amounts are based on current deposit ratios\n  /// @param burn_amount Quantity of LP tokens to burn in the withdrawal\n  /// @param min_amounts Minimum amounts of underlying coins to receive\n  /// @param receiver Address that receives the withdrawn coins\n  /// @return List of amounts of coins that were withdrawn\n  function remove_liquidity(\n    uint256 burn_amount,\n    uint256[] calldata min_amounts,\n    address receiver\n  ) external returns (uint256[] memory);\n\n  /// @notice Withdraw coins from the pool\n  /// @dev Withdrawal amounts are based on current deposit ratios\n  /// @param burn_amount Quantity of LP tokens to burn in the withdrawal\n  /// @param min_amounts Minimum amounts of underlying coins to receive\n  /// @param receiver Address that receives the withdrawn coins\n  /// @return List of amounts of coins that were withdrawn\n  function remove_liquidity(\n    uint256 burn_amount,\n    uint256[] calldata min_amounts,\n    address receiver,\n    bool claim_admin_fees\n  ) external returns (uint256[] memory);\n\n  /// @notice Claim admin fees. Callable by anyone.\n  function withdraw_admin_fees() external;\n}\n"},{"file_path":"@openzeppelin/contracts/utils/Address.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev The ETH balance of the account is not enough to perform the operation.\n     */\n    error AddressInsufficientBalance(address account);\n\n    /**\n     * @dev There's no code at `target` (it is not a contract).\n     */\n    error AddressEmptyCode(address target);\n\n    /**\n     * @dev A call to an address target failed. The target may have reverted.\n     */\n    error FailedInnerCall();\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        if (address(this).balance < amount) {\n            revert AddressInsufficientBalance(address(this));\n        }\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        if (!success) {\n            revert FailedInnerCall();\n        }\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason or custom error, it is bubbled\n     * up by this function (like regular Solidity function calls). However, if\n     * the call reverted with no returned reason, this function reverts with a\n     * {FailedInnerCall} error.\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        if (address(this).balance < value) {\n            revert AddressInsufficientBalance(address(this));\n        }\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n     * unsuccessful call.\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata\n    ) internal view returns (bytes memory) {\n        if (!success) {\n            _revert(returndata);\n        } else {\n            // only check if target is a contract if the call was successful and the return data is empty\n            // otherwise we already know that it was a contract\n            if (returndata.length == 0 && target.code.length == 0) {\n                revert AddressEmptyCode(target);\n            }\n            return returndata;\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n     * revert reason or with a default {FailedInnerCall} error.\n     */\n    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n        if (!success) {\n            _revert(returndata);\n        } else {\n            return returndata;\n        }\n    }\n\n    /**\n     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n     */\n    function _revert(bytes memory returndata) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            /// @solidity memory-safe-assembly\n            assembly {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert FailedInnerCall();\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/interfaces/IERC5267.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)\n\npragma solidity ^0.8.20;\n\ninterface IERC5267 {\n    /**\n     * @dev MAY be emitted to signal that the domain could have changed.\n     */\n    event EIP712DomainChanged();\n\n    /**\n     * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712\n     * signature.\n     */\n    function eip712Domain()\n        external\n        view\n        returns (\n            bytes1 fields,\n            string memory name,\n            string memory version,\n            uint256 chainId,\n            address verifyingContract,\n            bytes32 salt,\n            uint256[] memory extensions\n        );\n}\n"},{"file_path":"@openzeppelin/contracts/utils/cryptography/ECDSA.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS\n    }\n\n    /**\n     * @dev The signature derives the `address(0)`.\n     */\n    error ECDSAInvalidSignature();\n\n    /**\n     * @dev The signature has an invalid length.\n     */\n    error ECDSAInvalidSignatureLength(uint256 length);\n\n    /**\n     * @dev The signature has an S value that is in the upper half order.\n     */\n    error ECDSAInvalidSignatureS(bytes32 s);\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not\n     * return address(0) without also returning an error description. Errors are documented using an enum (error type)\n     * and a bytes32 providing additional information about the error.\n     *\n     * If no error is returned, then the address can be used for verification purposes.\n     *\n     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);\n        _throwError(error, errorArg);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     */\n    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {\n        unchecked {\n            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n            // We do not check for an overflow here since the shift operation results in 0 or 1.\n            uint8 v = uint8((uint256(vs) >> 255) + 27);\n            return tryRecover(hash, v, r, s);\n        }\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     */\n    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {\n        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);\n        _throwError(error, errorArg);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError, bytes32) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS, s);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature, bytes32(0));\n        }\n\n        return (signer, RecoverError.NoError, bytes32(0));\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {\n        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);\n        _throwError(error, errorArg);\n        return recovered;\n    }\n\n    /**\n     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.\n     */\n    function _throwError(RecoverError error, bytes32 errorArg) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert ECDSAInvalidSignature();\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert ECDSAInvalidSignatureLength(uint256(errorArg));\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert ECDSAInvalidSignatureS(errorArg);\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n    function __Context_init() internal onlyInitializing {\n    }\n\n    function __Context_init_unchained() internal onlyInitializing {\n    }\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"},{"file_path":"contracts/common/rewards/distributor/LinearRewardDistributor.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { AccessControlUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\";\n\nimport { IRewardDistributor } from \"./IRewardDistributor.sol\";\nimport { LinearReward } from \"./LinearReward.sol\";\n\n// solhint-disable no-empty-blocks\n// solhint-disable not-rely-on-time\n\nabstract contract LinearRewardDistributor is AccessControlUpgradeable, IRewardDistributor {\n  using SafeERC20 for IERC20;\n\n  using LinearReward for LinearReward.RewardData;\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @notice The role used to deposit rewards.\n  bytes32 public constant REWARD_DEPOSITOR_ROLE = keccak256(\"REWARD_DEPOSITOR_ROLE\");\n\n  /// @notice The length of reward period in seconds.\n  /// @dev If the value is zero, the reward will be distributed immediately.\n  /// It is either zero or at least 1 day (which is 86400).\n  uint40 public immutable periodLength;\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @notice The linear distribution reward data.\n  LinearReward.RewardData public rewardData;\n\n  /// @inheritdoc IRewardDistributor\n  address public override rewardToken;\n\n  /// @dev reserved slots.\n  uint256[48] private __gap;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(uint40 _periodLength) {\n    require(_periodLength == 0 || (_periodLength >= 1 days && _periodLength <= 28 days), \"invalid period length\");\n\n    periodLength = _periodLength;\n  }\n\n  // solhint-disable-next-line func-name-mixedcase\n  function __LinearRewardDistributor_init(address _rewardToken) internal onlyInitializing {\n    rewardToken = _rewardToken;\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @inheritdoc IRewardDistributor\n  function pendingRewards() public view override returns (uint256, uint256) {\n    return rewardData.pending();\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc IRewardDistributor\n  function depositReward(uint256 _amount) external override onlyRole(REWARD_DEPOSITOR_ROLE) {\n    if (_amount > 0) {\n      IERC20(rewardToken).safeTransferFrom(msg.sender, address(this), _amount);\n    }\n\n    _distributePendingReward();\n\n    _notifyReward(_amount);\n\n    _afterRewardDeposit(_amount);\n\n    emit DepositReward(_amount);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to notify new rewards.\n  ///\n  /// @param _amount The amount of new rewards.\n  function _notifyReward(uint256 _amount) internal {\n    if (periodLength == 0) {\n      _accumulateReward(_amount);\n    } else {\n      LinearReward.RewardData memory _data = rewardData;\n      _data.increase(periodLength, _amount);\n      rewardData = _data;\n    }\n  }\n\n  /// @dev Internal function to distribute all pending reward tokens.\n  function _distributePendingReward() internal {\n    if (periodLength == 0) return;\n\n    (uint256 _pending, ) = rewardData.pending();\n    rewardData.lastUpdate = uint40(block.timestamp);\n\n    if (_pending > 0) {\n      _accumulateReward(_pending);\n    }\n  }\n\n  /// @dev Internal function to accumulate distributed rewards.\n  ///\n  /// @param _amount The amount of rewards to accumulate.\n  function _accumulateReward(uint256 _amount) internal virtual;\n\n  /// @dev The hook for the deposited rewards.\n  /// @param _amount The amount of rewards deposited.\n  function _afterRewardDeposit(uint256 _amount) internal virtual {}\n}\n"},{"file_path":"contracts/common/EIP2535/interfaces/IERC165.sol","source_code":"// SPDX-License-Identifier: CC0-1.0\npragma solidity ^0.8.0;\n\ninterface IERC165 {\n  /// @notice Query if a contract implements an interface\n  /// @param interfaceId The interface identifier, as specified in ERC-165\n  /// @dev Interface identification is specified in ERC-165. This function\n  ///  uses less than 30,000 gas.\n  /// @return `true` if the contract implements `interfaceID` and\n  ///  `interfaceID` is not 0xffffffff, `false` otherwise\n  function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},{"file_path":"contracts/libraries/TickMath.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.26;\n\n/// @title library that calculates number \"tick\" and \"ratioX96\" from this: ratioX96 = (1.0015^tick) * 2^96\n/// @notice this library is used in Fluid Vault protocol for optimiziation.\n/// @dev \"tick\" supports between -32767 and 32767. \"ratioX96\" supports between 37075072 and 169307877264527972847801929085841449095838922544595\n///\n/// @dev Copy from https://github.com/Instadapp/fluid-contracts-public/blob/main/contracts/libraries/tickMath.sol\nlibrary TickMath {\n    /// The minimum tick that can be passed in getRatioAtTick. 1.0015**-32767\n    int24 internal constant MIN_TICK = -32767;\n    /// The maximum tick that can be passed in getRatioAtTick. 1.0015**32767\n    int24 internal constant MAX_TICK = 32767;\n\n    uint256 internal constant FACTOR00 = 0x100000000000000000000000000000000;\n    uint256 internal constant FACTOR01 = 0xff9dd7de423466c20352b1246ce4856f; // 2^128/1.0015**1 = 339772707859149738855091969477551883631\n    uint256 internal constant FACTOR02 = 0xff3bd55f4488ad277531fa1c725a66d0; // 2^128/1.0015**2 = 339263812140938331358054887146831636176\n    uint256 internal constant FACTOR03 = 0xfe78410fd6498b73cb96a6917f853259; // 2^128/1.0015**4 = 338248306163758188337119769319392490073\n    uint256 internal constant FACTOR04 = 0xfcf2d9987c9be178ad5bfeffaa123273; // 2^128/1.0015**8 = 336226404141693512316971918999264834163\n    uint256 internal constant FACTOR05 = 0xf9ef02c4529258b057769680fc6601b3; // 2^128/1.0015**16 = 332218786018727629051611634067491389875\n    uint256 internal constant FACTOR06 = 0xf402d288133a85a17784a411f7aba082; // 2^128/1.0015**32 = 324346285652234375371948336458280706178\n    uint256 internal constant FACTOR07 = 0xe895615b5beb6386553757b0352bda90; // 2^128/1.0015**64 = 309156521885964218294057947947195947664\n    uint256 internal constant FACTOR08 = 0xd34f17a00ffa00a8309940a15930391a; // 2^128/1.0015**128 = 280877777739312896540849703637713172762 \n    uint256 internal constant FACTOR09 = 0xae6b7961714e20548d88ea5123f9a0ff; // 2^128/1.0015**256 = 231843708922198649176471782639349113087\n    uint256 internal constant FACTOR10 = 0x76d6461f27082d74e0feed3b388c0ca1; // 2^128/1.0015**512 = 157961477267171621126394973980180876449\n    uint256 internal constant FACTOR11 = 0x372a3bfe0745d8b6b19d985d9a8b85bb; // 2^128/1.0015**1024 = 73326833024599564193373530205717235131\n    uint256 internal constant FACTOR12 = 0x0be32cbee48979763cf7247dd7bb539d; // 2^128/1.0015**2048 = 15801066890623697521348224657638773661\n    uint256 internal constant FACTOR13 = 0x8d4f70c9ff4924dac37612d1e2921e;   // 2^128/1.0015**4096 = 733725103481409245883800626999235102\n    uint256 internal constant FACTOR14 = 0x4e009ae5519380809a02ca7aec77;     // 2^128/1.0015**8192 = 1582075887005588088019997442108535\n    uint256 internal constant FACTOR15 = 0x17c45e641b6e95dee056ff10;         // 2^128/1.0015**16384 = 7355550435635883087458926352\n\n    /// The minimum value that can be returned from getRatioAtTick. Equivalent to getRatioAtTick(MIN_TICK). ~ Equivalent to `(1 << 96) * (1.0015**-32767)`\n    uint256 internal constant MIN_RATIOX96 = 37075072;\n    /// The maximum value that can be returned from getRatioAtTick. Equivalent to getRatioAtTick(MAX_TICK).\n    /// ~ Equivalent to `(1 << 96) * (1.0015**32767)`, rounding etc. leading to minor difference\n    uint256 internal constant MAX_RATIOX96 = 169307877264527972847801929085841449095838922544595;\n\n    uint256 internal constant ZERO_TICK_SCALED_RATIO = 0x1000000000000000000000000; // 1 << 96 // 79228162514264337593543950336\n    uint256 internal constant _1E26 = 1e26;\n\n    /// @notice ratioX96 = (1.0015^tick) * 2^96\n    /// @dev Throws if |tick| > max tick\n    /// @param tick The input tick for the above formula\n    /// @return ratioX96 ratio = (debt amount/collateral amount)\n    function getRatioAtTick(int tick) internal pure returns (uint256 ratioX96) {\n        assembly {\n            let absTick_ := sub(xor(tick, sar(255, tick)), sar(255, tick))\n\n            if gt(absTick_, MAX_TICK) {\n                revert(0, 0)\n            }\n            let factor_ := FACTOR00\n            if and(absTick_, 0x1) {\n                factor_ := FACTOR01\n            }\n            if and(absTick_, 0x2) {\n                factor_ := shr(128, mul(factor_, FACTOR02))\n            }\n            if and(absTick_, 0x4) {\n                factor_ := shr(128, mul(factor_, FACTOR03))\n            }\n            if and(absTick_, 0x8) {\n                factor_ := shr(128, mul(factor_, FACTOR04))\n            }\n            if and(absTick_, 0x10) {\n                factor_ := shr(128, mul(factor_, FACTOR05))\n            }\n            if and(absTick_, 0x20) {\n                factor_ := shr(128, mul(factor_, FACTOR06))\n            }\n            if and(absTick_, 0x40) {\n                factor_ := shr(128, mul(factor_, FACTOR07))\n            }\n            if and(absTick_, 0x80) {\n                factor_ := shr(128, mul(factor_, FACTOR08))\n            }\n            if and(absTick_, 0x100) {\n                factor_ := shr(128, mul(factor_, FACTOR09))\n            }\n            if and(absTick_, 0x200) {\n                factor_ := shr(128, mul(factor_, FACTOR10))\n            }\n            if and(absTick_, 0x400) {\n                factor_ := shr(128, mul(factor_, FACTOR11))\n            }\n            if and(absTick_, 0x800) {\n                factor_ := shr(128, mul(factor_, FACTOR12))\n            }\n            if and(absTick_, 0x1000) {\n                factor_ := shr(128, mul(factor_, FACTOR13))\n            }\n            if and(absTick_, 0x2000) {\n                factor_ := shr(128, mul(factor_, FACTOR14))\n            }\n            if and(absTick_, 0x4000) {\n                factor_ := shr(128, mul(factor_, FACTOR15))\n            }\n\n            let precision_ := 0\n            if iszero(and(tick, 0x8000000000000000000000000000000000000000000000000000000000000000)) {\n                factor_ := div(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, factor_)\n                // we round up in the division so getTickAtRatio of the output price is always consistent\n                if mod(factor_, 0x100000000) {\n                    precision_ := 1\n                }\n            }\n            ratioX96 := add(shr(32, factor_), precision_)\n        }\n    }\n\n    /// @notice ratioX96 = (1.0015^tick) * 2^96\n    /// @dev Throws if ratioX96 > max ratio || ratioX96 < min ratio\n    /// @param ratioX96 The input ratio; ratio = (debt amount/collateral amount)\n    /// @return tick The output tick for the above formula. Returns in round down form. if tick is 123.23 then 123, if tick is -123.23 then returns -124\n    /// @return perfectRatioX96 perfect ratio for the above tick\n    function getTickAtRatio(uint256 ratioX96) internal pure returns (int tick, uint perfectRatioX96) {\n        assembly {\n            if or(gt(ratioX96, MAX_RATIOX96), lt(ratioX96, MIN_RATIOX96)) {\n                revert(0, 0)\n            }\n\n            let cond := lt(ratioX96, ZERO_TICK_SCALED_RATIO)\n            let factor_\n\n            if iszero(cond) {\n                // if ratioX96 >= ZERO_TICK_SCALED_RATIO\n                factor_ := div(mul(ratioX96, _1E26), ZERO_TICK_SCALED_RATIO)\n            }\n            if cond {\n                // ratioX96 < ZERO_TICK_SCALED_RATIO\n                factor_ := div(mul(ZERO_TICK_SCALED_RATIO, _1E26), ratioX96)\n            }\n\n            // put in https://www.wolframalpha.com/ whole equation: (1.0015^tick) * 2^96 * 10^26 / 79228162514264337593543950336\n\n            // for tick = 16384\n            // ratioX96 = (1.0015^16384) * 2^96 = 3665252098134783297721995888537077351735\n            // 3665252098134783297721995888537077351735 * 10^26 / 79228162514264337593543950336 =\n            // 4626198540796508716348404308345255985.06131964639489434655721\n            if iszero(lt(factor_, 4626198540796508716348404308345255985)) {\n                tick := or(tick, 0x4000)\n                factor_ := div(mul(factor_, _1E26), 4626198540796508716348404308345255985)\n            }\n            // for tick = 8192\n            // ratioX96 = (1.0015^8192) * 2^96 = 17040868196391020479062776466509865\n            // 17040868196391020479062776466509865 * 10^26 / 79228162514264337593543950336 =\n            // 21508599537851153911767490449162.3037648642153898377655505172\n            if iszero(lt(factor_, 21508599537851153911767490449162)) {\n                tick := or(tick, 0x2000)\n                factor_ := div(mul(factor_, _1E26), 21508599537851153911767490449162)\n            }\n            // for tick = 4096\n            // ratioX96 = (1.0015^4096) * 2^96 = 36743933851015821532611831851150\n            // 36743933851015821532611831851150 * 10^26 / 79228162514264337593543950336 =\n            // 46377364670549310883002866648.9777607649742626173648716941385\n            if iszero(lt(factor_, 46377364670549310883002866649)) {\n                tick := or(tick, 0x1000)\n                factor_ := div(mul(factor_, _1E26), 46377364670549310883002866649)\n            }\n            // for tick = 2048\n            // ratioX96 = (1.0015^2048) * 2^96 = 1706210527034005899209104452335\n            // 1706210527034005899209104452335 * 10^26 / 79228162514264337593543950336 =\n            // 2153540449365864845468344760.06357108484096046743300420319322\n            if iszero(lt(factor_, 2153540449365864845468344760)) {\n                tick := or(tick, 0x800)\n                factor_ := div(mul(factor_, _1E26), 2153540449365864845468344760)\n            }\n            // for tick = 1024\n            // ratioX96 = (1.0015^1024) * 2^96 = 367668226692760093024536487236\n            // 367668226692760093024536487236 * 10^26 / 79228162514264337593543950336 =\n            // 464062544207767844008185024.950588990554136265212906454481127\n            if iszero(lt(factor_, 464062544207767844008185025)) {\n                tick := or(tick, 0x400)\n                factor_ := div(mul(factor_, _1E26), 464062544207767844008185025)\n            }\n            // for tick = 512\n            // ratioX96 = (1.0015^512) * 2^96 = 170674186729409605620119663668\n            // 170674186729409605620119663668 * 10^26 / 79228162514264337593543950336 =\n            // 215421109505955298802281577.031879604792139232258508172947569\n            if iszero(lt(factor_, 215421109505955298802281577)) {\n                tick := or(tick, 0x200)\n                factor_ := div(mul(factor_, _1E26), 215421109505955298802281577)\n            }\n            // for tick = 256\n            // ratioX96 = (1.0015^256) * 2^96 = 116285004205991934861656513301\n            // 116285004205991934861656513301 * 10^26 / 79228162514264337593543950336 =\n            // 146772309890508740607270614.667650899656438875541505058062410\n            if iszero(lt(factor_, 146772309890508740607270615)) {\n                tick := or(tick, 0x100)\n                factor_ := div(mul(factor_, _1E26), 146772309890508740607270615)\n            }\n            // for tick = 128\n            // ratioX96 = (1.0015^128) * 2^96 = 95984619659632141743747099590\n            // 95984619659632141743747099590 * 10^26 / 79228162514264337593543950336 =\n            // 121149622323187099817270416.157248837742741760456796835775887\n            if iszero(lt(factor_, 121149622323187099817270416)) {\n                tick := or(tick, 0x80)\n                factor_ := div(mul(factor_, _1E26), 121149622323187099817270416)\n            }\n            // for tick = 64\n            // ratioX96 = (1.0015^64) * 2^96 = 87204845308406958006717891124\n            // 87204845308406958006717891124 * 10^26 / 79228162514264337593543950336 =\n            // 110067989135437147685980801.568068573422377364214113968609839\n            if iszero(lt(factor_, 110067989135437147685980801)) {\n                tick := or(tick, 0x40)\n                factor_ := div(mul(factor_, _1E26), 110067989135437147685980801)\n            }\n            // for tick = 32\n            // ratioX96 = (1.0015^32) * 2^96 = 83120873769022354029916374475\n            // 83120873769022354029916374475 * 10^26 / 79228162514264337593543950336 =\n            // 104913292358707887270979599.831816586773651266562785765558183\n            if iszero(lt(factor_, 104913292358707887270979600)) {\n                tick := or(tick, 0x20)\n                factor_ := div(mul(factor_, _1E26), 104913292358707887270979600)\n            }\n            // for tick = 16\n            // ratioX96 = (1.0015^16) * 2^96 = 81151180492336368327184716176\n            // 81151180492336368327184716176 * 10^26 / 79228162514264337593543950336 =\n            // 102427189924701091191840927.762844039579442328381455567932128\n            if iszero(lt(factor_, 102427189924701091191840928)) {\n                tick := or(tick, 0x10)\n                factor_ := div(mul(factor_, _1E26), 102427189924701091191840928)\n            }\n            // for tick = 8\n            // ratioX96 = (1.0015^8) * 2^96 = 80183906840906820640659903620\n            // 80183906840906820640659903620 * 10^26 / 79228162514264337593543950336 =\n            // 101206318935480056907421312.890625\n            if iszero(lt(factor_, 101206318935480056907421313)) {\n                tick := or(tick, 0x8)\n                factor_ := div(mul(factor_, _1E26), 101206318935480056907421313)\n            }\n            // for tick = 4\n            // ratioX96 = (1.0015^4) * 2^96 = 79704602139525152702959747603\n            // 79704602139525152702959747603 * 10^26 / 79228162514264337593543950336 =\n            // 100601351350506250000000000\n            if iszero(lt(factor_, 100601351350506250000000000)) {\n                tick := or(tick, 0x4)\n                factor_ := div(mul(factor_, _1E26), 100601351350506250000000000)\n            }\n            // for tick = 2\n            // ratioX96 = (1.0015^2) * 2^96 = 79466025265172787701084167660\n            // 79466025265172787701084167660 * 10^26 / 79228162514264337593543950336 =\n            // 100300225000000000000000000\n            if iszero(lt(factor_, 100300225000000000000000000)) {\n                tick := or(tick, 0x2)\n                factor_ := div(mul(factor_, _1E26), 100300225000000000000000000)\n            }\n            // for tick = 1\n            // ratioX96 = (1.0015^1) * 2^96 = 79347004758035734099934266261\n            // 79347004758035734099934266261 * 10^26 / 79228162514264337593543950336 =\n            // 100150000000000000000000000\n            if iszero(lt(factor_, 100150000000000000000000000)) {\n                tick := or(tick, 0x1)\n                factor_ := div(mul(factor_, _1E26), 100150000000000000000000000)\n            }\n            if iszero(cond) {\n                // if ratioX96 >= ZERO_TICK_SCALED_RATIO\n                perfectRatioX96 := div(mul(ratioX96, _1E26), factor_)\n            }\n            if cond {\n                // ratioX96 < ZERO_TICK_SCALED_RATIO\n                tick := not(tick)\n                perfectRatioX96 := div(mul(ratioX96, factor_), 100150000000000000000000000)\n            }\n            // perfect ratio should always be <= ratioX96\n            // not sure if it can ever be bigger but better to have extra checks\n            if gt(perfectRatioX96, ratioX96) {\n                revert(0, 0)\n            }\n        }\n    }\n}\n"},{"file_path":"contracts/common/EIP2535/upgradeInitializers/DiamondMultiInit.sol","source_code":"// SPDX-License-Identifier: CC0-1.0\npragma solidity ^0.8.0;\n\n/******************************************************************************\\\n* Author: Nick Mudge <nick@perfectabstractions.com>, Twitter/Github: @mudgen\n* EIP-2535 Diamonds\n*\n* Contract used to initialize state variables during deployment or upgrade\n/******************************************************************************/\n\nimport { LibDiamond } from \"../libraries/LibDiamond.sol\";\n\nerror AddressAndCalldataLengthDoNotMatch(uint256 _addressesLength, uint256 _calldataLength);\n\ncontract DiamondMultiInit {\n  // This function is provided in the third parameter of the `diamondCut` function.\n  // The `diamondCut` function executes this function to execute multiple initializer functions for a single upgrade.\n\n  function multiInit(address[] calldata _addresses, bytes[] calldata _calldata) external {\n    if (_addresses.length != _calldata.length) {\n      revert AddressAndCalldataLengthDoNotMatch(_addresses.length, _calldata.length);\n    }\n    for (uint256 i; i < _addresses.length; i++) {\n      LibDiamond.initializeDiamondCut(_addresses[i], _calldata[i]);\n    }\n  }\n}\n"},{"file_path":"contracts/helpers/interfaces/ITokenConverter.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface ITokenConverter {\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice The address of Converter Registry.\n  function registry() external view returns (address);\n\n  /// @notice Return the input token and output token for the route.\n  /// @param route The encoding of the route.\n  /// @return tokenIn The address of input token.\n  /// @return tokenOut The address of output token.\n  function getTokenPair(uint256 route) external view returns (address tokenIn, address tokenOut);\n\n  /// @notice Query the output token amount according to the encoding.\n  ///\n  /// @dev See the comments in `convert` for the meaning of encoding.\n  ///\n  /// @param encoding The encoding used to convert.\n  /// @param amountIn The amount of input token.\n  /// @param amountOut The amount of output token received.\n  function queryConvert(uint256 encoding, uint256 amountIn) external returns (uint256 amountOut);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Convert input token to output token according to the encoding.\n  /// Assuming that the input token is already in the contract.\n  ///\n  /// @dev encoding for single route\n  /// |   8 bits  | 2 bits |  246 bits  |\n  /// | pool_type | action | customized |\n  ///\n  /// + pool_type = 0: UniswapV2, only action = 0\n  ///   customized = |   160 bits   | 24 bits |     1 bit    | 1 bit | ... |\n  ///                | pool address | fee_num | zero_for_one | twamm | ... |\n  /// + pool_type = 1: UniswapV3, only action = 0\n  ///   customized = |   160 bits   | 24 bits |     1 bit    | ... |\n  ///                | pool address | fee_num | zero_for_one | ... |\n  /// + pool_type = 2: BalancerV1, only action = 0\n  ///   customized = |   160 bits   | 3 bits |  3 bits  |   3 bits  | ... |\n  ///                | pool address | tokens | index in | index out | ... |\n  /// + pool_type = 3: BalancerV2, only action = 0\n  ///   customized = |   160 bits   | 3 bits |  3 bits  |   3 bits  | ... |\n  ///                | pool address | tokens | index in | index out | ... |\n  /// + pool_type = 4: CurvePlainPool or CurveFactoryPlainPool\n  ///   customized = |   160 bits   | 3 bits |  3 bits  |   3 bits  |  1 bit  | ... |\n  ///                | pool address | tokens | index in | index out | use_eth | ... |\n  /// + pool_type = 5: CurveAPool\n  ///   customized = |   160 bits   | 3 bits |  3 bits  |   3 bits  |     1 bits     | ... |\n  ///                | pool address | tokens | index in | index out | use_underlying | ... |\n  /// + pool_type = 6: CurveYPool\n  ///   customized = |   160 bits   | 3 bits |  3 bits  |   3 bits  |     1 bits     | ... |\n  ///                | pool address | tokens | index in | index out | use_underlying | ... |\n  /// + pool_type = 7: CurveMetaPool or CurveFactoryMetaPool\n  ///   customized = |   160 bits   | 3 bits |  3 bits  |   3 bits  | ... |\n  ///                | pool address | tokens | index in | index out | ... |\n  /// + pool_type = 8: CurveCryptoPool or CurveFactoryCryptoPool\n  ///   customized = |   160 bits   | 3 bits |  3 bits  |   3 bits  |  1 bit  | ... |\n  ///                | pool address | tokens | index in | index out | use_eth | ... |\n  /// + pool_type = 9: ERC4626, no action 0\n  ///   customized = |   160 bits   | ... |\n  ///                | pool address | ... |\n  /// + pool_type = 10: Lido, no action 0\n  ///   customized = |   160 bits   | ... |\n  ///                | pool address | ... |\n  /// + pool_type = 11:  ETHLSDConverter v1, no action 0\n  ///   supported in other pool type\n  ///     puffer: pufETH is ERC4626, base is stETH\n  ///     frax: sfrxETH is ERC4626, base is frxETH\n  ///     pirex: apxETH is ERC4626, base is pxETH\n  ///   supported in this pool type\n  ///     0=wBETH: mint wBETH from ETH\n  ///     1=RocketPool: mint rETH from ETH\n  ///     2=frax: mint frxETH from ETH\n  ///     3=pirex: mint pxETH from ETH\n  ///     4=renzo: mint ezETH from ETH, stETH, wBETH\n  ///     5=ether.fi: mint eETH from ETH, mint weETH from eETH, unwrap weETH to eETH\n  ///     6=kelpdao.xyz: mint rsETH from ETH, ETHx, stETH, sfrxETH, and etc.\n  ///   customized = |   160 bits   |  8 bits  | ... |\n  ///                | pool address | protocol | ... |\n  /// + pool_type = 12: CurveStableSwapNG\n  ///   customized = |   160 bits   | 3 bits |  3 bits  |   3 bits  | ... |\n  ///                | pool address | tokens | index in | index out | ... |\n  /// + pool_type = 13: CurveStableSwapMetaNG\n  ///   customized = |   160 bits   | 3 bits |  3 bits  |   3 bits  | ... |\n  ///                | pool address | tokens | index in | index out | ... |\n  /// + pool_type = 14: WETH\n  ///   customized = |   160 bits   | ... |\n  ///                | pool address | ... |\n  ///\n  /// Note: tokens + 1 is the number of tokens of the pool\n  ///\n  /// + action = 0: swap\n  /// + action = 1: add liquidity / wrap / stake\n  /// + action = 2: remove liquidity / unwrap / unstake\n  ///\n  /// @param encoding The encoding used to convert.\n  /// @param amountIn The amount of input token.\n  /// @param recipient The address of token receiver.\n  /// @return amountOut The amount of output token received.\n  function convert(\n    uint256 encoding,\n    uint256 amountIn,\n    address recipient\n  ) external payable returns (uint256 amountOut);\n\n  /// @notice Withdraw dust assets in this contract.\n  /// @param token The address of token to withdraw.\n  /// @param recipient The address of token receiver.\n  function withdrawFund(address token, address recipient) external;\n}\n"},{"file_path":"contracts/mocks/MockERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockERC20 is ERC20 {\n  uint8 private immutable _decimals;\n\n  constructor(string memory _name, string memory _symbol, uint8 __decimals) ERC20(_name, _symbol) {\n    _decimals = __decimals;\n  }\n\n  function decimals() public view virtual override returns (uint8) {\n    return _decimals;\n  }\n\n  function mint(address _recipient, uint256 _amount) external {\n    _mint(_recipient, _amount);\n  }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/utils/CountersUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title Counters\n * @author Matt Condon (@shrugs)\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\n *\n * Include with `using Counters for Counters.Counter;`\n */\nlibrary CountersUpgradeable {\n    struct Counter {\n        // This variable should never be directly accessed by users of the library: interactions must be restricted to\n        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\n        // this feature: see https://github.com/ethereum/solidity/issues/4637\n        uint256 _value; // default: 0\n    }\n\n    function current(Counter storage counter) internal view returns (uint256) {\n        return counter._value;\n    }\n\n    function increment(Counter storage counter) internal {\n        unchecked {\n            counter._value += 1;\n        }\n    }\n\n    function decrement(Counter storage counter) internal {\n        uint256 value = counter._value;\n        require(value > 0, \"Counter: decrement overflow\");\n        unchecked {\n            counter._value = value - 1;\n        }\n    }\n\n    function reset(Counter storage counter) internal {\n        counter._value = 0;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/access/IAccessControl.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n    /**\n     * @dev The `account` is missing a role.\n     */\n    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n    /**\n     * @dev The caller of a function is not the expected one.\n     *\n     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n     */\n    error AccessControlBadConfirmation();\n\n    /**\n     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n     *\n     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n     * {RoleAdminChanged} not being emitted signaling this.\n     */\n    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n    /**\n     * @dev Emitted when `account` is granted `role`.\n     *\n     * `sender` is the account that originated the contract call, an admin role\n     * bearer except when using {AccessControl-_setupRole}.\n     */\n    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Emitted when `account` is revoked `role`.\n     *\n     * `sender` is the account that originated the contract call:\n     *   - if using `revokeRole`, it is the admin role bearer\n     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)\n     */\n    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) external view returns (bool);\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function grantRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function revokeRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been granted `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `callerConfirmation`.\n     */\n    function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n"},{"file_path":"contracts/common/rewards/distributor/IMultipleRewardDistributor.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IMultipleRewardDistributor {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when new reward token is registered.\n  ///\n  /// @param token The address of reward token.\n  /// @param distributor The address of reward distributor.\n  event RegisterRewardToken(address indexed token, address indexed distributor);\n\n  /// @notice Emitted when the reward distributor is updated.\n  ///\n  /// @param token The address of reward token.\n  /// @param oldDistributor The address of previous reward distributor.\n  /// @param newDistributor The address of current reward distributor.\n  event UpdateRewardDistributor(address indexed token, address indexed oldDistributor, address indexed newDistributor);\n\n  /// @notice Emitted when a reward token is unregistered.\n  ///\n  /// @param token The address of reward token.\n  event UnregisterRewardToken(address indexed token);\n\n  /// @notice Emitted when a reward token is deposited.\n  ///\n  /// @param token The address of reward token.\n  /// @param amount The amount of reward token deposited.\n  event DepositReward(address indexed token, uint256 amount);\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when caller access an unactive reward token.\n  error NotActiveRewardToken();\n\n  /// @dev Thrown when the address of reward distributor is `address(0)`.\n  error RewardDistributorIsZero();\n\n  /// @dev Thrown when caller is not reward distributor.\n  error NotRewardDistributor();\n\n  /// @dev Thrown when caller try to register an existing reward token.\n  error DuplicatedRewardToken();\n\n  /// @dev Thrown when caller try to unregister a reward with pending rewards.\n  error RewardDistributionNotFinished();\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the address of reward distributor.\n  ///\n  /// @param token The address of reward token.\n  function distributors(address token) external view returns (address);\n\n  /// @notice Return the list of active reward tokens.\n  function getActiveRewardTokens() external view returns (address[] memory);\n\n  /// @notice Return the list of historical reward tokens.\n  function getHistoricalRewardTokens() external view returns (address[] memory);\n\n  /// @notice Return the amount of pending distributed rewards in current period.\n  ///\n  /// @param token The address of reward token.\n  /// @return distributable The amount of reward token can be distributed in current period.\n  /// @return undistributed The amount of reward token still locked in current period.\n  function pendingRewards(address token) external view returns (uint256 distributable, uint256 undistributed);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Deposit new rewards to this contract.\n  ///\n  /// @param token The address of reward token.\n  /// @param amount The amount of new rewards.\n  function depositReward(address token, uint256 amount) external;\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165Upgradeable is Initializable, IERC165 {\n    function __ERC165_init() internal onlyInitializing {\n    }\n\n    function __ERC165_init_unchained() internal onlyInitializing {\n    }\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n        return interfaceId == type(IERC165).interfaceId;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721Receiver {\n    /**\n     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n     * by `operator` from `from`, this function is called.\n     *\n     * It must return its Solidity selector to confirm the token transfer.\n     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be\n     * reverted.\n     *\n     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.\n     */\n    function onERC721Received(\n        address operator,\n        address from,\n        uint256 tokenId,\n        bytes calldata data\n    ) external returns (bytes4);\n}\n"},{"file_path":"@openzeppelin/contracts-v4/utils/Context.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"},{"file_path":"contracts/helpers/converter/MultiPathConverter.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IWrappedEther } from \"../../interfaces/IWrappedEther.sol\";\nimport { ITokenConverter } from \"../interfaces/ITokenConverter.sol\";\nimport { IMultiPathConverter } from \"../interfaces/IMultiPathConverter.sol\";\n\ncontract MultiPathConverter is IMultiPathConverter {\n  using SafeERC20 for IERC20;\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The address of WETH token.\n  address internal constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @notice The address of GeneralTokenConverter contract.\n  address public immutable converter;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _converter) {\n    converter = _converter;\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @inheritdoc IMultiPathConverter\n  function queryConvert(\n    uint256 _amount,\n    uint256 _encoding,\n    uint256[] calldata _routes\n  ) external returns (uint256 amountOut) {\n    uint256 _offset;\n    for (uint256 i = 0; i < 8; i++) {\n      uint256 _ratio = _encoding & 0xfffff;\n      uint256 _length = (_encoding >> 20) & 0xfff;\n      if (_ratio == 0) break;\n\n      uint256 _amountIn = (_amount * _ratio) / 0xfffff;\n      for (uint256 j = 0; j < _length; j++) {\n        _amountIn = ITokenConverter(converter).queryConvert(_routes[_offset], _amountIn);\n        _offset += 1;\n      }\n      _encoding >>= 32;\n      amountOut += _amountIn;\n    }\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc IMultiPathConverter\n  function convert(\n    address _tokenIn,\n    uint256 _amount,\n    uint256 _encoding,\n    uint256[] memory _routes\n  ) external payable returns (uint256 amountOut) {\n    if (_tokenIn == address(0)) {\n      IWrappedEther(WETH).deposit{ value: _amount }();\n      IERC20(WETH).safeTransfer(converter, _amount);\n    } else {\n      // convert all approved.\n      if (_amount == type(uint256).max) {\n        _amount = IERC20(_tokenIn).allowance(msg.sender, address(this));\n      }\n      IERC20(_tokenIn).safeTransferFrom(msg.sender, converter, _amount);\n    }\n\n    uint256 _offset;\n    for (uint256 i = 0; i < 8; i++) {\n      uint256 _ratio = _encoding & 0xfffff;\n      uint256 _length = (_encoding >> 20) & 0xfff;\n      if (_ratio == 0) break;\n\n      uint256 _amountIn = (_amount * _ratio) / 0xfffff;\n      for (uint256 j = 0; j < _length; j++) {\n        address _recipient = j < _length - 1 ? converter : msg.sender;\n        _amountIn = ITokenConverter(converter).convert(_routes[_offset], _amountIn, _recipient);\n        _offset += 1;\n      }\n      _encoding >>= 32;\n      amountOut += _amountIn;\n    }\n  }\n}\n"},{"file_path":"@openzeppelin/contracts-v4/proxy/ERC1967/ERC1967Upgrade.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../beacon/IBeacon.sol\";\nimport \"../../interfaces/IERC1967.sol\";\nimport \"../../interfaces/draft-IERC1822.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/StorageSlot.sol\";\n\n/**\n * @dev This abstract contract provides getters and event emitting update functions for\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\n *\n * _Available since v4.1._\n */\nabstract contract ERC1967Upgrade is IERC1967 {\n    // This is the keccak-256 hash of \"eip1967.proxy.rollback\" subtracted by 1\n    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\n\n    /**\n     * @dev Storage slot with the address of the current implementation.\n     * This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1, and is\n     * validated in the constructor.\n     */\n    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n    /**\n     * @dev Returns the current implementation address.\n     */\n    function _getImplementation() internal view returns (address) {\n        return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n    }\n\n    /**\n     * @dev Stores a new address in the EIP1967 implementation slot.\n     */\n    function _setImplementation(address newImplementation) private {\n        require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n        StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n    }\n\n    /**\n     * @dev Perform implementation upgrade\n     *\n     * Emits an {Upgraded} event.\n     */\n    function _upgradeTo(address newImplementation) internal {\n        _setImplementation(newImplementation);\n        emit Upgraded(newImplementation);\n    }\n\n    /**\n     * @dev Perform implementation upgrade with additional setup call.\n     *\n     * Emits an {Upgraded} event.\n     */\n    function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {\n        _upgradeTo(newImplementation);\n        if (data.length > 0 || forceCall) {\n            Address.functionDelegateCall(newImplementation, data);\n        }\n    }\n\n    /**\n     * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\n     *\n     * Emits an {Upgraded} event.\n     */\n    function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {\n        // Upgrades from old implementations will perform a rollback test. This test requires the new\n        // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\n        // this special case will break upgrade paths from old UUPS implementation to new ones.\n        if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {\n            _setImplementation(newImplementation);\n        } else {\n            try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\n                require(slot == _IMPLEMENTATION_SLOT, \"ERC1967Upgrade: unsupported proxiableUUID\");\n            } catch {\n                revert(\"ERC1967Upgrade: new implementation is not UUPS\");\n            }\n            _upgradeToAndCall(newImplementation, data, forceCall);\n        }\n    }\n\n    /**\n     * @dev Storage slot with the admin of the contract.\n     * This is the keccak-256 hash of \"eip1967.proxy.admin\" subtracted by 1, and is\n     * validated in the constructor.\n     */\n    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\n\n    /**\n     * @dev Returns the current admin.\n     */\n    function _getAdmin() internal view returns (address) {\n        return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;\n    }\n\n    /**\n     * @dev Stores a new address in the EIP1967 admin slot.\n     */\n    function _setAdmin(address newAdmin) private {\n        require(newAdmin != address(0), \"ERC1967: new admin is the zero address\");\n        StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;\n    }\n\n    /**\n     * @dev Changes the admin of the proxy.\n     *\n     * Emits an {AdminChanged} event.\n     */\n    function _changeAdmin(address newAdmin) internal {\n        emit AdminChanged(_getAdmin(), newAdmin);\n        _setAdmin(newAdmin);\n    }\n\n    /**\n     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\n     * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.\n     */\n    bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\n\n    /**\n     * @dev Returns the current beacon.\n     */\n    function _getBeacon() internal view returns (address) {\n        return StorageSlot.getAddressSlot(_BEACON_SLOT).value;\n    }\n\n    /**\n     * @dev Stores a new beacon in the EIP1967 beacon slot.\n     */\n    function _setBeacon(address newBeacon) private {\n        require(Address.isContract(newBeacon), \"ERC1967: new beacon is not a contract\");\n        require(\n            Address.isContract(IBeacon(newBeacon).implementation()),\n            \"ERC1967: beacon implementation is not a contract\"\n        );\n        StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;\n    }\n\n    /**\n     * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does\n     * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).\n     *\n     * Emits a {BeaconUpgraded} event.\n     */\n    function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {\n        _setBeacon(newBeacon);\n        emit BeaconUpgraded(newBeacon);\n        if (data.length > 0 || forceCall) {\n            Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/utils/cryptography/EIP712Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol)\n\npragma solidity ^0.8.8;\n\nimport \"./ECDSAUpgradeable.sol\";\nimport \"../../interfaces/IERC5267Upgradeable.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,\n * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding\n * they need in their contracts using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain\n * separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the\n * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.\n *\n * _Available since v3.4._\n *\n * @custom:storage-size 52\n */\nabstract contract EIP712Upgradeable is Initializable, IERC5267Upgradeable {\n    bytes32 private constant _TYPE_HASH =\n        keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\");\n\n    /// @custom:oz-renamed-from _HASHED_NAME\n    bytes32 private _hashedName;\n    /// @custom:oz-renamed-from _HASHED_VERSION\n    bytes32 private _hashedVersion;\n\n    string private _name;\n    string private _version;\n\n    /**\n     * @dev Initializes the domain separator and parameter caches.\n     *\n     * The meaning of `name` and `version` is specified in\n     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n     *\n     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n     * - `version`: the current major version of the signing domain.\n     *\n     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n     * contract upgrade].\n     */\n    function __EIP712_init(string memory name, string memory version) internal onlyInitializing {\n        __EIP712_init_unchained(name, version);\n    }\n\n    function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {\n        _name = name;\n        _version = version;\n\n        // Reset prior values in storage if upgrading\n        _hashedName = 0;\n        _hashedVersion = 0;\n    }\n\n    /**\n     * @dev Returns the domain separator for the current chain.\n     */\n    function _domainSeparatorV4() internal view returns (bytes32) {\n        return _buildDomainSeparator();\n    }\n\n    function _buildDomainSeparator() private view returns (bytes32) {\n        return keccak256(abi.encode(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(this)));\n    }\n\n    /**\n     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n     * function returns the hash of the fully encoded EIP712 message for this domain.\n     *\n     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n     *\n     * ```solidity\n     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n     *     keccak256(\"Mail(address to,string contents)\"),\n     *     mailTo,\n     *     keccak256(bytes(mailContents))\n     * )));\n     * address signer = ECDSA.recover(digest, signature);\n     * ```\n     */\n    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n        return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(), structHash);\n    }\n\n    /**\n     * @dev See {EIP-5267}.\n     *\n     * _Available since v4.9._\n     */\n    function eip712Domain()\n        public\n        view\n        virtual\n        override\n        returns (\n            bytes1 fields,\n            string memory name,\n            string memory version,\n            uint256 chainId,\n            address verifyingContract,\n            bytes32 salt,\n            uint256[] memory extensions\n        )\n    {\n        // If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized\n        // and the EIP712 domain is not reliable, as it will be missing name and version.\n        require(_hashedName == 0 && _hashedVersion == 0, \"EIP712: Uninitialized\");\n\n        return (\n            hex\"0f\", // 01111\n            _EIP712Name(),\n            _EIP712Version(),\n            block.chainid,\n            address(this),\n            bytes32(0),\n            new uint256[](0)\n        );\n    }\n\n    /**\n     * @dev The name parameter for the EIP712 domain.\n     *\n     * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs\n     * are a concern.\n     */\n    function _EIP712Name() internal virtual view returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev The version parameter for the EIP712 domain.\n     *\n     * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs\n     * are a concern.\n     */\n    function _EIP712Version() internal virtual view returns (string memory) {\n        return _version;\n    }\n\n    /**\n     * @dev The hash of the name parameter for the EIP712 domain.\n     *\n     * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead.\n     */\n    function _EIP712NameHash() internal view returns (bytes32) {\n        string memory name = _EIP712Name();\n        if (bytes(name).length > 0) {\n            return keccak256(bytes(name));\n        } else {\n            // If the name is empty, the contract may have been upgraded without initializing the new storage.\n            // We return the name hash in storage if non-zero, otherwise we assume the name is empty by design.\n            bytes32 hashedName = _hashedName;\n            if (hashedName != 0) {\n                return hashedName;\n            } else {\n                return keccak256(\"\");\n            }\n        }\n    }\n\n    /**\n     * @dev The hash of the version parameter for the EIP712 domain.\n     *\n     * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead.\n     */\n    function _EIP712VersionHash() internal view returns (bytes32) {\n        string memory version = _EIP712Version();\n        if (bytes(version).length > 0) {\n            return keccak256(bytes(version));\n        } else {\n            // If the version is empty, the contract may have been upgraded without initializing the new storage.\n            // We return the version hash in storage if non-zero, otherwise we assume the version is empty by design.\n            bytes32 hashedVersion = _hashedVersion;\n            if (hashedVersion != 0) {\n                return hashedVersion;\n            } else {\n                return keccak256(\"\");\n            }\n        }\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[48] private __gap;\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC721/IERC721.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n    /**\n     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n     */\n    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n     */\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    /**\n     * @dev Returns the number of tokens in ``owner``'s account.\n     */\n    function balanceOf(address owner) external view returns (uint256 balance);\n\n    /**\n     * @dev Returns the owner of the `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function ownerOf(uint256 tokenId) external view returns (address owner);\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon\n     *   a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n     * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or\n     *   {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon\n     *   a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId) external;\n\n    /**\n     * @dev Transfers `tokenId` token from `from` to `to`.\n     *\n     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721\n     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must\n     * understand this adds an external call which potentially creates a reentrancy vulnerability.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 tokenId) external;\n\n    /**\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n     * The approval is cleared when the token is transferred.\n     *\n     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n     *\n     * Requirements:\n     *\n     * - The caller must own the token or be an approved operator.\n     * - `tokenId` must exist.\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address to, uint256 tokenId) external;\n\n    /**\n     * @dev Approve or remove `operator` as an operator for the caller.\n     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n     *\n     * Requirements:\n     *\n     * - The `operator` cannot be the address zero.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function setApprovalForAll(address operator, bool approved) external;\n\n    /**\n     * @dev Returns the account approved for `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function getApproved(uint256 tokenId) external view returns (address operator);\n\n    /**\n     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n     *\n     * See {setApprovalForAll}\n     */\n    function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n"},{"file_path":"contracts/helpers/External.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport \"@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol\";\nimport \"@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol\";\n"},{"file_path":"contracts/v2/interfaces/IFxReservePool.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IFxReservePool {\n  /// @notice Request bonus token from Reserve Pool.\n  /// @param token The address of token to request.\n  /// @param receiver The address recipient for the bonus token.\n  /// @param originalAmount The original amount of token used.\n  /// @param bonus The amount of bonus token received.\n  function requestBonus(\n    address token,\n    address receiver,\n    uint256 originalAmount\n  ) external returns (uint256 bonus);\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/utils/NoncesUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol)\npragma solidity ^0.8.20;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides tracking nonces for addresses. Nonces will only increment.\n */\nabstract contract NoncesUpgradeable is Initializable {\n    /**\n     * @dev The nonce used for an `account` is not the expected current nonce.\n     */\n    error InvalidAccountNonce(address account, uint256 currentNonce);\n\n    /// @custom:storage-location erc7201:openzeppelin.storage.Nonces\n    struct NoncesStorage {\n        mapping(address account => uint256) _nonces;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Nonces\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant NoncesStorageLocation = 0x5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb00;\n\n    function _getNoncesStorage() private pure returns (NoncesStorage storage $) {\n        assembly {\n            $.slot := NoncesStorageLocation\n        }\n    }\n\n    function __Nonces_init() internal onlyInitializing {\n    }\n\n    function __Nonces_init_unchained() internal onlyInitializing {\n    }\n    /**\n     * @dev Returns the next unused nonce for an address.\n     */\n    function nonces(address owner) public view virtual returns (uint256) {\n        NoncesStorage storage $ = _getNoncesStorage();\n        return $._nonces[owner];\n    }\n\n    /**\n     * @dev Consumes a nonce.\n     *\n     * Returns the current value and increments nonce.\n     */\n    function _useNonce(address owner) internal virtual returns (uint256) {\n        NoncesStorage storage $ = _getNoncesStorage();\n        // For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be\n        // decremented or reset. This guarantees that the nonce never overflows.\n        unchecked {\n            // It is important to do x++ and not ++x here.\n            return $._nonces[owner]++;\n        }\n    }\n\n    /**\n     * @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`.\n     */\n    function _useCheckedNonce(address owner, uint256 nonce) internal virtual {\n        uint256 current = _useNonce(owner);\n        if (nonce != current) {\n            revert InvalidAccountNonce(owner, current);\n        }\n    }\n}\n"},{"file_path":"contracts/price-oracle/interfaces/ITwapOracle.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface ITwapOracle {\n  /// @notice Return TWAP with 18 decimal places in the epoch ending at the specified timestamp.\n  ///         Zero is returned if TWAP in the epoch is not available.\n  /// @param timestamp End Timestamp in seconds of the epoch\n  /// @return TWAP (18 decimal places) in the epoch, or zero if not available\n  function getTwap(uint256 timestamp) external view returns (uint256);\n\n  /// @notice Return the latest price with 18 decimal places.\n  function getLatest() external view returns (uint256);\n}\n"},{"file_path":"contracts/core/pool/TickLogic.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { WordCodec } from \"../../common/codec/WordCodec.sol\";\nimport { TickBitmap } from \"../../libraries/TickBitmap.sol\";\nimport { TickMath } from \"../../libraries/TickMath.sol\";\nimport { PoolStorage } from \"./PoolStorage.sol\";\n\nabstract contract TickLogic is PoolStorage {\n  using TickBitmap for mapping(int8 => uint256);\n  using WordCodec for bytes32;\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev Below are offsets of each variables in `TickTreeNode.metadata`.\n  uint256 private constant PARENT_OFFSET = 0;\n  uint256 private constant TICK_OFFSET = 48;\n  uint256 private constant COLL_RATIO_OFFSET = 64;\n  uint256 private constant DEBT_RATIO_OFFSET = 128;\n\n  /// @dev Below are offsets of each variables in `TickTreeNode.value`.\n  uint256 internal constant COLL_SHARE_OFFSET = 0;\n  uint256 internal constant DEBT_SHARE_OFFSET = 128;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  function __TickLogic_init() internal onlyInitializing {\n    _updateNextTreeNodeId(1);\n    _updateTopTick(type(int16).min);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to get the root of the given tree node.\n  /// @param node The id of the given tree node.\n  /// @return root The root node id.\n  /// @return collRatio The actual collateral ratio of the given node, multiplied by 2^60.\n  /// @return debtRatio The actual debt ratio of the given node, multiplied by 2^60.\n  function _getRootNode(uint256 node) internal view returns (uint256 root, uint256 collRatio, uint256 debtRatio) {\n    collRatio = E60;\n    debtRatio = E60;\n    while (true) {\n      bytes32 metadata = tickTreeData[node].metadata;\n      uint256 parent = metadata.decodeUint(PARENT_OFFSET, 48);\n      collRatio = (collRatio * metadata.decodeUint(COLL_RATIO_OFFSET, 64)) >> 60;\n      debtRatio = (debtRatio * metadata.decodeUint(DEBT_RATIO_OFFSET, 64)) >> 60;\n      if (parent == 0) break;\n      node = parent;\n    }\n    root = node;\n  }\n\n  /// @dev Internal function to get the root of the given tree node and compress path.\n  /// @param node The id of the given tree node.\n  /// @return root The root node id.\n  /// @return collRatio The actual collateral ratio of the given node, multiplied by 2^60.\n  /// @return debtRatio The actual debt ratio of the given node, multiplied by 2^60.\n  function _getRootNodeAndCompress(uint256 node) internal returns (uint256 root, uint256 collRatio, uint256 debtRatio) {\n    // @note We can change it to non-recursive version to avoid stack overflow. Normally, the depth should be `log(n)`,\n    // where `n` is the total number of tree nodes. So we don't need to worry much about this.\n    bytes32 metadata = tickTreeData[node].metadata;\n    uint256 parent = metadata.decodeUint(PARENT_OFFSET, 48);\n    collRatio = metadata.decodeUint(COLL_RATIO_OFFSET, 64);\n    debtRatio = metadata.decodeUint(DEBT_RATIO_OFFSET, 64);\n    if (parent == 0) {\n      root = node;\n    } else {\n      uint256 collRatioCompressed;\n      uint256 debtRatioCompressed;\n      (root, collRatioCompressed, debtRatioCompressed) = _getRootNodeAndCompress(parent);\n      collRatio = (collRatio * collRatioCompressed) >> 60;\n      debtRatio = (debtRatio * debtRatioCompressed) >> 60;\n      metadata = metadata.insertUint(root, PARENT_OFFSET, 48);\n      metadata = metadata.insertUint(collRatio, COLL_RATIO_OFFSET, 64);\n      metadata = metadata.insertUint(debtRatio, DEBT_RATIO_OFFSET, 64);\n      tickTreeData[node].metadata = metadata;\n    }\n  }\n\n  /// @dev Internal function to create a new tree node.\n  /// @param tick The tick where this tree node belongs to.\n  /// @return node The created tree node id.\n  function _newTickTreeNode(int16 tick) internal returns (uint48 node) {\n    unchecked {\n      node = _getNextTreeNodeId();\n      _updateNextTreeNodeId(node + 1);\n    }\n    tickData[tick] = node;\n\n    bytes32 metadata = bytes32(0);\n    metadata = metadata.insertInt(tick, TICK_OFFSET, 16); // set tick\n    metadata = metadata.insertUint(E60, COLL_RATIO_OFFSET, 64); // set coll ratio\n    metadata = metadata.insertUint(E60, DEBT_RATIO_OFFSET, 64); // set debt ratio\n    tickTreeData[node].metadata = metadata;\n  }\n\n  /// @dev Internal function to find first tick such that `TickMath.getRatioAtTick(tick) >= debts/colls`.\n  /// @param colls The collateral shares.\n  /// @param debts The debt shares.\n  /// @return tick The value of found first tick.\n  function _getTick(uint256 colls, uint256 debts) internal pure returns (int256 tick) {\n    uint256 ratio = (debts * TickMath.ZERO_TICK_SCALED_RATIO) / colls;\n    uint256 ratioAtTick;\n    (tick, ratioAtTick) = TickMath.getTickAtRatio(ratio);\n    if (ratio != ratioAtTick) {\n      tick++;\n      ratio = (ratioAtTick * 10015) / 10000;\n    }\n  }\n\n  /// @dev Internal function to retrieve or create a tree node.\n  /// @param tick The tick where this tree node belongs to.\n  /// @return node The tree node id.\n  function _getOrCreateTickNode(int256 tick) internal returns (uint48 node) {\n    node = tickData[tick];\n    if (node == 0) {\n      node = _newTickTreeNode(int16(tick));\n    }\n  }\n\n  /// @dev Internal function to add position collaterals and debts to some tick.\n  /// @param colls The collateral shares.\n  /// @param debts The debt shares.\n  /// @param checkDebts Whether we should check the value of `debts`.\n  /// @return tick The tick where this position belongs to.\n  /// @return node The corresponding tree node id for this tick.\n  function _addPositionToTick(\n    uint256 colls,\n    uint256 debts,\n    bool checkDebts\n  ) internal returns (int256 tick, uint48 node) {\n    if (debts > 0) {\n      if (checkDebts && int256(debts) < MIN_DEBT) {\n        revert ErrorDebtTooSmall();\n      }\n\n      tick = _getTick(colls, debts);\n      node = _getOrCreateTickNode(tick);\n      bytes32 value = tickTreeData[node].value;\n      uint256 newColls = value.decodeUint(COLL_SHARE_OFFSET, 128) + colls;\n      uint256 newDebts = value.decodeUint(DEBT_SHARE_OFFSET, 128) + debts;\n      value = value.insertUint(newColls, COLL_SHARE_OFFSET, 128);\n      value = value.insertUint(newDebts, DEBT_SHARE_OFFSET, 128);\n      tickTreeData[node].value = value;\n\n      if (newDebts == debts) {\n        tickBitmap.flipTick(int16(tick));\n      }\n\n      // update top tick\n      if (tick > _getTopTick()) {\n        _updateTopTick(int16(tick));\n      }\n    }\n  }\n\n  /// @dev Internal function to remove position from tick.\n  /// @param position The position struct to remove.\n  function _removePositionFromTick(PositionInfo memory position) internal {\n    if (position.nodeId == 0) return;\n\n    bytes32 value = tickTreeData[position.nodeId].value;\n    uint256 newColls = value.decodeUint(COLL_SHARE_OFFSET, 128) - position.colls;\n    uint256 newDebts = value.decodeUint(DEBT_SHARE_OFFSET, 128) - position.debts;\n    value = value.insertUint(newColls, COLL_SHARE_OFFSET, 128);\n    value = value.insertUint(newDebts, DEBT_SHARE_OFFSET, 128);\n    tickTreeData[position.nodeId].value = value;\n\n    if (newDebts == 0) {\n      int16 tick = int16(tickTreeData[position.nodeId].metadata.decodeInt(TICK_OFFSET, 16));\n      tickBitmap.flipTick(tick);\n\n      // top tick gone, update it to new one\n      int16 topTick = _getTopTick();\n      if (topTick == tick) {\n        _resetTopTick(topTick);\n      }\n    }\n  }\n\n  /// @dev Internal function to liquidate a tick.\n  ///      The caller make sure `max(liquidatedColl, liquidatedDebt) > 0`.\n  ///\n  /// @param tick The id of tick to liquidate.\n  /// @param liquidatedColl The amount of collateral shares liquidated.\n  /// @param liquidatedDebt The amount of debt shares liquidated.\n  function _liquidateTick(int16 tick, uint256 liquidatedColl, uint256 liquidatedDebt, uint256 price) internal {\n    uint48 node = tickData[tick];\n    // create new tree node for this tick\n    _newTickTreeNode(tick);\n    // clear bitmap first, and it will be updated later if needed.\n    tickBitmap.flipTick(tick);\n\n    bytes32 value = tickTreeData[node].value;\n    bytes32 metadata = tickTreeData[node].metadata;\n    uint256 tickColl = value.decodeUint(COLL_SHARE_OFFSET, 128);\n    uint256 tickDebt = value.decodeUint(DEBT_SHARE_OFFSET, 128);\n    uint256 tickCollAfter = tickColl - liquidatedColl;\n    uint256 tickDebtAfter = tickDebt - liquidatedDebt;\n    uint256 collRatio = (tickCollAfter * E60) / tickColl;\n    uint256 debtRatio = (tickDebtAfter * E60) / tickDebt;\n\n    // update metadata\n    metadata = metadata.insertUint(collRatio, COLL_RATIO_OFFSET, 64);\n    metadata = metadata.insertUint(debtRatio, DEBT_RATIO_OFFSET, 64);\n\n    int256 newTick = type(int256).min;\n    if (tickDebtAfter > 0) {\n      // partial liquidated, move funds to another tick\n      uint48 parentNode;\n      (newTick, parentNode) = _addPositionToTick(tickCollAfter, tickDebtAfter, false);\n      metadata = metadata.insertUint(parentNode, PARENT_OFFSET, 48);\n    }\n    emit TickMovement(tick, int16(newTick), tickCollAfter, tickDebtAfter, price);\n\n    // top tick liquidated, update it to new one\n    int16 topTick = _getTopTick();\n    if (topTick == tick && newTick != int256(tick)) {\n      _resetTopTick(topTick);\n    }\n    tickTreeData[node].metadata = metadata;\n  }\n\n  /// @dev Internal function to reset top tick.\n  /// @param oldTopTick The previous value of top tick.\n  function _resetTopTick(int16 oldTopTick) internal {\n    while (oldTopTick > type(int16).min) {\n      bool hasDebt;\n      (oldTopTick, hasDebt) = tickBitmap.nextDebtPositionWithinOneWord(oldTopTick - 1);\n      if (hasDebt) break;\n    }\n    _updateTopTick(oldTopTick);\n  }\n\n  /**\n   * @dev This empty reserved space is put in place to allow future versions to add new\n   * variables without shifting down storage in the inheritance chain.\n   */\n  uint256[50] private __gap;\n}\n"},{"file_path":"@openzeppelin/contracts/utils/math/SafeCast.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeCast {\n    /**\n     * @dev Value doesn't fit in an uint of `bits` size.\n     */\n    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);\n\n    /**\n     * @dev An int value doesn't fit in an uint of `bits` size.\n     */\n    error SafeCastOverflowedIntToUint(int256 value);\n\n    /**\n     * @dev Value doesn't fit in an int of `bits` size.\n     */\n    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);\n\n    /**\n     * @dev An uint value doesn't fit in an int of `bits` size.\n     */\n    error SafeCastOverflowedUintToInt(uint256 value);\n\n    /**\n     * @dev Returns the downcasted uint248 from uint256, reverting on\n     * overflow (when the input is greater than largest uint248).\n     *\n     * Counterpart to Solidity's `uint248` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 248 bits\n     */\n    function toUint248(uint256 value) internal pure returns (uint248) {\n        if (value > type(uint248).max) {\n            revert SafeCastOverflowedUintDowncast(248, value);\n        }\n        return uint248(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint240 from uint256, reverting on\n     * overflow (when the input is greater than largest uint240).\n     *\n     * Counterpart to Solidity's `uint240` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 240 bits\n     */\n    function toUint240(uint256 value) internal pure returns (uint240) {\n        if (value > type(uint240).max) {\n            revert SafeCastOverflowedUintDowncast(240, value);\n        }\n        return uint240(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint232 from uint256, reverting on\n     * overflow (when the input is greater than largest uint232).\n     *\n     * Counterpart to Solidity's `uint232` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 232 bits\n     */\n    function toUint232(uint256 value) internal pure returns (uint232) {\n        if (value > type(uint232).max) {\n            revert SafeCastOverflowedUintDowncast(232, value);\n        }\n        return uint232(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint224 from uint256, reverting on\n     * overflow (when the input is greater than largest uint224).\n     *\n     * Counterpart to Solidity's `uint224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     */\n    function toUint224(uint256 value) internal pure returns (uint224) {\n        if (value > type(uint224).max) {\n            revert SafeCastOverflowedUintDowncast(224, value);\n        }\n        return uint224(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint216 from uint256, reverting on\n     * overflow (when the input is greater than largest uint216).\n     *\n     * Counterpart to Solidity's `uint216` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 216 bits\n     */\n    function toUint216(uint256 value) internal pure returns (uint216) {\n        if (value > type(uint216).max) {\n            revert SafeCastOverflowedUintDowncast(216, value);\n        }\n        return uint216(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint208 from uint256, reverting on\n     * overflow (when the input is greater than largest uint208).\n     *\n     * Counterpart to Solidity's `uint208` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 208 bits\n     */\n    function toUint208(uint256 value) internal pure returns (uint208) {\n        if (value > type(uint208).max) {\n            revert SafeCastOverflowedUintDowncast(208, value);\n        }\n        return uint208(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint200 from uint256, reverting on\n     * overflow (when the input is greater than largest uint200).\n     *\n     * Counterpart to Solidity's `uint200` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 200 bits\n     */\n    function toUint200(uint256 value) internal pure returns (uint200) {\n        if (value > type(uint200).max) {\n            revert SafeCastOverflowedUintDowncast(200, value);\n        }\n        return uint200(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint192 from uint256, reverting on\n     * overflow (when the input is greater than largest uint192).\n     *\n     * Counterpart to Solidity's `uint192` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 192 bits\n     */\n    function toUint192(uint256 value) internal pure returns (uint192) {\n        if (value > type(uint192).max) {\n            revert SafeCastOverflowedUintDowncast(192, value);\n        }\n        return uint192(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint184 from uint256, reverting on\n     * overflow (when the input is greater than largest uint184).\n     *\n     * Counterpart to Solidity's `uint184` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 184 bits\n     */\n    function toUint184(uint256 value) internal pure returns (uint184) {\n        if (value > type(uint184).max) {\n            revert SafeCastOverflowedUintDowncast(184, value);\n        }\n        return uint184(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint176 from uint256, reverting on\n     * overflow (when the input is greater than largest uint176).\n     *\n     * Counterpart to Solidity's `uint176` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 176 bits\n     */\n    function toUint176(uint256 value) internal pure returns (uint176) {\n        if (value > type(uint176).max) {\n            revert SafeCastOverflowedUintDowncast(176, value);\n        }\n        return uint176(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint168 from uint256, reverting on\n     * overflow (when the input is greater than largest uint168).\n     *\n     * Counterpart to Solidity's `uint168` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 168 bits\n     */\n    function toUint168(uint256 value) internal pure returns (uint168) {\n        if (value > type(uint168).max) {\n            revert SafeCastOverflowedUintDowncast(168, value);\n        }\n        return uint168(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint160 from uint256, reverting on\n     * overflow (when the input is greater than largest uint160).\n     *\n     * Counterpart to Solidity's `uint160` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 160 bits\n     */\n    function toUint160(uint256 value) internal pure returns (uint160) {\n        if (value > type(uint160).max) {\n            revert SafeCastOverflowedUintDowncast(160, value);\n        }\n        return uint160(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint152 from uint256, reverting on\n     * overflow (when the input is greater than largest uint152).\n     *\n     * Counterpart to Solidity's `uint152` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 152 bits\n     */\n    function toUint152(uint256 value) internal pure returns (uint152) {\n        if (value > type(uint152).max) {\n            revert SafeCastOverflowedUintDowncast(152, value);\n        }\n        return uint152(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint144 from uint256, reverting on\n     * overflow (when the input is greater than largest uint144).\n     *\n     * Counterpart to Solidity's `uint144` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 144 bits\n     */\n    function toUint144(uint256 value) internal pure returns (uint144) {\n        if (value > type(uint144).max) {\n            revert SafeCastOverflowedUintDowncast(144, value);\n        }\n        return uint144(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint136 from uint256, reverting on\n     * overflow (when the input is greater than largest uint136).\n     *\n     * Counterpart to Solidity's `uint136` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 136 bits\n     */\n    function toUint136(uint256 value) internal pure returns (uint136) {\n        if (value > type(uint136).max) {\n            revert SafeCastOverflowedUintDowncast(136, value);\n        }\n        return uint136(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint128 from uint256, reverting on\n     * overflow (when the input is greater than largest uint128).\n     *\n     * Counterpart to Solidity's `uint128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     */\n    function toUint128(uint256 value) internal pure returns (uint128) {\n        if (value > type(uint128).max) {\n            revert SafeCastOverflowedUintDowncast(128, value);\n        }\n        return uint128(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint120 from uint256, reverting on\n     * overflow (when the input is greater than largest uint120).\n     *\n     * Counterpart to Solidity's `uint120` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 120 bits\n     */\n    function toUint120(uint256 value) internal pure returns (uint120) {\n        if (value > type(uint120).max) {\n            revert SafeCastOverflowedUintDowncast(120, value);\n        }\n        return uint120(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint112 from uint256, reverting on\n     * overflow (when the input is greater than largest uint112).\n     *\n     * Counterpart to Solidity's `uint112` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 112 bits\n     */\n    function toUint112(uint256 value) internal pure returns (uint112) {\n        if (value > type(uint112).max) {\n            revert SafeCastOverflowedUintDowncast(112, value);\n        }\n        return uint112(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint104 from uint256, reverting on\n     * overflow (when the input is greater than largest uint104).\n     *\n     * Counterpart to Solidity's `uint104` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 104 bits\n     */\n    function toUint104(uint256 value) internal pure returns (uint104) {\n        if (value > type(uint104).max) {\n            revert SafeCastOverflowedUintDowncast(104, value);\n        }\n        return uint104(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint96 from uint256, reverting on\n     * overflow (when the input is greater than largest uint96).\n     *\n     * Counterpart to Solidity's `uint96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     */\n    function toUint96(uint256 value) internal pure returns (uint96) {\n        if (value > type(uint96).max) {\n            revert SafeCastOverflowedUintDowncast(96, value);\n        }\n        return uint96(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint88 from uint256, reverting on\n     * overflow (when the input is greater than largest uint88).\n     *\n     * Counterpart to Solidity's `uint88` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 88 bits\n     */\n    function toUint88(uint256 value) internal pure returns (uint88) {\n        if (value > type(uint88).max) {\n            revert SafeCastOverflowedUintDowncast(88, value);\n        }\n        return uint88(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint80 from uint256, reverting on\n     * overflow (when the input is greater than largest uint80).\n     *\n     * Counterpart to Solidity's `uint80` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 80 bits\n     */\n    function toUint80(uint256 value) internal pure returns (uint80) {\n        if (value > type(uint80).max) {\n            revert SafeCastOverflowedUintDowncast(80, value);\n        }\n        return uint80(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint72 from uint256, reverting on\n     * overflow (when the input is greater than largest uint72).\n     *\n     * Counterpart to Solidity's `uint72` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 72 bits\n     */\n    function toUint72(uint256 value) internal pure returns (uint72) {\n        if (value > type(uint72).max) {\n            revert SafeCastOverflowedUintDowncast(72, value);\n        }\n        return uint72(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint64 from uint256, reverting on\n     * overflow (when the input is greater than largest uint64).\n     *\n     * Counterpart to Solidity's `uint64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     */\n    function toUint64(uint256 value) internal pure returns (uint64) {\n        if (value > type(uint64).max) {\n            revert SafeCastOverflowedUintDowncast(64, value);\n        }\n        return uint64(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint56 from uint256, reverting on\n     * overflow (when the input is greater than largest uint56).\n     *\n     * Counterpart to Solidity's `uint56` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 56 bits\n     */\n    function toUint56(uint256 value) internal pure returns (uint56) {\n        if (value > type(uint56).max) {\n            revert SafeCastOverflowedUintDowncast(56, value);\n        }\n        return uint56(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint48 from uint256, reverting on\n     * overflow (when the input is greater than largest uint48).\n     *\n     * Counterpart to Solidity's `uint48` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 48 bits\n     */\n    function toUint48(uint256 value) internal pure returns (uint48) {\n        if (value > type(uint48).max) {\n            revert SafeCastOverflowedUintDowncast(48, value);\n        }\n        return uint48(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint40 from uint256, reverting on\n     * overflow (when the input is greater than largest uint40).\n     *\n     * Counterpart to Solidity's `uint40` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 40 bits\n     */\n    function toUint40(uint256 value) internal pure returns (uint40) {\n        if (value > type(uint40).max) {\n            revert SafeCastOverflowedUintDowncast(40, value);\n        }\n        return uint40(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint32 from uint256, reverting on\n     * overflow (when the input is greater than largest uint32).\n     *\n     * Counterpart to Solidity's `uint32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     */\n    function toUint32(uint256 value) internal pure returns (uint32) {\n        if (value > type(uint32).max) {\n            revert SafeCastOverflowedUintDowncast(32, value);\n        }\n        return uint32(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint24 from uint256, reverting on\n     * overflow (when the input is greater than largest uint24).\n     *\n     * Counterpart to Solidity's `uint24` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 24 bits\n     */\n    function toUint24(uint256 value) internal pure returns (uint24) {\n        if (value > type(uint24).max) {\n            revert SafeCastOverflowedUintDowncast(24, value);\n        }\n        return uint24(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint16 from uint256, reverting on\n     * overflow (when the input is greater than largest uint16).\n     *\n     * Counterpart to Solidity's `uint16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     */\n    function toUint16(uint256 value) internal pure returns (uint16) {\n        if (value > type(uint16).max) {\n            revert SafeCastOverflowedUintDowncast(16, value);\n        }\n        return uint16(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint8 from uint256, reverting on\n     * overflow (when the input is greater than largest uint8).\n     *\n     * Counterpart to Solidity's `uint8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits\n     */\n    function toUint8(uint256 value) internal pure returns (uint8) {\n        if (value > type(uint8).max) {\n            revert SafeCastOverflowedUintDowncast(8, value);\n        }\n        return uint8(value);\n    }\n\n    /**\n     * @dev Converts a signed int256 into an unsigned uint256.\n     *\n     * Requirements:\n     *\n     * - input must be greater than or equal to 0.\n     */\n    function toUint256(int256 value) internal pure returns (uint256) {\n        if (value < 0) {\n            revert SafeCastOverflowedIntToUint(value);\n        }\n        return uint256(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int248 from int256, reverting on\n     * overflow (when the input is less than smallest int248 or\n     * greater than largest int248).\n     *\n     * Counterpart to Solidity's `int248` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 248 bits\n     */\n    function toInt248(int256 value) internal pure returns (int248 downcasted) {\n        downcasted = int248(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(248, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int240 from int256, reverting on\n     * overflow (when the input is less than smallest int240 or\n     * greater than largest int240).\n     *\n     * Counterpart to Solidity's `int240` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 240 bits\n     */\n    function toInt240(int256 value) internal pure returns (int240 downcasted) {\n        downcasted = int240(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(240, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int232 from int256, reverting on\n     * overflow (when the input is less than smallest int232 or\n     * greater than largest int232).\n     *\n     * Counterpart to Solidity's `int232` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 232 bits\n     */\n    function toInt232(int256 value) internal pure returns (int232 downcasted) {\n        downcasted = int232(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(232, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int224 from int256, reverting on\n     * overflow (when the input is less than smallest int224 or\n     * greater than largest int224).\n     *\n     * Counterpart to Solidity's `int224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     */\n    function toInt224(int256 value) internal pure returns (int224 downcasted) {\n        downcasted = int224(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(224, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int216 from int256, reverting on\n     * overflow (when the input is less than smallest int216 or\n     * greater than largest int216).\n     *\n     * Counterpart to Solidity's `int216` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 216 bits\n     */\n    function toInt216(int256 value) internal pure returns (int216 downcasted) {\n        downcasted = int216(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(216, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int208 from int256, reverting on\n     * overflow (when the input is less than smallest int208 or\n     * greater than largest int208).\n     *\n     * Counterpart to Solidity's `int208` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 208 bits\n     */\n    function toInt208(int256 value) internal pure returns (int208 downcasted) {\n        downcasted = int208(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(208, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int200 from int256, reverting on\n     * overflow (when the input is less than smallest int200 or\n     * greater than largest int200).\n     *\n     * Counterpart to Solidity's `int200` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 200 bits\n     */\n    function toInt200(int256 value) internal pure returns (int200 downcasted) {\n        downcasted = int200(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(200, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int192 from int256, reverting on\n     * overflow (when the input is less than smallest int192 or\n     * greater than largest int192).\n     *\n     * Counterpart to Solidity's `int192` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 192 bits\n     */\n    function toInt192(int256 value) internal pure returns (int192 downcasted) {\n        downcasted = int192(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(192, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int184 from int256, reverting on\n     * overflow (when the input is less than smallest int184 or\n     * greater than largest int184).\n     *\n     * Counterpart to Solidity's `int184` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 184 bits\n     */\n    function toInt184(int256 value) internal pure returns (int184 downcasted) {\n        downcasted = int184(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(184, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int176 from int256, reverting on\n     * overflow (when the input is less than smallest int176 or\n     * greater than largest int176).\n     *\n     * Counterpart to Solidity's `int176` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 176 bits\n     */\n    function toInt176(int256 value) internal pure returns (int176 downcasted) {\n        downcasted = int176(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(176, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int168 from int256, reverting on\n     * overflow (when the input is less than smallest int168 or\n     * greater than largest int168).\n     *\n     * Counterpart to Solidity's `int168` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 168 bits\n     */\n    function toInt168(int256 value) internal pure returns (int168 downcasted) {\n        downcasted = int168(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(168, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int160 from int256, reverting on\n     * overflow (when the input is less than smallest int160 or\n     * greater than largest int160).\n     *\n     * Counterpart to Solidity's `int160` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 160 bits\n     */\n    function toInt160(int256 value) internal pure returns (int160 downcasted) {\n        downcasted = int160(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(160, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int152 from int256, reverting on\n     * overflow (when the input is less than smallest int152 or\n     * greater than largest int152).\n     *\n     * Counterpart to Solidity's `int152` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 152 bits\n     */\n    function toInt152(int256 value) internal pure returns (int152 downcasted) {\n        downcasted = int152(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(152, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int144 from int256, reverting on\n     * overflow (when the input is less than smallest int144 or\n     * greater than largest int144).\n     *\n     * Counterpart to Solidity's `int144` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 144 bits\n     */\n    function toInt144(int256 value) internal pure returns (int144 downcasted) {\n        downcasted = int144(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(144, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int136 from int256, reverting on\n     * overflow (when the input is less than smallest int136 or\n     * greater than largest int136).\n     *\n     * Counterpart to Solidity's `int136` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 136 bits\n     */\n    function toInt136(int256 value) internal pure returns (int136 downcasted) {\n        downcasted = int136(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(136, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int128 from int256, reverting on\n     * overflow (when the input is less than smallest int128 or\n     * greater than largest int128).\n     *\n     * Counterpart to Solidity's `int128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     */\n    function toInt128(int256 value) internal pure returns (int128 downcasted) {\n        downcasted = int128(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(128, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int120 from int256, reverting on\n     * overflow (when the input is less than smallest int120 or\n     * greater than largest int120).\n     *\n     * Counterpart to Solidity's `int120` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 120 bits\n     */\n    function toInt120(int256 value) internal pure returns (int120 downcasted) {\n        downcasted = int120(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(120, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int112 from int256, reverting on\n     * overflow (when the input is less than smallest int112 or\n     * greater than largest int112).\n     *\n     * Counterpart to Solidity's `int112` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 112 bits\n     */\n    function toInt112(int256 value) internal pure returns (int112 downcasted) {\n        downcasted = int112(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(112, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int104 from int256, reverting on\n     * overflow (when the input is less than smallest int104 or\n     * greater than largest int104).\n     *\n     * Counterpart to Solidity's `int104` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 104 bits\n     */\n    function toInt104(int256 value) internal pure returns (int104 downcasted) {\n        downcasted = int104(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(104, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int96 from int256, reverting on\n     * overflow (when the input is less than smallest int96 or\n     * greater than largest int96).\n     *\n     * Counterpart to Solidity's `int96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     */\n    function toInt96(int256 value) internal pure returns (int96 downcasted) {\n        downcasted = int96(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(96, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int88 from int256, reverting on\n     * overflow (when the input is less than smallest int88 or\n     * greater than largest int88).\n     *\n     * Counterpart to Solidity's `int88` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 88 bits\n     */\n    function toInt88(int256 value) internal pure returns (int88 downcasted) {\n        downcasted = int88(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(88, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int80 from int256, reverting on\n     * overflow (when the input is less than smallest int80 or\n     * greater than largest int80).\n     *\n     * Counterpart to Solidity's `int80` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 80 bits\n     */\n    function toInt80(int256 value) internal pure returns (int80 downcasted) {\n        downcasted = int80(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(80, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int72 from int256, reverting on\n     * overflow (when the input is less than smallest int72 or\n     * greater than largest int72).\n     *\n     * Counterpart to Solidity's `int72` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 72 bits\n     */\n    function toInt72(int256 value) internal pure returns (int72 downcasted) {\n        downcasted = int72(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(72, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int64 from int256, reverting on\n     * overflow (when the input is less than smallest int64 or\n     * greater than largest int64).\n     *\n     * Counterpart to Solidity's `int64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     */\n    function toInt64(int256 value) internal pure returns (int64 downcasted) {\n        downcasted = int64(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(64, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int56 from int256, reverting on\n     * overflow (when the input is less than smallest int56 or\n     * greater than largest int56).\n     *\n     * Counterpart to Solidity's `int56` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 56 bits\n     */\n    function toInt56(int256 value) internal pure returns (int56 downcasted) {\n        downcasted = int56(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(56, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int48 from int256, reverting on\n     * overflow (when the input is less than smallest int48 or\n     * greater than largest int48).\n     *\n     * Counterpart to Solidity's `int48` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 48 bits\n     */\n    function toInt48(int256 value) internal pure returns (int48 downcasted) {\n        downcasted = int48(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(48, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int40 from int256, reverting on\n     * overflow (when the input is less than smallest int40 or\n     * greater than largest int40).\n     *\n     * Counterpart to Solidity's `int40` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 40 bits\n     */\n    function toInt40(int256 value) internal pure returns (int40 downcasted) {\n        downcasted = int40(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(40, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int32 from int256, reverting on\n     * overflow (when the input is less than smallest int32 or\n     * greater than largest int32).\n     *\n     * Counterpart to Solidity's `int32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     */\n    function toInt32(int256 value) internal pure returns (int32 downcasted) {\n        downcasted = int32(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(32, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int24 from int256, reverting on\n     * overflow (when the input is less than smallest int24 or\n     * greater than largest int24).\n     *\n     * Counterpart to Solidity's `int24` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 24 bits\n     */\n    function toInt24(int256 value) internal pure returns (int24 downcasted) {\n        downcasted = int24(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(24, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int16 from int256, reverting on\n     * overflow (when the input is less than smallest int16 or\n     * greater than largest int16).\n     *\n     * Counterpart to Solidity's `int16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     */\n    function toInt16(int256 value) internal pure returns (int16 downcasted) {\n        downcasted = int16(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(16, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int8 from int256, reverting on\n     * overflow (when the input is less than smallest int8 or\n     * greater than largest int8).\n     *\n     * Counterpart to Solidity's `int8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits\n     */\n    function toInt8(int256 value) internal pure returns (int8 downcasted) {\n        downcasted = int8(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(8, value);\n        }\n    }\n\n    /**\n     * @dev Converts an unsigned uint256 into a signed int256.\n     *\n     * Requirements:\n     *\n     * - input must be less than or equal to maxInt256.\n     */\n    function toInt256(uint256 value) internal pure returns (int256) {\n        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n        if (value > uint256(type(int256).max)) {\n            revert SafeCastOverflowedUintToInt(value);\n        }\n        return int256(value);\n    }\n}\n"},{"file_path":"contracts/interfaces/IFxUSDRegeneracy.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IFxUSDRegeneracy {\n  /**********\n   * Events *\n   **********/\n  \n  /// @notice Emitted when rebalance/liquidate with stable token.\n  /// @param amountStable The amount of stable token used.\n  /// @param amountFxUSD The corresponding amount of fxUSD.\n  event RebalanceWithStable(uint256 amountStable, uint256 amountFxUSD);\n  \n  /// @notice Emitted when buyback fxUSD with stable reserve.\n  /// @param amountStable the amount of stable token used.\n  /// @param amountFxUSD The amount of fxUSD bought.\n  /// @param bonusFxUSD The amount of fxUSD as bonus for caller.\n  event Buyback(uint256 amountStable, uint256 amountFxUSD, uint256 bonusFxUSD);\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice The address of `PoolManager` contract.\n  function poolManager() external view returns (address);\n\n  /// @notice The address of stable token.\n  function stableToken() external view returns (address);\n\n  /// @notice The address of `PegKeeper` contract.\n  function pegKeeper() external view returns (address);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Mint fxUSD token someone.\n  function mint(address to, uint256 amount) external;\n\n  /// @notice Burn fxUSD from someone.\n  function burn(address from, uint256 amount) external;\n\n  /// @notice Hook for rebalance/liquidate with stable token.\n  /// @param amountStableToken The amount of stable token.\n  /// @param amountFxUSD The amount of fxUSD.\n  function onRebalanceWithStable(uint256 amountStableToken, uint256 amountFxUSD) external;\n\n  /// @notice Buyback fxUSD with stable token.\n  /// @param amountIn the amount of stable token to use.\n  /// @param receiver The address of bonus receiver.\n  /// @param data The hook data to PegKeeper.\n  /// @return amountOut The amount of fxUSD swapped.\n  /// @return bonusOut The amount of bonus fxUSD.\n  function buyback(\n    uint256 amountIn,\n    address receiver,\n    bytes calldata data\n  ) external returns (uint256 amountOut, uint256 bonusOut);\n}\n"},{"file_path":"@openzeppelin/contracts-v4/proxy/beacon/IBeacon.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\n */\ninterface IBeacon {\n    /**\n     * @dev Must return an address that can be used as a delegate call target.\n     *\n     * {BeaconProxy} will check that this address is a contract.\n     */\n    function implementation() external view returns (address);\n}\n"},{"file_path":"contracts/core/pool/PoolConstant.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IPool } from \"../../interfaces/IPool.sol\";\n\nabstract contract PoolConstant is IPool {\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The value of minimum collateral.\n  int256 internal constant MIN_COLLATERAL = 1e9;\n\n  /// @dev The value of minimum debts.\n  int256 internal constant MIN_DEBT = 1e9;\n\n  /// @dev The precision used for various calculation.\n  uint256 internal constant PRECISION = 1e18;\n\n  /// @dev The precision used for fee ratio calculation.\n  uint256 internal constant FEE_PRECISION = 1e9;\n\n  /// @dev bit operation related constants\n  uint256 internal constant E60 = 2 ** 60; // 2^60\n  uint256 internal constant E96 = 2 ** 96; // 2^96\n\n  uint256 internal constant X60 = 0xfffffffffffffff; // 2^60 - 1\n  uint256 internal constant X96 = 0xffffffffffffffffffffffff; // 2^96 - 1\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @inheritdoc IPool\n  address public immutable fxUSD;\n\n  /// @inheritdoc IPool\n  address public immutable poolManager;\n\n  /// @inheritdoc IPool\n  address public immutable pegKeeper;\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/ERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC20Metadata} from \"./extensions/IERC20Metadata.sol\";\nimport {Context} from \"../../utils/Context.sol\";\nimport {IERC20Errors} from \"../../interfaces/draft-IERC6093.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n */\nabstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {\n    mapping(address account => uint256) private _balances;\n\n    mapping(address account => mapping(address spender => uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n\n    string private _name;\n    string private _symbol;\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    constructor(string memory name_, string memory symbol_) {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the default value returned by this function, unless\n     * it's overridden.\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - the caller must have a balance of at least `value`.\n     */\n    function transfer(address to, uint256 value) public virtual returns (bool) {\n        address owner = _msgSender();\n        _transfer(owner, to, value);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on\n     * `transferFrom`. This is semantically equivalent to an infinite approval.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 value) public virtual returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, value);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * NOTE: Does not update the allowance if the current allowance\n     * is the maximum `uint256`.\n     *\n     * Requirements:\n     *\n     * - `from` and `to` cannot be the zero address.\n     * - `from` must have a balance of at least `value`.\n     * - the caller must have allowance for ``from``'s tokens of at least\n     * `value`.\n     */\n    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {\n        address spender = _msgSender();\n        _spendAllowance(from, spender, value);\n        _transfer(from, to, value);\n        return true;\n    }\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * NOTE: This function is not virtual, {_update} should be overridden instead.\n     */\n    function _transfer(address from, address to, uint256 value) internal {\n        if (from == address(0)) {\n            revert ERC20InvalidSender(address(0));\n        }\n        if (to == address(0)) {\n            revert ERC20InvalidReceiver(address(0));\n        }\n        _update(from, to, value);\n    }\n\n    /**\n     * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`\n     * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding\n     * this function.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _update(address from, address to, uint256 value) internal virtual {\n        if (from == address(0)) {\n            // Overflow check required: The rest of the code assumes that totalSupply never overflows\n            _totalSupply += value;\n        } else {\n            uint256 fromBalance = _balances[from];\n            if (fromBalance < value) {\n                revert ERC20InsufficientBalance(from, fromBalance, value);\n            }\n            unchecked {\n                // Overflow not possible: value <= fromBalance <= totalSupply.\n                _balances[from] = fromBalance - value;\n            }\n        }\n\n        if (to == address(0)) {\n            unchecked {\n                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.\n                _totalSupply -= value;\n            }\n        } else {\n            unchecked {\n                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.\n                _balances[to] += value;\n            }\n        }\n\n        emit Transfer(from, to, value);\n    }\n\n    /**\n     * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).\n     * Relies on the `_update` mechanism\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * NOTE: This function is not virtual, {_update} should be overridden instead.\n     */\n    function _mint(address account, uint256 value) internal {\n        if (account == address(0)) {\n            revert ERC20InvalidReceiver(address(0));\n        }\n        _update(address(0), account, value);\n    }\n\n    /**\n     * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.\n     * Relies on the `_update` mechanism.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * NOTE: This function is not virtual, {_update} should be overridden instead\n     */\n    function _burn(address account, uint256 value) internal {\n        if (account == address(0)) {\n            revert ERC20InvalidSender(address(0));\n        }\n        _update(account, address(0), value);\n    }\n\n    /**\n     * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     *\n     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.\n     */\n    function _approve(address owner, address spender, uint256 value) internal {\n        _approve(owner, spender, value, true);\n    }\n\n    /**\n     * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.\n     *\n     * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by\n     * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any\n     * `Approval` event during `transferFrom` operations.\n     *\n     * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to\n     * true using the following override:\n     * ```\n     * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {\n     *     super._approve(owner, spender, value, true);\n     * }\n     * ```\n     *\n     * Requirements are the same as {_approve}.\n     */\n    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {\n        if (owner == address(0)) {\n            revert ERC20InvalidApprover(address(0));\n        }\n        if (spender == address(0)) {\n            revert ERC20InvalidSpender(address(0));\n        }\n        _allowances[owner][spender] = value;\n        if (emitEvent) {\n            emit Approval(owner, spender, value);\n        }\n    }\n\n    /**\n     * @dev Updates `owner` s allowance for `spender` based on spent `value`.\n     *\n     * Does not update the allowance value in case of infinite allowance.\n     * Revert if not enough allowance is available.\n     *\n     * Does not emit an {Approval} event.\n     */\n    function _spendAllowance(address owner, address spender, uint256 value) internal virtual {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            if (currentAllowance < value) {\n                revert ERC20InsufficientAllowance(spender, currentAllowance, value);\n            }\n            unchecked {\n                _approve(owner, spender, currentAllowance - value, false);\n            }\n        }\n    }\n}\n"},{"file_path":"contracts/price-oracle/SpotPriceOracleBase.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport { Ownable2Step } from \"@openzeppelin/contracts/access/Ownable2Step.sol\";\n\nimport { AggregatorV3Interface } from \"../interfaces/Chainlink/AggregatorV3Interface.sol\";\nimport { ISpotPriceOracle } from \"./interfaces/ISpotPriceOracle.sol\";\n\nabstract contract SpotPriceOracleBase is Ownable2Step {\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the given encodings are invalid.\n  error ErrorInvalidEncodings();\n\n  /// @dev Thrown when update some parameters to the same value.\n  error ErrorParameterUnchanged();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The precision for oracle price.\n  uint256 internal constant PRECISION = 1e18;\n\n  /// @dev The address of `SpotPriceOracle` contract.\n  address immutable spotPriceOracle;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _spotPriceOracle) Ownable(_msgSender()) {\n    spotPriceOracle = _spotPriceOracle;\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev The encoding is below.\n  /// ```text\n  /// |  32 bits  | 64 bits |  160 bits  |\n  /// | heartbeat |  scale  | price_feed |\n  /// |low                          high |\n  /// ```\n  function _readSpotPriceByChainlink(bytes32 encoding) internal view returns (uint256) {\n    address aggregator;\n    uint256 scale;\n    uint256 heartbeat;\n    assembly {\n      aggregator := shr(96, encoding)\n      scale := and(shr(32, encoding), 0xffffffffffffffff)\n      heartbeat := and(encoding, 0xffffffff)\n    }\n    (, int256 answer, , uint256 updatedAt, ) = AggregatorV3Interface(aggregator).latestRoundData();\n    if (answer <= 0) revert(\"invalid\");\n    if (block.timestamp - updatedAt > heartbeat) revert(\"expired\");\n    return uint256(answer) * scale;\n  }\n\n  /// @dev Internal function to calculate spot price by encodings.\n  ///\n  /// The details of the encoding is below\n  /// ```text\n  /// |   1 byte   |    ...    |    ...    | ... |    ...    |\n  /// | num_source | source[0] | source[1] | ... | source[n] |\n  ///\n  /// source encoding:\n  /// |  1 byte  | 32 bytes | 32 bytes | ... | 32 bytes |\n  /// | num_pool |  pool[0] |  pool[1] | ... |  pool[n] |\n  /// 1 <= num_pool <= 3\n  ///\n  /// The encoding of each pool can be found in `SpotPriceOracle` contract.\n  /// ```\n  /// @return prices The list of prices of each source, multiplied by 1e18.\n  function _getSpotPriceByEncoding(bytes memory encodings) internal view returns (uint256[] memory prices) {\n    uint256 ptr;\n    uint256 length;\n    assembly {\n      ptr := add(encodings, 0x21)\n      length := byte(0, mload(sub(ptr, 1)))\n    }\n    prices = new uint256[](length);\n    for (uint256 i = 0; i < length; i++) {\n      uint256 encoding1;\n      uint256 encoding2;\n      uint256 encoding3;\n      assembly {\n        let cnt := byte(0, mload(ptr))\n        ptr := add(ptr, 0x01)\n        if gt(cnt, 0) {\n          encoding1 := mload(ptr)\n          ptr := add(ptr, 0x20)\n        }\n        if gt(cnt, 1) {\n          encoding2 := mload(ptr)\n          ptr := add(ptr, 0x20)\n        }\n        if gt(cnt, 2) {\n          encoding3 := mload(ptr)\n          ptr := add(ptr, 0x20)\n        }\n      }\n      if (encoding1 == 0) {\n        revert ErrorInvalidEncodings();\n      } else if (encoding2 == 0) {\n        prices[i] = _readSpotPrice(encoding1);\n      } else if (encoding3 == 0) {\n        prices[i] = _readSpotPrice(encoding1, encoding2);\n      } else {\n        prices[i] = _readSpotPrice(encoding1, encoding2, encoding3);\n      }\n    }\n  }\n\n  /// @dev Internal function to calculate spot price of single pool.\n  /// @param encoding The encoding for the pool.\n  /// @return price The spot price of the source, multiplied by 1e18.\n  function _readSpotPrice(uint256 encoding) private view returns (uint256 price) {\n    price = ISpotPriceOracle(spotPriceOracle).getSpotPrice(encoding);\n  }\n\n  /// @dev Internal function to calculate spot price of two pools.\n  /// @param encoding1 The encoding for the first pool.\n  /// @param encoding2 The encoding for the second pool.\n  /// @return price The spot price of the source, multiplied by 1e18.\n  function _readSpotPrice(uint256 encoding1, uint256 encoding2) private view returns (uint256 price) {\n    unchecked {\n      price = (_readSpotPrice(encoding1) * _readSpotPrice(encoding2)) / PRECISION;\n    }\n  }\n\n  /// @dev Internal function to calculate spot price of three pools.\n  /// @param encoding1 The encoding for the first pool.\n  /// @param encoding2 The encoding for the second pool.\n  /// @param encoding3 The encoding for the third pool.\n  /// @return price The spot price of the source, multiplied by 1e18.\n  function _readSpotPrice(\n    uint256 encoding1,\n    uint256 encoding2,\n    uint256 encoding3\n  ) private view returns (uint256 price) {\n    unchecked {\n      price = (_readSpotPrice(encoding1, encoding2) * _readSpotPrice(encoding3)) / PRECISION;\n    }\n  }\n}\n"},{"file_path":"contracts/price-oracle/StETHPriceOracle.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { ICurvePoolOracle } from \"../interfaces/Curve/ICurvePoolOracle.sol\";\n\nimport { SpotPriceOracleBase } from \"./SpotPriceOracleBase.sol\";\nimport { LSDPriceOracleBase } from \"./LSDPriceOracleBase.sol\";\n\ncontract StETHPriceOracle is LSDPriceOracleBase {\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @notice The address of curve ETH/stETH pool.\n  address public immutable Curve_ETH_stETH_Pool;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(\n    address _spotPriceOracle,\n    bytes32 _Chainlink_ETH_USD_Spot,\n    address _Curve_ETH_stETH_Pool\n  ) SpotPriceOracleBase(_spotPriceOracle) LSDPriceOracleBase(_Chainlink_ETH_USD_Spot) {\n    Curve_ETH_stETH_Pool = _Curve_ETH_stETH_Pool;\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @inheritdoc LSDPriceOracleBase\n  /// @dev [Curve stETH/ETH ema price] * [Chainlink ETH/USD spot]\n  function _getLSDUSDAnchorPrice() internal view virtual override returns (uint256) {\n    uint256 stETH_ETH_CurveEma = ICurvePoolOracle(Curve_ETH_stETH_Pool).price_oracle();\n    uint256 ETH_USD_ChainlinkSpot = _readSpotPriceByChainlink(Chainlink_ETH_USD_Spot);\n    unchecked {\n      return (stETH_ETH_CurveEma * ETH_USD_ChainlinkSpot) / PRECISION;\n    }\n  }\n}\n"},{"file_path":"contracts/mocks/MockStakedFxUSD.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\nimport { AggregatorV3Interface } from \"../interfaces/Chainlink/AggregatorV3Interface.sol\";\nimport { IPoolManager } from \"../interfaces/IPoolManager.sol\";\n\ncontract MockFxUSDSave {\n  /// @notice The address of `PoolManager` contract.\n  address public immutable poolManager;\n\n  /// @notice The address of `PegKeeper` contract.\n  address public immutable pegKeeper;\n\n  /// @dev This is also the address of FxUSD token.\n  address public immutable yieldToken;\n\n  /// @dev The address of USDC token.\n  address public immutable stableToken;\n\n  uint256 private immutable stableTokenScale;\n\n  /// @notice The Chainlink USDC/USD price feed.\n  /// @dev The encoding is below.\n  /// ```text\n  /// |  32 bits  | 64 bits |  160 bits  |\n  /// | heartbeat |  scale  | price_feed |\n  /// |low                          high |\n  /// ```\n  bytes32 public immutable Chainlink_USDC_USD_Spot;\n\n  constructor(\n    address _poolManager,\n    address _pegKeeper,\n    address _yieldToken,\n    address _stableToken,\n    bytes32 _Chainlink_USDC_USD_Spot\n  ) {\n    poolManager = _poolManager;\n    pegKeeper = _pegKeeper;\n    yieldToken = _yieldToken;\n    stableToken = _stableToken;\n    Chainlink_USDC_USD_Spot = _Chainlink_USDC_USD_Spot;\n\n    stableTokenScale = 10 ** (18 - IERC20Metadata(_stableToken).decimals());\n  }\n\n  function totalYieldToken() external view returns (uint256) {\n    return IERC20Metadata(yieldToken).balanceOf(address(this));\n  }\n\n  /// @notice The total amount of stable token managed in this contract\n  function totalStableToken() external view returns (uint256) {\n    return IERC20Metadata(stableToken).balanceOf(address(this));\n  }\n\n  function getStableTokenPrice() public view returns (uint256) {\n    bytes32 encoding = Chainlink_USDC_USD_Spot;\n    address aggregator;\n    uint256 scale;\n    uint256 heartbeat;\n    assembly {\n      aggregator := shr(96, encoding)\n      scale := and(shr(32, encoding), 0xffffffffffffffff)\n      heartbeat := and(encoding, 0xffffffff)\n    }\n    (, int256 answer, , uint256 updatedAt, ) = AggregatorV3Interface(aggregator).latestRoundData();\n    if (answer < 0) revert(\"invalid\");\n    if (block.timestamp - updatedAt > heartbeat) revert(\"expired\");\n    return uint256(answer) * scale;\n  }\n\n  function getStableTokenPriceWithScale() public view returns (uint256) {\n    return getStableTokenPrice() * stableTokenScale;\n  }\n\n  function rebalance(\n    address pool,\n    int16 tickId,\n    uint256 maxFxUSD,\n    uint256 maxStable\n  ) external returns (uint256 colls, uint256 yieldTokenUsed, uint256 stableTokenUsed) {\n    IERC20Metadata(yieldToken).approve(poolManager, type(uint256).max);\n    IERC20Metadata(stableToken).approve(poolManager, type(uint256).max);\n    (colls, yieldTokenUsed, stableTokenUsed) = IPoolManager(poolManager).rebalance(\n      pool,\n      msg.sender,\n      tickId,\n      maxFxUSD,\n      maxStable\n    );\n  }\n\n  function rebalance(\n    address pool,\n    uint32 positionId,\n    uint256 maxFxUSD,\n    uint256 maxStable\n  ) external returns (uint256 colls, uint256 yieldTokenUsed, uint256 stableTokenUsed) {\n    IERC20Metadata(yieldToken).approve(poolManager, type(uint256).max);\n    IERC20Metadata(stableToken).approve(poolManager, type(uint256).max);\n    (colls, yieldTokenUsed, stableTokenUsed) = IPoolManager(poolManager).rebalance(\n      pool,\n      msg.sender,\n      positionId,\n      maxFxUSD,\n      maxStable\n    );\n  }\n\n  function liquidate(\n    address pool,\n    uint32 positionId,\n    uint256 maxFxUSD,\n    uint256 maxStable\n  ) external returns (uint256 colls, uint256 yieldTokenUsed, uint256 stableTokenUsed) {\n    IERC20Metadata(yieldToken).approve(poolManager, type(uint256).max);\n    IERC20Metadata(stableToken).approve(poolManager, type(uint256).max);\n    (colls, yieldTokenUsed, stableTokenUsed) = IPoolManager(poolManager).liquidate(\n      pool,\n      msg.sender,\n      positionId,\n      maxFxUSD,\n      maxStable\n    );\n  }\n}\n"},{"file_path":"contracts/periphery/facets/FxUSDBasePoolFacet.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IFxUSDBasePool } from \"../../interfaces/IFxUSDBasePool.sol\";\nimport { IFxShareableRebalancePool } from \"../../v2/interfaces/IFxShareableRebalancePool.sol\";\nimport { IFxUSD } from \"../../v2/interfaces/IFxUSD.sol\";\nimport { ILiquidityGauge } from \"../../voting-escrow/interfaces/ILiquidityGauge.sol\";\n\nimport { WordCodec } from \"../../common/codec/WordCodec.sol\";\nimport { LibRouter } from \"../libraries/LibRouter.sol\";\n\ncontract FxUSDBasePoolFacet {\n  using SafeERC20 for IERC20;\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @notice The address of USDC token.\n  address private constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;\n\n  /// @notice The address of fxUSD token.\n  address private constant fxUSD = 0x085780639CC2cACd35E474e71f4d000e2405d8f6;\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @dev The address of `PoolManager` contract.\n  address private immutable poolManager;\n\n  /// @dev The address of `FxUSDBasePool` contract.\n  address private immutable fxBASE;\n\n  /// @dev The address of fxBASE gauge contract.\n  address private immutable gauge;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _poolManager, address _fxBASE, address _gauge) {\n    poolManager = _poolManager;\n    fxBASE = _fxBASE;\n    gauge = _gauge;\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Migrate fxUSD from rebalance pool to fxBASE.\n  /// @param pool The address of rebalance pool.\n  /// @param amountIn The amount of rebalance pool shares to migrate.\n  /// @param minShares The minimum shares should receive.\n  /// @param receiver The address of fxBASE share recipient.\n  function migrateToFxBase(address pool, uint256 amountIn, uint256 minShares, address receiver) external {\n    IFxShareableRebalancePool(pool).withdrawFrom(msg.sender, amountIn, address(this));\n    address baseToken = IFxShareableRebalancePool(pool).baseToken();\n    address asset = IFxShareableRebalancePool(pool).asset();\n    LibRouter.approve(asset, fxUSD, amountIn);\n    IFxUSD(fxUSD).wrap(baseToken, amountIn, address(this));\n    LibRouter.approve(fxUSD, fxBASE, amountIn);\n    IFxUSDBasePool(fxBASE).deposit(receiver, fxUSD, amountIn, minShares);\n  }\n\n  /// @notice Migrate fxUSD from rebalance pool to fxBASE gauge.\n  /// @param pool The address of rebalance pool.\n  /// @param amountIn The amount of rebalance pool shares to migrate.\n  /// @param minShares The minimum shares should receive.\n  /// @param receiver The address of fxBASE share recipient.\n  function migrateToFxBaseGauge(address pool, uint256 amountIn, uint256 minShares, address receiver) external {\n    IFxShareableRebalancePool(pool).withdrawFrom(msg.sender, amountIn, address(this));\n    address baseToken = IFxShareableRebalancePool(pool).baseToken();\n    address asset = IFxShareableRebalancePool(pool).asset();\n    LibRouter.approve(asset, fxUSD, amountIn);\n    IFxUSD(fxUSD).wrap(baseToken, amountIn, address(this));\n    LibRouter.approve(fxUSD, fxBASE, amountIn);\n    uint256 shares = IFxUSDBasePool(fxBASE).deposit(address(this), fxUSD, amountIn, minShares);\n    LibRouter.approve(fxBASE, gauge, shares);\n    ILiquidityGauge(gauge).deposit(shares, receiver);\n  }\n\n  /// @notice Deposit token to fxBASE.\n  /// @param params The parameters to convert source token to `tokenOut`.\n  /// @param tokenOut The target token, USDC or fxUSD.\n  /// @param minShares The minimum shares should receive.\n  /// @param receiver The address of fxBASE share recipient.\n  function depositToFxBase(\n    LibRouter.ConvertInParams memory params,\n    address tokenOut,\n    uint256 minShares,\n    address receiver\n  ) external payable {\n    uint256 amountIn = LibRouter.transferInAndConvert(params, tokenOut);\n    LibRouter.approve(tokenOut, fxBASE, amountIn);\n    IFxUSDBasePool(fxBASE).deposit(receiver, tokenOut, amountIn, minShares);\n  }\n\n  /// @notice Deposit token to fxBase and then deposit to gauge.\n  /// @param params The parameters to convert source token to `tokenOut`.\n  /// @param tokenOut The target token, USDC or fxUSD.\n  /// @param minShares The minimum shares should receive.\n  /// @param receiver The address of gauge share recipient.\n  function depositToFxBaseGauge(\n    LibRouter.ConvertInParams memory params,\n    address tokenOut,\n    uint256 minShares,\n    address receiver\n  ) external payable {\n    uint256 amountIn = LibRouter.transferInAndConvert(params, tokenOut);\n    LibRouter.approve(tokenOut, fxBASE, amountIn);\n    uint256 shares = IFxUSDBasePool(fxBASE).deposit(address(this), tokenOut, amountIn, minShares);\n    LibRouter.approve(fxBASE, gauge, shares);\n    ILiquidityGauge(gauge).deposit(shares, receiver);\n  }\n  \n  /*\n  /// @notice Burn fxBASE shares and then convert USDC and fxUSD to another token.\n  /// @param fxusdParams The parameters to convert fxUSD to target token.\n  /// @param usdcParams The parameters to convert USDC to target token.\n  /// @param amountIn The amount of fxBASE to redeem.\n  /// @param receiver The address of token recipient.\n  function redeemFromFxBase(\n    LibRouter.ConvertOutParams memory fxusdParams,\n    LibRouter.ConvertOutParams memory usdcParams,\n    uint256 amountIn,\n    address receiver\n  ) external {\n    IERC20(fxBASE).safeTransferFrom(msg.sender, address(this), amountIn);\n    (uint256 amountFxUSD, uint256 amountUSDC) = IFxUSDBasePool(fxBASE).redeem(address(this), amountIn);\n    LibRouter.convertAndTransferOut(fxusdParams, fxUSD, amountFxUSD, receiver);\n    LibRouter.convertAndTransferOut(usdcParams, USDC, amountUSDC, receiver);\n  }\n\n  /// @notice Burn fxBASE shares from gauge and then convert USDC and fxUSD to another token.\n  /// @param fxusdParams The parameters to convert fxUSD to target token.\n  /// @param usdcParams The parameters to convert USDC to target token.\n  /// @param amountIn The amount of fxBASE to redeem.\n  /// @param receiver The address of token recipient.\n  function redeemFromFxBaseGauge(\n    LibRouter.ConvertOutParams memory fxusdParams,\n    LibRouter.ConvertOutParams memory usdcParams,\n    uint256 amountIn,\n    address receiver\n  ) external {\n    IERC20(gauge).safeTransferFrom(msg.sender, address(this), amountIn);\n    ILiquidityGauge(gauge).withdraw(amountIn);\n    (uint256 amountFxUSD, uint256 amountUSDC) = IFxUSDBasePool(fxBASE).redeem(address(this), amountIn);\n    LibRouter.convertAndTransferOut(fxusdParams, fxUSD, amountFxUSD, receiver);\n    LibRouter.convertAndTransferOut(usdcParams, USDC, amountUSDC, receiver);\n  }\n  */\n}\n"},{"file_path":"contracts/common/codec/WordCodec.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n// solhint-disable no-inline-assembly\n\n/// @dev A subset copied from the following contracts:\n///\n/// + `balancer-labs/v2-solidity-utils/contracts/helpers/WordCodec.sol`\n/// + `balancer-labs/v2-solidity-utils/contracts/helpers/WordCodecHelpers.sol`\nlibrary WordCodec {\n  /// @dev Inserts an unsigned integer of bitLength, shifted by an offset, into a 256 bit word,\n  /// replacing the old value. Returns the new word.\n  function insertUint(\n    bytes32 word,\n    uint256 value,\n    uint256 offset,\n    uint256 bitLength\n  ) internal pure returns (bytes32 result) {\n    // Equivalent to:\n    // uint256 mask = (1 << bitLength) - 1;\n    // bytes32 clearedWord = bytes32(uint256(word) & ~(mask << offset));\n    // result = clearedWord | bytes32(value << offset);\n    assembly {\n      let mask := sub(shl(bitLength, 1), 1)\n      let clearedWord := and(word, not(shl(offset, mask)))\n      result := or(clearedWord, shl(offset, value))\n    }\n  }\n\n  /// @dev Decodes and returns an unsigned integer with `bitLength` bits, shifted by an offset, from a 256 bit word.\n  function decodeUint(\n    bytes32 word,\n    uint256 offset,\n    uint256 bitLength\n  ) internal pure returns (uint256 result) {\n    // Equivalent to:\n    // result = uint256(word >> offset) & ((1 << bitLength) - 1);\n    assembly {\n      result := and(shr(offset, word), sub(shl(bitLength, 1), 1))\n    }\n  }\n\n  /// @dev Inserts a signed integer shifted by an offset into a 256 bit word, replacing the old value. Returns\n  /// the new word.\n  ///\n  /// Assumes `value` can be represented using `bitLength` bits.\n  function insertInt(\n    bytes32 word,\n    int256 value,\n    uint256 offset,\n    uint256 bitLength\n  ) internal pure returns (bytes32) {\n    unchecked {\n      uint256 mask = (1 << bitLength) - 1;\n      bytes32 clearedWord = bytes32(uint256(word) & ~(mask << offset));\n      // Integer values need masking to remove the upper bits of negative values.\n      return clearedWord | bytes32((uint256(value) & mask) << offset);\n    }\n  }\n\n  /// @dev Decodes and returns a signed integer with `bitLength` bits, shifted by an offset, from a 256 bit word.\n  function decodeInt(\n    bytes32 word,\n    uint256 offset,\n    uint256 bitLength\n  ) internal pure returns (int256 result) {\n    unchecked {\n      int256 maxInt = int256((1 << (bitLength - 1)) - 1);\n      uint256 mask = (1 << bitLength) - 1;\n\n      int256 value = int256(uint256(word >> offset) & mask);\n      // In case the decoded value is greater than the max positive integer that can be represented with bitLength\n      // bits, we know it was originally a negative integer. Therefore, we mask it to restore the sign in the 256 bit\n      // representation.\n      //\n      // Equivalent to:\n      // result = value > maxInt ? (value | int256(~mask)) : value;\n      assembly {\n        result := or(mul(gt(value, maxInt), not(mask)), value)\n      }\n    }\n  }\n\n  /// @dev Decodes and returns a boolean shifted by an offset from a 256 bit word.\n  function decodeBool(bytes32 word, uint256 offset) internal pure returns (bool result) {\n    // Equivalent to:\n    // result = (uint256(word >> offset) & 1) == 1;\n    assembly {\n      result := and(shr(offset, word), 1)\n    }\n  }\n\n  /// @dev Inserts a boolean value shifted by an offset into a 256 bit word, replacing the old value. Returns the new\n  /// word.\n  function insertBool(\n    bytes32 word,\n    bool value,\n    uint256 offset\n  ) internal pure returns (bytes32 result) {\n    // Equivalent to:\n    // bytes32 clearedWord = bytes32(uint256(word) & ~(1 << offset));\n    // bytes32 referenceInsertBool = clearedWord | bytes32(uint256(value ? 1 : 0) << offset);\n    assembly {\n      let clearedWord := and(word, not(shl(offset, 1)))\n      result := or(clearedWord, shl(offset, value))\n    }\n  }\n\n  function clearWordAtPosition(\n    bytes32 word,\n    uint256 offset,\n    uint256 bitLength\n  ) internal pure returns (bytes32 clearedWord) {\n    unchecked {\n      uint256 mask = (1 << bitLength) - 1;\n      clearedWord = bytes32(uint256(word) & ~(mask << offset));\n    }\n  }\n}\n"},{"file_path":"contracts/common/EIP2535/facets/DiamondLoupeFacet.sol","source_code":"// SPDX-License-Identifier: CC0-1.0\npragma solidity ^0.8.0;\n\n/******************************************************************************\\\n* Author: Nick Mudge <nick@perfectabstractions.com>, Twitter/Github: @mudgen\n* EIP-2535 Diamonds\n/******************************************************************************/\n\n// The functions in DiamondLoupeFacet MUST be added to a diamond.\n// The EIP-2535 Diamond standard requires these functions.\n\nimport { LibDiamond } from \"../libraries/LibDiamond.sol\";\nimport { IDiamondLoupe } from \"../interfaces/IDiamondLoupe.sol\";\nimport { IERC165 } from \"../interfaces/IERC165.sol\";\n\n// solhint-disable no-inline-assembly\n\ncontract DiamondLoupeFacet is IDiamondLoupe, IERC165 {\n  // Diamond Loupe Functions\n  ////////////////////////////////////////////////////////////////////\n  /// These functions are expected to be called frequently by tools.\n  //\n  // struct Facet {\n  //     address facetAddress;\n  //     bytes4[] functionSelectors;\n  // }\n  /// @notice Gets all facets and their selectors.\n  /// @return facets_ Facet\n  function facets() external view override returns (Facet[] memory facets_) {\n    LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();\n    uint256 selectorCount = ds.selectors.length;\n    // create an array set to the maximum size possible\n    facets_ = new Facet[](selectorCount);\n    // create an array for counting the number of selectors for each facet\n    uint16[] memory numFacetSelectors = new uint16[](selectorCount);\n    // total number of facets\n    uint256 numFacets;\n    // loop through function selectors\n    for (uint256 selectorIndex; selectorIndex < selectorCount; selectorIndex++) {\n      bytes4 selector = ds.selectors[selectorIndex];\n      address facetAddress_ = ds.facetAddressAndSelectorPosition[selector].facetAddress;\n      bool continueLoop = false;\n      // find the functionSelectors array for selector and add selector to it\n      for (uint256 facetIndex; facetIndex < numFacets; facetIndex++) {\n        if (facets_[facetIndex].facetAddress == facetAddress_) {\n          facets_[facetIndex].functionSelectors[numFacetSelectors[facetIndex]] = selector;\n          numFacetSelectors[facetIndex]++;\n          continueLoop = true;\n          break;\n        }\n      }\n      // if functionSelectors array exists for selector then continue loop\n      if (continueLoop) {\n        continueLoop = false;\n        continue;\n      }\n      // create a new functionSelectors array for selector\n      facets_[numFacets].facetAddress = facetAddress_;\n      facets_[numFacets].functionSelectors = new bytes4[](selectorCount);\n      facets_[numFacets].functionSelectors[0] = selector;\n      numFacetSelectors[numFacets] = 1;\n      numFacets++;\n    }\n    for (uint256 facetIndex; facetIndex < numFacets; facetIndex++) {\n      uint256 numSelectors = numFacetSelectors[facetIndex];\n      bytes4[] memory selectors = facets_[facetIndex].functionSelectors;\n      // setting the number of selectors\n      assembly {\n        mstore(selectors, numSelectors)\n      }\n    }\n    // setting the number of facets\n    assembly {\n      mstore(facets_, numFacets)\n    }\n  }\n\n  /// @notice Gets all the function selectors supported by a specific facet.\n  /// @param _facet The facet address.\n  /// @return _facetFunctionSelectors The selectors associated with a facet address.\n  function facetFunctionSelectors(address _facet)\n    external\n    view\n    override\n    returns (bytes4[] memory _facetFunctionSelectors)\n  {\n    LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();\n    uint256 selectorCount = ds.selectors.length;\n    uint256 numSelectors;\n    _facetFunctionSelectors = new bytes4[](selectorCount);\n    // loop through function selectors\n    for (uint256 selectorIndex; selectorIndex < selectorCount; selectorIndex++) {\n      bytes4 selector = ds.selectors[selectorIndex];\n      address facetAddress_ = ds.facetAddressAndSelectorPosition[selector].facetAddress;\n      if (_facet == facetAddress_) {\n        _facetFunctionSelectors[numSelectors] = selector;\n        numSelectors++;\n      }\n    }\n    // Set the number of selectors in the array\n    assembly {\n      mstore(_facetFunctionSelectors, numSelectors)\n    }\n  }\n\n  /// @notice Get all the facet addresses used by a diamond.\n  /// @return facetAddresses_\n  function facetAddresses() external view override returns (address[] memory facetAddresses_) {\n    LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();\n    uint256 selectorCount = ds.selectors.length;\n    // create an array set to the maximum size possible\n    facetAddresses_ = new address[](selectorCount);\n    uint256 numFacets;\n    // loop through function selectors\n    for (uint256 selectorIndex; selectorIndex < selectorCount; selectorIndex++) {\n      bytes4 selector = ds.selectors[selectorIndex];\n      address facetAddress_ = ds.facetAddressAndSelectorPosition[selector].facetAddress;\n      bool continueLoop = false;\n      // see if we have collected the address already and break out of loop if we have\n      for (uint256 facetIndex; facetIndex < numFacets; facetIndex++) {\n        if (facetAddress_ == facetAddresses_[facetIndex]) {\n          continueLoop = true;\n          break;\n        }\n      }\n      // continue loop if we already have the address\n      if (continueLoop) {\n        continueLoop = false;\n        continue;\n      }\n      // include address\n      facetAddresses_[numFacets] = facetAddress_;\n      numFacets++;\n    }\n    // Set the number of facet addresses in the array\n    assembly {\n      mstore(facetAddresses_, numFacets)\n    }\n  }\n\n  /// @notice Gets the facet address that supports the given selector.\n  /// @dev If facet is not found return address(0).\n  /// @param _functionSelector The function selector.\n  /// @return facetAddress_ The facet address.\n  function facetAddress(bytes4 _functionSelector) external view override returns (address facetAddress_) {\n    LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();\n    facetAddress_ = ds.facetAddressAndSelectorPosition[_functionSelector].facetAddress;\n  }\n\n  // This implements ERC-165.\n  function supportsInterface(bytes4 _interfaceId) external view override returns (bool) {\n    LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();\n    return ds.supportedInterfaces[_interfaceId];\n  }\n}\n"},{"file_path":"contracts/periphery/libraries/LibRouter.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { IMultiPathConverter } from \"../../helpers/interfaces/IMultiPathConverter.sol\";\nimport { IWrappedEther } from \"../../interfaces/IWrappedEther.sol\";\n\nlibrary LibRouter {\n  using SafeERC20 for IERC20;\n  using EnumerableSet for EnumerableSet.AddressSet;\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when use unapproved target contract.\n  error ErrorTargetNotApproved();\n\n  /// @dev Thrown when msg.value is different from amount.\n  error ErrorMsgValueMismatch();\n\n  /// @dev Thrown when the output token is not enough.\n  error ErrorInsufficientOutput();\n\n  /// @dev Thrown when the whitelisted account type is incorrect.\n  error ErrorNotWhitelisted();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The storage slot for router storage.\n  bytes32 private constant ROUTER_STORAGE_SLOT = keccak256(\"diamond.router.storage\");\n\n  /// @dev The address of WETH token.\n  address internal constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n\n  uint8 internal constant NOT_FLASH_LOAN = 0;\n\n  uint8 internal constant HAS_FLASH_LOAN = 1;\n\n  uint8 internal constant NOT_ENTRANT = 0;\n\n  uint8 internal constant HAS_ENTRANT = 1;\n\n  /***********\n   * Structs *\n   ***********/\n\n  /// @param spenders Mapping from target address to token spender address.\n  /// @param approvedTargets The list of approved target contracts.\n  /// @param whitelisted The list of whitelisted contracts.\n  struct RouterStorage {\n    mapping(address => address) spenders;\n    EnumerableSet.AddressSet approvedTargets;\n    EnumerableSet.AddressSet whitelisted;\n    address revenuePool;\n    uint8 flashLoanContext;\n    uint8 reentrantContext;\n  }\n\n  /// @notice The struct for input token convert parameters.\n  ///\n  /// @param tokenIn The address of source token.\n  /// @param amount The amount of source token.\n  /// @param target The address of converter contract.\n  /// @param data The calldata passing to the target contract.\n  /// @param minOut The minimum amount of output token should receive.\n  /// @param signature The optional data for future usage.\n  struct ConvertInParams {\n    address tokenIn;\n    uint256 amount;\n    address target;\n    bytes data;\n    uint256 minOut;\n    bytes signature;\n  }\n\n  /// @notice The struct for output token convert parameters.\n  /// @param tokenOut The address of output token.\n  /// @param converter The address of converter contract.\n  /// @param encodings The encodings for `MultiPathConverter`.\n  /// @param minOut The minimum amount of output token should receive.\n  /// @param routes The convert route encodings.\n  /// @param signature The optional data for future usage.\n  struct ConvertOutParams {\n    address tokenOut;\n    address converter;\n    uint256 encodings;\n    uint256[] routes;\n    uint256 minOut;\n    bytes signature;\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Return the RouterStorage reference.\n  function routerStorage() internal pure returns (RouterStorage storage gs) {\n    bytes32 position = ROUTER_STORAGE_SLOT;\n    assembly {\n      gs.slot := position\n    }\n  }\n\n  /// @dev Approve contract to be used in token converting.\n  function approveTarget(address target, address spender) internal {\n    RouterStorage storage $ = routerStorage();\n\n    if ($.approvedTargets.add(target) && target != spender) {\n      $.spenders[target] = spender;\n    }\n  }\n\n  /// @dev Remove approve contract in token converting.\n  function removeTarget(address target) internal {\n    RouterStorage storage $ = routerStorage();\n\n    if ($.approvedTargets.remove(target)) {\n      delete $.spenders[target];\n    }\n  }\n\n  /// @dev Whitelist account with type.\n  function updateWhitelist(address account, bool status) internal {\n    RouterStorage storage $ = routerStorage();\n\n    if (status) {\n      $.whitelisted.add(account);\n    } else {\n      $.whitelisted.remove(account);\n    }\n  }\n\n  /// @dev Check whether the account is whitelisted with specific type.\n  function ensureWhitelisted(address account) internal view {\n    RouterStorage storage $ = routerStorage();\n    if (!$.whitelisted.contains(account)) {\n      revert ErrorNotWhitelisted();\n    }\n  }\n\n  function updateRevenuePool(address revenuePool) internal {\n    RouterStorage storage $ = routerStorage();\n    $.revenuePool = revenuePool;\n  }\n\n  /// @dev Transfer token into this contract and convert to `tokenOut`.\n  /// @param params The parameters used in token converting.\n  /// @param tokenOut The address of final converted token.\n  /// @return amountOut The amount of token received.\n  function transferInAndConvert(ConvertInParams memory params, address tokenOut) internal returns (uint256 amountOut) {\n    RouterStorage storage $ = routerStorage();\n    if (!$.approvedTargets.contains(params.target)) {\n      revert ErrorTargetNotApproved();\n    }\n\n    transferTokenIn(params.tokenIn, address(this), params.amount);\n\n    amountOut = IERC20(tokenOut).balanceOf(address(this));\n    if (params.tokenIn == tokenOut) return amountOut;\n\n    bool _success;\n    if (params.tokenIn == address(0)) {\n      (_success, ) = params.target.call{ value: params.amount }(params.data);\n    } else {\n      address _spender = $.spenders[params.target];\n      if (_spender == address(0)) _spender = params.target;\n\n      approve(params.tokenIn, _spender, params.amount);\n      (_success, ) = params.target.call(params.data);\n    }\n\n    // below lines will propagate inner error up\n    if (!_success) {\n      // solhint-disable-next-line no-inline-assembly\n      assembly {\n        let ptr := mload(0x40)\n        let size := returndatasize()\n        returndatacopy(ptr, 0, size)\n        revert(ptr, size)\n      }\n    }\n\n    amountOut = IERC20(tokenOut).balanceOf(address(this)) - amountOut;\n  }\n\n  /// @dev Convert `tokenIn` to other token and transfer out.\n  /// @param params The parameters used in token converting.\n  /// @param tokenIn The address of token to convert.\n  /// @param amountIn The amount of token to convert.\n  /// @return amountOut The amount of token received.\n  function convertAndTransferOut(\n    ConvertOutParams memory params,\n    address tokenIn,\n    uint256 amountIn,\n    address receiver\n  ) internal returns (uint256 amountOut) {\n    RouterStorage storage $ = routerStorage();\n    if (!$.approvedTargets.contains(params.converter)) {\n      revert ErrorTargetNotApproved();\n    }\n    if (amountIn == 0) return 0;\n\n    amountOut = amountIn;\n    if (params.routes.length > 0) {\n      approve(tokenIn, params.converter, amountIn);\n      amountOut = IMultiPathConverter(params.converter).convert(tokenIn, amountIn, params.encodings, params.routes);\n    }\n    if (amountOut < params.minOut) revert ErrorInsufficientOutput();\n    if (params.tokenOut == address(0)) {\n      IWrappedEther(WETH).withdraw(amountOut);\n      Address.sendValue(payable(receiver), amountOut);\n    } else {\n      IERC20(params.tokenOut).safeTransfer(receiver, amountOut);\n    }\n  }\n\n  /// @dev Internal function to transfer token to this contract.\n  /// @param token The address of token to transfer.\n  /// @param amount The amount of token to transfer.\n  /// @return uint256 The amount of token transferred.\n  function transferTokenIn(address token, address receiver, uint256 amount) internal returns (uint256) {\n    if (token == address(0)) {\n      if (msg.value != amount) revert ErrorMsgValueMismatch();\n    } else {\n      IERC20(token).safeTransferFrom(msg.sender, receiver, amount);\n    }\n    return amount;\n  }\n\n  /// @dev Internal function to refund extra token.\n  /// @param token The address of token to refund.\n  /// @param recipient The address of the token receiver.\n  function refundERC20(address token, address recipient) internal {\n    uint256 _balance = IERC20(token).balanceOf(address(this));\n    if (_balance > 0) {\n      IERC20(token).safeTransfer(recipient, _balance);\n    }\n  }\n\n  /// @dev Internal function to approve token.\n  function approve(address token, address spender, uint256 amount) internal {\n    IERC20(token).forceApprove(spender, amount);\n  }\n}\n"},{"file_path":"contracts/common/rewards/distributor/IRewardDistributor.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IRewardDistributor {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when a reward token is deposited.\n  ///\n  /// @param amount The amount of reward token deposited.\n  event DepositReward(uint256 amount);\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the address of reward token.\n  function rewardToken() external view returns (address);\n\n  /// @notice Return the amount of pending distributed rewards in current period.\n  /// @return distributable The amount of reward token can be distributed in current period.\n  /// @return undistributed The amount of reward token still locked in current period.\n  function pendingRewards() external view returns (uint256 distributable, uint256 undistributed);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Deposit new rewards to this contract.\n  ///\n  /// @param amount The amount of new rewards.\n  function depositReward(uint256 amount) external;\n}\n"},{"file_path":"@openzeppelin/contracts-v4/access/Ownable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/proxy/utils/Initializable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\n *     }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n *     function initializeV2() reinitializer(2) public {\n *         __ERC20Permit_init(\"MyToken\");\n *     }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n *     _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n    /**\n     * @dev Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 version);\n\n    /**\n     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n     * `onlyInitializing` functions can be used to initialize parent contracts.\n     *\n     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n     * constructor.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = !_initializing;\n        require(\n            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n            \"Initializable: contract is already initialized\"\n        );\n        _initialized = 1;\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(1);\n        }\n    }\n\n    /**\n     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n     * used to initialize parent contracts.\n     *\n     * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n     * are added through upgrades and that require initialization.\n     *\n     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n     * cannot be nested. If one is invoked in the context of another, execution will revert.\n     *\n     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n     * a contract, executing them in the right order is up to the developer or operator.\n     *\n     * WARNING: setting the version to 255 will prevent any future reinitialization.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier reinitializer(uint8 version) {\n        require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n        _initialized = version;\n        _initializing = true;\n        _;\n        _initializing = false;\n        emit Initialized(version);\n    }\n\n    /**\n     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n     * {initializer} and {reinitializer} modifiers, directly or indirectly.\n     */\n    modifier onlyInitializing() {\n        require(_initializing, \"Initializable: contract is not initializing\");\n        _;\n    }\n\n    /**\n     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n     * through proxies.\n     *\n     * Emits an {Initialized} event the first time it is successfully executed.\n     */\n    function _disableInitializers() internal virtual {\n        require(!_initializing, \"Initializable: contract is initializing\");\n        if (_initialized != type(uint8).max) {\n            _initialized = type(uint8).max;\n            emit Initialized(type(uint8).max);\n        }\n    }\n\n    /**\n     * @dev Returns the highest version that has been initialized. See {reinitializer}.\n     */\n    function _getInitializedVersion() internal view returns (uint8) {\n        return _initialized;\n    }\n\n    /**\n     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n     */\n    function _isInitializing() internal view returns (bool) {\n        return _initializing;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/token/ERC20/utils/SafeERC20Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\nimport \"../extensions/IERC20PermitUpgradeable.sol\";\nimport \"../../../utils/AddressUpgradeable.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20Upgradeable {\n    using AddressUpgradeable for address;\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n     * to be set to zero before setting it to a non-zero value, such as USDT.\n     */\n    function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.\n     * Revert on invalid signature.\n     */\n    function safePermit(\n        IERC20PermitUpgradeable token,\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        uint256 nonceBefore = token.nonces(owner);\n        token.permit(owner, spender, value, deadline, v, r, s);\n        uint256 nonceAfter = token.nonces(owner);\n        require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        require(returndata.length == 0 || abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n        // and not revert is the subcall reverts.\n\n        (bool success, bytes memory returndata) = address(token).call(data);\n        return\n            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token));\n    }\n}\n"},{"file_path":"contracts/v2/interfaces/IFxTreasuryV2.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IFxTreasuryV2 {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when the platform contract is updated.\n  /// @param oldPlatform The address of previous platform contract.\n  /// @param newPlatform The address of current platform contract.\n  event UpdatePlatform(address indexed oldPlatform, address indexed newPlatform);\n\n  /// @notice Emitted when the RebalancePoolSplitter contract is updated.\n  /// @param oldRebalancePoolSplitter The address of previous RebalancePoolSplitter contract.\n  /// @param newRebalancePoolSplitter The address of current RebalancePoolSplitter.\n  event UpdateRebalancePoolSplitter(address indexed oldRebalancePoolSplitter, address indexed newRebalancePoolSplitter);\n\n  /// @notice Emitted when the price oracle contract is updated.\n  /// @param oldPriceOracle The address of previous price oracle.\n  /// @param newPriceOracle The address of current price oracle.\n  event UpdatePriceOracle(address indexed oldPriceOracle, address indexed newPriceOracle);\n\n  /// @notice Emitted when the strategy contract is updated.\n  /// @param oldStrategy The address of previous strategy.\n  /// @param newStrategy The address of current strategy.\n  event UpdateStrategy(address indexed oldStrategy, address indexed newStrategy);\n\n  /// @notice Emitted when the base token cap is updated.\n  /// @param oldBaseTokenCap The value of previous base token cap.\n  /// @param newBaseTokenCap The value of current base token cap.\n  event UpdateBaseTokenCap(uint256 oldBaseTokenCap, uint256 newBaseTokenCap);\n\n  /// @notice Emitted when the EMA sample interval is updated.\n  /// @param oldSampleInterval The value of previous EMA sample interval.\n  /// @param newSampleInterval The value of current EMA sample interval.\n  event UpdateEMASampleInterval(uint256 oldSampleInterval, uint256 newSampleInterval);\n\n  /// @notice Emitted when the reference price is updated.\n  /// @param oldPrice The value of previous reference price.\n  /// @param newPrice The value of current reference price.\n  event Settle(uint256 oldPrice, uint256 newPrice);\n\n  /// @notice Emitted when the ratio for rebalance pool is updated.\n  /// @param oldRatio The value of the previous ratio, multiplied by 1e9.\n  /// @param newRatio The value of the current ratio, multiplied by 1e9.\n  event UpdateRebalancePoolRatio(uint256 oldRatio, uint256 newRatio);\n\n  /// @notice Emitted when the ratio for harvester is updated.\n  /// @param oldRatio The value of the previous ratio, multiplied by 1e9.\n  /// @param newRatio The value of the current ratio, multiplied by 1e9.\n  event UpdateHarvesterRatio(uint256 oldRatio, uint256 newRatio);\n\n  /// @notice Emitted when someone harvest pending stETH rewards.\n  /// @param caller The address of caller.\n  /// @param totalRewards The amount of total harvested rewards.\n  /// @param rebalancePoolRewards The amount of harvested rewards distributed to stability pool.\n  /// @param harvestBounty The amount of harvested rewards distributed to caller as harvest bounty.\n  event Harvest(address indexed caller, uint256 totalRewards, uint256 rebalancePoolRewards, uint256 harvestBounty);\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the collateral ratio is smaller than 100%.\n  error ErrorCollateralRatioTooSmall();\n\n  /// @dev Thrown when mint exceed total capacity.\n  error ErrorExceedTotalCap();\n\n  /// @dev Thrown when the oracle price is invalid.\n  error ErrorInvalidOraclePrice();\n\n  /// @dev Thrown when the twap price is invalid.\n  error ErrorInvalidTwapPrice();\n\n  /// @dev Thrown when initialize protocol twice.\n  error ErrorProtocolInitialized();\n\n  /// @dev Thrown when the initial amount of base token is not enough.\n  error ErrorInsufficientInitialBaseToken();\n\n  /// @dev Thrown when current is under collateral.\n  error ErrorUnderCollateral();\n\n  /// @dev Thrown when the sample internal for EMA is too small.\n  error ErrorEMASampleIntervalTooSmall();\n\n  /// @dev Thrown when the expense ratio exceeds `MAX_REBALANCE_POOL_RATIO`.\n  error ErrorRebalancePoolRatioTooLarge();\n\n  /// @dev Thrown when the harvester ratio exceeds `MAX_HARVESTER_RATIO`.\n  error ErrorHarvesterRatioTooLarge();\n\n  /// @dev Thrown when the given address is zero.\n  error ErrorZeroAddress();\n\n  /*********\n   * Enums *\n   *********/\n\n  enum Action {\n    None,\n    MintFToken,\n    MintXToken,\n    RedeemFToken,\n    RedeemXToken\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the address of price oracle contract.\n  function priceOracle() external view returns (address);\n\n  /// @notice Return the address of base token.\n  function baseToken() external view returns (address);\n\n  /// @notice Return the address fractional base token.\n  function fToken() external view returns (address);\n\n  /// @notice Return the address leveraged base token.\n  function xToken() external view returns (address);\n\n  /// @notice The reference base token price.\n  function referenceBaseTokenPrice() external view returns (uint256);\n\n  /// @notice The current base token price.\n  function currentBaseTokenPrice() external view returns (uint256);\n\n  /// @notice Return whether the price is valid.\n  function isBaseTokenPriceValid() external view returns (bool);\n\n  /// @notice Return the total amount of underlying value of base token deposited.\n  function totalBaseToken() external view returns (uint256);\n\n  /// @notice Return the address of strategy contract.\n  function strategy() external view returns (address);\n\n  /// @notice Return the total amount of base token managed by strategy.\n  function strategyUnderlying() external view returns (uint256);\n\n  /// @notice Return the current collateral ratio of fToken, multiplied by 1e18.\n  function collateralRatio() external view returns (uint256);\n\n  /// @notice Return whether the system is under collateral.\n  function isUnderCollateral() external view returns (bool);\n\n  /// @notice Compute the amount of base token needed to reach the new collateral ratio.\n  /// @param newCollateralRatio The target collateral ratio, multiplied by 1e18.\n  /// @return maxBaseIn The amount of underlying value of base token needed.\n  /// @return maxFTokenMintable The amount of fToken can be minted.\n  function maxMintableFToken(uint256 newCollateralRatio)\n    external\n    view\n    returns (uint256 maxBaseIn, uint256 maxFTokenMintable);\n\n  /// @notice Compute the amount of base token needed to reach the new collateral ratio.\n  /// @param newCollateralRatio The target collateral ratio, multiplied by 1e18.\n  /// @return maxBaseIn The amount of underlying value of base token needed.\n  /// @return maxXTokenMintable The amount of xToken can be minted.\n  function maxMintableXToken(uint256 newCollateralRatio)\n    external\n    view\n    returns (uint256 maxBaseIn, uint256 maxXTokenMintable);\n\n  /// @notice Compute the amount of fToken needed to reach the new collateral ratio.\n  /// @param newCollateralRatio The target collateral ratio, multiplied by 1e18.\n  /// @return maxBaseOut The amount of underlying value of base token redeemed.\n  /// @return maxFTokenRedeemable The amount of fToken needed.\n  function maxRedeemableFToken(uint256 newCollateralRatio)\n    external\n    view\n    returns (uint256 maxBaseOut, uint256 maxFTokenRedeemable);\n\n  /// @notice Compute the amount of xToken needed to reach the new collateral ratio.\n  /// @param newCollateralRatio The target collateral ratio, multiplied by 1e18.\n  /// @return maxBaseOut The amount of underlying value of base token redeemed.\n  /// @return maxXTokenRedeemable The amount of xToken needed.\n  function maxRedeemableXToken(uint256 newCollateralRatio)\n    external\n    view\n    returns (uint256 maxBaseOut, uint256 maxXTokenRedeemable);\n\n  /// @notice Return the exponential moving average of the leverage ratio.\n  function leverageRatio() external view returns (uint256);\n\n  /// @notice Convert underlying token amount to wrapped token amount.\n  /// @param amount The underlying token amount.\n  function getWrapppedValue(uint256 amount) external view returns (uint256);\n\n  /// @notice Convert wrapped token amount to underlying token amount.\n  /// @param amount The wrapped token amount.\n  function getUnderlyingValue(uint256 amount) external view returns (uint256);\n\n  /// @notice Return the fee ratio distributed to rebalance pool, multiplied by 1e9.\n  function getRebalancePoolRatio() external view returns (uint256);\n\n  /// @notice Return the fee ratio distributed to harvester, multiplied by 1e9.\n  function getHarvesterRatio() external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Initialize the protocol.\n  /// @param baseIn The amount of underlying value of the base token used to initialize.\n  function initializeProtocol(uint256 baseIn) external returns (uint256 fTokenOut, uint256 xTokenOut);\n\n  /// @notice Mint fToken with some base token.\n  /// @param baseIn The amount of underlying value of base token deposited.\n  /// @param recipient The address of receiver.\n  /// @return fTokenOut The amount of fToken minted.\n  function mintFToken(uint256 baseIn, address recipient) external returns (uint256 fTokenOut);\n\n  /// @notice Mint xToken with some base token.\n  /// @param baseIn The amount of underlying value of base token deposited.\n  /// @param recipient The address of receiver.\n  /// @return xTokenOut The amount of xToken minted.\n  function mintXToken(uint256 baseIn, address recipient) external returns (uint256 xTokenOut);\n\n  /// @notice Redeem fToken and xToken to base token.\n  /// @param fTokenIn The amount of fToken to redeem.\n  /// @param xTokenIn The amount of xToken to redeem.\n  /// @param owner The owner of the fToken or xToken.\n  /// @param baseOut The amount of underlying value of base token redeemed.\n  function redeem(\n    uint256 fTokenIn,\n    uint256 xTokenIn,\n    address owner\n  ) external returns (uint256 baseOut);\n\n  /// @notice Settle the nav of base token, fToken and xToken.\n  function settle() external;\n\n  /// @notice Transfer some base token to strategy contract.\n  /// @param amount The amount of token to transfer.\n  function transferToStrategy(uint256 amount) external;\n\n  /// @notice Notify base token profit from strategy contract.\n  /// @param amount The amount of base token.\n  function notifyStrategyProfit(uint256 amount) external;\n\n  /// @notice Harvest pending rewards to stability pool.\n  function harvest() external;\n}\n"},{"file_path":"contracts/libraries/BitMath.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\n\npragma solidity ^0.8.0;\n\n/// @title BitMath\n/// @dev This library provides functionality for computing bit properties of an unsigned integer\n///\n/// copy from: https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/BitMath.sol\nlibrary BitMath {\n    /// @notice Returns the index of the most significant bit of the number,\n    ///     where the least significant bit is at index 0 and the most significant bit is at index 255\n    /// @dev The function satisfies the property:\n    ///     x >= 2**mostSignificantBit(x) and x < 2**(mostSignificantBit(x)+1)\n    /// @param x the value for which to compute the most significant bit, must be greater than 0\n    /// @return r the index of the most significant bit\n    function mostSignificantBit(uint256 x) internal pure returns (uint8 r) {\n        require(x > 0);\n\n        if (x >= 0x100000000000000000000000000000000) {\n            x >>= 128;\n            r += 128;\n        }\n        if (x >= 0x10000000000000000) {\n            x >>= 64;\n            r += 64;\n        }\n        if (x >= 0x100000000) {\n            x >>= 32;\n            r += 32;\n        }\n        if (x >= 0x10000) {\n            x >>= 16;\n            r += 16;\n        }\n        if (x >= 0x100) {\n            x >>= 8;\n            r += 8;\n        }\n        if (x >= 0x10) {\n            x >>= 4;\n            r += 4;\n        }\n        if (x >= 0x4) {\n            x >>= 2;\n            r += 2;\n        }\n        if (x >= 0x2) r += 1;\n    }\n\n    /// @notice Returns the index of the least significant bit of the number,\n    ///     where the least significant bit is at index 0 and the most significant bit is at index 255\n    /// @dev The function satisfies the property:\n    ///     (x & 2**leastSignificantBit(x)) != 0 and (x & (2**(leastSignificantBit(x)) - 1)) == 0)\n    /// @param x the value for which to compute the least significant bit, must be greater than 0\n    /// @return r the index of the least significant bit\n    function leastSignificantBit(uint256 x) internal pure returns (uint8 r) {\n        require(x > 0);\n\n        r = 255;\n        if (x & type(uint128).max > 0) {\n            r -= 128;\n        } else {\n            x >>= 128;\n        }\n        if (x & type(uint64).max > 0) {\n            r -= 64;\n        } else {\n            x >>= 64;\n        }\n        if (x & type(uint32).max > 0) {\n            r -= 32;\n        } else {\n            x >>= 32;\n        }\n        if (x & type(uint16).max > 0) {\n            r -= 16;\n        } else {\n            x >>= 16;\n        }\n        if (x & type(uint8).max > 0) {\n            r -= 8;\n        } else {\n            x >>= 8;\n        }\n        if (x & 0xf > 0) {\n            r -= 4;\n        } else {\n            x >>= 4;\n        }\n        if (x & 0x3 > 0) {\n            r -= 2;\n        } else {\n            x >>= 2;\n        }\n        if (x & 0x1 > 0) r -= 1;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC20Permit} from \"../extensions/IERC20Permit.sol\";\nimport {Address} from \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using Address for address;\n\n    /**\n     * @dev An operation with an ERC20 token failed.\n     */\n    error SafeERC20FailedOperation(address token);\n\n    /**\n     * @dev Indicates a failed `decreaseAllowance` request.\n     */\n    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        forceApprove(token, spender, oldAllowance + value);\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n     * value, non-reverting calls are assumed to be successful.\n     */\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n        unchecked {\n            uint256 currentAllowance = token.allowance(address(this), spender);\n            if (currentAllowance < requestedDecrease) {\n                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n            }\n            forceApprove(token, spender, currentAllowance - requestedDecrease);\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n     * to be set to zero before setting it to a non-zero value, such as USDT.\n     */\n    function forceApprove(IERC20 token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data);\n        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n        // and not revert is the subcall reverts.\n\n        (bool success, bytes memory returndata) = address(token).call(data);\n        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;\n    }\n}\n"},{"file_path":"contracts/common/EIP2535/interfaces/IDiamond.sol","source_code":"// SPDX-License-Identifier: CC0-1.0\npragma solidity ^0.8.0;\n\n/******************************************************************************\\\n* Author: Nick Mudge <nick@perfectabstractions.com>, Twitter/Github: @mudgen\n* EIP-2535 Diamonds\n/******************************************************************************/\n\ninterface IDiamond {\n  enum FacetCutAction {\n    Add,\n    Replace,\n    Remove\n  }\n  // Add=0, Replace=1, Remove=2\n\n  struct FacetCut {\n    address facetAddress;\n    FacetCutAction action;\n    bytes4[] functionSelectors;\n  }\n\n  event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/security/ReentrancyGuardUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant _NOT_ENTERED = 1;\n    uint256 private constant _ENTERED = 2;\n\n    uint256 private _status;\n\n    function __ReentrancyGuard_init() internal onlyInitializing {\n        __ReentrancyGuard_init_unchained();\n    }\n\n    function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        // On the first call to nonReentrant, _status will be _NOT_ENTERED\n        require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n        // Any calls to nonReentrant after this point will fail\n        _status = _ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n     * `nonReentrant` function in the call stack.\n     */\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        return _status == _ENTERED;\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"},{"file_path":"contracts/mocks/MockMultipleRewardDistributor.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { LinearMultipleRewardDistributor } from \"../common/rewards/distributor/LinearMultipleRewardDistributor.sol\";\n\ncontract MockMultipleRewardDistributor is LinearMultipleRewardDistributor {\n  constructor() LinearMultipleRewardDistributor(1 weeks) {}\n\n  function initialize() external {\n    _grantRole(DEFAULT_ADMIN_ROLE, _msgSender());\n  }\n\n  function _accumulateReward(address _token, uint256 _amount) internal virtual override {}\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/utils/math/MathUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary MathUpgradeable {\n    enum Rounding {\n        Down, // Toward negative infinity\n        Up, // Toward infinity\n        Zero // Toward zero\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds up instead\n     * of rounding down.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n     * with further edits by Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod0 := mul(x, y)\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n                // The surrounding unchecked block does not change this fact.\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1, \"Math: mulDiv overflow\");\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n            // in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10 ** 64) {\n                value /= 10 ** 64;\n                result += 64;\n            }\n            if (value >= 10 ** 32) {\n                value /= 10 ** 32;\n                result += 32;\n            }\n            if (value >= 10 ** 16) {\n                value /= 10 ** 16;\n                result += 16;\n            }\n            if (value >= 10 ** 8) {\n                value /= 10 ** 8;\n                result += 8;\n            }\n            if (value >= 10 ** 4) {\n                value /= 10 ** 4;\n                result += 4;\n            }\n            if (value >= 10 ** 2) {\n                value /= 10 ** 2;\n                result += 2;\n            }\n            if (value >= 10 ** 1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\n        }\n    }\n}\n"},{"file_path":"contracts/interfaces/IFxUSDBasePool.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IFxUSDBasePool {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when the stable depeg price is updated.\n  /// @param oldPrice The value of previous depeg price, multiplied by 1e18.\n  /// @param newPrice The value of current depeg price, multiplied by 1e18.\n  event UpdateStableDepegPrice(uint256 oldPrice, uint256 newPrice);\n\n  /// @notice Emitted when the redeem cool down period is updated.\n  /// @param oldPeriod The value of previous redeem cool down period.\n  /// @param newPeriod The value of current redeem cool down period.\n  event UpdateRedeemCoolDownPeriod(uint256 oldPeriod, uint256 newPeriod);\n\n  /// @notice Emitted when deposit tokens.\n  /// @param caller The address of caller.\n  /// @param receiver The address of pool share recipient.\n  /// @param tokenIn The address of input token.\n  /// @param amountDeposited The amount of input tokens.\n  /// @param amountSharesOut The amount of pool shares minted.\n  event Deposit(\n    address indexed caller,\n    address indexed receiver,\n    address indexed tokenIn,\n    uint256 amountDeposited,\n    uint256 amountSharesOut\n  );\n  \n  /// @notice Emitted when users request redeem.\n  /// @param caller The address of caller.\n  /// @param shares The amount of shares to redeem.\n  /// @param unlockAt The timestamp when this share can be redeemed.\n  event RequestRedeem(address indexed caller, uint256 shares, uint256 unlockAt);\n\n  /// @notice Emitted when redeem pool shares.\n  /// @param caller The address of caller.\n  /// @param receiver The address of pool share recipient.\n  /// @param amountSharesToRedeem The amount of pool shares burned.\n  /// @param amountYieldTokenOut The amount of yield tokens redeemed.\n  /// @param amountStableTokenOut The amount of stable tokens redeemed.\n  event Redeem(\n    address indexed caller,\n    address indexed receiver,\n    uint256 amountSharesToRedeem,\n    uint256 amountYieldTokenOut,\n    uint256 amountStableTokenOut\n  );\n\n  /// @notice Emitted when rebalance or liquidate.\n  /// @param caller The address of caller.\n  /// @param tokenIn The address of input token.\n  /// @param amountTokenIn The amount of input token used.\n  /// @param amountCollateral The amount of collateral token rebalanced.\n  /// @param amountYieldToken The amount of yield token used.\n  /// @param amountStableToken The amount of stable token used.\n  event Rebalance(\n    address indexed caller,\n    address indexed tokenIn,\n    uint256 amountTokenIn,\n    uint256 amountCollateral,\n    uint256 amountYieldToken,\n    uint256 amountStableToken\n  );\n\n  /// @notice Emitted when arbitrage in curve pool.\n  /// @param caller The address of caller.\n  /// @param tokenIn The address of input token.\n  /// @param amountIn The amount of input token used.\n  /// @param amountOut The amount of output token swapped.\n  /// @param bonusOut The amount of bonus token.\n  event Arbitrage(\n    address indexed caller,\n    address indexed tokenIn,\n    uint256 amountIn,\n    uint256 amountOut,\n    uint256 bonusOut\n  );\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice The address of yield token.\n  function yieldToken() external view returns (address);\n\n  /// @notice The address of stable token.\n  function stableToken() external view returns (address);\n\n  /// @notice The total amount of yield token managed in this contract\n  function totalYieldToken() external view returns (uint256);\n\n  /// @notice The total amount of stable token managed in this contract\n  function totalStableToken() external view returns (uint256);\n\n  /// @notice The net asset value, multiplied by 1e18.\n  function nav() external view returns (uint256);\n\n  /// @notice Return the stable token price, multiplied by 1e18.\n  function getStableTokenPrice() external view returns (uint256);\n\n  /// @notice Return the stable token price with scaling to 18 decimals, multiplied by 1e18.\n  function getStableTokenPriceWithScale() external view returns (uint256);\n\n  /// @notice Preview the result of deposit.\n  /// @param tokenIn The address of input token.\n  /// @param amount The amount of input tokens to deposit.\n  /// @return amountSharesOut The amount of pool shares should receive.\n  function previewDeposit(address tokenIn, uint256 amount) external view returns (uint256 amountSharesOut);\n\n  /// @notice Preview the result of redeem.\n  /// @param amountSharesToRedeem The amount of pool shares to redeem.\n  /// @return amountYieldOut The amount of yield token should receive.\n  /// @return amountStableOut The amount of stable token should receive.\n  function previewRedeem(\n    uint256 amountSharesToRedeem\n  ) external view returns (uint256 amountYieldOut, uint256 amountStableOut);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Deposit token.\n  /// @param receiver The address of pool shares recipient.\n  /// @param tokenIn The address of input token.\n  /// @param amountTokenToDeposit The amount of input tokens to deposit.\n  /// @param minSharesOut The minimum amount of pool shares should receive.\n  /// @return amountSharesOut The amount of pool shares received.\n  function deposit(\n    address receiver,\n    address tokenIn,\n    uint256 amountTokenToDeposit,\n    uint256 minSharesOut\n  ) external returns (uint256 amountSharesOut);\n\n  /// @notice Request redeem.\n  /// @param shares The amount of shares to request.\n  function requestRedeem(uint256 shares) external;\n\n  /// @notice Redeem pool shares.\n  /// @param receiver The address of token recipient.\n  /// @param shares The amount of pool shares to redeem.\n  /// @return amountYieldOut The amount of yield token should received.\n  /// @return amountStableOut The amount of stable token should received.\n  function redeem(address receiver, uint256 shares) external returns (uint256 amountYieldOut, uint256 amountStableOut);\n\n  /// @notice Rebalance all positions in the given tick.\n  /// @param pool The address of pool to rebalance.\n  /// @param tick The index of tick to rebalance.\n  /// @param tokenIn The address of token to rebalance.\n  /// @param maxAmount The maximum amount of input token to rebalance.\n  /// @param minBaseOut The minimum amount of collateral tokens should receive.\n  /// @return tokenUsed The amount of input token used to rebalance.\n  /// @return baseOut The amount of collateral tokens rebalanced.\n  function rebalance(\n    address pool,\n    int16 tick,\n    address tokenIn,\n    uint256 maxAmount,\n    uint256 minBaseOut\n  ) external returns (uint256 tokenUsed, uint256 baseOut);\n\n  /// @notice Rebalance the give position.\n  /// @param pool The address of pool to rebalance.\n  /// @param position The index of position to rebalance.\n  /// @param tokenIn The address of token to rebalance.\n  /// @param maxAmount The maximum amount of input token to rebalance.\n  /// @param minBaseOut The minimum amount of collateral tokens should receive.\n  /// @return tokenUsed The amount of input token used to rebalance.\n  /// @return baseOut The amount of collateral tokens rebalanced.\n  function rebalance(\n    address pool,\n    uint32 position,\n    address tokenIn,\n    uint256 maxAmount,\n    uint256 minBaseOut\n  ) external returns (uint256 tokenUsed, uint256 baseOut);\n\n  /// @notice Liquidate the give position.\n  /// @param pool The address of pool to rebalance.\n  /// @param position The index of position to rebalance.\n  /// @param tokenIn The address of token to rebalance.\n  /// @param maxAmount The maximum amount of input token to rebalance.\n  /// @param minBaseOut The minimum amount of collateral tokens should receive.\n  /// @return tokenUsed The amount of input token used to rebalance.\n  /// @return baseOut The amount of collateral tokens rebalanced.\n  function liquidate(\n    address pool,\n    uint32 position,\n    address tokenIn,\n    uint256 maxAmount,\n    uint256 minBaseOut\n  ) external returns (uint256 tokenUsed, uint256 baseOut);\n\n  /// @notice Arbitrage between yield token and stable token.\n  /// @param srcToken The address of source token.\n  /// @param amountIn The amount of source token to use.\n  /// @param receiver The address of bonus receiver.\n  /// @param data The hook data to `onSwap`.\n  /// @return amountOut The amount of target token swapped.\n  /// @return bonusOut The amount of bonus token.\n  function arbitrage(\n    address srcToken,\n    uint256 amountIn,\n    address receiver,\n    bytes calldata data\n  ) external returns (uint256 amountOut, uint256 bonusOut);\n}\n"},{"file_path":"contracts/libraries/Math.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nlibrary Math {\n  enum Rounding {\n    Up,\n    Down\n  }\n\n  /// @dev Internal return the value of min(a, b).\n  function min(uint256 a, uint256 b) internal pure returns (uint256) {\n    return a < b ? a : b;\n  }\n\n  /// @dev Internal return the value of max(a, b).\n  function max(uint256 a, uint256 b) internal pure returns (uint256) {\n    return a > b ? a : b;\n  }\n\n  /// @dev Internal return the value of a * b / c, with rounding.\n  function mulDiv(uint256 a, uint256 b, uint256 c, Rounding rounding) internal pure returns (uint256) {\n    return rounding == Rounding.Down ? mulDivDown(a, b, c) : mulDivUp(a, b, c);\n  }\n\n  /// @dev Internal return the value of ceil(a * b / c).\n  function mulDivUp(uint256 a, uint256 b, uint256 c) internal pure returns (uint256) {\n    return (a * b + c - 1) / c;\n  }\n\n  /// @dev Internal return the value of floor(a * b / c).\n  function mulDivDown(uint256 a, uint256 b, uint256 c) internal pure returns (uint256) {\n    return (a * b) / c;\n  }\n}\n"},{"file_path":"contracts/helpers/EmptyContract.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\ncontract EmptyContract {}\n"},{"file_path":"@openzeppelin/contracts/utils/Strings.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)\n\npragma solidity ^0.8.20;\n\nimport {Math} from \"./math/Math.sol\";\nimport {SignedMath} from \"./math/SignedMath.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant HEX_DIGITS = \"0123456789abcdef\";\n    uint8 private constant ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev The `value` string doesn't fit in the specified `length`.\n     */\n    error StringsInsufficientHexLength(uint256 value, uint256 length);\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            uint256 length = Math.log10(value) + 1;\n            string memory buffer = new string(length);\n            uint256 ptr;\n            /// @solidity memory-safe-assembly\n            assembly {\n                ptr := add(buffer, add(32, length))\n            }\n            while (true) {\n                ptr--;\n                /// @solidity memory-safe-assembly\n                assembly {\n                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))\n                }\n                value /= 10;\n                if (value == 0) break;\n            }\n            return buffer;\n        }\n    }\n\n    /**\n     * @dev Converts a `int256` to its ASCII `string` decimal representation.\n     */\n    function toStringSigned(int256 value) internal pure returns (string memory) {\n        return string.concat(value < 0 ? \"-\" : \"\", toString(SignedMath.abs(value)));\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            return toHexString(value, Math.log256(value) + 1);\n        }\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        uint256 localValue = value;\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i > 1; --i) {\n            buffer[i] = HEX_DIGITS[localValue & 0xf];\n            localValue >>= 4;\n        }\n        if (localValue != 0) {\n            revert StringsInsufficientHexLength(value, length);\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal\n     * representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);\n    }\n\n    /**\n     * @dev Returns true if the two strings are equal.\n     */\n    function equal(string memory a, string memory b) internal pure returns (bool) {\n        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));\n    }\n}\n"},{"file_path":"contracts/interfaces/IWrappedEther.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IWrappedEther {\n  function deposit() external payable;\n\n  function withdraw(uint256 wad) external;\n}\n"},{"file_path":"contracts/core/pool/PoolStorage.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { AccessControlUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\";\nimport { ERC721Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol\";\n\nimport { IPool } from \"../../interfaces/IPool.sol\";\n\nimport { WordCodec } from \"../../common/codec/WordCodec.sol\";\nimport { PoolConstant } from \"./PoolConstant.sol\";\nimport { PoolErrors } from \"./PoolErrors.sol\";\n\nabstract contract PoolStorage is ERC721Upgradeable, AccessControlUpgradeable, PoolConstant, PoolErrors {\n  using WordCodec for bytes32;\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev Below are offsets of each variables in `miscData`.\n  uint256 private constant BORROW_FLAG_OFFSET = 0;\n  uint256 private constant REDEEM_FLAG_OFFSET = 1;\n  uint256 private constant TOP_TICK_OFFSET = 2;\n  uint256 private constant NEXT_POSITION_OFFSET = 18;\n  uint256 private constant NEXT_NODE_OFFSET = 50;\n  uint256 private constant MIN_DEBT_RATIO_OFFSET = 98;\n  uint256 private constant MAX_DEBT_RATIO_OFFSET = 158;\n  uint256 private constant MAX_REDEEM_RATIO_OFFSET = 218;\n\n  /// @dev Below are offsets of each variables in `rebalanceRatioData`.\n  uint256 private constant REBALANCE_DEBT_RATIO_OFFSET = 0;\n  uint256 private constant REBALANCE_BONUS_RATIO_OFFSET = 60;\n  uint256 private constant LIQUIDATE_DEBT_RATIO_OFFSET = 90;\n  uint256 private constant LIQUIDATE_BONUS_RATIO_OFFSET = 150;\n\n  /// @dev Below are offsets of each variables in `indexData`.\n  uint256 private constant DEBT_INDEX_OFFSET = 0;\n  uint256 private constant COLLATERAL_INDEX_OFFSET = 128;\n\n  /// @dev Below are offsets of each variables in `sharesData`.\n  uint256 private constant DEBT_SHARES_OFFSET = 0;\n  uint256 private constant COLLATERAL_SHARES_OFFSET = 128;\n\n  /***********\n   * Structs *\n   ***********/\n\n  /// @dev if nodeId = 0, tick is not used and this position only has collateral\n  ///\n  /// @param tick The tick this position belongs to at the beginning.\n  /// @param nodeId The tree node id this position belongs to at the beginning.\n  /// @param colls The collateral shares this position has.\n  /// @param debts The debt shares this position has.\n  struct PositionInfo {\n    int16 tick;\n    uint48 nodeId;\n    // `uint96` is enough, since we use `86` bits in `PoolManager`.\n    uint96 colls;\n    // `uint96` is enough, since we use `96` bits in `PoolManager`.\n    uint96 debts;\n  }\n\n  /// @dev The compiler will pack it into two `uint256`.\n  /// @param metadata The metadata for tree node.\n  ///   ```text\n  ///   * Field           Bits    Index       Comments\n  ///   * parent          48      0           The index for parent tree node.\n  ///   * tick            16      48          The original tick for this tree node.\n  ///   * coll ratio      64      64          The remained coll share ratio base on parent node, the value is real ratio * 2^60.\n  ///   * debt ratio      64      128         The remained debt share ratio base on parent node, the value is real ratio * 2^60.\n  ///   ```\n  /// @param value The value for tree node\n  ///   ```text\n  ///   * Field           Bits    Index       Comments\n  ///   * coll share      128     0           The original total coll share before rebalance or redeem.\n  ///   * debt share      128     128         The original total debt share before rebalance or redeem.\n  ///   ```\n  struct TickTreeNode {\n    bytes32 metadata;\n    bytes32 value;\n  }\n\n  /*********************\n   * Storage Variables *\n   *********************/\n\n  /// @inheritdoc IPool\n  address public collateralToken;\n\n  /// @inheritdoc IPool\n  address public priceOracle;\n\n  /// @dev `miscData` is a storage slot that can be used to store unrelated pieces of information.\n  ///\n  /// - The *borrow flag* indicates whether borrow fxUSD is allowed, 1 means paused.\n  /// - The *redeem flag* indicates whether redeem fxUSD is allowed, 1 means paused.\n  /// - The *top tick* is the largest tick with debts.\n  /// - The *next position* is the next unassigned position id.\n  /// - The *next node* is the next unassigned tree node id.\n  /// - The *min debt ratio* is the minimum allowed debt ratio, multiplied by 1e18.\n  /// - The *max debt ratio* is the maximum allowed debt ratio, multiplied by 1e18.\n  /// - The *max redeem ratio* is the maximum allowed redeem ratio per tick, multiplied by 1e9.\n  ///\n  /// [ borrow flag | redeem flag | top tick | next position | next node | min debt ratio | max debt ratio | max redeem ratio | reserved ]\n  /// [    1 bit    |    1 bit    | 16  bits |    32 bits    |  48 bits  |    60  bits    |    60  bits    |      30 bits     |  8 bits  ]\n  /// [ MSB                                                                                                                          LSB ]\n  bytes32 private miscData;\n\n  /// @dev `rebalanceRatioData` is a storage slot used to store rebalance and liquidate information.\n  ///\n  /// - The *rebalance debt ratio* is the min debt ratio to start rebalance, multiplied by 1e18.\n  /// - The *rebalance bonus ratio* is the bonus ratio during rebalance, multiplied by 1e9.\n  /// - The *liquidate debt ratio* is the min debt ratio to start liquidate, multiplied by 1e18.\n  /// - The *liquidate bonus ratio* is the bonus ratio during liquidate, multiplied by 1e9.\n  ///\n  /// [ rebalance debt ratio | rebalance bonus ratio | liquidate debt ratio | liquidate bonus ratio | reserved ]\n  /// [       60  bits       |        30 bits        |       60  bits       |        30 bits        | 76  bits ]\n  /// [ MSB                                                                                                LSB ]\n  bytes32 private rebalanceRatioData;\n\n  /// @dev `indexData` is a storage slot used to store debt/collateral index.\n  ///\n  /// - The *debt index* is the index for each debt shares, only increasing, starting from 2^96, max 2^128-1.\n  /// - The *collateral index* is the index for each collateral shares, only increasing, starting from 2^96, max 2^128-1\n  ///\n  /// [ debt index | collateral index ]\n  /// [  128 bits  |     128 bits     ]\n  /// [ MSB                       LSB ]\n  bytes32 private indexData;\n\n  /// @dev `sharesData` is a storage slot used to store debt/collateral shares.\n  ///\n  /// - The *debt shares* is the total debt shares. The actual number of total debts\n  ///   is `<debt shares> * <debt index>`.\n  /// - The *collateral shares* is the total collateral shares. The actual number of\n  ///   total collateral is `<collateral shares> / <collateral index>`.\n  ///\n  /// [ debt shares | collateral shares ]\n  /// [  128  bits  |     128  bits     ]\n  /// [ MSB                         LSB ]\n  bytes32 private sharesData;\n\n  /// @dev Mapping from position id to position information.\n  mapping(uint256 => PositionInfo) public positionData;\n\n  /// @dev Mapping from position id to position metadata.\n  /// [ open timestamp | reserved ]\n  /// [    40  bits    | 216 bits ]\n  /// [ MSB                   LSB ]\n  mapping(uint256 => bytes32) public positionMetadata;\n\n  /// @dev The bitmap for ticks with debts.\n  mapping(int8 => uint256) public tickBitmap;\n\n  /// @dev Mapping from tick to tree node id.\n  mapping(int256 => uint48) public tickData;\n\n  /// @dev Mapping from tree node id to tree node data.\n  mapping(uint256 => TickTreeNode) public tickTreeData;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  function __PoolStorage_init(address _collateralToken, address _priceOracle) internal onlyInitializing {\n    _checkAddressNotZero(_collateralToken);\n\n    collateralToken = _collateralToken;\n    _updatePriceOracle(_priceOracle);\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @inheritdoc AccessControlUpgradeable\n  function supportsInterface(\n    bytes4 interfaceId\n  ) public view virtual override(AccessControlUpgradeable, ERC721Upgradeable) returns (bool) {\n    return super.supportsInterface(interfaceId);\n  }\n\n  /// @inheritdoc IPool\n  function isBorrowPaused() external view returns (bool) {\n    return _isBorrowPaused();\n  }\n\n  /// @inheritdoc IPool\n  function isRedeemPaused() external view returns (bool) {\n    return _isRedeemPaused();\n  }\n\n  /// @inheritdoc IPool\n  function getTopTick() external view returns (int16) {\n    return _getTopTick();\n  }\n\n  /// @inheritdoc IPool\n  function getNextPositionId() external view returns (uint32) {\n    return _getNextPositionId();\n  }\n\n  /// @inheritdoc IPool\n  function getNextTreeNodeId() external view returns (uint48) {\n    return _getNextTreeNodeId();\n  }\n\n  /// @inheritdoc IPool\n  function getDebtRatioRange() external view returns (uint256, uint256) {\n    return _getDebtRatioRange();\n  }\n\n  /// @inheritdoc IPool\n  function getMaxRedeemRatioPerTick() external view returns (uint256) {\n    return _getMaxRedeemRatioPerTick();\n  }\n\n  /// @inheritdoc IPool\n  function getRebalanceRatios() external view returns (uint256, uint256) {\n    return _getRebalanceRatios();\n  }\n\n  /// @inheritdoc IPool\n  function getLiquidateRatios() external view returns (uint256, uint256) {\n    return _getLiquidateRatios();\n  }\n\n  /// @inheritdoc IPool\n  function getDebtAndCollateralIndex() external view returns (uint256, uint256) {\n    return _getDebtAndCollateralIndex();\n  }\n\n  /// @inheritdoc IPool\n  function getDebtAndCollateralShares() external view returns (uint256, uint256) {\n    return _getDebtAndCollateralShares();\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to update price oracle.\n  /// @param newOracle The address of new price oracle;\n  function _updatePriceOracle(address newOracle) internal {\n    _checkAddressNotZero(newOracle);\n\n    address oldOracle = priceOracle;\n    priceOracle = newOracle;\n\n    emit UpdatePriceOracle(oldOracle, newOracle);\n  }\n\n  /*************************************\n   * Internal Functions For `miscData` *\n   *************************************/\n\n  /// @dev Internal function to get the borrow pause status.\n  function _isBorrowPaused() internal view returns (bool) {\n    return miscData.decodeBool(BORROW_FLAG_OFFSET);\n  }\n\n  /// @dev Internal function to update borrow pause status.\n  /// @param status The status to update.\n  function _updateBorrowStatus(bool status) internal {\n    miscData = miscData.insertBool(status, BORROW_FLAG_OFFSET);\n\n    emit UpdateBorrowStatus(status);\n  }\n\n  /// @dev Internal function to get the redeem pause status.\n  function _isRedeemPaused() internal view returns (bool) {\n    return miscData.decodeBool(REDEEM_FLAG_OFFSET);\n  }\n\n  /// @dev Internal function to update redeem pause status.\n  /// @param status The status to update.\n  function _updateRedeemStatus(bool status) internal {\n    miscData = miscData.insertBool(status, REDEEM_FLAG_OFFSET);\n\n    emit UpdateRedeemStatus(status);\n  }\n\n  /// @dev Internal function to get the value of top tick.\n  function _getTopTick() internal view returns (int16) {\n    return int16(miscData.decodeInt(TOP_TICK_OFFSET, 16));\n  }\n\n  /// @dev Internal function to update the top tick.\n  /// @param tick The new top tick.\n  function _updateTopTick(int16 tick) internal {\n    miscData = miscData.insertInt(tick, TOP_TICK_OFFSET, 16);\n  }\n\n  /// @dev Internal function to get next available position id.\n  function _getNextPositionId() internal view returns (uint32) {\n    return uint32(miscData.decodeUint(NEXT_POSITION_OFFSET, 32));\n  }\n\n  /// @dev Internal function to update next available position id.\n  /// @param id The position id to update.\n  function _updateNextPositionId(uint32 id) internal {\n    miscData = miscData.insertUint(id, NEXT_POSITION_OFFSET, 32);\n  }\n\n  /// @dev Internal function to get next available tree node id.\n  function _getNextTreeNodeId() internal view returns (uint48) {\n    return uint48(miscData.decodeUint(NEXT_NODE_OFFSET, 48));\n  }\n\n  /// @dev Internal function to update next available tree node id.\n  /// @param id The tree node id to update.\n  function _updateNextTreeNodeId(uint48 id) internal {\n    miscData = miscData.insertUint(id, NEXT_NODE_OFFSET, 48);\n  }\n\n  /// @dev Internal function to get `minDebtRatio` and `maxDebtRatio`, both multiplied by 1e18.\n  function _getDebtRatioRange() internal view returns (uint256 minDebtRatio, uint256 maxDebtRatio) {\n    bytes32 data = miscData;\n    minDebtRatio = data.decodeUint(MIN_DEBT_RATIO_OFFSET, 60);\n    maxDebtRatio = data.decodeUint(MAX_DEBT_RATIO_OFFSET, 60);\n  }\n\n  /// @dev Internal function to update debt ratio range.\n  /// @param minDebtRatio The minimum allowed debt ratio to update, multiplied by 1e18.\n  /// @param maxDebtRatio The maximum allowed debt ratio to update, multiplied by 1e18.\n  function _updateDebtRatioRange(uint256 minDebtRatio, uint256 maxDebtRatio) internal {\n    _checkValueTooLarge(minDebtRatio, maxDebtRatio);\n    _checkValueTooLarge(maxDebtRatio, PRECISION);\n\n    bytes32 data = miscData;\n    data = data.insertUint(minDebtRatio, MIN_DEBT_RATIO_OFFSET, 60);\n    miscData = data.insertUint(maxDebtRatio, MAX_DEBT_RATIO_OFFSET, 60);\n\n    emit UpdateDebtRatioRange(minDebtRatio, maxDebtRatio);\n  }\n\n  /// @dev Internal function to get the `maxRedeemRatioPerTick`.\n  function _getMaxRedeemRatioPerTick() internal view returns (uint256) {\n    return miscData.decodeUint(MAX_REDEEM_RATIO_OFFSET, 30);\n  }\n\n  /// @dev Internal function to update maximum redeem ratio per tick.\n  /// @param ratio The ratio to update, multiplied by 1e9.\n  function _updateMaxRedeemRatioPerTick(uint256 ratio) internal {\n    _checkValueTooLarge(ratio, FEE_PRECISION);\n\n    miscData = miscData.insertUint(ratio, MAX_REDEEM_RATIO_OFFSET, 30);\n\n    emit UpdateMaxRedeemRatioPerTick(ratio);\n  }\n\n  /***********************************************\n   * Internal Functions For `rebalanceRatioData` *\n   ***********************************************/\n\n  /// @dev Internal function to get `debtRatio` and `bonusRatio` for rebalance.\n  /// @return debtRatio The minimum debt ratio to start rebalance, multiplied by 1e18.\n  /// @return bonusRatio The bonus ratio during rebalance, multiplied by 1e9.\n  function _getRebalanceRatios() internal view returns (uint256 debtRatio, uint256 bonusRatio) {\n    bytes32 data = rebalanceRatioData;\n    debtRatio = data.decodeUint(REBALANCE_DEBT_RATIO_OFFSET, 60);\n    bonusRatio = data.decodeUint(REBALANCE_BONUS_RATIO_OFFSET, 30);\n  }\n\n  /// @dev Internal function to update ratio for rebalance.\n  /// @param debtRatio The minimum debt ratio to start rebalance, multiplied by 1e18.\n  /// @param bonusRatio The bonus ratio during rebalance, multiplied by 1e9.\n  function _updateRebalanceRatios(uint256 debtRatio, uint256 bonusRatio) internal {\n    _checkValueTooLarge(debtRatio, PRECISION);\n    _checkValueTooLarge(bonusRatio, FEE_PRECISION);\n\n    bytes32 data = rebalanceRatioData;\n    data = data.insertUint(debtRatio, REBALANCE_DEBT_RATIO_OFFSET, 60);\n    rebalanceRatioData = data.insertUint(bonusRatio, REBALANCE_BONUS_RATIO_OFFSET, 30);\n\n    emit UpdateRebalanceRatios(debtRatio, bonusRatio);\n  }\n\n  /// @dev Internal function to get `debtRatio` and `bonusRatio` for liquidate.\n  /// @return debtRatio The minimum debt ratio to start liquidate, multiplied by 1e18.\n  /// @return bonusRatio The bonus ratio during liquidate, multiplied by 1e9.\n  function _getLiquidateRatios() internal view returns (uint256 debtRatio, uint256 bonusRatio) {\n    bytes32 data = rebalanceRatioData;\n    debtRatio = data.decodeUint(LIQUIDATE_DEBT_RATIO_OFFSET, 60);\n    bonusRatio = data.decodeUint(LIQUIDATE_BONUS_RATIO_OFFSET, 30);\n  }\n\n  /// @dev Internal function to update ratio for liquidate.\n  /// @param debtRatio The minimum debt ratio to start liquidate, multiplied by 1e18.\n  /// @param bonusRatio The bonus ratio during liquidate, multiplied by 1e9.\n  function _updateLiquidateRatios(uint256 debtRatio, uint256 bonusRatio) internal {\n    _checkValueTooLarge(debtRatio, PRECISION);\n    _checkValueTooLarge(bonusRatio, FEE_PRECISION);\n\n    bytes32 data = rebalanceRatioData;\n    data = data.insertUint(debtRatio, LIQUIDATE_DEBT_RATIO_OFFSET, 60);\n    rebalanceRatioData = data.insertUint(bonusRatio, LIQUIDATE_BONUS_RATIO_OFFSET, 30);\n\n    emit UpdateLiquidateRatios(debtRatio, bonusRatio);\n  }\n\n  /**************************************\n   * Internal Functions For `indexData` *\n   **************************************/\n\n  /// @dev Internal function to get debt and collateral index.\n  /// @return debtIndex The index for debt shares.\n  /// @return collIndex The index for collateral shares.\n  function _getDebtAndCollateralIndex() internal view returns (uint256 debtIndex, uint256 collIndex) {\n    bytes32 data = indexData;\n    debtIndex = data.decodeUint(DEBT_INDEX_OFFSET, 128);\n    collIndex = data.decodeUint(COLLATERAL_INDEX_OFFSET, 128);\n  }\n\n  /// @dev Internal function to update debt index.\n  /// @param index The debt index to update.\n  function _updateDebtIndex(uint256 index) internal {\n    indexData = indexData.insertUint(index, DEBT_INDEX_OFFSET, 128);\n\n    emit DebtIndexSnapshot(index);\n  }\n\n  /// @dev Internal function to update collateral index.\n  /// @param index The collateral index to update.\n  function _updateCollateralIndex(uint256 index) internal {\n    indexData = indexData.insertUint(index, COLLATERAL_INDEX_OFFSET, 128);\n\n    emit CollateralIndexSnapshot(index);\n  }\n\n  /**************************************\n   * Internal Functions For `sharesData` *\n   **************************************/\n\n  /// @dev Internal function to get debt and collateral shares.\n  /// @return debtShares The total number of debt shares.\n  /// @return collShares The total number of collateral shares.\n  function _getDebtAndCollateralShares() internal view returns (uint256 debtShares, uint256 collShares) {\n    bytes32 data = sharesData;\n    debtShares = data.decodeUint(DEBT_SHARES_OFFSET, 128);\n    collShares = data.decodeUint(COLLATERAL_SHARES_OFFSET, 128);\n  }\n\n  /// @dev Internal function to update debt and collateral shares.\n  /// @param debtShares The debt shares to update.\n  /// @param collShares The collateral shares to update.\n  function _updateDebtAndCollateralShares(uint256 debtShares, uint256 collShares) internal {\n    bytes32 data = sharesData;\n    data = data.insertUint(debtShares, DEBT_SHARES_OFFSET, 128);\n    sharesData = data.insertUint(collShares, COLLATERAL_SHARES_OFFSET, 128);\n  }\n\n  /// @dev Internal function to update debt shares.\n  /// @param shares The debt shares to update.\n  function _updateDebtShares(uint256 shares) internal {\n    sharesData = sharesData.insertUint(shares, DEBT_SHARES_OFFSET, 128);\n  }\n\n  /// @dev Internal function to update collateral shares.\n  /// @param shares The collateral shares to update.\n  function _updateCollateralShares(uint256 shares) internal {\n    sharesData = sharesData.insertUint(shares, COLLATERAL_SHARES_OFFSET, 128);\n  }\n\n  /**\n   * @dev This empty reserved space is put in place to allow future versions to add new\n   * variables without shifting down storage in the inheritance chain.\n   */\n  uint256[40] private __gap;\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"},{"file_path":"contracts/core/PegKeeper.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { AccessControlUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\";\n\nimport { IMultiPathConverter } from \"../helpers/interfaces/IMultiPathConverter.sol\";\nimport { ICurveStableSwapNG } from \"../interfaces/Curve/ICurveStableSwapNG.sol\";\nimport { IFxUSDRegeneracy } from \"../interfaces/IFxUSDRegeneracy.sol\";\nimport { IPegKeeper } from \"../interfaces/IPegKeeper.sol\";\nimport { IFxUSDBasePool } from \"../interfaces/IFxUSDBasePool.sol\";\n\ncontract PegKeeper is AccessControlUpgradeable, IPegKeeper {\n  using SafeERC20 for IERC20;\n\n  /**********\n   * Errors *\n   **********/\n\n  error ErrorNotInCallbackContext();\n\n  error ErrorZeroAddress();\n\n  error ErrorInsufficientOutput();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The precision used to compute nav.\n  uint256 private constant PRECISION = 1e18;\n\n  /// @notice The role for buyback.\n  bytes32 public constant BUYBACK_ROLE = keccak256(\"BUYBACK_ROLE\");\n\n  /// @notice The role for stabilize.\n  bytes32 public constant STABILIZE_ROLE = keccak256(\"STABILIZE_ROLE\");\n\n  /// @dev contexts for buyback and stabilize callback\n  uint8 private constant CONTEXT_NO_CONTEXT = 1;\n  uint8 private constant CONTEXT_BUYBACK = 2;\n  uint8 private constant CONTEXT_STABILIZE = 3;\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @notice The address of fxUSD.\n  address public immutable fxUSD;\n\n  /// @notice The address of stable token.\n  address public immutable stable;\n\n  /// @notice The address of FxUSDBasePool.\n  address public immutable fxBASE;\n\n  /*********************\n   * Storage Variables *\n   *********************/\n\n  /// @dev The context for buyback and stabilize callback.\n  uint8 private context;\n\n  /// @notice The address of MultiPathConverter.\n  address public converter;\n\n  /// @notice The curve pool for stable and fxUSD\n  address public curvePool;\n\n  /// @notice The fxUSD depeg price threshold.\n  uint256 public priceThreshold;\n\n  /*************\n   * Modifiers *\n   *************/\n\n  modifier setContext(uint8 c) {\n    context = c;\n    _;\n    context = CONTEXT_NO_CONTEXT;\n  }\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _fxBASE) {\n    fxBASE = _fxBASE;\n    fxUSD = IFxUSDBasePool(_fxBASE).yieldToken();\n    stable = IFxUSDBasePool(_fxBASE).stableToken();\n  }\n\n  function initialize(address admin, address _converter, address _curvePool) external initializer {\n    __Context_init();\n    __ERC165_init();\n    __AccessControl_init();\n\n    _grantRole(DEFAULT_ADMIN_ROLE, admin);\n\n    _updateConverter(_converter);\n    _updateCurvePool(_curvePool);\n    _updatePriceThreshold(995000000000000000); // 0.995\n\n    context = CONTEXT_NO_CONTEXT;\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @inheritdoc IPegKeeper\n  function isBorrowAllowed() external view returns (bool) {\n    return _getFxUSDEmaPrice() >= priceThreshold;\n  }\n\n  /// @inheritdoc IPegKeeper\n  function isFundingEnabled() external view returns (bool) {\n    return _getFxUSDEmaPrice() < priceThreshold;\n  }\n\n  /// @inheritdoc IPegKeeper\n  function getFxUSDPrice() external view returns (uint256) {\n    return _getFxUSDEmaPrice();\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc IPegKeeper\n  function buyback(\n    uint256 amountIn,\n    bytes calldata data\n  ) external onlyRole(BUYBACK_ROLE) setContext(CONTEXT_BUYBACK) returns (uint256 amountOut, uint256 bonus) {\n    (amountOut, bonus) = IFxUSDRegeneracy(fxUSD).buyback(amountIn, _msgSender(), data);\n  }\n\n  /// @inheritdoc IPegKeeper\n  function stabilize(\n    address srcToken,\n    uint256 amountIn,\n    bytes calldata data\n  ) external onlyRole(STABILIZE_ROLE) setContext(CONTEXT_STABILIZE) returns (uint256 amountOut, uint256 bonus) {\n    (amountOut, bonus) = IFxUSDBasePool(fxBASE).arbitrage(srcToken, amountIn, _msgSender(), data);\n  }\n\n  /// @inheritdoc IPegKeeper\n  /// @dev This function will be called in `buyback`, `stabilize`.\n  function onSwap(\n    address srcToken,\n    address targetToken,\n    uint256 amountIn,\n    bytes calldata data\n  ) external returns (uint256 amountOut) {\n    // check callback validity\n    if (context == CONTEXT_NO_CONTEXT) revert ErrorNotInCallbackContext();\n\n    amountOut = _doSwap(srcToken, amountIn, data);\n    IERC20(targetToken).safeTransfer(_msgSender(), amountOut);\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Update the address of converter.\n  /// @param newConverter The address of converter.\n  function updateConverter(address newConverter) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateConverter(newConverter);\n  }\n\n  /// @notice Update the address of curve pool.\n  /// @param newPool The address of curve pool.\n  function updateCurvePool(address newPool) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateCurvePool(newPool);\n  }\n\n  /// @notice Update the value of depeg price threshold.\n  /// @param newThreshold The value of new price threshold.\n  function updatePriceThreshold(uint256 newThreshold) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updatePriceThreshold(newThreshold);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to update the address of converter.\n  /// @param newConverter The address of converter.\n  function _updateConverter(address newConverter) internal {\n    if (newConverter == address(0)) revert ErrorZeroAddress();\n\n    address oldConverter = converter;\n    converter = newConverter;\n\n    emit UpdateConverter(oldConverter, newConverter);\n  }\n\n  /// @dev Internal function to update the address of curve pool.\n  /// @param newPool The address of curve pool.\n  function _updateCurvePool(address newPool) internal {\n    if (newPool == address(0)) revert ErrorZeroAddress();\n\n    address oldPool = curvePool;\n    curvePool = newPool;\n\n    emit UpdateCurvePool(oldPool, newPool);\n  }\n\n  /// @dev Internal function to update the value of depeg price threshold.\n  /// @param newThreshold The value of new price threshold.\n  function _updatePriceThreshold(uint256 newThreshold) internal {\n    uint256 oldThreshold = priceThreshold;\n    priceThreshold = newThreshold;\n\n    emit UpdatePriceThreshold(oldThreshold, newThreshold);\n  }\n\n  /// @dev Internal function to do swap.\n  /// @param srcToken The address of source token.\n  /// @param amountIn The amount of token to use.\n  /// @param data The callback data.\n  /// @return amountOut The amount of token swapped.\n  function _doSwap(address srcToken, uint256 amountIn, bytes calldata data) internal returns (uint256 amountOut) {\n    IERC20(srcToken).forceApprove(converter, amountIn);\n\n    (uint256 minOut, uint256 encoding, uint256[] memory routes) = abi.decode(data, (uint256, uint256, uint256[]));\n    amountOut = IMultiPathConverter(converter).convert(srcToken, amountIn, encoding, routes);\n    if (amountOut < minOut) revert ErrorInsufficientOutput();\n  }\n\n  /// @dev Internal function to get curve ema price for fxUSD.\n  /// @return price The value of ema price, multiplied by 1e18.\n  function _getFxUSDEmaPrice() internal view returns (uint256 price) {\n    address cachedCurvePool = curvePool; // gas saving\n    address firstCoin = ICurveStableSwapNG(cachedCurvePool).coins(0);\n    price = ICurveStableSwapNG(cachedCurvePool).price_oracle(0);\n    if (firstCoin == fxUSD) {\n      price = (PRECISION * PRECISION) / price;\n    }\n  }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {IERC20Metadata} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport {ContextUpgradeable} from \"../../utils/ContextUpgradeable.sol\";\nimport {IERC20Errors} from \"@openzeppelin/contracts/interfaces/draft-IERC6093.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n */\nabstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, IERC20Metadata, IERC20Errors {\n    /// @custom:storage-location erc7201:openzeppelin.storage.ERC20\n    struct ERC20Storage {\n        mapping(address account => uint256) _balances;\n\n        mapping(address account => mapping(address spender => uint256)) _allowances;\n\n        uint256 _totalSupply;\n\n        string _name;\n        string _symbol;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.ERC20\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant ERC20StorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00;\n\n    function _getERC20Storage() private pure returns (ERC20Storage storage $) {\n        assembly {\n            $.slot := ERC20StorageLocation\n        }\n    }\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {\n        __ERC20_init_unchained(name_, symbol_);\n    }\n\n    function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {\n        ERC20Storage storage $ = _getERC20Storage();\n        $._name = name_;\n        $._symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual returns (string memory) {\n        ERC20Storage storage $ = _getERC20Storage();\n        return $._name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual returns (string memory) {\n        ERC20Storage storage $ = _getERC20Storage();\n        return $._symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the default value returned by this function, unless\n     * it's overridden.\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual returns (uint256) {\n        ERC20Storage storage $ = _getERC20Storage();\n        return $._totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual returns (uint256) {\n        ERC20Storage storage $ = _getERC20Storage();\n        return $._balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - the caller must have a balance of at least `value`.\n     */\n    function transfer(address to, uint256 value) public virtual returns (bool) {\n        address owner = _msgSender();\n        _transfer(owner, to, value);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual returns (uint256) {\n        ERC20Storage storage $ = _getERC20Storage();\n        return $._allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on\n     * `transferFrom`. This is semantically equivalent to an infinite approval.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 value) public virtual returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, value);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * NOTE: Does not update the allowance if the current allowance\n     * is the maximum `uint256`.\n     *\n     * Requirements:\n     *\n     * - `from` and `to` cannot be the zero address.\n     * - `from` must have a balance of at least `value`.\n     * - the caller must have allowance for ``from``'s tokens of at least\n     * `value`.\n     */\n    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {\n        address spender = _msgSender();\n        _spendAllowance(from, spender, value);\n        _transfer(from, to, value);\n        return true;\n    }\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * NOTE: This function is not virtual, {_update} should be overridden instead.\n     */\n    function _transfer(address from, address to, uint256 value) internal {\n        if (from == address(0)) {\n            revert ERC20InvalidSender(address(0));\n        }\n        if (to == address(0)) {\n            revert ERC20InvalidReceiver(address(0));\n        }\n        _update(from, to, value);\n    }\n\n    /**\n     * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`\n     * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding\n     * this function.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _update(address from, address to, uint256 value) internal virtual {\n        ERC20Storage storage $ = _getERC20Storage();\n        if (from == address(0)) {\n            // Overflow check required: The rest of the code assumes that totalSupply never overflows\n            $._totalSupply += value;\n        } else {\n            uint256 fromBalance = $._balances[from];\n            if (fromBalance < value) {\n                revert ERC20InsufficientBalance(from, fromBalance, value);\n            }\n            unchecked {\n                // Overflow not possible: value <= fromBalance <= totalSupply.\n                $._balances[from] = fromBalance - value;\n            }\n        }\n\n        if (to == address(0)) {\n            unchecked {\n                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.\n                $._totalSupply -= value;\n            }\n        } else {\n            unchecked {\n                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.\n                $._balances[to] += value;\n            }\n        }\n\n        emit Transfer(from, to, value);\n    }\n\n    /**\n     * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).\n     * Relies on the `_update` mechanism\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * NOTE: This function is not virtual, {_update} should be overridden instead.\n     */\n    function _mint(address account, uint256 value) internal {\n        if (account == address(0)) {\n            revert ERC20InvalidReceiver(address(0));\n        }\n        _update(address(0), account, value);\n    }\n\n    /**\n     * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.\n     * Relies on the `_update` mechanism.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * NOTE: This function is not virtual, {_update} should be overridden instead\n     */\n    function _burn(address account, uint256 value) internal {\n        if (account == address(0)) {\n            revert ERC20InvalidSender(address(0));\n        }\n        _update(account, address(0), value);\n    }\n\n    /**\n     * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     *\n     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.\n     */\n    function _approve(address owner, address spender, uint256 value) internal {\n        _approve(owner, spender, value, true);\n    }\n\n    /**\n     * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.\n     *\n     * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by\n     * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any\n     * `Approval` event during `transferFrom` operations.\n     *\n     * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to\n     * true using the following override:\n     * ```\n     * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {\n     *     super._approve(owner, spender, value, true);\n     * }\n     * ```\n     *\n     * Requirements are the same as {_approve}.\n     */\n    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {\n        ERC20Storage storage $ = _getERC20Storage();\n        if (owner == address(0)) {\n            revert ERC20InvalidApprover(address(0));\n        }\n        if (spender == address(0)) {\n            revert ERC20InvalidSpender(address(0));\n        }\n        $._allowances[owner][spender] = value;\n        if (emitEvent) {\n            emit Approval(owner, spender, value);\n        }\n    }\n\n    /**\n     * @dev Updates `owner` s allowance for `spender` based on spent `value`.\n     *\n     * Does not update the allowance value in case of infinite allowance.\n     * Revert if not enough allowance is available.\n     *\n     * Does not emit an {Approval} event.\n     */\n    function _spendAllowance(address owner, address spender, uint256 value) internal virtual {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            if (currentAllowance < value) {\n                revert ERC20InsufficientAllowance(spender, currentAllowance, value);\n            }\n            unchecked {\n                _approve(owner, spender, currentAllowance - value, false);\n            }\n        }\n    }\n}\n"},{"file_path":"contracts/interfaces/IAaveFundingPool.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IPool } from \"./IPool.sol\";\n\ninterface IAaveFundingPool is IPool {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when interest snapshot is taken.\n  /// @param borrowIndex The borrow index, multiplied by 1e27.\n  /// @param timestamp The timestamp when this snapshot is taken.\n  event SnapshotAaveBorrowIndex(uint256 borrowIndex, uint256 timestamp);\n\n  /// @notice Emitted when the open fee ratio related parameters are updated.\n  /// @param ratio The open ratio value, multiplied by 1e9.\n  /// @param step The open ratio step value, multiplied by 1e18.\n  event UpdateOpenRatio(uint256 ratio, uint256 step);\n\n  /// @notice Emitted when the open fee ratio is updated.\n  /// @param oldRatio The value of previous close fee ratio, multiplied by 1e9.\n  /// @param newRatio The value of current close fee ratio, multiplied by 1e9.\n  event UpdateCloseFeeRatio(uint256 oldRatio, uint256 newRatio);\n\n  /// @notice Emitted when the funding fee ratio is updated.\n  /// @param oldRatio The value of previous funding fee ratio, multiplied by 1e9.\n  /// @param newRatio The value of current funding fee ratio, multiplied by 1e9.\n  event UpdateFundingRatio(uint256 oldRatio, uint256 newRatio);\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the value of funding ratio, multiplied by 1e9.\n  function getFundingRatio() external view returns (uint256);\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/utils/introspection/ERC165Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165Upgradeable.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {\n    function __ERC165_init() internal onlyInitializing {\n    }\n\n    function __ERC165_init_unchained() internal onlyInitializing {\n    }\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IERC165Upgradeable).interfaceId;\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[50] private __gap;\n}\n"},{"file_path":"contracts/interfaces/Aave/IAaveV3Pool.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IAaveV3Pool {\n  struct ReserveConfigurationMap {\n    //bit 0-15: LTV\n    //bit 16-31: Liq. threshold\n    //bit 32-47: Liq. bonus\n    //bit 48-55: Decimals\n    //bit 56: reserve is active\n    //bit 57: reserve is frozen\n    //bit 58: borrowing is enabled\n    //bit 59: DEPRECATED: stable rate borrowing enabled\n    //bit 60: asset is paused\n    //bit 61: borrowing in isolation mode is enabled\n    //bit 62: siloed borrowing enabled\n    //bit 63: flashloaning enabled\n    //bit 64-79: reserve factor\n    //bit 80-115: borrow cap in whole tokens, borrowCap == 0 => no cap\n    //bit 116-151: supply cap in whole tokens, supplyCap == 0 => no cap\n    //bit 152-167: liquidation protocol fee\n    //bit 168-175: DEPRECATED: eMode category\n    //bit 176-211: unbacked mint cap in whole tokens, unbackedMintCap == 0 => minting disabled\n    //bit 212-251: debt ceiling for isolation mode with (ReserveConfiguration::DEBT_CEILING_DECIMALS) decimals\n    //bit 252: virtual accounting is enabled for the reserve\n    //bit 253-255 unused\n\n    uint256 data;\n  }\n\n  /**\n   * This exists specifically to maintain the `getReserveData()` interface, since the new, internal\n   * `ReserveData` struct includes the reserve's `virtualUnderlyingBalance`.\n   */\n  struct ReserveDataLegacy {\n    //stores the reserve configuration\n    ReserveConfigurationMap configuration;\n    //the liquidity index. Expressed in ray\n    uint128 liquidityIndex;\n    //the current supply rate. Expressed in ray\n    uint128 currentLiquidityRate;\n    //variable borrow index. Expressed in ray\n    uint128 variableBorrowIndex;\n    //the current variable borrow rate. Expressed in ray\n    uint128 currentVariableBorrowRate;\n    // DEPRECATED on v3.2.0\n    uint128 currentStableBorrowRate;\n    //timestamp of last update\n    uint40 lastUpdateTimestamp;\n    //the id of the reserve. Represents the position in the list of the active reserves\n    uint16 id;\n    //aToken address\n    address aTokenAddress;\n    // DEPRECATED on v3.2.0\n    address stableDebtTokenAddress;\n    //variableDebtToken address\n    address variableDebtTokenAddress;\n    //address of the interest rate strategy\n    address interestRateStrategyAddress;\n    //the current treasury balance, scaled\n    uint128 accruedToTreasury;\n    //the outstanding unbacked aTokens minted through the bridging feature\n    uint128 unbacked;\n    //the outstanding debt borrowed against this asset in isolation mode\n    uint128 isolationModeTotalDebt;\n  }\n\n  /**\n   * @notice Returns the state and configuration of the reserve\n   * @param asset The address of the underlying asset of the reserve\n   * @return The state and configuration data of the reserve\n   */\n  function getReserveData(address asset) external view returns (ReserveDataLegacy memory);\n\n  /**\n   * @notice Returns the normalized variable debt per unit of asset\n   * @dev WARNING: This function is intended to be used primarily by the protocol itself to get a\n   * \"dynamic\" variable index based on time, current stored index and virtual rate at the current\n   * moment (approx. a borrower would get if opening a position). This means that is always used in\n   * combination with variable debt supply/balances.\n   * If using this function externally, consider that is possible to have an increasing normalized\n   * variable debt that is not equivalent to how the variable debt index would be updated in storage\n   * (e.g. only updates with non-zero variable debt supply)\n   * @param asset The address of the underlying asset of the reserve\n   * @return The reserve normalized variable debt\n   */\n  function getReserveNormalizedVariableDebt(address asset) external view returns (uint256);\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/token/ERC20/extensions/IERC20MetadataUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20MetadataUpgradeable is IERC20Upgradeable {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"},{"file_path":"contracts/mocks/MockMultiPathConverter.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IWrappedEther } from \"../interfaces/IWrappedEther.sol\";\n\ncontract MockMultiPathConverter {\n  using SafeERC20 for IERC20;\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The address of WETH token.\n  address internal constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n\n  address tokenOut;\n  uint256 amountOut;\n\n  function setTokenOut(address _tokenOut, uint256 _amountOut) external {\n    tokenOut = _tokenOut;\n    amountOut = _amountOut;\n  }\n\n  function convert(address _tokenIn, uint256 _amount, uint256, uint256[] calldata) external payable returns (uint256) {\n    if (_tokenIn == address(0)) {\n      IWrappedEther(WETH).deposit{ value: _amount }();\n      IERC20(WETH).safeTransfer(address(this), _amount);\n    } else {\n      // convert all approved.\n      if (_amount == type(uint256).max) {\n        _amount = IERC20(_tokenIn).allowance(msg.sender, address(this));\n      }\n      IERC20(_tokenIn).safeTransferFrom(msg.sender, address(this), _amount);\n    }\n    IERC20(tokenOut).safeTransfer(msg.sender, amountOut);\n    return amountOut;\n  }\n}\n"},{"file_path":"contracts/common/EIP2535/interfaces/IDiamondLoupe.sol","source_code":"// SPDX-License-Identifier: CC0-1.0\npragma solidity ^0.8.0;\n\n/******************************************************************************\\\n* Author: Nick Mudge <nick@perfectabstractions.com>, Twitter/Github: @mudgen\n* EIP-2535 Diamonds\n/******************************************************************************/\n\n// A loupe is a small magnifying glass used to look at diamonds.\n// These functions look at diamonds\ninterface IDiamondLoupe {\n  /// These functions are expected to be called frequently\n  /// by tools.\n\n  struct Facet {\n    address facetAddress;\n    bytes4[] functionSelectors;\n  }\n\n  /// @notice Gets all facet addresses and their four byte function selectors.\n  /// @return facets_ Facet\n  function facets() external view returns (Facet[] memory facets_);\n\n  /// @notice Gets all the function selectors supported by a specific facet.\n  /// @param _facet The facet address.\n  /// @return facetFunctionSelectors_\n  function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory facetFunctionSelectors_);\n\n  /// @notice Get all the facet addresses used by a diamond.\n  /// @return facetAddresses_\n  function facetAddresses() external view returns (address[] memory facetAddresses_);\n\n  /// @notice Gets the facet that supports the given selector.\n  /// @dev If facet is not found return address(0).\n  /// @param _functionSelector The function selector.\n  /// @return facetAddress_ The facet address.\n  function facetAddress(bytes4 _functionSelector) external view returns (address facetAddress_);\n}\n"},{"file_path":"contracts/periphery/facets/FlashLoanFacetBase.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { IBalancerVault } from \"../../interfaces/Balancer/IBalancerVault.sol\";\n\nimport { LibRouter } from \"../libraries/LibRouter.sol\";\n\nabstract contract FlashLoanFacetBase {\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the caller is not self.\n  error ErrorNotFromSelf();\n\n  /// @dev Unauthorized reentrant call.\n  error ReentrancyGuardReentrantCall();\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @dev The address of Balancer V2 Vault.\n  address private immutable balancer;\n\n  /*************\n   * Modifiers *\n   *************/\n\n  modifier onlySelf() {\n    if (msg.sender != address(this)) revert ErrorNotFromSelf();\n    _;\n  }\n\n  modifier onFlashLoan() {\n    LibRouter.RouterStorage storage $ = LibRouter.routerStorage();\n    $.flashLoanContext = LibRouter.HAS_FLASH_LOAN;\n    _;\n    $.flashLoanContext = LibRouter.NOT_FLASH_LOAN;\n  }\n\n  modifier nonReentrant() {\n    LibRouter.RouterStorage storage $ = LibRouter.routerStorage();\n    if ($.reentrantContext == LibRouter.HAS_ENTRANT) {\n      revert ReentrancyGuardReentrantCall();\n    }\n    $.reentrantContext = LibRouter.HAS_ENTRANT;\n    _;\n    $.reentrantContext = LibRouter.NOT_ENTRANT;\n  }\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _balancer) {\n    balancer = _balancer;\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  function _invokeFlashLoan(address token, uint256 amount, bytes memory data) internal onFlashLoan {\n    address[] memory tokens = new address[](1);\n    uint256[] memory amounts = new uint256[](1);\n    tokens[0] = token;\n    amounts[0] = amount;\n    IBalancerVault(balancer).flashLoan(address(this), tokens, amounts, data);\n  }\n}\n"},{"file_path":"contracts/periphery/facets/PositionOperateFlashLoanFacet.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC721 } from \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\n\nimport { IMultiPathConverter } from \"../../helpers/interfaces/IMultiPathConverter.sol\";\nimport { IPoolManager } from \"../../interfaces/IPoolManager.sol\";\nimport { IPool } from \"../../interfaces/IPool.sol\";\n\nimport { WordCodec } from \"../../common/codec/WordCodec.sol\";\nimport { LibRouter } from \"../libraries/LibRouter.sol\";\nimport { FlashLoanFacetBase } from \"./FlashLoanFacetBase.sol\";\n\ncontract PositionOperateFlashLoanFacet is FlashLoanFacetBase {\n  using SafeERC20 for IERC20;\n  using WordCodec for bytes32;\n\n  /**********\n   * Events *\n   **********/\n\n  event OpenOrAdd(address pool, uint256 position, address recipient, uint256 colls, uint256 debts, uint256 borrows);\n\n  event CloseOrRemove(address pool, uint256 position, address recipient, uint256 colls, uint256 debts, uint256 borrows);\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the amount of tokens swapped are not enough.\n  error ErrorInsufficientAmountSwapped();\n\n  /// @dev Thrown when debt ratio out of range.\n  error ErrorDebtRatioOutOfRange();\n\n  /*************\n   * Constants *\n   *************/\n\n  address private constant fxUSD = 0x085780639CC2cACd35E474e71f4d000e2405d8f6;\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @dev The address of `PoolManager` contract.\n  address private immutable poolManager;\n\n  /// @dev The address of `MultiPathConverter` contract.\n  address private immutable converter;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _balancer, address _poolManager, address _converter) FlashLoanFacetBase(_balancer) {\n    poolManager = _poolManager;\n    converter = _converter;\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Open a new position or add collateral to position with any tokens.\n  /// @param params The parameters to convert source token to collateral token.\n  /// @param pool The address of fx position pool.\n  /// @param positionId The index of position.\n  /// @param borrowAmount The amount of collateral token to borrow.\n  /// @param data Hook data passing to `onOpenOrAddPositionFlashLoan`.\n  function openOrAddPositionFlashLoan(\n    LibRouter.ConvertInParams memory params,\n    address pool,\n    uint256 positionId,\n    uint256 borrowAmount,\n    bytes calldata data\n  ) external payable nonReentrant {\n    uint256 amountIn = LibRouter.transferInAndConvert(params, IPool(pool).collateralToken()) + borrowAmount;\n    _invokeFlashLoan(\n      IPool(pool).collateralToken(),\n      borrowAmount,\n      abi.encodeCall(\n        PositionOperateFlashLoanFacet.onOpenOrAddPositionFlashLoan,\n        (pool, positionId, amountIn, borrowAmount, msg.sender, data)\n      )\n    );\n    // refund collateral token to caller\n    LibRouter.refundERC20(IPool(pool).collateralToken(), LibRouter.routerStorage().revenuePool);\n  }\n\n  /// @notice Close a position or remove collateral from position.\n  /// @param params The parameters to convert collateral token to target token.\n  /// @param positionId The index of position.\n  /// @param pool The address of fx position pool.\n  /// @param borrowAmount The amount of collateral token to borrow.\n  /// @param data Hook data passing to `onCloseOrRemovePositionFlashLoan`.\n  function closeOrRemovePositionFlashLoan(\n    LibRouter.ConvertOutParams memory params,\n    address pool,\n    uint256 positionId,\n    uint256 amountOut,\n    uint256 borrowAmount,\n    bytes calldata data\n  ) external nonReentrant {\n    address collateralToken = IPool(pool).collateralToken();\n\n    _invokeFlashLoan(\n      collateralToken,\n      borrowAmount,\n      abi.encodeCall(\n        PositionOperateFlashLoanFacet.onCloseOrRemovePositionFlashLoan,\n        (pool, positionId, amountOut, borrowAmount, msg.sender, data)\n      )\n    );\n\n    // convert collateral token to other token\n    amountOut = IERC20(collateralToken).balanceOf(address(this));\n    LibRouter.convertAndTransferOut(params, collateralToken, amountOut, msg.sender);\n\n    // refund rest fxUSD and leveraged token\n    LibRouter.refundERC20(fxUSD, LibRouter.routerStorage().revenuePool);\n  }\n\n  /// @notice Hook for `openOrAddPositionFlashLoan`.\n  /// @param pool The address of fx position pool.\n  /// @param position The index of position.\n  /// @param amount The amount of collateral token to supply.\n  /// @param repayAmount The amount of collateral token to repay.\n  /// @param recipient The address of position holder.\n  /// @param data Hook data passing to `onOpenOrAddPositionFlashLoan`.\n  function onOpenOrAddPositionFlashLoan(\n    address pool,\n    uint256 position,\n    uint256 amount,\n    uint256 repayAmount,\n    address recipient,\n    bytes memory data\n  ) external onlySelf {\n    (bytes32 miscData, uint256 fxUSDAmount, uint256 swapEncoding, uint256[] memory swapRoutes) = abi.decode(\n      data,\n      (bytes32, uint256, uint256, uint256[])\n    );\n\n    // open or add collateral to position\n    if (position != 0) {\n      IERC721(pool).transferFrom(recipient, address(this), position);\n    }\n    LibRouter.approve(IPool(pool).collateralToken(), poolManager, amount);\n    position = IPoolManager(poolManager).operate(pool, position, int256(amount), int256(fxUSDAmount));\n    _checkPositionDebtRatio(pool, position, miscData);\n    IERC721(pool).transferFrom(address(this), recipient, position);\n\n    emit OpenOrAdd(pool, position, recipient, amount, fxUSDAmount, repayAmount);\n\n    // swap fxUSD to collateral token\n    _swap(fxUSD, fxUSDAmount, repayAmount, swapEncoding, swapRoutes);\n  }\n\n  /// @notice Hook for `closeOrRemovePositionFlashLoan`.\n  /// @param pool The address of fx position pool.\n  /// @param position The index of position.\n  /// @param amount The amount of collateral token to withdraw.\n  /// @param repayAmount The amount of collateral token to repay.\n  /// @param recipient The address of position holder.\n  /// @param data Hook data passing to `onCloseOrRemovePositionFlashLoan`.\n  function onCloseOrRemovePositionFlashLoan(\n    address pool,\n    uint256 position,\n    uint256 amount,\n    uint256 repayAmount,\n    address recipient,\n    bytes memory data\n  ) external onlySelf {\n    (bytes32 miscData, uint256 fxUSDAmount, uint256 swapEncoding, uint256[] memory swapRoutes) = abi.decode(\n      data,\n      (bytes32, uint256, uint256, uint256[])\n    );\n\n    // swap collateral token to fxUSD\n    _swap(IPool(pool).collateralToken(), repayAmount, fxUSDAmount, swapEncoding, swapRoutes);\n\n    // close or remove collateral from position\n    IERC721(pool).transferFrom(recipient, address(this), position);\n    (, uint256 maxFxUSD) = IPool(pool).getPosition(position);\n    if (fxUSDAmount >= maxFxUSD) {\n      // close entire position\n      IPoolManager(poolManager).operate(pool, position, type(int256).min, type(int256).min);\n    } else {\n      IPoolManager(poolManager).operate(pool, position, -int256(amount), -int256(fxUSDAmount));\n      _checkPositionDebtRatio(pool, position, miscData);\n    }\n    IERC721(pool).transferFrom(address(this), recipient, position);\n\n    emit CloseOrRemove(pool, position, recipient, amount, fxUSDAmount, repayAmount);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to do swap.\n  /// @param token The address of input token.\n  /// @param amountIn The amount of input token.\n  /// @param minOut The minimum amount of output tokens should receive.\n  /// @param encoding The encoding for swap routes.\n  /// @param routes The swap routes to `MultiPathConverter`.\n  /// @return amountOut The amount of output tokens received.\n  function _swap(\n    address token,\n    uint256 amountIn,\n    uint256 minOut,\n    uint256 encoding,\n    uint256[] memory routes\n  ) internal returns (uint256 amountOut) {\n    if (amountIn == 0) return 0;\n\n    LibRouter.approve(token, converter, amountIn);\n    amountOut = IMultiPathConverter(converter).convert(token, amountIn, encoding, routes);\n    if (amountOut < minOut) revert ErrorInsufficientAmountSwapped();\n  }\n\n  /// @dev Internal function to check debt ratio for the position.\n  /// @param pool The address of fx position pool.\n  /// @param positionId The index of the position.\n  /// @param miscData The encoded data for debt ratio range.\n  function _checkPositionDebtRatio(address pool, uint256 positionId, bytes32 miscData) internal view {\n    uint256 debtRatio = IPool(pool).getPositionDebtRatio(positionId);\n    uint256 minDebtRatio = miscData.decodeUint(0, 60);\n    uint256 maxDebtRatio = miscData.decodeUint(60, 60);\n    if (debtRatio < minDebtRatio || debtRatio > maxDebtRatio) {\n      revert ErrorDebtRatioOutOfRange();\n    }\n  }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/interfaces/IERC5267Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol)\n\npragma solidity ^0.8.0;\n\ninterface IERC5267Upgradeable {\n    /**\n     * @dev MAY be emitted to signal that the domain could have changed.\n     */\n    event EIP712DomainChanged();\n\n    /**\n     * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712\n     * signature.\n     */\n    function eip712Domain()\n        external\n        view\n        returns (\n            bytes1 fields,\n            string memory name,\n            string memory version,\n            uint256 chainId,\n            address verifyingContract,\n            bytes32 salt,\n            uint256[] memory extensions\n        );\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/access/AccessControlUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControlUpgradeable.sol\";\nimport \"../utils/ContextUpgradeable.sol\";\nimport \"../utils/StringsUpgradeable.sol\";\nimport \"../utils/introspection/ERC165Upgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n *     require(hasRole(MY_ROLE, msg.sender));\n *     ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {\n    struct RoleData {\n        mapping(address => bool) members;\n        bytes32 adminRole;\n    }\n\n    mapping(bytes32 => RoleData) private _roles;\n\n    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n    /**\n     * @dev Modifier that checks that an account has a specific role. Reverts\n     * with a standardized message including the required role.\n     *\n     * The format of the revert reason is given by the following regular expression:\n     *\n     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n     *\n     * _Available since v4.1._\n     */\n    modifier onlyRole(bytes32 role) {\n        _checkRole(role);\n        _;\n    }\n\n    function __AccessControl_init() internal onlyInitializing {\n    }\n\n    function __AccessControl_init_unchained() internal onlyInitializing {\n    }\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\n        return _roles[role].members[account];\n    }\n\n    /**\n     * @dev Revert with a standard message if `_msgSender()` is missing `role`.\n     * Overriding this function changes the behavior of the {onlyRole} modifier.\n     *\n     * Format of the revert message is described in {_checkRole}.\n     *\n     * _Available since v4.6._\n     */\n    function _checkRole(bytes32 role) internal view virtual {\n        _checkRole(role, _msgSender());\n    }\n\n    /**\n     * @dev Revert with a standard message if `account` is missing `role`.\n     *\n     * The format of the revert reason is given by the following regular expression:\n     *\n     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n     */\n    function _checkRole(bytes32 role, address account) internal view virtual {\n        if (!hasRole(role, account)) {\n            revert(\n                string(\n                    abi.encodePacked(\n                        \"AccessControl: account \",\n                        StringsUpgradeable.toHexString(account),\n                        \" is missing role \",\n                        StringsUpgradeable.toHexString(uint256(role), 32)\n                    )\n                )\n            );\n        }\n    }\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\n        return _roles[role].adminRole;\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n        _grantRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n        _revokeRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been revoked `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `account`.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function renounceRole(bytes32 role, address account) public virtual override {\n        require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n        _revokeRole(role, account);\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event. Note that unlike {grantRole}, this function doesn't perform any\n     * checks on the calling account.\n     *\n     * May emit a {RoleGranted} event.\n     *\n     * [WARNING]\n     * ====\n     * This function should only be called from the constructor when setting\n     * up the initial roles for the system.\n     *\n     * Using this function in any other way is effectively circumventing the admin\n     * system imposed by {AccessControl}.\n     * ====\n     *\n     * NOTE: This function is deprecated in favor of {_grantRole}.\n     */\n    function _setupRole(bytes32 role, address account) internal virtual {\n        _grantRole(role, account);\n    }\n\n    /**\n     * @dev Sets `adminRole` as ``role``'s admin role.\n     *\n     * Emits a {RoleAdminChanged} event.\n     */\n    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n        bytes32 previousAdminRole = getRoleAdmin(role);\n        _roles[role].adminRole = adminRole;\n        emit RoleAdminChanged(role, previousAdminRole, adminRole);\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function _grantRole(bytes32 role, address account) internal virtual {\n        if (!hasRole(role, account)) {\n            _roles[role].members[account] = true;\n            emit RoleGranted(role, account, _msgSender());\n        }\n    }\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function _revokeRole(bytes32 role, address account) internal virtual {\n        if (hasRole(role, account)) {\n            _roles[role].members[account] = false;\n            emit RoleRevoked(role, account, _msgSender());\n        }\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n *     doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n *     token.safeTransferFrom(msg.sender, address(this), value);\n *     ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     *\n     * CAUTION: See Security Considerations above.\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    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"},{"file_path":"contracts/core/pool/PoolErrors.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nabstract contract PoolErrors {\n  /**********\n   * Errors *\n   **********/\n  \n  /// @dev Thrown when the given address is zero.\n  error ErrorZeroAddress();\n\n  /// @dev Thrown when the given value exceeds maximum value.\n  error ErrorValueTooLarge();\n  \n  /// @dev Thrown when the caller is not pool manager.\n  error ErrorCallerNotPoolManager();\n  \n  /// @dev Thrown when the debt amount is too small.\n  error ErrorDebtTooSmall();\n\n  /// @dev Thrown when the collateral amount is too small.\n  error ErrorCollateralTooSmall();\n  \n  /// @dev Thrown when both collateral amount and debt amount are zero.\n  error ErrorNoSupplyAndNoBorrow();\n  \n  /// @dev Thrown when borrow is paused.\n  error ErrorBorrowPaused();\n\n  /// @dev Thrown when redeem is paused.\n  error ErrorRedeemPaused();\n  \n  /// @dev Thrown when the caller is not position owner during withdraw or borrow.\n  error ErrorNotPositionOwner();\n  \n  /// @dev Thrown when withdraw more than supplied.\n  error ErrorWithdrawExceedSupply();\n  \n  /// @dev Thrown when the debt ratio is too small.\n  error ErrorDebtRatioTooSmall();\n\n  /// @dev Thrown when the debt ratio is too large.\n  error ErrorDebtRatioTooLarge();\n  \n  /// @dev Thrown when pool is under collateral.\n  error ErrorPoolUnderCollateral();\n  \n  /// @dev Thrown when the current debt ratio <= rebalance debt ratio.\n  error ErrorRebalanceDebtRatioNotReached();\n\n  /// @dev Thrown when the current debt ratio <= liquidate debt ratio.\n  error ErrorLiquidateDebtRatioNotReached();\n\n  /// @dev Thrown when the current debt ratio > liquidate debt ratio.\n  error ErrorPositionInLiquidationMode();\n\n  error ErrorRebalanceOnLiquidatableTick();\n\n  error ErrorRebalanceOnLiquidatablePosition();\n\n  error ErrorInsufficientCollateralToLiquidate();\n\n  error ErrorOverflow();\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to check value not too large.\n  /// @param value The value to check.\n  /// @param upperBound The upper bound for the given value.\n  function _checkValueTooLarge(uint256 value, uint256 upperBound) internal pure {\n    if (value > upperBound) revert ErrorValueTooLarge();\n  }\n\n  function _checkAddressNotZero(address value) internal pure {\n    if (value == address(0)) revert ErrorZeroAddress();\n  }\n}\n"},{"file_path":"contracts/interfaces/Balancer/IBalancerVault.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\npragma abicoder v2;\n\ninterface IBalancerVault {\n  enum JoinKind {\n    INIT,\n    EXACT_TOKENS_IN_FOR_BPT_OUT,\n    TOKEN_IN_FOR_EXACT_BPT_OUT,\n    ALL_TOKENS_IN_FOR_EXACT_BPT_OUT\n  }\n\n  enum ExitKind {\n    EXACT_BPT_IN_FOR_ONE_TOKEN_OUT,\n    EXACT_BPT_IN_FOR_TOKENS_OUT,\n    BPT_IN_FOR_EXACT_TOKENS_OUT\n  }\n\n  enum SwapKind {\n    GIVEN_IN,\n    GIVEN_OUT\n  }\n\n  struct SingleSwap {\n    bytes32 poolId;\n    SwapKind kind;\n    address assetIn;\n    address assetOut;\n    uint256 amount;\n    bytes userData;\n  }\n\n  struct FundManagement {\n    address sender;\n    bool fromInternalBalance;\n    address payable recipient;\n    bool toInternalBalance;\n  }\n\n  function getPoolTokens(bytes32 poolId)\n    external\n    view\n    returns (\n      address[] memory tokens,\n      uint256[] memory balances,\n      uint256 lastChangeBlock\n    );\n\n  function swap(\n    SingleSwap memory singleSwap,\n    FundManagement memory funds,\n    uint256 limit,\n    uint256 deadline\n  ) external payable returns (uint256 amountCalculated);\n\n  struct JoinPoolRequest {\n    address[] assets;\n    uint256[] maxAmountsIn;\n    bytes userData;\n    bool fromInternalBalance;\n  }\n\n  function joinPool(\n    bytes32 poolId,\n    address sender,\n    address recipient,\n    JoinPoolRequest memory request\n  ) external payable;\n\n  struct ExitPoolRequest {\n    address[] assets;\n    uint256[] minAmountsOut;\n    bytes userData;\n    bool toInternalBalance;\n  }\n\n  function exitPool(\n    bytes32 poolId,\n    address sender,\n    address payable recipient,\n    ExitPoolRequest memory request\n  ) external;\n\n  /**\n   * @dev Data for each individual swap executed by `batchSwap`. The asset in and out fields are indexes into the\n   * `assets` array passed to that function, and ETH assets are converted to WETH.\n   *\n   * If `amount` is zero, the multihop mechanism is used to determine the actual amount based on the amount in/out\n   * from the previous swap, depending on the swap kind.\n   *\n   * The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be\n   * used to extend swap behavior.\n   */\n  struct BatchSwapStep {\n    bytes32 poolId;\n    uint256 assetInIndex;\n    uint256 assetOutIndex;\n    uint256 amount;\n    bytes userData;\n  }\n\n  // This function is not marked as `nonReentrant` because the underlying mechanism relies on reentrancy\n  function queryBatchSwap(\n    SwapKind kind,\n    BatchSwapStep[] memory swaps,\n    address[] memory assets,\n    FundManagement memory funds\n  ) external returns (int256[] memory);\n\n  function flashLoan(\n    address recipient,\n    address[] memory tokens,\n    uint256[] memory amounts,\n    bytes memory userData\n  ) external;\n}\n"},{"file_path":"contracts/v2/interfaces/IFxFractionalTokenV2.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IFxFractionalTokenV2 {\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when caller is not treasury contract.\n  error ErrorCallerIsNotTreasury();\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the net asset value for the token, multiplied by 1e18.\n  function nav() external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Mint some token to someone.\n  /// @param to The address of recipient.\n  /// @param amount The amount of token to mint.\n  function mint(address to, uint256 amount) external;\n\n  /// @notice Burn some token from someone.\n  /// @param from The address of owner to burn.\n  /// @param amount The amount of token to burn.\n  function burn(address from, uint256 amount) external;\n}\n"},{"file_path":"@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.3) (proxy/transparent/ProxyAdmin.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./TransparentUpgradeableProxy.sol\";\nimport \"../../access/Ownable.sol\";\n\n/**\n * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an\n * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.\n */\ncontract ProxyAdmin is Ownable {\n    /**\n     * @dev Returns the current implementation of `proxy`.\n     *\n     * Requirements:\n     *\n     * - This contract must be the admin of `proxy`.\n     */\n    function getProxyImplementation(ITransparentUpgradeableProxy proxy) public view virtual returns (address) {\n        // We need to manually run the static call since the getter cannot be flagged as view\n        // bytes4(keccak256(\"implementation()\")) == 0x5c60da1b\n        (bool success, bytes memory returndata) = address(proxy).staticcall(hex\"5c60da1b\");\n        require(success);\n        return abi.decode(returndata, (address));\n    }\n\n    /**\n     * @dev Returns the current admin of `proxy`.\n     *\n     * Requirements:\n     *\n     * - This contract must be the admin of `proxy`.\n     */\n    function getProxyAdmin(ITransparentUpgradeableProxy proxy) public view virtual returns (address) {\n        // We need to manually run the static call since the getter cannot be flagged as view\n        // bytes4(keccak256(\"admin()\")) == 0xf851a440\n        (bool success, bytes memory returndata) = address(proxy).staticcall(hex\"f851a440\");\n        require(success);\n        return abi.decode(returndata, (address));\n    }\n\n    /**\n     * @dev Changes the admin of `proxy` to `newAdmin`.\n     *\n     * Requirements:\n     *\n     * - This contract must be the current admin of `proxy`.\n     */\n    function changeProxyAdmin(ITransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {\n        proxy.changeAdmin(newAdmin);\n    }\n\n    /**\n     * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.\n     *\n     * Requirements:\n     *\n     * - This contract must be the admin of `proxy`.\n     */\n    function upgrade(ITransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {\n        proxy.upgradeTo(implementation);\n    }\n\n    /**\n     * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See\n     * {TransparentUpgradeableProxy-upgradeToAndCall}.\n     *\n     * Requirements:\n     *\n     * - This contract must be the admin of `proxy`.\n     */\n    function upgradeAndCall(\n        ITransparentUpgradeableProxy proxy,\n        address implementation,\n        bytes memory data\n    ) public payable virtual onlyOwner {\n        proxy.upgradeToAndCall{value: msg.value}(implementation, data);\n    }\n}\n"},{"file_path":"contracts/common/EIP2535/Diamond.sol","source_code":"// SPDX-License-Identifier: CC0-1.0\npragma solidity ^0.8.0;\n\n/******************************************************************************\\\n* Author: Nick Mudge <nick@perfectabstractions.com>, Twitter/Github: @mudgen\n* EIP-2535 Diamonds\n*\n* Implementation of a diamond.\n/******************************************************************************/\n\nimport { LibDiamond } from \"./libraries/LibDiamond.sol\";\nimport { IDiamondCut } from \"./interfaces/IDiamondCut.sol\";\nimport { IDiamondLoupe } from \"./interfaces/IDiamondLoupe.sol\";\nimport { IERC173 } from \"./interfaces/IERC173.sol\";\nimport { IERC165 } from \"./interfaces/IERC165.sol\";\n\n// solhint-disable no-complex-fallback\n// solhint-disable no-inline-assembly\n// solhint-disable no-empty-blocks\n\n// When no function exists for function called\nerror FunctionNotFound(bytes4 _functionSelector);\n\n// This is used in diamond constructor\n// more arguments are added to this struct\n// this avoids stack too deep errors\nstruct DiamondArgs {\n  address owner;\n  address init;\n  bytes initCalldata;\n}\n\ncontract Diamond {\n  constructor(IDiamondCut.FacetCut[] memory _diamondCut, DiamondArgs memory _args) payable {\n    LibDiamond.setContractOwner(_args.owner);\n    LibDiamond.diamondCut(_diamondCut, _args.init, _args.initCalldata);\n\n    // Code can be added here to perform actions and set state variables.\n  }\n\n  // Find facet for function that is called and execute the\n  // function if a facet is found and return any value.\n  fallback() external payable {\n    LibDiamond.DiamondStorage storage ds;\n    bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION;\n    // get diamond storage\n    assembly {\n      ds.slot := position\n    }\n    // get facet from function selector\n    address facet = ds.facetAddressAndSelectorPosition[msg.sig].facetAddress;\n    if (facet == address(0)) {\n      revert FunctionNotFound(msg.sig);\n    }\n    // Execute external function from facet using delegatecall and return any value.\n    assembly {\n      // copy function selector and any arguments\n      calldatacopy(0, 0, calldatasize())\n      // execute function call using the facet\n      let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)\n      // get any return value\n      returndatacopy(0, 0, returndatasize())\n      // return any return value or error back to the caller\n      switch result\n      case 0 {\n        revert(0, returndatasize())\n      }\n      default {\n        return(0, returndatasize())\n      }\n    }\n  }\n\n  receive() external payable {}\n}\n"},{"file_path":"contracts/common/ERC3156/IERC3156FlashBorrower.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IERC3156FlashBorrower {\n  /**\n   * @dev Receive a flash loan.\n   * @param initiator The initiator of the loan.\n   * @param token The loan currency.\n   * @param amount The amount of tokens lent.\n   * @param fee The additional amount of tokens to repay.\n   * @param data Arbitrary data structure, intended to contain user-defined parameters.\n   * @return The keccak256 hash of \"ERC3156FlashBorrower.onFlashLoan\"\n   */\n  function onFlashLoan(\n    address initiator,\n    address token,\n    uint256 amount,\n    uint256 fee,\n    bytes calldata data\n  ) external returns (bytes32);\n}\n"},{"file_path":"contracts/core/ReservePool.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.25;\npragma abicoder v2;\n\nimport { AccessControl } from \"@openzeppelin/contracts/access/AccessControl.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { IReservePool } from \"../interfaces/IReservePool.sol\";\n\ncontract ReservePool is AccessControl, IReservePool {\n  using EnumerableSet for EnumerableSet.AddressSet;\n  using SafeERC20 for IERC20;\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown the bonus ratio is too large.\n  error ErrorRatioTooLarge();\n\n  /// @dev Thrown when add an already added rebalance pool.\n  error ErrorRebalancePoolAlreadyAdded();\n\n  /// @dev Thrown when remove an unknown rebalance pool.\n  error ErrorRebalancePoolNotAdded();\n\n  /// @dev Thrown when the caller is not `FxOmniVault`.\n  error ErrorCallerNotPoolManager();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The address of `PoolManager` contract.\n  address public immutable poolManager;\n\n  /*************\n   * Variables *\n   *************/\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address admin, address _poolManager) {\n    poolManager = _poolManager;\n\n    _grantRole(DEFAULT_ADMIN_ROLE, admin);\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @inheritdoc IReservePool\n  function getBalance(address token) external view returns (uint256) {\n    return _getBalance(token);\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  // solhint-disable-next-line no-empty-blocks\n  receive() external payable {}\n\n  /// @inheritdoc IReservePool\n  function requestBonus(address _token, address _recipient, uint256 _bonus) external {\n    if (_msgSender() != poolManager) revert ErrorCallerNotPoolManager();\n\n    uint256 _balance = _getBalance(_token);\n\n    if (_bonus > _balance) {\n      _bonus = _balance;\n    }\n    if (_bonus > 0) {\n      _transferToken(_token, _recipient, _bonus);\n\n      emit RequestBonus(_token, _recipient, _bonus);\n    }\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Withdraw dust assets in this contract.\n  /// @param _token The address of token to withdraw.\n  /// @param _recipient The address of token receiver.\n  function withdrawFund(address _token, uint256 amount, address _recipient) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _transferToken(_token, _recipient, amount);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to return the balance of the token in this contract.\n  /// @param _token The address of token to query.\n  function _getBalance(address _token) internal view returns (uint256) {\n    if (_token == address(0)) {\n      return address(this).balance;\n    } else {\n      return IERC20(_token).balanceOf(address(this));\n    }\n  }\n\n  /// @dev Internal function to transfer ETH or ERC20 tokens to some `_receiver`.\n  ///\n  /// @param _token The address of token to transfer, user `_token=address(0)` if transfer ETH.\n  /// @param _receiver The address of token receiver.\n  /// @param _amount The amount of token to transfer.\n  function _transferToken(address _token, address _receiver, uint256 _amount) internal {\n    if (_token == address(0)) {\n      Address.sendValue(payable(_receiver), _amount);\n    } else {\n      IERC20(_token).safeTransfer(_receiver, _amount);\n    }\n  }\n}\n"},{"file_path":"contracts/mocks/MockAaveV3Pool.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IAaveV3Pool } from \"../interfaces/Aave/IAaveV3Pool.sol\";\n\ncontract MockAaveV3Pool is IAaveV3Pool {\n  uint128 public variableBorrowRate;\n  uint256 public reserveNormalizedVariableDebt;\n\n  constructor(uint128 _variableBorrowRate) {\n    variableBorrowRate = _variableBorrowRate;\n  }\n\n  function setVariableBorrowRate(uint128 _variableBorrowRate) external {\n    variableBorrowRate = _variableBorrowRate;\n  }\n\n  function setReserveNormalizedVariableDebt(uint256 _reserveNormalizedVariableDebt) external {\n    reserveNormalizedVariableDebt = _reserveNormalizedVariableDebt;\n  }\n\n  function getReserveData(address) external view returns (ReserveDataLegacy memory result) {\n    result.currentVariableBorrowRate = variableBorrowRate;\n  }\n\n  function getReserveNormalizedVariableDebt(address) external view returns (uint256) {\n    return reserveNormalizedVariableDebt;\n  }\n}\n"},{"file_path":"contracts/common/utils/PermissionedSwap.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { AccessControlUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n// solhint-disable avoid-low-level-calls\n// solhint-disable no-inline-assembly\n\nabstract contract PermissionedSwap is AccessControlUpgradeable {\n  using SafeERC20 for IERC20;\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the amount of output token is not enough.\n  error InsufficientOutputToken();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @notice The role for permissioned trader.\n  bytes32 public constant PERMISSIONED_TRADER_ROLE = keccak256(\"PERMISSIONED_TRADER_ROLE\");\n\n  /// @notice The role for permissioned trading router.\n  bytes32 public constant PERMISSIONED_ROUTER_ROLE = keccak256(\"PERMISSIONED_ROUTER_ROLE\");\n\n  /***********\n   * Structs *\n   ***********/\n\n  /// @notice The struct for trading parameters.\n  ///\n  /// @param router The address of trading router.\n  /// @param data The calldata passing to the router contract.\n  /// @param minOut The minimum amount of output token should receive.\n  struct TradingParameter {\n    address router;\n    bytes data;\n    uint256 minOut;\n  }\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @dev reserved slots.\n  uint256[50] private __gap;\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Withdraw base token to someone else.\n  /// @dev This should be only used when we are retiring this contract.\n  /// @param baseToken The address of base token.\n  function withdraw(address baseToken, address recipient) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    uint256 amountIn = IERC20(baseToken).balanceOf(address(this));\n    IERC20(baseToken).safeTransfer(recipient, amountIn);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to convert token with routes.\n  /// @param srcToken The address of source token.\n  /// @param dstToken The address of destination token.\n  /// @param amountIn The amount of input token.\n  /// @param params The token converting parameters.\n  /// @return amountOut The amount of output token received.\n  function _doTrade(\n    address srcToken,\n    address dstToken,\n    uint256 amountIn,\n    TradingParameter memory params\n  ) internal virtual onlyRole(PERMISSIONED_TRADER_ROLE) returns (uint256 amountOut) {\n    if (srcToken == dstToken) return amountIn;\n\n    // router should be permissioned\n    _checkRole(PERMISSIONED_ROUTER_ROLE, params.router);\n\n    // approve to router\n    IERC20(srcToken).forceApprove(params.router, amountIn);\n\n    // do trading\n    amountOut = IERC20(dstToken).balanceOf(address(this));\n    (bool success, ) = params.router.call(params.data);\n    if (!success) {\n      // below lines will propagate inner error up\n      assembly {\n        let ptr := mload(0x40)\n        let size := returndatasize()\n        returndatacopy(ptr, 0, size)\n        revert(ptr, size)\n      }\n    }\n\n    amountOut = IERC20(dstToken).balanceOf(address(this)) - amountOut;\n    if (amountOut < params.minOut) {\n      revert InsufficientOutputToken();\n    }\n  }\n}\n"},{"file_path":"@openzeppelin/contracts-v4/proxy/Proxy.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM\n * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to\n * be specified by overriding the virtual {_implementation} function.\n *\n * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a\n * different contract through the {_delegate} function.\n *\n * The success and return data of the delegated call will be returned back to the caller of the proxy.\n */\nabstract contract Proxy {\n    /**\n     * @dev Delegates the current call to `implementation`.\n     *\n     * This function does not return to its internal call site, it will return directly to the external caller.\n     */\n    function _delegate(address implementation) internal virtual {\n        assembly {\n            // Copy msg.data. We take full control of memory in this inline assembly\n            // block because it will not return to Solidity code. We overwrite the\n            // Solidity scratch pad at memory position 0.\n            calldatacopy(0, 0, calldatasize())\n\n            // Call the implementation.\n            // out and outsize are 0 because we don't know the size yet.\n            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\n\n            // Copy the returned data.\n            returndatacopy(0, 0, returndatasize())\n\n            switch result\n            // delegatecall returns 0 on error.\n            case 0 {\n                revert(0, returndatasize())\n            }\n            default {\n                return(0, returndatasize())\n            }\n        }\n    }\n\n    /**\n     * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function\n     * and {_fallback} should delegate.\n     */\n    function _implementation() internal view virtual returns (address);\n\n    /**\n     * @dev Delegates the current call to the address returned by `_implementation()`.\n     *\n     * This function does not return to its internal call site, it will return directly to the external caller.\n     */\n    function _fallback() internal virtual {\n        _beforeFallback();\n        _delegate(_implementation());\n    }\n\n    /**\n     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\n     * function in the contract matches the call data.\n     */\n    fallback() external payable virtual {\n        _fallback();\n    }\n\n    /**\n     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data\n     * is empty.\n     */\n    receive() external payable virtual {\n        _fallback();\n    }\n\n    /**\n     * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`\n     * call, or as part of the Solidity `fallback` or `receive` functions.\n     *\n     * If overridden should call `super._beforeFallback()`.\n     */\n    function _beforeFallback() internal virtual {}\n}\n"},{"file_path":"contracts/v2/MarketV2.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { AccessControlUpgradeable } from \"@openzeppelin/contracts-upgradeable-v4/access/AccessControlUpgradeable.sol\";\nimport { ReentrancyGuardUpgradeable } from \"@openzeppelin/contracts-upgradeable-v4/security/ReentrancyGuardUpgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable-v4/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable-v4/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\nimport { WordCodec } from \"../common/codec/WordCodec.sol\";\n\nimport { IFxMarketV2 } from \"./interfaces/IFxMarketV2.sol\";\nimport { IFxRebalancePoolRegistry } from \"./interfaces/IFxRebalancePoolRegistry.sol\";\nimport { IFxReservePool } from \"./interfaces/IFxReservePool.sol\";\nimport { IFxTreasuryV2 } from \"./interfaces/IFxTreasuryV2.sol\";\n\n// solhint-disable max-states-count\n\ncontract MarketV2 is AccessControlUpgradeable, ReentrancyGuardUpgradeable, IFxMarketV2 {\n  using SafeERC20Upgradeable for IERC20Upgradeable;\n\n  using WordCodec for bytes32;\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @notice The role for emergency dao.\n  bytes32 public constant EMERGENCY_DAO_ROLE = keccak256(\"EMERGENCY_DAO_ROLE\");\n\n  /// @notice The role for migrator.\n  bytes32 public constant MIGRATOR_ROLE = keccak256(\"MIGRATOR_ROLE\");\n\n  /// @dev The precision used to compute nav.\n  uint256 private constant FEE_PRECISION = 1e18;\n\n  /// @dev The offset of mint flag in `marketConfigData`.\n  uint256 private constant MINT_FLAG_OFFSET = 0;\n\n  /// @dev The offset of redeem flag in `marketConfigData`.\n  uint256 private constant REDEEM_FLAG_OFFSET = 1;\n\n  /// @dev The offset of stability mode mint flag in `marketConfigData`.\n  uint256 private constant MINT_FLAG_STABILITY_OFFSET = 2;\n\n  /// @dev The offset of stability mode redeem flag in `marketConfigData`.\n  uint256 private constant REDEEM_FLAG_STABILITY_OFFSET = 3;\n\n  /// @dev The offset of stability ratio in `marketConfigData`.\n  uint256 private constant STABILITY_RATIO_OFFSET = 34;\n\n  /// @dev The offset of default fToken fee ratio in `mintFeeData` and `redeemFeeData`.\n  uint256 private constant FTOKEN_DEFAULT_FEE_OFFSET = 0;\n\n  /// @dev The offset of delta fToken fee ratio in `mintFeeData` and `redeemFeeData`.\n  uint256 private constant FTOKEN_DELTA_FEE_OFFSET = 64;\n\n  /// @dev The offset of default xToken fee ratio in `mintFeeData` and `redeemFeeData`.\n  uint256 private constant XTOKEN_DEFAULT_FEE_OFFSET = 128;\n\n  /// @dev The offset of delta xToken fee ratio in `mintFeeData` and `redeemFeeData`.\n  uint256 private constant XTOKEN_DELTA_FEE_OFFSET = 192;\n\n  /// @inheritdoc IFxMarketV2\n  address public immutable override treasury;\n\n  /// @inheritdoc IFxMarketV2\n  address public immutable override baseToken;\n\n  /// @inheritdoc IFxMarketV2\n  address public immutable override fToken;\n\n  /// @inheritdoc IFxMarketV2\n  address public immutable override xToken;\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @dev `marketConfigData` is a storage slot that can be used to store market configuration.\n  ///\n  /// - The *mint flag* indicate whether the token mint is paused (both fToken and xToken).\n  /// - The *redeem flag* indicate whether the token redeem is paused (both fToken and xToken).\n  /// - The *mint flag stability* indicate whether the fToken mint is paused in stability mode.\n  /// - The *redeem flag stability* indicate whether the xToken redeem is paused in stability mode.\n  /// - The *stability ratio* is the collateral ratio to enter stability mode, multiplied by 1e18.\n  ///\n  /// [ mint flag | redeem flag | mint flag stability | redeem flag stability | stability ratio | available ]\n  /// [   1 bit   |    1 bit    |        1 bit        |         1 bit         |     64 bits     |  188 bits ]\n  /// [ MSB                                                                                             LSB ]\n  bytes32 private marketConfigData;\n\n  /// @dev `mintFeeData` is a storage slot that can be used to store mint fee ratio.\n  ///\n  /// [ default fToken | delta fToken | default xToken | delta xToken |\n  /// [     64 bit     |    64 bit    |     64 bit     |    64 bit    ]\n  /// [ MSB                                                       LSB ]\n  bytes32 private mintFeeData;\n\n  /// @dev `redeemFeeData` is a storage slot that can be used to store redeem fee ratio.\n  ///\n  /// [ default fToken | delta fToken | default xToken | delta xToken |\n  /// [     64 bit     |    64 bit    |     64 bit     |    64 bit    ]\n  /// [ MSB                                                       LSB ]\n  bytes32 private redeemFeeData;\n\n  /// @notice The address of platform contract;\n  address public platform;\n\n  /// @notice The address of ReservePool contract.\n  address public reservePool;\n\n  /// @notice The address of RebalancePoolRegistry contract.\n  address public registry;\n\n  /// @inheritdoc IFxMarketV2\n  address public fxUSD;\n\n  /// @dev Slots for future use.\n  uint256[43] private _gap;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _treasury) {\n    treasury = _treasury;\n\n    baseToken = IFxTreasuryV2(_treasury).baseToken();\n    fToken = IFxTreasuryV2(_treasury).fToken();\n    xToken = IFxTreasuryV2(_treasury).xToken();\n  }\n\n  function initialize(address _platform, address _reservePool, address _registry) external initializer {\n    __Context_init();\n    __ERC165_init();\n    __AccessControl_init();\n    __ReentrancyGuard_init();\n\n    _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());\n\n    _updatePlatform(_platform);\n    _updateReservePool(_reservePool);\n    _updateRebalancePoolRegistry(_registry);\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return whether token mint is paused.\n  function mintPaused() public view returns (bool) {\n    return marketConfigData.decodeBool(MINT_FLAG_OFFSET);\n  }\n\n  /// @notice Return whether token redeem is paused.\n  function redeemPaused() public view returns (bool) {\n    return marketConfigData.decodeBool(REDEEM_FLAG_OFFSET);\n  }\n\n  /// @notice Return whether fToken mint is paused in stability mode.\n  function fTokenMintPausedInStabilityMode() public view returns (bool) {\n    return marketConfigData.decodeBool(MINT_FLAG_STABILITY_OFFSET);\n  }\n\n  /// @notice Return whether xToken redeem is paused in stability mode.\n  function xTokenRedeemPausedInStabilityMode() public view returns (bool) {\n    return marketConfigData.decodeBool(REDEEM_FLAG_STABILITY_OFFSET);\n  }\n\n  /// @inheritdoc IFxMarketV2\n  function stabilityRatio() public view returns (uint256) {\n    return marketConfigData.decodeUint(STABILITY_RATIO_OFFSET, 64);\n  }\n\n  /// @notice The mint fee ratio for fToken.\n  function fTokenMintFeeRatio() public view returns (uint256 defaultFee, int256 deltaFee) {\n    bytes32 _mintFeeData = mintFeeData;\n    defaultFee = _mintFeeData.decodeUint(FTOKEN_DEFAULT_FEE_OFFSET, 64);\n    deltaFee = _mintFeeData.decodeInt(FTOKEN_DELTA_FEE_OFFSET, 64);\n  }\n\n  /// @notice The mint fee ratio for xToken.\n  function xTokenMintFeeRatio() public view returns (uint256 defaultFee, int256 deltaFee) {\n    bytes32 _mintFeeData = mintFeeData;\n    defaultFee = _mintFeeData.decodeUint(XTOKEN_DEFAULT_FEE_OFFSET, 64);\n    deltaFee = _mintFeeData.decodeInt(XTOKEN_DELTA_FEE_OFFSET, 64);\n  }\n\n  /// @notice The redeem fee ratio for fToken.\n  function fTokenRedeemFeeRatio() public view returns (uint256 defaultFee, int256 deltaFee) {\n    bytes32 _redeemFeeData = redeemFeeData;\n    defaultFee = _redeemFeeData.decodeUint(FTOKEN_DEFAULT_FEE_OFFSET, 64);\n    deltaFee = _redeemFeeData.decodeInt(FTOKEN_DELTA_FEE_OFFSET, 64);\n  }\n\n  /// @notice The redeem fee ratio for xToken.\n  function xTokenRedeemFeeRatio() public view returns (uint256 defaultFee, int256 deltaFee) {\n    bytes32 _redeemFeeData = redeemFeeData;\n    defaultFee = _redeemFeeData.decodeUint(XTOKEN_DEFAULT_FEE_OFFSET, 64);\n    deltaFee = _redeemFeeData.decodeInt(XTOKEN_DELTA_FEE_OFFSET, 64);\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc IFxMarketV2\n  function mintFToken(\n    uint256 _baseIn,\n    address _recipient,\n    uint256 _minFTokenMinted\n  ) external override nonReentrant returns (uint256 _fTokenMinted) {\n    if (mintPaused()) revert ErrorMintPaused();\n\n    // make sure caller is fxUSD, when fxUSD is enabled\n    {\n      address _fxUSD = fxUSD;\n      if (_fxUSD != address(0) && _fxUSD != _msgSender()) revert ErrorCallerNotFUSD();\n    }\n    _beforeMintFToken();\n\n    if (_baseIn == type(uint256).max) {\n      _baseIn = IERC20Upgradeable(baseToken).balanceOf(_msgSender());\n    }\n    if (_baseIn == 0) revert ErrorMintZeroAmount();\n\n    uint256 _stabilityRatio = stabilityRatio();\n    (uint256 _maxBaseInBeforeSystemStabilityMode, ) = IFxTreasuryV2(treasury).maxMintableFToken(_stabilityRatio);\n    if (_maxBaseInBeforeSystemStabilityMode > 0) {\n      _maxBaseInBeforeSystemStabilityMode = IFxTreasuryV2(treasury).getWrapppedValue(\n        _maxBaseInBeforeSystemStabilityMode\n      );\n    }\n\n    if (fTokenMintPausedInStabilityMode()) {\n      uint256 _collateralRatio = IFxTreasuryV2(treasury).collateralRatio();\n      if (_collateralRatio <= _stabilityRatio) revert ErrorFTokenMintPausedInStabilityMode();\n\n      // bound maximum amount of base token to mint fToken.\n      if (_baseIn > _maxBaseInBeforeSystemStabilityMode) {\n        _baseIn = _maxBaseInBeforeSystemStabilityMode;\n      }\n    }\n\n    uint256 _amountWithoutFee = _deductFTokenMintFee(_baseIn, _maxBaseInBeforeSystemStabilityMode);\n    IERC20Upgradeable(baseToken).safeTransferFrom(_msgSender(), treasury, _amountWithoutFee);\n\n    _fTokenMinted = IFxTreasuryV2(treasury).mintFToken(\n      IFxTreasuryV2(treasury).getUnderlyingValue(_amountWithoutFee),\n      _recipient\n    );\n    if (_fTokenMinted < _minFTokenMinted) revert ErrorInsufficientFTokenOutput();\n\n    emit MintFToken(_msgSender(), _recipient, _baseIn, _fTokenMinted, _baseIn - _amountWithoutFee);\n  }\n\n  /// @inheritdoc IFxMarketV2\n  function mintXToken(\n    uint256 _baseIn,\n    address _recipient,\n    uint256 _minXTokenMinted\n  ) external override nonReentrant returns (uint256 _xTokenMinted, uint256 _bonus) {\n    if (mintPaused()) revert ErrorMintPaused();\n    _beforeMintXToken();\n\n    if (_baseIn == type(uint256).max) {\n      _baseIn = IERC20Upgradeable(baseToken).balanceOf(_msgSender());\n    }\n    if (_baseIn == 0) revert ErrorMintZeroAmount();\n\n    uint256 _stabilityRatio = stabilityRatio();\n    (uint256 _maxBaseInBeforeSystemStabilityMode, ) = IFxTreasuryV2(treasury).maxMintableXToken(_stabilityRatio);\n    if (_maxBaseInBeforeSystemStabilityMode > 0) {\n      _maxBaseInBeforeSystemStabilityMode = IFxTreasuryV2(treasury).getWrapppedValue(\n        _maxBaseInBeforeSystemStabilityMode\n      );\n    }\n\n    uint256 _amountWithoutFee = _deductXTokenMintFee(_baseIn, _maxBaseInBeforeSystemStabilityMode);\n    IERC20Upgradeable(baseToken).safeTransferFrom(_msgSender(), treasury, _amountWithoutFee);\n\n    _xTokenMinted = IFxTreasuryV2(treasury).mintXToken(\n      IFxTreasuryV2(treasury).getUnderlyingValue(_amountWithoutFee),\n      _recipient\n    );\n    if (_xTokenMinted < _minXTokenMinted) revert ErrorInsufficientXTokenOutput();\n\n    // give bnous\n    if (_amountWithoutFee < _maxBaseInBeforeSystemStabilityMode) {\n      _bonus = _amountWithoutFee;\n    } else {\n      _bonus = _maxBaseInBeforeSystemStabilityMode;\n    }\n    if (_bonus > 0 && IFxRebalancePoolRegistry(registry).totalSupply() == 0) {\n      _bonus = IFxReservePool(reservePool).requestBonus(baseToken, _recipient, _bonus);\n    } else {\n      _bonus = 0;\n    }\n\n    emit MintXToken(_msgSender(), _recipient, _baseIn, _xTokenMinted, _bonus, _baseIn - _amountWithoutFee);\n  }\n\n  /// @inheritdoc IFxMarketV2\n  function redeemFToken(\n    uint256 _fTokenIn,\n    address _recipient,\n    uint256 _minBaseOut\n  ) external override nonReentrant returns (uint256 _baseOut, uint256 _bonus) {\n    if (redeemPaused()) revert ErrorRedeemPaused();\n    _beforeRedeemFToken();\n\n    if (_fTokenIn == type(uint256).max) {\n      _fTokenIn = IERC20Upgradeable(fToken).balanceOf(_msgSender());\n    }\n    if (_fTokenIn == 0) revert ErrorRedeemZeroAmount();\n\n    uint256 _stabilityRatio = stabilityRatio();\n    (uint256 _maxBaseOut, uint256 _maxFTokenInBeforeSystemStabilityMode) = IFxTreasuryV2(treasury).maxRedeemableFToken(\n      _stabilityRatio\n    );\n    uint256 _feeRatio;\n    if (!hasRole(MIGRATOR_ROLE, _msgSender())) {\n      _feeRatio = _computeFTokenRedeemFeeRatio(_fTokenIn, _maxFTokenInBeforeSystemStabilityMode);\n    }\n\n    _baseOut = IFxTreasuryV2(treasury).redeem(_fTokenIn, 0, _msgSender());\n    // give bonus when redeem fToken\n    if (_baseOut < _maxBaseOut) {\n      _bonus = _baseOut;\n    } else {\n      _bonus = _maxBaseOut;\n    }\n\n    // request bonus\n    if (_bonus > 0 && IFxRebalancePoolRegistry(registry).totalSupply() == 0) {\n      (uint256 _defaultRatio, int256 _deltaRatio) = fTokenMintFeeRatio();\n      _bonus -= (_bonus * uint256(int256(_defaultRatio) + _deltaRatio)) / FEE_PRECISION; // deduct fee\n      _bonus = IFxReservePool(reservePool).requestBonus(\n        baseToken,\n        _recipient,\n        IFxTreasuryV2(treasury).getWrapppedValue(_bonus)\n      );\n    } else {\n      _bonus = 0;\n    }\n\n    _baseOut = IFxTreasuryV2(treasury).getWrapppedValue(_baseOut);\n    uint256 _balance = IERC20Upgradeable(baseToken).balanceOf(address(this));\n    // consider possible slippage\n    if (_balance < _baseOut) {\n      _baseOut = _balance;\n    }\n\n    uint256 _fee = (_baseOut * _feeRatio) / FEE_PRECISION;\n    if (_fee > 0) {\n      IERC20Upgradeable(baseToken).safeTransfer(platform, _fee);\n      _baseOut = _baseOut - _fee;\n    }\n    if (_baseOut < _minBaseOut) revert ErrorInsufficientBaseOutput();\n\n    IERC20Upgradeable(baseToken).safeTransfer(_recipient, _baseOut);\n\n    emit RedeemFToken(_msgSender(), _recipient, _fTokenIn, _baseOut, _bonus, _fee);\n  }\n\n  /// @inheritdoc IFxMarketV2\n  function redeemXToken(\n    uint256 _xTokenIn,\n    address _recipient,\n    uint256 _minBaseOut\n  ) external override nonReentrant returns (uint256 _baseOut) {\n    if (redeemPaused()) revert ErrorRedeemPaused();\n    _beforeRedeemXToken();\n\n    if (_xTokenIn == type(uint256).max) {\n      _xTokenIn = IERC20Upgradeable(xToken).balanceOf(_msgSender());\n    }\n    if (_xTokenIn == 0) revert ErrorRedeemZeroAmount();\n\n    uint256 _stabilityRatio = stabilityRatio();\n    uint256 _feeRatio;\n    (, uint256 _maxXTokenInBeforeSystemStabilityMode) = IFxTreasuryV2(treasury).maxRedeemableXToken(_stabilityRatio);\n\n    if (xTokenRedeemPausedInStabilityMode()) {\n      uint256 _collateralRatio = IFxTreasuryV2(treasury).collateralRatio();\n      if (_collateralRatio <= _stabilityRatio) revert ErrorXTokenRedeemPausedInStabilityMode();\n\n      // bound maximum amount of xToken to redeem.\n      if (_xTokenIn > _maxXTokenInBeforeSystemStabilityMode) {\n        _xTokenIn = _maxXTokenInBeforeSystemStabilityMode;\n      }\n    }\n\n    if (!hasRole(MIGRATOR_ROLE, _msgSender())) {\n      _feeRatio = _computeXTokenRedeemFeeRatio(_xTokenIn, _maxXTokenInBeforeSystemStabilityMode);\n    }\n\n    _baseOut = IFxTreasuryV2(treasury).redeem(0, _xTokenIn, _msgSender());\n    _baseOut = IFxTreasuryV2(treasury).getWrapppedValue(_baseOut);\n    uint256 _balance = IERC20Upgradeable(baseToken).balanceOf(address(this));\n    // consider possible slippage\n    if (_balance < _baseOut) {\n      _baseOut = _balance;\n    }\n\n    uint256 _fee = (_baseOut * _feeRatio) / FEE_PRECISION;\n    if (_fee > 0) {\n      IERC20Upgradeable(baseToken).safeTransfer(platform, _fee);\n      _baseOut = _baseOut - _fee;\n    }\n    if (_baseOut < _minBaseOut) revert ErrorInsufficientBaseOutput();\n\n    IERC20Upgradeable(baseToken).safeTransfer(_recipient, _baseOut);\n\n    emit RedeemXToken(_msgSender(), _recipient, _xTokenIn, _baseOut, _fee);\n  }\n\n  /*******************************\n   * Public Restricted Functions *\n   *******************************/\n\n  /// @notice Update the fee ratio for redeeming.\n  /// @param _defaultFeeRatio The new default fee ratio, multipled by 1e18.\n  /// @param _extraFeeRatio The new extra fee ratio, multipled by 1e18.\n  /// @param _isFToken Whether we are updating for fToken.\n  function updateRedeemFeeRatio(\n    uint256 _defaultFeeRatio,\n    int256 _extraFeeRatio,\n    bool _isFToken\n  ) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _validateFeeRatio(_defaultFeeRatio, _extraFeeRatio);\n\n    bytes32 _redeemFeeData = redeemFeeData;\n    if (_isFToken) {\n      _redeemFeeData = _redeemFeeData.insertUint(_defaultFeeRatio, FTOKEN_DEFAULT_FEE_OFFSET, 64);\n      _redeemFeeData = _redeemFeeData.insertInt(_extraFeeRatio, FTOKEN_DELTA_FEE_OFFSET, 64);\n      emit UpdateRedeemFeeRatioFToken(_defaultFeeRatio, _extraFeeRatio);\n    } else {\n      _redeemFeeData = _redeemFeeData.insertUint(_defaultFeeRatio, XTOKEN_DEFAULT_FEE_OFFSET, 64);\n      _redeemFeeData = _redeemFeeData.insertInt(_extraFeeRatio, XTOKEN_DELTA_FEE_OFFSET, 64);\n      emit UpdateRedeemFeeRatioXToken(_defaultFeeRatio, _extraFeeRatio);\n    }\n    redeemFeeData = _redeemFeeData;\n  }\n\n  /// @notice Update the fee ratio for minting.\n  /// @param _defaultFeeRatio The new default fee ratio, multipled by 1e18.\n  /// @param _extraFeeRatio The new extra fee ratio, multipled by 1e18.\n  /// @param _isFToken Whether we are updating for fToken.\n  function updateMintFeeRatio(\n    uint128 _defaultFeeRatio,\n    int128 _extraFeeRatio,\n    bool _isFToken\n  ) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _validateFeeRatio(_defaultFeeRatio, _extraFeeRatio);\n\n    bytes32 _mintFeeData = mintFeeData;\n    if (_isFToken) {\n      _mintFeeData = _mintFeeData.insertUint(_defaultFeeRatio, FTOKEN_DEFAULT_FEE_OFFSET, 64);\n      _mintFeeData = _mintFeeData.insertInt(_extraFeeRatio, FTOKEN_DELTA_FEE_OFFSET, 64);\n      emit UpdateMintFeeRatioFToken(_defaultFeeRatio, _extraFeeRatio);\n    } else {\n      _mintFeeData = _mintFeeData.insertUint(_defaultFeeRatio, XTOKEN_DEFAULT_FEE_OFFSET, 64);\n      _mintFeeData = _mintFeeData.insertInt(_extraFeeRatio, XTOKEN_DELTA_FEE_OFFSET, 64);\n      emit UpdateMintFeeRatioXToken(_defaultFeeRatio, _extraFeeRatio);\n    }\n    mintFeeData = _mintFeeData;\n  }\n\n  /// @notice Update the stability ratio.\n  /// @param _newRatio The new collateral ratio to enter stability mode, multiplied by 1e18.\n  function updateStabilityRatio(uint256 _newRatio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateStabilityRatio(_newRatio);\n  }\n\n  /// @notice Update mint pause status.\n  /// @param _newStatus The new mint pause status.\n  function updateMintStatus(bool _newStatus) external onlyRole(EMERGENCY_DAO_ROLE) {\n    bool _oldStatus = _updateBoolInMarketConfigData(MINT_FLAG_OFFSET, _newStatus);\n\n    emit UpdateMintStatus(_oldStatus, _newStatus);\n  }\n\n  /// @notice Update redeem pause status.\n  /// @param _newStatus The new redeem pause status.\n  function updateRedeemStatus(bool _newStatus) external onlyRole(EMERGENCY_DAO_ROLE) {\n    bool _oldStatus = _updateBoolInMarketConfigData(REDEEM_FLAG_OFFSET, _newStatus);\n\n    emit UpdateRedeemStatus(_oldStatus, _newStatus);\n  }\n\n  /// @notice Update fToken mint pause status in stability mode.\n  /// @param _newStatus The new mint pause status.\n  function updateFTokenMintStatusInStabilityMode(bool _newStatus) external onlyRole(EMERGENCY_DAO_ROLE) {\n    bool _oldStatus = _updateBoolInMarketConfigData(MINT_FLAG_STABILITY_OFFSET, _newStatus);\n\n    emit UpdateFTokenMintStatusInStabilityMode(_oldStatus, _newStatus);\n  }\n\n  /// @notice Update xToken redeem status in stability mode\n  /// @param _newStatus The new redeem pause status.\n  function updateXTokenRedeemStatusInStabilityMode(bool _newStatus) external onlyRole(EMERGENCY_DAO_ROLE) {\n    bool _oldStatus = _updateBoolInMarketConfigData(REDEEM_FLAG_STABILITY_OFFSET, _newStatus);\n\n    emit UpdateXTokenRedeemStatusInStabilityMode(_oldStatus, _newStatus);\n  }\n\n  /// @notice Change address of platform contract.\n  /// @param _newPlatform The new address of platform contract.\n  function updatePlatform(address _newPlatform) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updatePlatform(_newPlatform);\n  }\n\n  /// @notice Change address of reserve pool contract.\n  /// @param _newReservePool The new address of reserve pool contract.\n  function updateReservePool(address _newReservePool) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateReservePool(_newReservePool);\n  }\n\n  /// @notice Change address of RebalancePoolRegistry contract.\n  /// @param _newRegistry The new address of RebalancePoolRegistry contract.\n  function updateRebalancePoolRegistry(address _newRegistry) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateRebalancePoolRegistry(_newRegistry);\n  }\n\n  /// @notice Enable fxUSD mint.\n  /// @param _fxUSD The address of fxUSD token.\n  function enableFxUSD(address _fxUSD) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    if (_fxUSD == address(0)) revert ErrorZeroAddress();\n\n    if (fxUSD == address(0)) fxUSD = _fxUSD;\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Hook function to call before mint fToken.\n  function _beforeMintFToken() internal virtual {}\n\n  /// @dev Hook function to call before mint xToken.\n  function _beforeMintXToken() internal virtual {}\n\n  /// @dev Hook function to call before redeem fToken.\n  function _beforeRedeemFToken() internal virtual {}\n\n  /// @dev Hook function to call before redeem xToken.\n  function _beforeRedeemXToken() internal virtual {}\n\n  /// @dev Internal function to validate fee ratio.\n  function _validateFeeRatio(uint256 _defaultFeeRatio, int256 _extraFeeRatio) internal pure {\n    if (_defaultFeeRatio > FEE_PRECISION) revert ErrorDefaultFeeTooLarge();\n    if (_extraFeeRatio < 0) {\n      if (uint256(-_extraFeeRatio) > _defaultFeeRatio) revert ErrorDeltaFeeTooSmall();\n    } else {\n      if (uint256(_extraFeeRatio) > FEE_PRECISION - _defaultFeeRatio) revert ErrorTotalFeeTooLarge();\n    }\n  }\n\n  /// @dev Internal function to update bool value in `marketConfigData`.\n  /// @param offset The offset of the value in `marketConfigData`.\n  /// @param newValue The value to update.\n  /// @return oldValue The original value in the `offset`.\n  function _updateBoolInMarketConfigData(uint256 offset, bool newValue) private returns (bool oldValue) {\n    bytes32 _data = marketConfigData;\n    oldValue = _data.decodeBool(offset);\n    marketConfigData = _data.insertBool(newValue, offset);\n  }\n\n  /// @dev Internal function to update stability ratio.\n  /// @param _newRatio The new collateral ratio to enter stability mode, multiplied by 1e18.\n  function _updateStabilityRatio(uint256 _newRatio) private {\n    if (_newRatio > type(uint64).max) revert ErrorStabilityRatioTooLarge();\n\n    bytes32 _data = marketConfigData;\n    uint256 _oldRatio = _data.decodeUint(STABILITY_RATIO_OFFSET, 64);\n    marketConfigData = _data.insertUint(_newRatio, STABILITY_RATIO_OFFSET, 64);\n\n    emit UpdateStabilityRatio(_oldRatio, _newRatio);\n  }\n\n  /// @notice Change address of platform contract.\n  /// @param _newPlatform The new address of platform contract.\n  function _updatePlatform(address _newPlatform) private {\n    if (_newPlatform == address(0)) revert ErrorZeroAddress();\n\n    address _oldPlatform = platform;\n    platform = _newPlatform;\n\n    emit UpdatePlatform(_oldPlatform, _newPlatform);\n  }\n\n  /// @notice Change address of reserve pool contract.\n  /// @param _newReservePool The new address of reserve pool contract.\n  function _updateReservePool(address _newReservePool) private {\n    if (_newReservePool == address(0)) revert ErrorZeroAddress();\n\n    address _oldReservePool = reservePool;\n    reservePool = _newReservePool;\n\n    emit UpdateReservePool(_oldReservePool, _newReservePool);\n  }\n\n  /// @notice Change address of RebalancePoolRegistry contract.\n  /// @param _newRegistry The new address of RebalancePoolRegistry contract.\n  function _updateRebalancePoolRegistry(address _newRegistry) private {\n    if (_newRegistry == address(0)) revert ErrorZeroAddress();\n\n    address _oldRegistry = registry;\n    registry = _newRegistry;\n\n    emit UpdateRebalancePoolRegistry(_oldRegistry, _newRegistry);\n  }\n\n  /// @dev Internal function to deduct fToken mint fee for base token.\n  /// @param _baseIn The amount of base token.\n  /// @param _maxBaseInBeforeSystemStabilityMode The maximum amount of base token can be deposit before entering system stability mode.\n  /// @return _baseInWithoutFee The amount of base token without fee.\n  function _deductFTokenMintFee(\n    uint256 _baseIn,\n    uint256 _maxBaseInBeforeSystemStabilityMode\n  ) private returns (uint256 _baseInWithoutFee) {\n    // [0, _maxBaseInBeforeSystemStabilityMode) => default = fee_ratio_0\n    // [_maxBaseInBeforeSystemStabilityMode, infinity) => default + extra = fee_ratio_1\n\n    (uint256 _defaultRatio, int256 _deltaRatio) = fTokenMintFeeRatio();\n    uint256 _feeRatio0 = _defaultRatio;\n    uint256 _feeRatio1 = uint256(int256(_defaultRatio) + _deltaRatio);\n\n    _baseInWithoutFee = _deductMintFee(_baseIn, _feeRatio0, _feeRatio1, _maxBaseInBeforeSystemStabilityMode);\n  }\n\n  /// @dev Internal function to deduct fToken mint fee for base token.\n  /// @param _baseIn The amount of base token.\n  /// @param _maxBaseInBeforeSystemStabilityMode The maximum amount of base token can be deposit before entering system stability mode.\n  /// @return _baseInWithoutFee The amount of base token without fee.\n  function _deductXTokenMintFee(\n    uint256 _baseIn,\n    uint256 _maxBaseInBeforeSystemStabilityMode\n  ) private returns (uint256 _baseInWithoutFee) {\n    // [0, _maxBaseInBeforeSystemStabilityMode) => default + extra = fee_ratio_0\n    // [_maxBaseInBeforeSystemStabilityMode, infinity) => default = fee_ratio_1\n\n    (uint256 _defaultRatio, int256 _deltaRatio) = xTokenMintFeeRatio();\n    uint256 _feeRatio0 = uint256(int256(_defaultRatio) + _deltaRatio);\n    uint256 _feeRatio1 = _defaultRatio;\n\n    _baseInWithoutFee = _deductMintFee(_baseIn, _feeRatio0, _feeRatio1, _maxBaseInBeforeSystemStabilityMode);\n  }\n\n  function _deductMintFee(\n    uint256 _baseIn,\n    uint256 _feeRatio0,\n    uint256 _feeRatio1,\n    uint256 _maxBaseInBeforeSystemStabilityMode\n  ) private returns (uint256 _baseInWithoutFee) {\n    uint256 _maxBaseIn = (_maxBaseInBeforeSystemStabilityMode * FEE_PRECISION) / (FEE_PRECISION - _feeRatio0);\n\n    // compute fee\n    uint256 _fee;\n    if (_baseIn <= _maxBaseIn) {\n      _fee = (_baseIn * _feeRatio0) / FEE_PRECISION;\n    } else {\n      _fee = (_maxBaseIn * _feeRatio0) / FEE_PRECISION;\n      _fee += ((_baseIn - _maxBaseIn) * _feeRatio1) / FEE_PRECISION;\n    }\n\n    _baseInWithoutFee = _baseIn - _fee;\n    // take fee to platform\n    if (_fee > 0) {\n      IERC20Upgradeable(baseToken).safeTransferFrom(_msgSender(), platform, _fee);\n    }\n  }\n\n  /// @dev Internal function to deduct mint fee for base token.\n  /// @param _amountIn The amount of fToken.\n  /// @param _maxInBeforeSystemStabilityMode The maximum amount of fToken can be redeemed before leaving system stability mode.\n  /// @return _feeRatio The computed fee ratio for base token redeemed.\n  function _computeFTokenRedeemFeeRatio(\n    uint256 _amountIn,\n    uint256 _maxInBeforeSystemStabilityMode\n  ) private view returns (uint256 _feeRatio) {\n    // [0, _maxBaseInBeforeSystemStabilityMode) => default + extra = fee_ratio_0\n    // [_maxBaseInBeforeSystemStabilityMode, infinity) => default = fee_ratio_1\n\n    (uint256 _defaultRatio, int256 _deltaRatio) = fTokenRedeemFeeRatio();\n    uint256 _feeRatio0 = uint256(int256(_defaultRatio) + _deltaRatio);\n    uint256 _feeRatio1 = _defaultRatio;\n\n    _feeRatio = _computeRedeemFeeRatio(_amountIn, _feeRatio0, _feeRatio1, _maxInBeforeSystemStabilityMode);\n  }\n\n  /// @dev Internal function to deduct mint fee for base token.\n  /// @param _amountIn The amount of xToken.\n  /// @param _maxInBeforeSystemStabilityMode The maximum amount of xToken can be redeemed before entering system stability mode.\n  /// @return _feeRatio The computed fee ratio for base token redeemed.\n  function _computeXTokenRedeemFeeRatio(\n    uint256 _amountIn,\n    uint256 _maxInBeforeSystemStabilityMode\n  ) private view returns (uint256 _feeRatio) {\n    // [0, _maxBaseInBeforeSystemStabilityMode) => default = fee_ratio_0\n    // [_maxBaseInBeforeSystemStabilityMode, infinity) => default + extra = fee_ratio_1\n\n    (uint256 _defaultRatio, int256 _deltaRatio) = xTokenRedeemFeeRatio();\n    uint256 _feeRatio0 = _defaultRatio;\n    uint256 _feeRatio1 = uint256(int256(_defaultRatio) + _deltaRatio);\n\n    _feeRatio = _computeRedeemFeeRatio(_amountIn, _feeRatio0, _feeRatio1, _maxInBeforeSystemStabilityMode);\n  }\n\n  /// @dev Internal function to deduct mint fee for base token.\n  /// @param _amountIn The amount of fToken or xToken.\n  /// @param _feeRatio0 The default fee ratio.\n  /// @param _feeRatio1 The second fee ratio.\n  /// @param _maxInBeforeSystemStabilityMode The maximum amount of fToken/xToken can be redeemed before entering/leaving system stability mode.\n  /// @return _feeRatio The computed fee ratio for base token redeemed.\n  function _computeRedeemFeeRatio(\n    uint256 _amountIn,\n    uint256 _feeRatio0,\n    uint256 _feeRatio1,\n    uint256 _maxInBeforeSystemStabilityMode\n  ) private pure returns (uint256 _feeRatio) {\n    if (_amountIn <= _maxInBeforeSystemStabilityMode) {\n      return _feeRatio0;\n    }\n    uint256 _fee = _maxInBeforeSystemStabilityMode * _feeRatio0;\n    _fee += (_amountIn - _maxInBeforeSystemStabilityMode) * _feeRatio1;\n    return _fee / _amountIn;\n  }\n}\n"},{"file_path":"@openzeppelin/contracts-v4/utils/StorageSlot.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)\n// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC1967 implementation slot:\n * ```solidity\n * contract ERC1967 {\n *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n *     function _getImplementation() internal view returns (address) {\n *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n *     }\n *\n *     function _setImplementation(address newImplementation) internal {\n *         require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n *     }\n * }\n * ```\n *\n * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._\n * _Available since v4.9 for `string`, `bytes`._\n */\nlibrary StorageSlot {\n    struct AddressSlot {\n        address value;\n    }\n\n    struct BooleanSlot {\n        bool value;\n    }\n\n    struct Bytes32Slot {\n        bytes32 value;\n    }\n\n    struct Uint256Slot {\n        uint256 value;\n    }\n\n    struct StringSlot {\n        string value;\n    }\n\n    struct BytesSlot {\n        bytes value;\n    }\n\n    /**\n     * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n     */\n    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\n     */\n    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\n     */\n    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\n     */\n    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `StringSlot` with member `value` located at `slot`.\n     */\n    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.\n     */\n    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := store.slot\n        }\n    }\n\n    /**\n     * @dev Returns an `BytesSlot` with member `value` located at `slot`.\n     */\n    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.\n     */\n    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := store.slot\n        }\n    }\n}\n"},{"file_path":"contracts/common/EIP2535/libraries/LibDiamond.sol","source_code":"// SPDX-License-Identifier: CC0-1.0\npragma solidity ^0.8.0;\n\n/******************************************************************************\\\n* Author: Nick Mudge <nick@perfectabstractions.com>, Twitter/Github: @mudgen\n* EIP-2535 Diamonds\n/******************************************************************************/\nimport { IDiamond } from \"../interfaces/IDiamond.sol\";\nimport { IDiamondCut } from \"../interfaces/IDiamondCut.sol\";\n\n// solhint-disable avoid-low-level-calls\n// solhint-disable no-inline-assembly\n\n// Remember to add the loupe functions from DiamondLoupeFacet to the diamond.\n// The loupe functions are required by the EIP2535 Diamonds standard\n\nerror NoSelectorsGivenToAdd();\nerror NotContractOwner(address _user, address _contractOwner);\nerror NoSelectorsProvidedForFacetForCut(address _facetAddress);\nerror CannotAddSelectorsToZeroAddress(bytes4[] _selectors);\nerror NoBytecodeAtAddress(address _contractAddress, string _message);\nerror IncorrectFacetCutAction(uint8 _action);\nerror CannotAddFunctionToDiamondThatAlreadyExists(bytes4 _selector);\nerror CannotReplaceFunctionsFromFacetWithZeroAddress(bytes4[] _selectors);\nerror CannotReplaceImmutableFunction(bytes4 _selector);\nerror CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet(bytes4 _selector);\nerror CannotReplaceFunctionThatDoesNotExists(bytes4 _selector);\nerror RemoveFacetAddressMustBeZeroAddress(address _facetAddress);\nerror CannotRemoveFunctionThatDoesNotExist(bytes4 _selector);\nerror CannotRemoveImmutableFunction(bytes4 _selector);\nerror InitializationFunctionReverted(address _initializationContractAddress, bytes _calldata);\n\nlibrary LibDiamond {\n  bytes32 internal constant DIAMOND_STORAGE_POSITION = keccak256(\"diamond.standard.diamond.storage\");\n\n  struct FacetAddressAndSelectorPosition {\n    address facetAddress;\n    uint16 selectorPosition;\n  }\n\n  struct DiamondStorage {\n    // function selector => facet address and selector position in selectors array\n    mapping(bytes4 => FacetAddressAndSelectorPosition) facetAddressAndSelectorPosition;\n    bytes4[] selectors;\n    mapping(bytes4 => bool) supportedInterfaces;\n    // owner of the contract\n    address contractOwner;\n  }\n\n  function diamondStorage() internal pure returns (DiamondStorage storage ds) {\n    bytes32 position = DIAMOND_STORAGE_POSITION;\n    assembly {\n      ds.slot := position\n    }\n  }\n\n  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n  function setContractOwner(address _newOwner) internal {\n    DiamondStorage storage ds = diamondStorage();\n    address previousOwner = ds.contractOwner;\n    ds.contractOwner = _newOwner;\n    emit OwnershipTransferred(previousOwner, _newOwner);\n  }\n\n  function contractOwner() internal view returns (address contractOwner_) {\n    contractOwner_ = diamondStorage().contractOwner;\n  }\n\n  function enforceIsContractOwner() internal view {\n    if (msg.sender != diamondStorage().contractOwner) {\n      revert NotContractOwner(msg.sender, diamondStorage().contractOwner);\n    }\n  }\n\n  event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);\n\n  // Internal function version of diamondCut\n  function diamondCut(\n    IDiamondCut.FacetCut[] memory _diamondCut,\n    address _init,\n    bytes memory _calldata\n  ) internal {\n    for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {\n      bytes4[] memory functionSelectors = _diamondCut[facetIndex].functionSelectors;\n      address facetAddress = _diamondCut[facetIndex].facetAddress;\n      if (functionSelectors.length == 0) {\n        revert NoSelectorsProvidedForFacetForCut(facetAddress);\n      }\n      IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;\n      if (action == IDiamond.FacetCutAction.Add) {\n        addFunctions(facetAddress, functionSelectors);\n      } else if (action == IDiamond.FacetCutAction.Replace) {\n        replaceFunctions(facetAddress, functionSelectors);\n      } else if (action == IDiamond.FacetCutAction.Remove) {\n        removeFunctions(facetAddress, functionSelectors);\n      } else {\n        revert IncorrectFacetCutAction(uint8(action));\n      }\n    }\n    emit DiamondCut(_diamondCut, _init, _calldata);\n    initializeDiamondCut(_init, _calldata);\n  }\n\n  function addFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {\n    if (_facetAddress == address(0)) {\n      revert CannotAddSelectorsToZeroAddress(_functionSelectors);\n    }\n    DiamondStorage storage ds = diamondStorage();\n    uint16 selectorCount = uint16(ds.selectors.length);\n    enforceHasContractCode(_facetAddress, \"LibDiamondCut: Add facet has no code\");\n    for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {\n      bytes4 selector = _functionSelectors[selectorIndex];\n      address oldFacetAddress = ds.facetAddressAndSelectorPosition[selector].facetAddress;\n      if (oldFacetAddress != address(0)) {\n        revert CannotAddFunctionToDiamondThatAlreadyExists(selector);\n      }\n      ds.facetAddressAndSelectorPosition[selector] = FacetAddressAndSelectorPosition(_facetAddress, selectorCount);\n      ds.selectors.push(selector);\n      selectorCount++;\n    }\n  }\n\n  function replaceFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {\n    DiamondStorage storage ds = diamondStorage();\n    if (_facetAddress == address(0)) {\n      revert CannotReplaceFunctionsFromFacetWithZeroAddress(_functionSelectors);\n    }\n    enforceHasContractCode(_facetAddress, \"LibDiamondCut: Replace facet has no code\");\n    for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {\n      bytes4 selector = _functionSelectors[selectorIndex];\n      address oldFacetAddress = ds.facetAddressAndSelectorPosition[selector].facetAddress;\n      // can't replace immutable functions -- functions defined directly in the diamond in this case\n      if (oldFacetAddress == address(this)) {\n        revert CannotReplaceImmutableFunction(selector);\n      }\n      if (oldFacetAddress == _facetAddress) {\n        revert CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet(selector);\n      }\n      if (oldFacetAddress == address(0)) {\n        revert CannotReplaceFunctionThatDoesNotExists(selector);\n      }\n      // replace old facet address\n      ds.facetAddressAndSelectorPosition[selector].facetAddress = _facetAddress;\n    }\n  }\n\n  function removeFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {\n    DiamondStorage storage ds = diamondStorage();\n    uint256 selectorCount = ds.selectors.length;\n    if (_facetAddress != address(0)) {\n      revert RemoveFacetAddressMustBeZeroAddress(_facetAddress);\n    }\n    for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {\n      bytes4 selector = _functionSelectors[selectorIndex];\n      FacetAddressAndSelectorPosition memory oldFacetAddressAndSelectorPosition = ds.facetAddressAndSelectorPosition[\n        selector\n      ];\n      if (oldFacetAddressAndSelectorPosition.facetAddress == address(0)) {\n        revert CannotRemoveFunctionThatDoesNotExist(selector);\n      }\n\n      // can't remove immutable functions -- functions defined directly in the diamond\n      if (oldFacetAddressAndSelectorPosition.facetAddress == address(this)) {\n        revert CannotRemoveImmutableFunction(selector);\n      }\n      // replace selector with last selector\n      selectorCount--;\n      if (oldFacetAddressAndSelectorPosition.selectorPosition != selectorCount) {\n        bytes4 lastSelector = ds.selectors[selectorCount];\n        ds.selectors[oldFacetAddressAndSelectorPosition.selectorPosition] = lastSelector;\n        ds.facetAddressAndSelectorPosition[lastSelector].selectorPosition = oldFacetAddressAndSelectorPosition\n          .selectorPosition;\n      }\n      // delete last selector\n      ds.selectors.pop();\n      delete ds.facetAddressAndSelectorPosition[selector];\n    }\n  }\n\n  function initializeDiamondCut(address _init, bytes memory _calldata) internal {\n    if (_init == address(0)) {\n      return;\n    }\n    enforceHasContractCode(_init, \"LibDiamondCut: _init address has no code\");\n    (bool success, bytes memory error) = _init.delegatecall(_calldata);\n    if (!success) {\n      if (error.length > 0) {\n        // bubble up error\n        /// @solidity memory-safe-assembly\n        assembly {\n          let returndata_size := mload(error)\n          revert(add(32, error), returndata_size)\n        }\n      } else {\n        revert InitializationFunctionReverted(_init, _calldata);\n      }\n    }\n  }\n\n  function enforceHasContractCode(address _contract, string memory _errorMessage) internal view {\n    uint256 contractSize;\n    assembly {\n      contractSize := extcodesize(_contract)\n    }\n    if (contractSize == 0) {\n      revert NoBytecodeAtAddress(_contract, _errorMessage);\n    }\n  }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/utils/cryptography/ECDSAUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../StringsUpgradeable.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSAUpgradeable {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV // Deprecated in v4.8\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {\n        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) >> 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x00, \"\\x19Ethereum Signed Message:\\n32\")\n            mstore(0x1c, hash)\n            message := keccak256(0x00, 0x3c)\n        }\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", StringsUpgradeable.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let ptr := mload(0x40)\n            mstore(ptr, \"\\x19\\x01\")\n            mstore(add(ptr, 0x02), domainSeparator)\n            mstore(add(ptr, 0x22), structHash)\n            data := keccak256(ptr, 0x42)\n        }\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Data with intended validator, created from a\n     * `validator` and `data` according to the version 0 of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x00\", validator, data));\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/ERC721.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC721} from \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\nimport {IERC721Receiver} from \"@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol\";\nimport {IERC721Metadata} from \"@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol\";\nimport {ContextUpgradeable} from \"../../utils/ContextUpgradeable.sol\";\nimport {Strings} from \"@openzeppelin/contracts/utils/Strings.sol\";\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {ERC165Upgradeable} from \"../../utils/introspection/ERC165Upgradeable.sol\";\nimport {IERC721Errors} from \"@openzeppelin/contracts/interfaces/draft-IERC6093.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including\n * the Metadata extension, but not including the Enumerable extension, which is available separately as\n * {ERC721Enumerable}.\n */\nabstract contract ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721, IERC721Metadata, IERC721Errors {\n    using Strings for uint256;\n\n    /// @custom:storage-location erc7201:openzeppelin.storage.ERC721\n    struct ERC721Storage {\n        // Token name\n        string _name;\n\n        // Token symbol\n        string _symbol;\n\n        mapping(uint256 tokenId => address) _owners;\n\n        mapping(address owner => uint256) _balances;\n\n        mapping(uint256 tokenId => address) _tokenApprovals;\n\n        mapping(address owner => mapping(address operator => bool)) _operatorApprovals;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.ERC721\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant ERC721StorageLocation = 0x80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab0079300;\n\n    function _getERC721Storage() private pure returns (ERC721Storage storage $) {\n        assembly {\n            $.slot := ERC721StorageLocation\n        }\n    }\n\n    /**\n     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.\n     */\n    function __ERC721_init(string memory name_, string memory symbol_) internal onlyInitializing {\n        __ERC721_init_unchained(name_, symbol_);\n    }\n\n    function __ERC721_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {\n        ERC721Storage storage $ = _getERC721Storage();\n        $._name = name_;\n        $._symbol = symbol_;\n    }\n\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165) returns (bool) {\n        return\n            interfaceId == type(IERC721).interfaceId ||\n            interfaceId == type(IERC721Metadata).interfaceId ||\n            super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev See {IERC721-balanceOf}.\n     */\n    function balanceOf(address owner) public view virtual returns (uint256) {\n        ERC721Storage storage $ = _getERC721Storage();\n        if (owner == address(0)) {\n            revert ERC721InvalidOwner(address(0));\n        }\n        return $._balances[owner];\n    }\n\n    /**\n     * @dev See {IERC721-ownerOf}.\n     */\n    function ownerOf(uint256 tokenId) public view virtual returns (address) {\n        return _requireOwned(tokenId);\n    }\n\n    /**\n     * @dev See {IERC721Metadata-name}.\n     */\n    function name() public view virtual returns (string memory) {\n        ERC721Storage storage $ = _getERC721Storage();\n        return $._name;\n    }\n\n    /**\n     * @dev See {IERC721Metadata-symbol}.\n     */\n    function symbol() public view virtual returns (string memory) {\n        ERC721Storage storage $ = _getERC721Storage();\n        return $._symbol;\n    }\n\n    /**\n     * @dev See {IERC721Metadata-tokenURI}.\n     */\n    function tokenURI(uint256 tokenId) public view virtual returns (string memory) {\n        _requireOwned(tokenId);\n\n        string memory baseURI = _baseURI();\n        return bytes(baseURI).length > 0 ? string.concat(baseURI, tokenId.toString()) : \"\";\n    }\n\n    /**\n     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each\n     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty\n     * by default, can be overridden in child contracts.\n     */\n    function _baseURI() internal view virtual returns (string memory) {\n        return \"\";\n    }\n\n    /**\n     * @dev See {IERC721-approve}.\n     */\n    function approve(address to, uint256 tokenId) public virtual {\n        _approve(to, tokenId, _msgSender());\n    }\n\n    /**\n     * @dev See {IERC721-getApproved}.\n     */\n    function getApproved(uint256 tokenId) public view virtual returns (address) {\n        _requireOwned(tokenId);\n\n        return _getApproved(tokenId);\n    }\n\n    /**\n     * @dev See {IERC721-setApprovalForAll}.\n     */\n    function setApprovalForAll(address operator, bool approved) public virtual {\n        _setApprovalForAll(_msgSender(), operator, approved);\n    }\n\n    /**\n     * @dev See {IERC721-isApprovedForAll}.\n     */\n    function isApprovedForAll(address owner, address operator) public view virtual returns (bool) {\n        ERC721Storage storage $ = _getERC721Storage();\n        return $._operatorApprovals[owner][operator];\n    }\n\n    /**\n     * @dev See {IERC721-transferFrom}.\n     */\n    function transferFrom(address from, address to, uint256 tokenId) public virtual {\n        if (to == address(0)) {\n            revert ERC721InvalidReceiver(address(0));\n        }\n        // Setting an \"auth\" arguments enables the `_isAuthorized` check which verifies that the token exists\n        // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here.\n        address previousOwner = _update(to, tokenId, _msgSender());\n        if (previousOwner != from) {\n            revert ERC721IncorrectOwner(from, tokenId, previousOwner);\n        }\n    }\n\n    /**\n     * @dev See {IERC721-safeTransferFrom}.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId) public {\n        safeTransferFrom(from, to, tokenId, \"\");\n    }\n\n    /**\n     * @dev See {IERC721-safeTransferFrom}.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual {\n        transferFrom(from, to, tokenId);\n        _checkOnERC721Received(from, to, tokenId, data);\n    }\n\n    /**\n     * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist\n     *\n     * IMPORTANT: Any overrides to this function that add ownership of tokens not tracked by the\n     * core ERC721 logic MUST be matched with the use of {_increaseBalance} to keep balances\n     * consistent with ownership. The invariant to preserve is that for any address `a` the value returned by\n     * `balanceOf(a)` must be equal to the number of tokens such that `_ownerOf(tokenId)` is `a`.\n     */\n    function _ownerOf(uint256 tokenId) internal view virtual returns (address) {\n        ERC721Storage storage $ = _getERC721Storage();\n        return $._owners[tokenId];\n    }\n\n    /**\n     * @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted.\n     */\n    function _getApproved(uint256 tokenId) internal view virtual returns (address) {\n        ERC721Storage storage $ = _getERC721Storage();\n        return $._tokenApprovals[tokenId];\n    }\n\n    /**\n     * @dev Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in\n     * particular (ignoring whether it is owned by `owner`).\n     *\n     * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this\n     * assumption.\n     */\n    function _isAuthorized(address owner, address spender, uint256 tokenId) internal view virtual returns (bool) {\n        return\n            spender != address(0) &&\n            (owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender);\n    }\n\n    /**\n     * @dev Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner.\n     * Reverts if `spender` does not have approval from the provided `owner` for the given token or for all its assets\n     * the `spender` for the specific `tokenId`.\n     *\n     * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this\n     * assumption.\n     */\n    function _checkAuthorized(address owner, address spender, uint256 tokenId) internal view virtual {\n        if (!_isAuthorized(owner, spender, tokenId)) {\n            if (owner == address(0)) {\n                revert ERC721NonexistentToken(tokenId);\n            } else {\n                revert ERC721InsufficientApproval(spender, tokenId);\n            }\n        }\n    }\n\n    /**\n     * @dev Unsafe write access to the balances, used by extensions that \"mint\" tokens using an {ownerOf} override.\n     *\n     * NOTE: the value is limited to type(uint128).max. This protect against _balance overflow. It is unrealistic that\n     * a uint256 would ever overflow from increments when these increments are bounded to uint128 values.\n     *\n     * WARNING: Increasing an account's balance using this function tends to be paired with an override of the\n     * {_ownerOf} function to resolve the ownership of the corresponding tokens so that balances and ownership\n     * remain consistent with one another.\n     */\n    function _increaseBalance(address account, uint128 value) internal virtual {\n        ERC721Storage storage $ = _getERC721Storage();\n        unchecked {\n            $._balances[account] += value;\n        }\n    }\n\n    /**\n     * @dev Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner\n     * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update.\n     *\n     * The `auth` argument is optional. If the value passed is non 0, then this function will check that\n     * `auth` is either the owner of the token, or approved to operate on the token (by the owner).\n     *\n     * Emits a {Transfer} event.\n     *\n     * NOTE: If overriding this function in a way that tracks balances, see also {_increaseBalance}.\n     */\n    function _update(address to, uint256 tokenId, address auth) internal virtual returns (address) {\n        ERC721Storage storage $ = _getERC721Storage();\n        address from = _ownerOf(tokenId);\n\n        // Perform (optional) operator check\n        if (auth != address(0)) {\n            _checkAuthorized(from, auth, tokenId);\n        }\n\n        // Execute the update\n        if (from != address(0)) {\n            // Clear approval. No need to re-authorize or emit the Approval event\n            _approve(address(0), tokenId, address(0), false);\n\n            unchecked {\n                $._balances[from] -= 1;\n            }\n        }\n\n        if (to != address(0)) {\n            unchecked {\n                $._balances[to] += 1;\n            }\n        }\n\n        $._owners[tokenId] = to;\n\n        emit Transfer(from, to, tokenId);\n\n        return from;\n    }\n\n    /**\n     * @dev Mints `tokenId` and transfers it to `to`.\n     *\n     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible\n     *\n     * Requirements:\n     *\n     * - `tokenId` must not exist.\n     * - `to` cannot be the zero address.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _mint(address to, uint256 tokenId) internal {\n        if (to == address(0)) {\n            revert ERC721InvalidReceiver(address(0));\n        }\n        address previousOwner = _update(to, tokenId, address(0));\n        if (previousOwner != address(0)) {\n            revert ERC721InvalidSender(address(0));\n        }\n    }\n\n    /**\n     * @dev Mints `tokenId`, transfers it to `to` and checks for `to` acceptance.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must not exist.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _safeMint(address to, uint256 tokenId) internal {\n        _safeMint(to, tokenId, \"\");\n    }\n\n    /**\n     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is\n     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.\n     */\n    function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual {\n        _mint(to, tokenId);\n        _checkOnERC721Received(address(0), to, tokenId, data);\n    }\n\n    /**\n     * @dev Destroys `tokenId`.\n     * The approval is cleared when the token is burned.\n     * This is an internal function that does not check if the sender is authorized to operate on the token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _burn(uint256 tokenId) internal {\n        address previousOwner = _update(address(0), tokenId, address(0));\n        if (previousOwner == address(0)) {\n            revert ERC721NonexistentToken(tokenId);\n        }\n    }\n\n    /**\n     * @dev Transfers `tokenId` from `from` to `to`.\n     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _transfer(address from, address to, uint256 tokenId) internal {\n        if (to == address(0)) {\n            revert ERC721InvalidReceiver(address(0));\n        }\n        address previousOwner = _update(to, tokenId, address(0));\n        if (previousOwner == address(0)) {\n            revert ERC721NonexistentToken(tokenId);\n        } else if (previousOwner != from) {\n            revert ERC721IncorrectOwner(from, tokenId, previousOwner);\n        }\n    }\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`, checking that contract recipients\n     * are aware of the ERC721 standard to prevent tokens from being forever locked.\n     *\n     * `data` is additional data, it has no specified format and it is sent in call to `to`.\n     *\n     * This internal function is like {safeTransferFrom} in the sense that it invokes\n     * {IERC721Receiver-onERC721Received} on the receiver, and can be used to e.g.\n     * implement alternative mechanisms to perform token transfer, such as signature-based.\n     *\n     * Requirements:\n     *\n     * - `tokenId` token must exist and be owned by `from`.\n     * - `to` cannot be the zero address.\n     * - `from` cannot be the zero address.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _safeTransfer(address from, address to, uint256 tokenId) internal {\n        _safeTransfer(from, to, tokenId, \"\");\n    }\n\n    /**\n     * @dev Same as {xref-ERC721-_safeTransfer-address-address-uint256-}[`_safeTransfer`], with an additional `data` parameter which is\n     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.\n     */\n    function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual {\n        _transfer(from, to, tokenId);\n        _checkOnERC721Received(from, to, tokenId, data);\n    }\n\n    /**\n     * @dev Approve `to` to operate on `tokenId`\n     *\n     * The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is\n     * either the owner of the token, or approved to operate on all tokens held by this owner.\n     *\n     * Emits an {Approval} event.\n     *\n     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.\n     */\n    function _approve(address to, uint256 tokenId, address auth) internal {\n        _approve(to, tokenId, auth, true);\n    }\n\n    /**\n     * @dev Variant of `_approve` with an optional flag to enable or disable the {Approval} event. The event is not\n     * emitted in the context of transfers.\n     */\n    function _approve(address to, uint256 tokenId, address auth, bool emitEvent) internal virtual {\n        ERC721Storage storage $ = _getERC721Storage();\n        // Avoid reading the owner unless necessary\n        if (emitEvent || auth != address(0)) {\n            address owner = _requireOwned(tokenId);\n\n            // We do not use _isAuthorized because single-token approvals should not be able to call approve\n            if (auth != address(0) && owner != auth && !isApprovedForAll(owner, auth)) {\n                revert ERC721InvalidApprover(auth);\n            }\n\n            if (emitEvent) {\n                emit Approval(owner, to, tokenId);\n            }\n        }\n\n        $._tokenApprovals[tokenId] = to;\n    }\n\n    /**\n     * @dev Approve `operator` to operate on all of `owner` tokens\n     *\n     * Requirements:\n     * - operator can't be the address zero.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {\n        ERC721Storage storage $ = _getERC721Storage();\n        if (operator == address(0)) {\n            revert ERC721InvalidOperator(operator);\n        }\n        $._operatorApprovals[owner][operator] = approved;\n        emit ApprovalForAll(owner, operator, approved);\n    }\n\n    /**\n     * @dev Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned).\n     * Returns the owner.\n     *\n     * Overrides to ownership logic should be done to {_ownerOf}.\n     */\n    function _requireOwned(uint256 tokenId) internal view returns (address) {\n        address owner = _ownerOf(tokenId);\n        if (owner == address(0)) {\n            revert ERC721NonexistentToken(tokenId);\n        }\n        return owner;\n    }\n\n    /**\n     * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target address. This will revert if the\n     * recipient doesn't accept the token transfer. The call is not executed if the target address is not a contract.\n     *\n     * @param from address representing the previous owner of the given token ID\n     * @param to target address that will receive the tokens\n     * @param tokenId uint256 ID of the token to be transferred\n     * @param data bytes optional data to send along with the call\n     */\n    function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory data) private {\n        if (to.code.length > 0) {\n            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {\n                if (retval != IERC721Receiver.onERC721Received.selector) {\n                    revert ERC721InvalidReceiver(to);\n                }\n            } catch (bytes memory reason) {\n                if (reason.length == 0) {\n                    revert ERC721InvalidReceiver(to);\n                } else {\n                    /// @solidity memory-safe-assembly\n                    assembly {\n                        revert(add(32, reason), mload(reason))\n                    }\n                }\n            }\n        }\n    }\n}\n"},{"file_path":"contracts/core/pool/PositionLogic.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IPool } from \"../../interfaces/IPool.sol\";\nimport { IPriceOracle } from \"../../price-oracle/interfaces/IPriceOracle.sol\";\n\nimport { WordCodec } from \"../../common/codec/WordCodec.sol\";\nimport { Math } from \"../../libraries/Math.sol\";\nimport { TickLogic } from \"./TickLogic.sol\";\n\nabstract contract PositionLogic is TickLogic {\n  using WordCodec for bytes32;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  function __PositionLogic_init() internal onlyInitializing {\n    _updateNextPositionId(1);\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @inheritdoc IPool\n  function getPosition(uint256 tokenId) public view returns (uint256 rawColls, uint256 rawDebts) {\n    // compute actual shares\n    PositionInfo memory position = positionData[tokenId];\n    rawColls = position.colls;\n    rawDebts = position.debts;\n    if (position.nodeId > 0) {\n      (, uint256 collRatio, uint256 debtRatio) = _getRootNode(position.nodeId);\n      rawColls = (rawColls * collRatio) >> 60;\n      rawDebts = (rawDebts * debtRatio) >> 60;\n    }\n\n    // convert shares to actual amount\n    (uint256 debtIndex, uint256 collIndex) = _getDebtAndCollateralIndex();\n    rawColls = _convertToRawColl(rawColls, collIndex, Math.Rounding.Down);\n    rawDebts = _convertToRawDebt(rawDebts, debtIndex, Math.Rounding.Down);\n  }\n\n  /// @inheritdoc IPool\n  function getPositionDebtRatio(uint256 tokenId) external view returns (uint256 debtRatio) {\n    (uint256 rawColls, uint256 rawDebts) = getPosition(tokenId);\n    // price precision and ratio precision are both 1e18, use anchor price here\n    (uint256 price, , ) = IPriceOracle(priceOracle).getPrice();\n    if (rawColls == 0) return 0;\n    return (rawDebts * PRECISION * PRECISION) / (price * rawColls);\n  }\n\n  /// @inheritdoc IPool\n  function getTotalRawCollaterals() external view returns (uint256) {\n    (, uint256 totalColls) = _getDebtAndCollateralShares();\n    (, uint256 collIndex) = _getDebtAndCollateralIndex();\n    return _convertToRawColl(totalColls, collIndex, Math.Rounding.Down);\n  }\n\n  /// @inheritdoc IPool\n  function getTotalRawDebts() external view returns (uint256) {\n    (uint256 totalDebts, ) = _getDebtAndCollateralShares();\n    (uint256 debtIndex, ) = _getDebtAndCollateralIndex();\n    return _convertToRawDebt(totalDebts, debtIndex, Math.Rounding.Down);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to mint a new position.\n  /// @param owner The address of position owner.\n  /// @return positionId The id of the position.\n  function _mintPosition(address owner) internal returns (uint32 positionId) {\n    unchecked {\n      positionId = _getNextPositionId();\n      _updateNextPositionId(positionId + 1);\n    }\n\n    positionMetadata[positionId] = bytes32(0).insertUint(block.timestamp, 0, 40);\n    _mint(owner, positionId);\n  }\n\n  /// @dev Internal function to get and update position.\n  /// @param tokenId The id of the position.\n  /// @return position The position struct.\n  function _getAndUpdatePosition(uint256 tokenId) internal returns (PositionInfo memory position) {\n    position = positionData[tokenId];\n    if (position.nodeId > 0) {\n      (uint256 root, uint256 collRatio, uint256 debtRatio) = _getRootNodeAndCompress(position.nodeId);\n      position.colls = uint96((position.colls * collRatio) >> 60);\n      position.debts = uint96((position.debts * debtRatio) >> 60);\n      position.nodeId = uint32(root);\n      positionData[tokenId] = position;\n    }\n  }\n\n  /// @dev Internal function to convert raw collateral amounts to collateral shares.\n  function _convertToCollShares(\n    uint256 raw,\n    uint256 index,\n    Math.Rounding rounding\n  ) internal pure returns (uint256 shares) {\n    shares = Math.mulDiv(raw, index, E96, rounding);\n  }\n\n  /// @dev Internal function to convert raw debt amounts to debt shares.\n  function _convertToDebtShares(\n    uint256 raw,\n    uint256 index,\n    Math.Rounding rounding\n  ) internal pure returns (uint256 shares) {\n    shares = Math.mulDiv(raw, E96, index, rounding);\n  }\n\n  /// @dev Internal function to convert raw collateral shares to collateral amounts.\n  function _convertToRawColl(\n    uint256 shares,\n    uint256 index,\n    Math.Rounding rounding\n  ) internal pure returns (uint256 raw) {\n    raw = Math.mulDiv(shares, E96, index, rounding);\n  }\n\n  /// @dev Internal function to convert raw debt shares to debt amounts.\n  function _convertToRawDebt(\n    uint256 shares,\n    uint256 index,\n    Math.Rounding rounding\n  ) internal pure returns (uint256 raw) {\n    raw = Math.mulDiv(shares, index, E96, rounding);\n  }\n\n  /**\n   * @dev This empty reserved space is put in place to allow future versions to add new\n   * variables without shifting down storage in the inheritance chain.\n   */\n  uint256[50] private __gap;\n}\n"},{"file_path":"contracts/interfaces/IPool.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IPool {\n  /**********\n   * Events *\n   **********/\n  \n  /// @notice Emitted when price oracle is updated.\n  /// @param oldOracle The previous address of price oracle.\n  /// @param newOracle The current address of price oracle.\n  event UpdatePriceOracle(address oldOracle, address newOracle);\n  \n  /// @notice Emitted when borrow status is updated.\n  /// @param status The updated borrow status.\n  event UpdateBorrowStatus(bool status);\n\n  /// @notice Emitted when redeem status is updated.\n  /// @param status The updated redeem status.\n  event UpdateRedeemStatus(bool status);\n  \n  /// @notice Emitted when debt ratio range is updated.\n  /// @param minDebtRatio The current value of minimum debt ratio, multiplied by 1e18.\n  /// @param maxDebtRatio The current value of maximum debt ratio, multiplied by 1e18.\n  event UpdateDebtRatioRange(uint256 minDebtRatio, uint256 maxDebtRatio);\n  \n  /// @notice Emitted when max redeem ratio per tick is updated.\n  /// @param ratio The current value of max redeem ratio per tick, multiplied by 1e9.\n  event UpdateMaxRedeemRatioPerTick(uint256 ratio);\n  \n  /// @notice Emitted when the rebalance ratio is updated.\n  /// @param debtRatio The current value of rebalance debt ratio, multiplied by 1e18.\n  /// @param bonusRatio The current value of rebalance bonus ratio, multiplied by 1e9.\n  event UpdateRebalanceRatios(uint256 debtRatio, uint256 bonusRatio);\n\n  /// @notice Emitted when the liquidate ratio is updated.\n  /// @param debtRatio The current value of liquidate debt ratio, multiplied by 1e18.\n  /// @param bonusRatio The current value of liquidate bonus ratio, multiplied by 1e9.\n  event UpdateLiquidateRatios(uint256 debtRatio, uint256 bonusRatio);\n  \n  /// @notice Emitted when position is updated.\n  /// @param position The index of this position.\n  /// @param tick The index of tick, this position belongs to.\n  /// @param collShares The amount of collateral shares in this position.\n  /// @param debtShares The amount of debt shares in this position.\n  /// @param price The price used for this operation.\n  event PositionSnapshot(uint256 position, int16 tick, uint256 collShares, uint256 debtShares, uint256 price);\n  \n  /// @notice Emitted when tick moved due to rebalance, liquidate or redeem.\n  /// @param oldTick The index of the previous tick.\n  /// @param newTick The index of the current tick.\n  /// @param collShares The amount of collateral shares added to new tick.\n  /// @param debtShares The amount of debt shares added to new tick.\n  /// @param price The price used for this operation.\n  event TickMovement(int16 oldTick, int16 newTick, uint256 collShares, uint256 debtShares, uint256 price);\n\n  /// @notice Emitted when debt index increase.\n  event DebtIndexSnapshot(uint256 index);\n  \n  /// @notice Emitted when collateral index increase.\n  event CollateralIndexSnapshot(uint256 index);\n\n  /***********\n   * Structs *\n   ***********/\n\n  /// @dev The result for liquidation.\n  /// @param rawColls The amount of collateral tokens liquidated.\n  /// @param rawDebts The amount of debt tokens liquidated.\n  /// @param bonusRawColls The amount of bonus collateral tokens given.\n  /// @param bonusFromReserve The amount of bonus collateral tokens coming from reserve pool.\n  struct LiquidateResult {\n    uint256 rawColls;\n    uint256 rawDebts;\n    uint256 bonusRawColls;\n    uint256 bonusFromReserve;\n  }\n\n  /// @dev The result for rebalance.\n  /// @param rawColls The amount of collateral tokens rebalanced.\n  /// @param rawDebts The amount of debt tokens rebalanced.\n  /// @param bonusRawColls The amount of bonus collateral tokens given.\n  struct RebalanceResult {\n    uint256 rawColls;\n    uint256 rawDebts;\n    uint256 bonusRawColls;\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice The address of fxUSD.\n  function fxUSD() external view returns (address);\n\n  /// @notice The address of `PoolManager` contract.\n  function poolManager() external view returns (address);\n\n  /// @notice The address of `PegKeeper` contract.\n  function pegKeeper() external view returns (address);\n\n  /// @notice The address of collateral token.\n  function collateralToken() external view returns (address);\n\n  /// @notice The address of price oracle.\n  function priceOracle() external view returns (address);\n  \n  /// @notice Return whether borrow is paused.\n  function isBorrowPaused() external view returns (bool);\n\n  /// @notice Return whether redeem is paused.\n  function isRedeemPaused() external view returns (bool);\n  \n  /// @notice Return the current top tick with debts.\n  function getTopTick() external view returns (int16);\n\n  /// @notice Return the next position id.\n  function getNextPositionId() external view returns (uint32);\n\n  /// @notice Return the next tick tree node id.\n  function getNextTreeNodeId() external view returns (uint48);\n\n  /// @notice Return the debt ratio range.\n  /// @param minDebtRatio The minimum required debt ratio, multiplied by 1e18.\n  /// @param maxDebtRatio The minimum allowed debt ratio, multiplied by 1e18.\n  function getDebtRatioRange() external view returns (uint256 minDebtRatio, uint256 maxDebtRatio);\n\n  /// @notice Return the maximum redeem percentage per tick, multiplied by 1e9.\n  function getMaxRedeemRatioPerTick() external view returns (uint256);\n\n  /// @notice Get `debtRatio` and `bonusRatio` for rebalance.\n  /// @return debtRatio The minimum debt ratio to start rebalance, multiplied by 1e18.\n  /// @return bonusRatio The bonus ratio during rebalance, multiplied by 1e9.\n  function getRebalanceRatios() external view returns (uint256 debtRatio, uint256 bonusRatio);\n\n  /// @notice Get `debtRatio` and `bonusRatio` for liquidate.\n  /// @return debtRatio The minimum debt ratio to start liquidate, multiplied by 1e18.\n  /// @return bonusRatio The bonus ratio during liquidate, multiplied by 1e9.\n  function getLiquidateRatios() external view returns (uint256 debtRatio, uint256 bonusRatio);\n\n  /// @notice Get debt and collateral index.\n  /// @return debtIndex The index for debt shares.\n  /// @return collIndex The index for collateral shares.\n  function getDebtAndCollateralIndex() external view returns (uint256 debtIndex, uint256 collIndex);\n\n  /// @notice Get debt and collateral shares.\n  /// @return debtShares The total number of debt shares.\n  /// @return collShares The total number of collateral shares.\n  function getDebtAndCollateralShares() external view returns (uint256 debtShares, uint256 collShares);\n\n  /// @notice Return the details of the given position.\n  /// @param tokenId The id of position to query.\n  /// @return rawColls The amount of collateral tokens supplied in this position.\n  /// @return rawDebts The amount of debt tokens borrowed in this position.\n  function getPosition(uint256 tokenId) external view returns (uint256 rawColls, uint256 rawDebts);\n\n  /// @notice Return the debt ratio of the given position.\n  /// @param tokenId The id of position to query.\n  /// @return debtRatio The debt ratio of this position.\n  function getPositionDebtRatio(uint256 tokenId) external view returns (uint256 debtRatio);\n\n  /// @notice The total amount of raw collateral tokens.\n  function getTotalRawCollaterals() external view returns (uint256);\n\n  /// @notice The total amount of raw debt tokens.\n  function getTotalRawDebts() external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Open a new position or operate on an old position.\n  /// @param positionId The id of the position. If `positionId=0`, it means we need to open a new position.\n  /// @param newRawColl The amount of collateral token to supply (positive value) or withdraw (negative value).\n  /// @param newRawColl The amount of debt token to borrow (positive value) or repay (negative value).\n  /// @param owner The address of position owner.\n  /// @return actualPositionId The id of this position.\n  /// @return actualRawColl The actual amount of collateral tokens supplied (positive value) or withdrawn (negative value).\n  /// @return actualRawDebt The actual amount of debt tokens borrowed (positive value) or repay (negative value).\n  function operate(\n    uint256 positionId,\n    int256 newRawColl,\n    int256 newRawDebt,\n    address owner\n  ) external returns (uint256 actualPositionId, int256 actualRawColl, int256 actualRawDebt, uint256 protocolFees);\n\n  /// @notice Redeem debt tokens to get collateral tokens.\n  /// @param rawDebts The amount of debt tokens to redeem.\n  /// @return rawColls The amount of collateral tokens to redeemed.\n  function redeem(uint256 rawDebts) external returns (uint256 rawColls);\n\n  /// @notice Rebalance all positions in the given tick.\n  /// @param tick The id of tick to rebalance.\n  /// @param maxRawDebts The maximum amount of debt tokens to rebalance.\n  /// @return result The result of rebalance.\n  function rebalance(int16 tick, uint256 maxRawDebts) external returns (RebalanceResult memory result);\n\n  /// @notice Rebalance the given position.\n  /// @param positionId The id of position to rebalance.\n  /// @param maxRawDebts The maximum amount of debt tokens to rebalance.\n  /// @return result The result of rebalance.\n  function rebalance(uint32 positionId, uint256 maxRawDebts) external returns (RebalanceResult memory result);\n\n  /// @notice Liquidate the given position.\n  /// @param positionId The id of position to liquidate.\n  /// @param maxRawDebts The maximum amount of debt tokens to liquidate.\n  /// @param reservedRawColls The amount of collateral tokens in reserve pool.\n  /// @return result The result of liquidate.\n  function liquidate(\n    uint256 positionId,\n    uint256 maxRawDebts,\n    uint256 reservedRawColls\n  ) external returns (LiquidateResult memory result);\n}\n"},{"file_path":"contracts/mocks/MockRateProvider.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IRateProvider } from \"../rate-provider/interfaces/IRateProvider.sol\";\n\ncontract MockRateProvider is IRateProvider {\n  uint256 public rate;\n\n  constructor(uint256 _rate) {\n    rate = _rate;\n  }\n\n  function setRate(uint256 _rate) external {\n    rate = _rate;\n  }\n\n  function getRate() external view returns (uint256) {\n    return rate;\n  }\n}\n"},{"file_path":"contracts/helpers/GaugeRewarder.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IMultipleRewardDistributor } from \"../common/rewards/distributor/IMultipleRewardDistributor.sol\";\nimport { IRewardSplitter } from \"../interfaces/IRewardSplitter.sol\";\n\nimport { PermissionedSwap } from \"../common/utils/PermissionedSwap.sol\";\n\ncontract GaugeRewarder is PermissionedSwap, IRewardSplitter {\n  using SafeERC20 for IERC20;\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @notice The address of `LiquidityGauge` contract.\n  address public immutable gauge;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _gauge) initializer {\n    __Context_init();\n    __ERC165_init();\n    __AccessControl_init();\n\n    gauge = _gauge;\n\n    _grantRole(DEFAULT_ADMIN_ROLE, _msgSender());\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc IRewardSplitter\n  function split(address token) external override {\n    // do nothing\n  }\n\n  /// @inheritdoc IRewardSplitter\n  function depositReward(address token, uint256 amount) external override {\n    IERC20(token).safeTransferFrom(_msgSender(), address(this), amount);\n  }\n\n  /// @notice Harvest base token to target token by amm trading and distribute to fxBASE gauge.\n  /// @param baseToken The address of base token to use.\n  /// @param targetToken The address target token.\n  /// @param params The parameters used for trading.\n  /// @return amountOut The amount of target token received.\n  function swapAndDistribute(\n    address baseToken,\n    address targetToken,\n    TradingParameter memory params\n  ) external returns (uint256 amountOut) {\n    uint256 amountIn = IERC20(baseToken).balanceOf(address(this));\n\n    // swap base token to target\n    amountOut = _doTrade(baseToken, targetToken, amountIn, params);\n\n    // deposit target token to gauge\n    IERC20(targetToken).forceApprove(gauge, amountOut);\n    IMultipleRewardDistributor(gauge).depositReward(targetToken, amountOut);\n  }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Permit.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20Permit} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\";\nimport {ERC20Upgradeable} from \"../ERC20Upgradeable.sol\";\nimport {ECDSA} from \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport {EIP712Upgradeable} from \"../../../utils/cryptography/EIP712Upgradeable.sol\";\nimport {NoncesUpgradeable} from \"../../../utils/NoncesUpgradeable.sol\";\nimport {Initializable} from \"../../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\nabstract contract ERC20PermitUpgradeable is Initializable, ERC20Upgradeable, IERC20Permit, EIP712Upgradeable, NoncesUpgradeable {\n    bytes32 private constant PERMIT_TYPEHASH =\n        keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n\n    /**\n     * @dev Permit deadline has expired.\n     */\n    error ERC2612ExpiredSignature(uint256 deadline);\n\n    /**\n     * @dev Mismatched signature.\n     */\n    error ERC2612InvalidSigner(address signer, address owner);\n\n    /**\n     * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\"1\"`.\n     *\n     * It's a good idea to use the same `name` that is defined as the ERC20 token name.\n     */\n    function __ERC20Permit_init(string memory name) internal onlyInitializing {\n        __EIP712_init_unchained(name, \"1\");\n    }\n\n    function __ERC20Permit_init_unchained(string memory) internal onlyInitializing {}\n\n    /**\n     * @inheritdoc IERC20Permit\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        if (block.timestamp > deadline) {\n            revert ERC2612ExpiredSignature(deadline);\n        }\n\n        bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));\n\n        bytes32 hash = _hashTypedDataV4(structHash);\n\n        address signer = ECDSA.recover(hash, v, r, s);\n        if (signer != owner) {\n            revert ERC2612InvalidSigner(signer, owner);\n        }\n\n        _approve(owner, spender, value);\n    }\n\n    /**\n     * @inheritdoc IERC20Permit\n     */\n    function nonces(address owner) public view virtual override(IERC20Permit, NoncesUpgradeable) returns (uint256) {\n        return super.nonces(owner);\n    }\n\n    /**\n     * @inheritdoc IERC20Permit\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view virtual returns (bytes32) {\n        return _domainSeparatorV4();\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/interfaces/draft-IERC6093.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)\npragma solidity ^0.8.20;\n\n/**\n * @dev Standard ERC20 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.\n */\ninterface IERC20Errors {\n    /**\n     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     * @param balance Current balance for the interacting account.\n     * @param needed Minimum amount required to perform a transfer.\n     */\n    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);\n\n    /**\n     * @dev Indicates a failure with the token `sender`. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     */\n    error ERC20InvalidSender(address sender);\n\n    /**\n     * @dev Indicates a failure with the token `receiver`. Used in transfers.\n     * @param receiver Address to which tokens are being transferred.\n     */\n    error ERC20InvalidReceiver(address receiver);\n\n    /**\n     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.\n     * @param spender Address that may be allowed to operate on tokens without being their owner.\n     * @param allowance Amount of tokens a `spender` is allowed to operate with.\n     * @param needed Minimum amount required to perform a transfer.\n     */\n    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);\n\n    /**\n     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n     * @param approver Address initiating an approval operation.\n     */\n    error ERC20InvalidApprover(address approver);\n\n    /**\n     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.\n     * @param spender Address that may be allowed to operate on tokens without being their owner.\n     */\n    error ERC20InvalidSpender(address spender);\n}\n\n/**\n * @dev Standard ERC721 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.\n */\ninterface IERC721Errors {\n    /**\n     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.\n     * Used in balance queries.\n     * @param owner Address of the current owner of a token.\n     */\n    error ERC721InvalidOwner(address owner);\n\n    /**\n     * @dev Indicates a `tokenId` whose `owner` is the zero address.\n     * @param tokenId Identifier number of a token.\n     */\n    error ERC721NonexistentToken(uint256 tokenId);\n\n    /**\n     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     * @param tokenId Identifier number of a token.\n     * @param owner Address of the current owner of a token.\n     */\n    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);\n\n    /**\n     * @dev Indicates a failure with the token `sender`. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     */\n    error ERC721InvalidSender(address sender);\n\n    /**\n     * @dev Indicates a failure with the token `receiver`. Used in transfers.\n     * @param receiver Address to which tokens are being transferred.\n     */\n    error ERC721InvalidReceiver(address receiver);\n\n    /**\n     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.\n     * @param operator Address that may be allowed to operate on tokens without being their owner.\n     * @param tokenId Identifier number of a token.\n     */\n    error ERC721InsufficientApproval(address operator, uint256 tokenId);\n\n    /**\n     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n     * @param approver Address initiating an approval operation.\n     */\n    error ERC721InvalidApprover(address approver);\n\n    /**\n     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.\n     * @param operator Address that may be allowed to operate on tokens without being their owner.\n     */\n    error ERC721InvalidOperator(address operator);\n}\n\n/**\n * @dev Standard ERC1155 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.\n */\ninterface IERC1155Errors {\n    /**\n     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     * @param balance Current balance for the interacting account.\n     * @param needed Minimum amount required to perform a transfer.\n     * @param tokenId Identifier number of a token.\n     */\n    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);\n\n    /**\n     * @dev Indicates a failure with the token `sender`. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     */\n    error ERC1155InvalidSender(address sender);\n\n    /**\n     * @dev Indicates a failure with the token `receiver`. Used in transfers.\n     * @param receiver Address to which tokens are being transferred.\n     */\n    error ERC1155InvalidReceiver(address receiver);\n\n    /**\n     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.\n     * @param operator Address that may be allowed to operate on tokens without being their owner.\n     * @param owner Address of the current owner of a token.\n     */\n    error ERC1155MissingApprovalForAll(address operator, address owner);\n\n    /**\n     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n     * @param approver Address initiating an approval operation.\n     */\n    error ERC1155InvalidApprover(address approver);\n\n    /**\n     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.\n     * @param operator Address that may be allowed to operate on tokens without being their owner.\n     */\n    error ERC1155InvalidOperator(address operator);\n\n    /**\n     * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.\n     * Used in batch transfers.\n     * @param idsLength Length of the array of token identifiers\n     * @param valuesLength Length of the array of token amounts\n     */\n    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);\n}\n"},{"file_path":"contracts/core/FxUSDBasePool.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.25;\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { AccessControlUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\";\nimport { ERC20PermitUpgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol\";\nimport { ERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol\";\nimport { ReentrancyGuardUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol\";\n\nimport { AggregatorV3Interface } from \"../interfaces/Chainlink/AggregatorV3Interface.sol\";\nimport { IPegKeeper } from \"../interfaces/IPegKeeper.sol\";\nimport { IPool } from \"../interfaces/IPool.sol\";\nimport { IPoolManager } from \"../interfaces/IPoolManager.sol\";\nimport { IFxUSDBasePool } from \"../interfaces/IFxUSDBasePool.sol\";\n\nimport { AssetManagement } from \"../fund/AssetManagement.sol\";\nimport { Math } from \"../libraries/Math.sol\";\n\ncontract FxUSDBasePool is\n  ERC20PermitUpgradeable,\n  AccessControlUpgradeable,\n  ReentrancyGuardUpgradeable,\n  AssetManagement,\n  IFxUSDBasePool\n{\n  using SafeERC20 for IERC20;\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the deposited amount is zero.\n  error ErrDepositZeroAmount();\n\n  /// @dev Thrown when the minted shares are not enough.\n  error ErrInsufficientSharesOut();\n\n  /// @dev Thrown the input token in invalid.\n  error ErrInvalidTokenIn();\n\n  /// @dev Thrown when the redeemed shares is zero.\n  error ErrRedeemZeroShares();\n\n  error ErrorCallerNotPegKeeper();\n\n  error ErrorStableTokenDepeg();\n\n  error ErrorSwapExceedBalance();\n\n  error ErrorInsufficientOutput();\n\n  error ErrorInsufficientArbitrage();\n\n  error ErrorRedeemCoolDownPeriodTooLarge();\n\n  error ErrorRedeemMoreThanBalance();\n\n  error ErrorRedeemLockedShares();\n\n  error ErrorInsufficientFreeBalance();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The exchange rate precision.\n  uint256 internal constant PRECISION = 1e18;\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @notice The address of `PoolManager` contract.\n  address public immutable poolManager;\n\n  /// @notice The address of `PegKeeper` contract.\n  address public immutable pegKeeper;\n\n  /// @inheritdoc IFxUSDBasePool\n  /// @dev This is also the address of FxUSD token.\n  address public immutable yieldToken;\n\n  /// @inheritdoc IFxUSDBasePool\n  /// @dev The address of USDC token.\n  address public immutable stableToken;\n\n  uint256 private immutable stableTokenScale;\n\n  /// @notice The Chainlink USDC/USD price feed.\n  /// @dev The encoding is below.\n  /// ```text\n  /// |  32 bits  | 64 bits |  160 bits  |\n  /// | heartbeat |  scale  | price_feed |\n  /// |low                          high |\n  /// ```\n  bytes32 public immutable Chainlink_USDC_USD_Spot;\n\n  /***********\n   * Structs *\n   ***********/\n\n  struct RebalanceMemoryVar {\n    uint256 stablePrice;\n    uint256 totalYieldToken;\n    uint256 totalStableToken;\n    uint256 yieldTokenToUse;\n    uint256 stableTokenToUse;\n    uint256 colls;\n    uint256 yieldTokenUsed;\n    uint256 stableTokenUsed;\n  }\n\n  struct RedeemRequest {\n    uint128 amount;\n    uint128 unlockAt;\n  }\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @inheritdoc IFxUSDBasePool\n  uint256 public totalYieldToken;\n\n  /// @inheritdoc IFxUSDBasePool\n  uint256 public totalStableToken;\n\n  /// @notice The depeg price for stable token.\n  uint256 public stableDepegPrice;\n\n  /// @notice Mapping from user address to redeem request.\n  mapping(address => RedeemRequest) public redeemRequests;\n\n  /// @notice The number of seconds of cool down before redeem from this pool.\n  uint256 public redeemCoolDownPeriod;\n\n  /*************\n   * Modifiers *\n   *************/\n\n  modifier onlyValidToken(address token) {\n    if (token != stableToken && token != yieldToken) {\n      revert ErrInvalidTokenIn();\n    }\n    _;\n  }\n\n  modifier onlyPegKeeper() {\n    if (_msgSender() != pegKeeper) revert ErrorCallerNotPegKeeper();\n    _;\n  }\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(\n    address _poolManager,\n    address _pegKeeper,\n    address _yieldToken,\n    address _stableToken,\n    bytes32 _Chainlink_USDC_USD_Spot\n  ) {\n    poolManager = _poolManager;\n    pegKeeper = _pegKeeper;\n    yieldToken = _yieldToken;\n    stableToken = _stableToken;\n    Chainlink_USDC_USD_Spot = _Chainlink_USDC_USD_Spot;\n\n    stableTokenScale = 10 ** (18 - IERC20Metadata(_stableToken).decimals());\n  }\n\n  function initialize(\n    address admin,\n    string memory _name,\n    string memory _symbol,\n    uint256 _stableDepegPrice,\n    uint256 _redeemCoolDownPeriod\n  ) external initializer {\n    __Context_init();\n    __ERC165_init();\n    __AccessControl_init();\n    __ReentrancyGuard_init();\n\n    __ERC20_init(_name, _symbol);\n    __ERC20Permit_init(_name);\n\n    _grantRole(DEFAULT_ADMIN_ROLE, admin);\n\n    _updateStableDepegPrice(_stableDepegPrice);\n    _updateRedeemCoolDownPeriod(_redeemCoolDownPeriod);\n\n    // approve\n    IERC20(yieldToken).forceApprove(poolManager, type(uint256).max);\n    IERC20(stableToken).forceApprove(poolManager, type(uint256).max);\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @inheritdoc IFxUSDBasePool\n  function previewDeposit(\n    address tokenIn,\n    uint256 amountTokenToDeposit\n  ) public view override onlyValidToken(tokenIn) returns (uint256 amountSharesOut) {\n    uint256 price = getStableTokenPriceWithScale();\n    uint256 amountUSD = amountTokenToDeposit;\n    if (tokenIn == stableToken) {\n      amountUSD = (amountUSD * price) / PRECISION;\n    }\n\n    uint256 _totalSupply = totalSupply();\n    if (_totalSupply == 0) {\n      amountSharesOut = amountUSD;\n    } else {\n      uint256 totalUSD = totalYieldToken + (totalStableToken * price) / PRECISION;\n      amountSharesOut = (amountUSD * _totalSupply) / totalUSD;\n    }\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function previewRedeem(\n    uint256 amountSharesToRedeem\n  ) external view returns (uint256 amountYieldOut, uint256 amountStableOut) {\n    uint256 cachedTotalYieldToken = totalYieldToken;\n    uint256 cachedTotalStableToken = totalStableToken;\n    uint256 cachedTotalSupply = totalSupply();\n    amountYieldOut = (amountSharesToRedeem * cachedTotalYieldToken) / cachedTotalSupply;\n    amountStableOut = (amountSharesToRedeem * cachedTotalStableToken) / cachedTotalSupply;\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function nav() external view returns (uint256) {\n    uint256 _totalSupply = totalSupply();\n    if (_totalSupply == 0) {\n      return PRECISION;\n    } else {\n      uint256 stablePrice = getStableTokenPriceWithScale();\n      uint256 yieldPrice = IPegKeeper(pegKeeper).getFxUSDPrice();\n      return (totalYieldToken * yieldPrice + totalStableToken * stablePrice) / _totalSupply;\n    }\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function getStableTokenPrice() public view returns (uint256) {\n    bytes32 encoding = Chainlink_USDC_USD_Spot;\n    address aggregator;\n    uint256 scale;\n    uint256 heartbeat;\n    assembly {\n      aggregator := shr(96, encoding)\n      scale := and(shr(32, encoding), 0xffffffffffffffff)\n      heartbeat := and(encoding, 0xffffffff)\n    }\n    (, int256 answer, , uint256 updatedAt, ) = AggregatorV3Interface(aggregator).latestRoundData();\n    if (answer < 0) revert(\"invalid\");\n    if (block.timestamp - updatedAt > heartbeat) revert(\"expired\");\n    return uint256(answer) * scale;\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function getStableTokenPriceWithScale() public view returns (uint256) {\n    return getStableTokenPrice() * stableTokenScale;\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc IFxUSDBasePool\n  function deposit(\n    address receiver,\n    address tokenIn,\n    uint256 amountTokenToDeposit,\n    uint256 minSharesOut\n  ) external override nonReentrant onlyValidToken(tokenIn) returns (uint256 amountSharesOut) {\n    if (amountTokenToDeposit == 0) revert ErrDepositZeroAmount();\n\n    // we are very sure every token is normal token, so no fot check here.\n    IERC20(tokenIn).safeTransferFrom(_msgSender(), address(this), amountTokenToDeposit);\n\n    amountSharesOut = _deposit(tokenIn, amountTokenToDeposit);\n    if (amountSharesOut < minSharesOut) revert ErrInsufficientSharesOut();\n\n    _mint(receiver, amountSharesOut);\n\n    emit Deposit(_msgSender(), receiver, tokenIn, amountTokenToDeposit, amountSharesOut);\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function requestRedeem(uint256 shares) external {\n    address caller = _msgSender();\n    uint256 balance = balanceOf(caller);\n    RedeemRequest memory request = redeemRequests[caller];\n    if (request.amount + shares > balance) revert ErrorRedeemMoreThanBalance();\n    request.amount += uint128(shares);\n    request.unlockAt = uint128(block.timestamp + redeemCoolDownPeriod);\n    redeemRequests[caller] = request;\n\n    emit RequestRedeem(caller, shares, request.unlockAt);\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function redeem(\n    address receiver,\n    uint256 amountSharesToRedeem\n  ) external nonReentrant returns (uint256 amountYieldOut, uint256 amountStableOut) {\n    address caller = _msgSender();\n    RedeemRequest memory request = redeemRequests[caller];\n    if (request.unlockAt > block.timestamp) revert ErrorRedeemLockedShares();\n    if (request.amount < amountSharesToRedeem) {\n      amountSharesToRedeem = request.amount;\n    }\n    if (amountSharesToRedeem == 0) revert ErrRedeemZeroShares();\n    request.amount -= uint128(amountSharesToRedeem);\n    redeemRequests[caller] = request;\n\n    uint256 cachedTotalYieldToken = totalYieldToken;\n    uint256 cachedTotalStableToken = totalStableToken;\n    uint256 cachedTotalSupply = totalSupply();\n\n    amountYieldOut = (amountSharesToRedeem * cachedTotalYieldToken) / cachedTotalSupply;\n    amountStableOut = (amountSharesToRedeem * cachedTotalStableToken) / cachedTotalSupply;\n\n    _burn(caller, amountSharesToRedeem);\n\n    if (amountYieldOut > 0) {\n      IERC20(yieldToken).safeTransfer(receiver, amountYieldOut);\n      unchecked {\n        totalYieldToken = cachedTotalYieldToken - amountYieldOut;\n      }\n    }\n    if (amountStableOut > 0) {\n      IERC20(stableToken).safeTransfer(receiver, amountStableOut);\n      unchecked {\n        totalStableToken = cachedTotalStableToken - amountStableOut;\n      }\n    }\n\n    emit Redeem(caller, receiver, amountSharesToRedeem, amountYieldOut, amountStableOut);\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function rebalance(\n    address pool,\n    int16 tickId,\n    address tokenIn,\n    uint256 maxAmount,\n    uint256 minCollOut\n  ) external onlyValidToken(tokenIn) nonReentrant returns (uint256 tokenUsed, uint256 colls) {\n    RebalanceMemoryVar memory op = _beforeRebalanceOrLiquidate(tokenIn, maxAmount);\n    (op.colls, op.yieldTokenUsed, op.stableTokenUsed) = IPoolManager(poolManager).rebalance(\n      pool,\n      _msgSender(),\n      tickId,\n      op.yieldTokenToUse,\n      op.stableTokenToUse\n    );\n    tokenUsed = _afterRebalanceOrLiquidate(tokenIn, minCollOut, op);\n    colls = op.colls;\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function rebalance(\n    address pool,\n    uint32 positionId,\n    address tokenIn,\n    uint256 maxAmount,\n    uint256 minCollOut\n  ) external onlyValidToken(tokenIn) nonReentrant returns (uint256 tokenUsed, uint256 colls) {\n    RebalanceMemoryVar memory op = _beforeRebalanceOrLiquidate(tokenIn, maxAmount);\n    (op.colls, op.yieldTokenUsed, op.stableTokenUsed) = IPoolManager(poolManager).rebalance(\n      pool,\n      _msgSender(),\n      positionId,\n      op.yieldTokenToUse,\n      op.stableTokenToUse\n    );\n    tokenUsed = _afterRebalanceOrLiquidate(tokenIn, minCollOut, op);\n    colls = op.colls;\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function liquidate(\n    address pool,\n    uint32 positionId,\n    address tokenIn,\n    uint256 maxAmount,\n    uint256 minCollOut\n  ) external onlyValidToken(tokenIn) nonReentrant returns (uint256 tokenUsed, uint256 colls) {\n    RebalanceMemoryVar memory op = _beforeRebalanceOrLiquidate(tokenIn, maxAmount);\n    (op.colls, op.yieldTokenUsed, op.stableTokenUsed) = IPoolManager(poolManager).liquidate(\n      pool,\n      _msgSender(),\n      positionId,\n      op.yieldTokenToUse,\n      op.stableTokenToUse\n    );\n    tokenUsed = _afterRebalanceOrLiquidate(tokenIn, minCollOut, op);\n    colls = op.colls;\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function arbitrage(\n    address srcToken,\n    uint256 amountIn,\n    address receiver,\n    bytes calldata data\n  ) external onlyValidToken(srcToken) onlyPegKeeper nonReentrant returns (uint256 amountOut, uint256 bonusOut) {\n    address dstToken;\n    uint256 expectedOut;\n    uint256 cachedTotalYieldToken = totalYieldToken;\n    uint256 cachedTotalStableToken = totalStableToken;\n    {\n      uint256 price = getStableTokenPrice();\n      uint256 scaledPrice = price * stableTokenScale;\n      if (srcToken == yieldToken) {\n        // check if usdc depeg\n        if (price < stableDepegPrice) revert ErrorStableTokenDepeg();\n        if (amountIn > cachedTotalYieldToken) revert ErrorSwapExceedBalance();\n        dstToken = stableToken;\n        unchecked {\n          // rounding up\n          expectedOut = Math.mulDivUp(amountIn, PRECISION, scaledPrice);\n          cachedTotalYieldToken -= amountIn;\n          cachedTotalStableToken += expectedOut;\n        }\n      } else {\n        if (amountIn > cachedTotalStableToken) revert ErrorSwapExceedBalance();\n        dstToken = yieldToken;\n        unchecked {\n          // rounding up\n          expectedOut = Math.mulDivUp(amountIn, scaledPrice, PRECISION);\n          cachedTotalStableToken -= amountIn;\n          cachedTotalYieldToken += expectedOut;\n        }\n      }\n    }\n    IERC20(srcToken).safeTransfer(pegKeeper, amountIn);\n    uint256 actualOut = IERC20(dstToken).balanceOf(address(this));\n    amountOut = IPegKeeper(pegKeeper).onSwap(srcToken, dstToken, amountIn, data);\n    actualOut = IERC20(dstToken).balanceOf(address(this)) - actualOut;\n    // check actual fxUSD swapped in case peg keeper is hacked.\n    if (amountOut > actualOut) revert ErrorInsufficientOutput();\n    // check swapped token has no loss\n    if (amountOut < expectedOut) revert ErrorInsufficientArbitrage();\n\n    totalYieldToken = cachedTotalYieldToken;\n    totalStableToken = cachedTotalStableToken;\n    bonusOut = amountOut - expectedOut;\n    if (bonusOut > 0) {\n      IERC20(dstToken).safeTransfer(receiver, bonusOut);\n    }\n\n    emit Arbitrage(_msgSender(), srcToken, amountIn, amountOut, bonusOut);\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Update depeg price for stable token.\n  /// @param newPrice The new depeg price of stable token, multiplied by 1e18\n  function updateStableDepegPrice(uint256 newPrice) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateStableDepegPrice(newPrice);\n  }\n\n  /// @notice Update redeem cool down period.\n  /// @param newPeriod The new redeem cool down period, in seconds.\n  function updateRedeemCoolDownPeriod(uint256 newPeriod) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateRedeemCoolDownPeriod(newPeriod);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @inheritdoc ERC20Upgradeable\n  function _update(address from, address to, uint256 value) internal virtual override {\n    // make sure from don't transfer more than free balance\n    if (from != address(0) && to != address(0)) {\n      uint256 leftover = balanceOf(from) - redeemRequests[from].amount;\n      if (value > leftover) revert ErrorInsufficientFreeBalance();\n    }\n\n    super._update(from, to, value);\n  }\n\n  /// @dev Internal function to update depeg price for stable token.\n  /// @param newPrice The new depeg price of stable token, multiplied by 1e18\n  function _updateStableDepegPrice(uint256 newPrice) internal {\n    uint256 oldPrice = stableDepegPrice;\n    stableDepegPrice = newPrice;\n\n    emit UpdateStableDepegPrice(oldPrice, newPrice);\n  }\n\n  /// @dev Internal function to update redeem cool down period.\n  /// @param newPeriod The new redeem cool down period, in seconds.\n  function _updateRedeemCoolDownPeriod(uint256 newPeriod) internal {\n    if (newPeriod > 7 days) revert ErrorRedeemCoolDownPeriodTooLarge();\n\n    uint256 oldPeriod = redeemCoolDownPeriod;\n    redeemCoolDownPeriod = newPeriod;\n\n    emit UpdateRedeemCoolDownPeriod(oldPeriod, newPeriod);\n  }\n\n  /// @dev mint shares based on the deposited base tokens\n  /// @param tokenIn base token address used to mint shares\n  /// @param amountDeposited amount of base tokens deposited\n  /// @return amountSharesOut amount of shares minted\n  function _deposit(address tokenIn, uint256 amountDeposited) internal virtual returns (uint256 amountSharesOut) {\n    uint256 price = getStableTokenPriceWithScale();\n    if (price < stableDepegPrice * stableTokenScale) revert ErrorStableTokenDepeg();\n\n    uint256 amountUSD = amountDeposited;\n    if (tokenIn == stableToken) {\n      amountUSD = (amountUSD * price) / PRECISION;\n    }\n\n    uint256 cachedTotalYieldToken = totalYieldToken;\n    uint256 cachedTotalStableToken = totalStableToken;\n    uint256 totalUSD = cachedTotalYieldToken + (cachedTotalStableToken * price) / PRECISION;\n    uint256 cachedTotalSupply = totalSupply();\n    if (cachedTotalSupply == 0) {\n      amountSharesOut = amountUSD;\n    } else {\n      amountSharesOut = (amountUSD * cachedTotalSupply) / totalUSD;\n    }\n\n    if (tokenIn == stableToken) {\n      totalStableToken = cachedTotalStableToken + amountDeposited;\n    } else {\n      totalYieldToken = cachedTotalYieldToken + amountDeposited;\n    }\n  }\n\n  /// @dev Internal hook function to prepare before rebalance or liquidate.\n  /// @param tokenIn The address of input token.\n  /// @param maxAmount The maximum amount of input tokens.\n  function _beforeRebalanceOrLiquidate(\n    address tokenIn,\n    uint256 maxAmount\n  ) internal view returns (RebalanceMemoryVar memory op) {\n    op.stablePrice = getStableTokenPriceWithScale();\n    op.totalYieldToken = totalYieldToken;\n    op.totalStableToken = totalStableToken;\n\n    uint256 amountYieldToken = op.totalYieldToken;\n    uint256 amountStableToken;\n    // we always, try use fxUSD first then USDC\n    if (tokenIn == yieldToken) {\n      // user pays fxUSD\n      if (maxAmount < amountYieldToken) amountYieldToken = maxAmount;\n      else {\n        amountStableToken = ((maxAmount - amountYieldToken) * PRECISION) / op.stablePrice;\n      }\n    } else {\n      // user pays USDC\n      uint256 maxAmountInUSD = (maxAmount * op.stablePrice) / PRECISION;\n      if (maxAmountInUSD < amountYieldToken) amountYieldToken = maxAmountInUSD;\n      else {\n        amountStableToken = ((maxAmountInUSD - amountYieldToken) * PRECISION) / op.stablePrice;\n      }\n    }\n\n    if (amountStableToken > op.totalStableToken) {\n      amountStableToken = op.totalStableToken;\n    }\n\n    op.yieldTokenToUse = amountYieldToken;\n    op.stableTokenToUse = amountStableToken;\n  }\n\n  /// @dev Internal hook function after rebalance or liquidate.\n  /// @param tokenIn The address of input token.\n  /// @param minCollOut The minimum expected collateral tokens.\n  /// @param op The memory variable for rebalance or liquidate.\n  /// @return tokenUsed The amount of input token used.\n  function _afterRebalanceOrLiquidate(\n    address tokenIn,\n    uint256 minCollOut,\n    RebalanceMemoryVar memory op\n  ) internal returns (uint256 tokenUsed) {\n    if (op.colls < minCollOut) revert ErrorInsufficientOutput();\n\n    op.totalYieldToken -= op.yieldTokenUsed;\n    op.totalStableToken -= op.stableTokenUsed;\n\n    uint256 amountUSD = op.yieldTokenUsed + (op.stableTokenUsed * op.stablePrice) / PRECISION;\n    if (tokenIn == yieldToken) {\n      tokenUsed = amountUSD;\n      op.totalYieldToken += tokenUsed;\n    } else {\n      // rounding up\n      tokenUsed = Math.mulDivUp(amountUSD, PRECISION, op.stablePrice);\n      op.totalStableToken += tokenUsed;\n    }\n\n    totalYieldToken = op.totalYieldToken;\n    totalStableToken = op.totalStableToken;\n\n    // transfer token from caller, the collateral is already transferred to caller.\n    IERC20(tokenIn).safeTransferFrom(_msgSender(), address(this), tokenUsed);\n\n    emit Rebalance(_msgSender(), tokenIn, tokenUsed, op.colls, op.yieldTokenUsed, op.stableTokenUsed);\n  }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/utils/ContextUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)\n\npragma solidity ^0.8.0;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n    function __Context_init() internal onlyInitializing {\n    }\n\n    function __Context_init_unchained() internal onlyInitializing {\n    }\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[50] private __gap;\n}\n"},{"file_path":"contracts/price-oracle/LSDPriceOracleBase.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nimport { SpotPriceOracleBase } from \"./SpotPriceOracleBase.sol\";\n\nimport { IPriceOracle } from \"./interfaces/IPriceOracle.sol\";\nimport { ITwapOracle } from \"./interfaces/ITwapOracle.sol\";\n\nabstract contract LSDPriceOracleBase is SpotPriceOracleBase, IPriceOracle {\n  /*************\n   * Constants *\n   *************/\n\n  /// @notice The Chainlink ETH/USD price feed.\n  /// @dev See comments of `_readSpotPriceByChainlink` for more details.\n  bytes32 public immutable Chainlink_ETH_USD_Spot;\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @dev The encodings for ETH/USD spot sources.\n  bytes private onchainSpotEncodings_ETHUSD;\n\n  /// @dev The encodings for LSD/ETH spot sources.\n  bytes private onchainSpotEncodings_LSDETH;\n\n  /// @dev The encodings for LSD/USD spot sources.\n  bytes private onchainSpotEncodings_LSDUSD;\n\n  /// @notice The value of maximum price deviation, multiplied by 1e18.\n  uint256 public maxPriceDeviation;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(bytes32 _Chainlink_ETH_USD_Spot) {\n    Chainlink_ETH_USD_Spot = _Chainlink_ETH_USD_Spot;\n\n    _updateMaxPriceDeviation(1e16); // 1%\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the ETH/USD spot price.\n  /// @return chainlinkPrice The spot price from Chainlink price feed.\n  /// @return minPrice The minimum spot price among all available sources.\n  /// @return maxPrice The maximum spot price among all available sources.\n  function getETHUSDSpotPrice() external view returns (uint256 chainlinkPrice, uint256 minPrice, uint256 maxPrice) {\n    (chainlinkPrice, minPrice, maxPrice) = _getETHUSDSpotPrice();\n  }\n\n  /// @notice Return the ETH/USD spot prices.\n  /// @return prices The list of spot price among all available sources, multiplied by 1e18.\n  function getETHUSDSpotPrices() external view returns (uint256[] memory prices) {\n    prices = _getSpotPriceByEncoding(onchainSpotEncodings_ETHUSD);\n  }\n\n  /// @notice Return the LSD/ETH spot prices.\n  /// @return prices The list of spot price among all available sources, multiplied by 1e18.\n  function getLSDETHSpotPrices() public view returns (uint256[] memory prices) {\n    prices = _getSpotPriceByEncoding(onchainSpotEncodings_LSDETH);\n  }\n\n  /// @notice Return the LSD/ETH spot prices.\n  /// @return prices The list of spot price among all available sources, multiplied by 1e18.\n  function getLSDUSDSpotPrices() public view returns (uint256[] memory prices) {\n    prices = _getSpotPriceByEncoding(onchainSpotEncodings_LSDUSD);\n  }\n\n  /// @notice Return the LSD/USD anchor price, the price that is hard to manipulate in single tx.\n  /// @return price The anchor price, multiplied by 1e18.\n  function getLSDUSDAnchorPrice() external view returns (uint256 price) {\n    price = _getLSDUSDAnchorPrice();\n  }\n\n  /// @inheritdoc IPriceOracle\n  /// @dev The price is valid iff |maxPrice-minPrice|/minPrice < maxPriceDeviation\n  function getPrice() external view override returns (uint256 anchorPrice, uint256 minPrice, uint256 maxPrice) {\n    anchorPrice = _getLSDUSDAnchorPrice();\n    (minPrice, maxPrice) = _getLSDMinMaxPrice(anchorPrice);\n\n    uint256 cachedMaxPriceDeviation = maxPriceDeviation; // gas saving\n    // use anchor price when the price deviation between anchor price and min price exceed threshold\n    if ((anchorPrice - minPrice) * PRECISION > cachedMaxPriceDeviation * minPrice) {\n      minPrice = anchorPrice;\n    }\n\n    // use anchor price when the price deviation between anchor price and max price exceed threshold\n    if ((maxPrice - anchorPrice) * PRECISION > cachedMaxPriceDeviation * anchorPrice) {\n      maxPrice = anchorPrice;\n    }\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Update the on-chain spot encodings.\n  /// @param encodings The encodings to update. See `_getSpotPriceByEncoding` for more details.\n  /// @param spotType The type of the encodings.\n  function updateOnchainSpotEncodings(bytes memory encodings, uint256 spotType) external onlyOwner {\n    // validate encoding\n    uint256[] memory prices = _getSpotPriceByEncoding(encodings);\n\n    if (spotType == 0) {\n      onchainSpotEncodings_ETHUSD = encodings;\n      if (prices.length == 0) revert ErrorInvalidEncodings();\n    } else if (spotType == 1) {\n      onchainSpotEncodings_LSDETH = encodings;\n    } else if (spotType == 2) {\n      onchainSpotEncodings_LSDUSD = encodings;\n    }\n  }\n\n  /// @notice Update the value of maximum price deviation.\n  /// @param newMaxPriceDeviation The new value of maximum price deviation, multiplied by 1e18.\n  function updateMaxPriceDeviation(uint256 newMaxPriceDeviation) external onlyOwner {\n    _updateMaxPriceDeviation(newMaxPriceDeviation);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to update the value of maximum price deviation.\n  /// @param newMaxPriceDeviation The new value of maximum price deviation, multiplied by 1e18.\n  function _updateMaxPriceDeviation(uint256 newMaxPriceDeviation) private {\n    uint256 oldMaxPriceDeviation = maxPriceDeviation;\n    if (oldMaxPriceDeviation == newMaxPriceDeviation) {\n      revert ErrorParameterUnchanged();\n    }\n\n    maxPriceDeviation = newMaxPriceDeviation;\n\n    emit UpdateMaxPriceDeviation(oldMaxPriceDeviation, newMaxPriceDeviation);\n  }\n\n  /// @dev Internal function to calculate the ETH/USD spot price.\n  /// @return chainlinkPrice The spot price from Chainlink price feed, multiplied by 1e18.\n  /// @return minPrice The minimum spot price among all available sources, multiplied by 1e18.\n  /// @return maxPrice The maximum spot price among all available sources, multiplied by 1e18.\n  function _getETHUSDSpotPrice() internal view returns (uint256 chainlinkPrice, uint256 minPrice, uint256 maxPrice) {\n    chainlinkPrice = _readSpotPriceByChainlink(Chainlink_ETH_USD_Spot);\n    uint256[] memory prices = _getSpotPriceByEncoding(onchainSpotEncodings_ETHUSD);\n    minPrice = maxPrice = chainlinkPrice;\n    for (uint256 i = 0; i < prices.length; i++) {\n      if (prices[i] > maxPrice) maxPrice = prices[i];\n      if (prices[i] < minPrice) minPrice = prices[i];\n    }\n  }\n\n  /// @dev Internal function to return the min/max LSD/USD prices.\n  /// @param anchorPrice The LSD/USD anchor price, multiplied by 1e18.\n  /// @return minPrice The minimum price among all available sources (including twap), multiplied by 1e18.\n  /// @return maxPrice The maximum price among all available sources (including twap), multiplied by 1e18.\n  function _getLSDMinMaxPrice(uint256 anchorPrice) internal view returns (uint256 minPrice, uint256 maxPrice) {\n    minPrice = maxPrice = anchorPrice;\n    (, uint256 minETHUSDPrice, uint256 maxETHUSDPrice) = _getETHUSDSpotPrice();\n    uint256[] memory LSD_ETH_prices = getLSDETHSpotPrices();\n    uint256[] memory LSD_USD_prices = getLSDUSDSpotPrices();\n\n    uint256 length = LSD_ETH_prices.length;\n    uint256 LSD_ETH_minPrice = type(uint256).max;\n    uint256 LSD_ETH_maxPrice;\n    unchecked {\n      for (uint256 i = 0; i < length; i++) {\n        uint256 price = LSD_ETH_prices[i];\n        if (price > LSD_ETH_maxPrice) LSD_ETH_maxPrice = price;\n        if (price < LSD_ETH_minPrice) LSD_ETH_minPrice = price;\n      }\n      if (LSD_ETH_maxPrice != 0) {\n        minPrice = Math.min(minPrice, (LSD_ETH_minPrice * minETHUSDPrice) / PRECISION);\n        maxPrice = Math.max(maxPrice, (LSD_ETH_maxPrice * maxETHUSDPrice) / PRECISION);\n      }\n\n      length = LSD_USD_prices.length;\n      for (uint256 i = 0; i < length; i++) {\n        uint256 price = LSD_USD_prices[i];\n        if (price > maxPrice) maxPrice = price;\n        if (price < minPrice) minPrice = price;\n      }\n    }\n  }\n\n  /// @dev Internal function to return the LSD/USD anchor price.\n  /// @return price The anchor price of LSD/USD, multiplied by 1e18.\n  function _getLSDUSDAnchorPrice() internal view virtual returns (uint256 price);\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},{"file_path":"@openzeppelin/contracts/utils/math/SignedMath.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Standard signed math utilities missing in the Solidity language.\n */\nlibrary SignedMath {\n    /**\n     * @dev Returns the largest of two signed numbers.\n     */\n    function max(int256 a, int256 b) internal pure returns (int256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two signed numbers.\n     */\n    function min(int256 a, int256 b) internal pure returns (int256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two signed numbers without overflow.\n     * The result is rounded towards zero.\n     */\n    function average(int256 a, int256 b) internal pure returns (int256) {\n        // Formula from the book \"Hacker's Delight\"\n        int256 x = (a & b) + ((a ^ b) >> 1);\n        return x + (int256(uint256(x) >> 255) & (a ^ b));\n    }\n\n    /**\n     * @dev Returns the absolute unsigned value of a signed value.\n     */\n    function abs(int256 n) internal pure returns (uint256) {\n        unchecked {\n            // must be unchecked in order to support `n = type(int256).min`\n            return uint256(n >= 0 ? n : -n);\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-v4/interfaces/IERC1967.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.\n *\n * _Available since v4.8.3._\n */\ninterface IERC1967 {\n    /**\n     * @dev Emitted when the implementation is upgraded.\n     */\n    event Upgraded(address indexed implementation);\n\n    /**\n     * @dev Emitted when the admin account has changed.\n     */\n    event AdminChanged(address previousAdmin, address newAdmin);\n\n    /**\n     * @dev Emitted when the beacon is changed.\n     */\n    event BeaconUpgraded(address indexed beacon);\n}\n"},{"file_path":"contracts/price-oracle/interfaces/ISpotPriceOracle.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface ISpotPriceOracle {\n  /// @notice Return spot price with 18 decimal places.\n  ///\n  /// @dev encoding for single route\n  /// |   8 bits  | 160 bits |  88  bits  |\n  /// | pool_type |   pool   | customized |\n  /// assume all base and quote token has no more than 18 decimals.\n  ///\n  /// + pool_type = 0: UniswapV2\n  ///   customized = |   1  bit   |   8  bits   |   8 bits   | ... |\n  ///                | base_index | base_scale | quote_scale | ... |\n  /// + pool_type = 1: UniswapV3\n  ///   customized = |   1  bit   |   8 bits   |   8  bits   | ... |\n  ///                | base_index | base_scale | quote_scale | ... |\n  /// + pool_type = 2: Balancer V2 Weighted\n  ///   customized = |   3  bit   |    3 bit    |   8 bits   |   8  bits   | ... |\n  ///                | base_index | quote_index | base_scale | quote_scale | ... |\n  /// + pool_type = 3: Balancer V2 Stable\n  ///   customized = |   3 bits   |   3  bits   | ... |\n  ///                | base_index | quote_index | ... |\n  /// + pool_type = 4: Curve Plain\n  ///   customized = | 3 bits |   3 bits   |   3  bits   |     1  bits     |  8 bits  | ... |  8 bits  | ... |\n  ///                | tokens | base_index | quote_index | has_amm_precise | scale[0] | ... | scale[n] | ... |\n  /// + pool_type = 5: Curve Plain with oracle\n  ///   customized = |   1  bit   |   1 bit   |... |\n  ///                | base_index | use_cache | ... |\n  /// + pool_type = 6: Curve Plain NG\n  ///   customized = |   3 bits   |   3  bits   |   1 bit   | ... |\n  ///                | base_index | quote_index | use_cache | ... |\n  /// + pool_type = 7: Curve Crypto\n  ///   customized = |   1  bit   | ... |\n  ///                | base_index | ... |\n  /// + pool_type = 8: Curve TriCrypto\n  ///   customized = |   2 bits   |   2  bits   | ... |\n  ///                | base_index | quote_index | ... |\n  /// + pool_type = 9: ERC4626\n  ///   customized = |       1  bit       | ... |\n  ///                | base_is_underlying | ... |\n  /// + pool_type = 10: ETHLSD, wstETH, weETH, ezETH\n  ///   customized = |    1 bit    | ... |\n  ///                | base_is_ETH | ... |\n  /// + pool_type = 11: BalancerV2CachedRate\n  ///   customized = |   3 bits   | ... |\n  ///                | base_index | ... |\n  ///\n  /// @param encoding The encoding of the price source.\n  /// @return spotPrice The spot price with 18 decimal places.\n  function getSpotPrice(uint256 encoding) external view returns (uint256 spotPrice);\n}\n"},{"file_path":"contracts/interfaces/IReservePool.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IReservePool {\n  /// @notice Emitted when the market request bonus.\n  /// @param token The address of the token requested.\n  /// @param receiver The address of token receiver.\n  /// @param bonus The amount of bonus token.\n  event RequestBonus(address indexed token, address indexed receiver, uint256 bonus);\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the balance of token in this contract.\n  function getBalance(address token) external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Request bonus token from Reserve Pool.\n  /// @param token The address of token to request.\n  /// @param receiver The address recipient for the bonus token.\n  /// @param bonus The amount of bonus token to send.\n  function requestBonus(address token, address receiver, uint256 bonus) external;\n\n  /// @notice Withdraw dust assets in this contract.\n  /// @param token The address of token to withdraw.\n  /// @param amount The amount of token to withdraw.\n  /// @param recipient The address of token receiver.\n  function withdrawFund(address token, uint256 amount, address recipient) external;\n}\n"},{"file_path":"contracts/mocks/MockPriceOracle.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IPriceOracle } from \"../price-oracle/interfaces/IPriceOracle.sol\";\n\ncontract MockPriceOracle is IPriceOracle {\n  uint256 public anchorPrice;\n  uint256 public minPrice;\n  uint256 public maxPrice;\n\n  constructor(uint256 _anchorPrice, uint256 _minPrice, uint256 _maxPrice) {\n    anchorPrice = _anchorPrice;\n    minPrice = _minPrice;\n    maxPrice = _maxPrice;\n  }\n\n  function setPrices(uint256 _anchorPrice, uint256 _minPrice, uint256 _maxPrice) external {\n    anchorPrice = _anchorPrice;\n    minPrice = _minPrice;\n    maxPrice = _maxPrice;\n  }\n\n  function getPrice() external view returns (uint256, uint256, uint256) {\n    return (anchorPrice, minPrice, maxPrice);\n  }\n}\n"},{"file_path":"contracts/periphery/facets/FlashLoanCallbackFacet.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IFlashLoanRecipient } from \"../../interfaces/Balancer/IFlashLoanRecipient.sol\";\n\nimport { LibRouter } from \"../libraries/LibRouter.sol\";\n\ncontract FlashLoanCallbackFacet is IFlashLoanRecipient {\n  using SafeERC20 for IERC20;\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the caller is not balancer vault.\n  error ErrorNotFromBalancer();\n\n  error ErrorNotFromRouterFlashLoan();\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @dev The address of Balancer V2 Vault.\n  address private immutable balancer;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _balancer) {\n    balancer = _balancer;\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc IFlashLoanRecipient\n  /// @dev Balancer V2 callback\n  function receiveFlashLoan(\n    address[] memory tokens,\n    uint256[] memory amounts,\n    uint256[] memory feeAmounts,\n    bytes memory userData\n  ) external {\n    if (msg.sender != balancer) revert ErrorNotFromBalancer();\n\n    // make sure call invoked by router\n    LibRouter.RouterStorage storage $ = LibRouter.routerStorage();\n    if ($.flashLoanContext != LibRouter.HAS_FLASH_LOAN) revert ErrorNotFromRouterFlashLoan();\n\n    (bool success, ) = address(this).call(userData);\n    // below lines will propagate inner error up\n    if (!success) {\n      // solhint-disable-next-line no-inline-assembly\n      assembly {\n        let ptr := mload(0x40)\n        let size := returndatasize()\n        returndatacopy(ptr, 0, size)\n        revert(ptr, size)\n      }\n    }\n\n    for (uint256 i = 0; i < tokens.length; i++) {\n      IERC20(tokens[i]).safeTransfer(msg.sender, amounts[i] + feeAmounts[i]);\n    }\n  }\n}\n"},{"file_path":"@openzeppelin/contracts-v4/proxy/ERC1967/ERC1967Proxy.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Proxy.sol\";\nimport \"./ERC1967Upgrade.sol\";\n\n/**\n * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an\n * implementation address that can be changed. This address is stored in storage in the location specified by\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the\n * implementation behind the proxy.\n */\ncontract ERC1967Proxy is Proxy, ERC1967Upgrade {\n    /**\n     * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.\n     *\n     * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded\n     * function call, and allows initializing the storage of the proxy like a Solidity constructor.\n     */\n    constructor(address _logic, bytes memory _data) payable {\n        _upgradeToAndCall(_logic, _data, false);\n    }\n\n    /**\n     * @dev Returns the current implementation address.\n     */\n    function _implementation() internal view virtual override returns (address impl) {\n        return ERC1967Upgrade._getImplementation();\n    }\n}\n"},{"file_path":"contracts/rate-provider/interfaces/IRateProvider.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IRateProvider {\n  /// @notice Return the exchange rate from wrapped token to underlying rate,\n  /// multiplied by 1e18.\n  function getRate() external view returns (uint256);\n}\n"},{"file_path":"contracts/common/EIP2535/interfaces/IERC173.sol","source_code":"// SPDX-License-Identifier: CC0-1.0\npragma solidity ^0.8.0;\n\n/// @title ERC-173 Contract Ownership Standard\n///  Note: the ERC-165 identifier for this interface is 0x7f5828d0\n/* is ERC165 */\ninterface IERC173 {\n  /// @dev This emits when ownership of a contract changes.\n  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n  /// @notice Get the address of the owner\n  /// @return owner_ The address of the owner.\n  function owner() external view returns (address owner_);\n\n  /// @notice Set the address of the new owner of the contract\n  /// @dev Set _newOwner to address(0) to renounce any ownership.\n  /// @param _newOwner The address of the new owner of the contract\n  function transferOwnership(address _newOwner) external;\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/access/IAccessControlUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControlUpgradeable {\n    /**\n     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n     *\n     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n     * {RoleAdminChanged} not being emitted signaling this.\n     *\n     * _Available since v3.1._\n     */\n    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n    /**\n     * @dev Emitted when `account` is granted `role`.\n     *\n     * `sender` is the account that originated the contract call, an admin role\n     * bearer except when using {AccessControl-_setupRole}.\n     */\n    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Emitted when `account` is revoked `role`.\n     *\n     * `sender` is the account that originated the contract call:\n     *   - if using `revokeRole`, it is the admin role bearer\n     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)\n     */\n    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) external view returns (bool);\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function grantRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function revokeRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been granted `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `account`.\n     */\n    function renounceRole(bytes32 role, address account) external;\n}\n"},{"file_path":"@openzeppelin/contracts/access/AccessControl.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.20;\n\nimport {IAccessControl} from \"./IAccessControl.sol\";\nimport {Context} from \"../utils/Context.sol\";\nimport {ERC165} from \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n *     require(hasRole(MY_ROLE, msg.sender));\n *     ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n    struct RoleData {\n        mapping(address account => bool) hasRole;\n        bytes32 adminRole;\n    }\n\n    mapping(bytes32 role => RoleData) private _roles;\n\n    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n    /**\n     * @dev Modifier that checks that an account has a specific role. Reverts\n     * with an {AccessControlUnauthorizedAccount} error including the required role.\n     */\n    modifier onlyRole(bytes32 role) {\n        _checkRole(role);\n        _;\n    }\n\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n        return _roles[role].hasRole[account];\n    }\n\n    /**\n     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n     */\n    function _checkRole(bytes32 role) internal view virtual {\n        _checkRole(role, _msgSender());\n    }\n\n    /**\n     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n     * is missing `role`.\n     */\n    function _checkRole(bytes32 role, address account) internal view virtual {\n        if (!hasRole(role, account)) {\n            revert AccessControlUnauthorizedAccount(account, role);\n        }\n    }\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n        return _roles[role].adminRole;\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n        _grantRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n        _revokeRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been revoked `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `callerConfirmation`.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n        if (callerConfirmation != _msgSender()) {\n            revert AccessControlBadConfirmation();\n        }\n\n        _revokeRole(role, callerConfirmation);\n    }\n\n    /**\n     * @dev Sets `adminRole` as ``role``'s admin role.\n     *\n     * Emits a {RoleAdminChanged} event.\n     */\n    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n        bytes32 previousAdminRole = getRoleAdmin(role);\n        _roles[role].adminRole = adminRole;\n        emit RoleAdminChanged(role, previousAdminRole, adminRole);\n    }\n\n    /**\n     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n        if (!hasRole(role, account)) {\n            _roles[role].hasRole[account] = true;\n            emit RoleGranted(role, account, _msgSender());\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n        if (hasRole(role, account)) {\n            _roles[role].hasRole[account] = false;\n            emit RoleRevoked(role, account, _msgSender());\n            return true;\n        } else {\n            return false;\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\n *     }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n *     function initializeV2() reinitializer(2) public {\n *         __ERC20Permit_init(\"MyToken\");\n *     }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n *     _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n    /**\n     * @dev Storage of the initializable contract.\n     *\n     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\n     * when using with upgradeable contracts.\n     *\n     * @custom:storage-location erc7201:openzeppelin.storage.Initializable\n     */\n    struct InitializableStorage {\n        /**\n         * @dev Indicates that the contract has been initialized.\n         */\n        uint64 _initialized;\n        /**\n         * @dev Indicates that the contract is in the process of being initialized.\n         */\n        bool _initializing;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Initializable\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;\n\n    /**\n     * @dev The contract is already initialized.\n     */\n    error InvalidInitialization();\n\n    /**\n     * @dev The contract is not initializing.\n     */\n    error NotInitializing();\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint64 version);\n\n    /**\n     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n     * `onlyInitializing` functions can be used to initialize parent contracts.\n     *\n     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any\n     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in\n     * production.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier initializer() {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        // Cache values to avoid duplicated sloads\n        bool isTopLevelCall = !$._initializing;\n        uint64 initialized = $._initialized;\n\n        // Allowed calls:\n        // - initialSetup: the contract is not in the initializing state and no previous version was\n        //                 initialized\n        // - construction: the contract is initialized at version 1 (no reininitialization) and the\n        //                 current contract is just being deployed\n        bool initialSetup = initialized == 0 && isTopLevelCall;\n        bool construction = initialized == 1 && address(this).code.length == 0;\n\n        if (!initialSetup && !construction) {\n            revert InvalidInitialization();\n        }\n        $._initialized = 1;\n        if (isTopLevelCall) {\n            $._initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            $._initializing = false;\n            emit Initialized(1);\n        }\n    }\n\n    /**\n     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n     * used to initialize parent contracts.\n     *\n     * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n     * are added through upgrades and that require initialization.\n     *\n     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n     * cannot be nested. If one is invoked in the context of another, execution will revert.\n     *\n     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n     * a contract, executing them in the right order is up to the developer or operator.\n     *\n     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier reinitializer(uint64 version) {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        if ($._initializing || $._initialized >= version) {\n            revert InvalidInitialization();\n        }\n        $._initialized = version;\n        $._initializing = true;\n        _;\n        $._initializing = false;\n        emit Initialized(version);\n    }\n\n    /**\n     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n     * {initializer} and {reinitializer} modifiers, directly or indirectly.\n     */\n    modifier onlyInitializing() {\n        _checkInitializing();\n        _;\n    }\n\n    /**\n     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\n     */\n    function _checkInitializing() internal view virtual {\n        if (!_isInitializing()) {\n            revert NotInitializing();\n        }\n    }\n\n    /**\n     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n     * through proxies.\n     *\n     * Emits an {Initialized} event the first time it is successfully executed.\n     */\n    function _disableInitializers() internal virtual {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        if ($._initializing) {\n            revert InvalidInitialization();\n        }\n        if ($._initialized != type(uint64).max) {\n            $._initialized = type(uint64).max;\n            emit Initialized(type(uint64).max);\n        }\n    }\n\n    /**\n     * @dev Returns the highest version that has been initialized. See {reinitializer}.\n     */\n    function _getInitializedVersion() internal view returns (uint64) {\n        return _getInitializableStorage()._initialized;\n    }\n\n    /**\n     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n     */\n    function _isInitializing() internal view returns (bool) {\n        return _getInitializableStorage()._initializing;\n    }\n\n    /**\n     * @dev Returns a pointer to the storage namespace.\n     */\n    // solhint-disable-next-line var-name-mixedcase\n    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\n        assembly {\n            $.slot := INITIALIZABLE_STORAGE\n        }\n    }\n}\n"},{"file_path":"contracts/v2/interfaces/IFxMarketV2.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IFxMarketV2 {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when fToken is minted.\n  /// @param owner The address of base token owner.\n  /// @param recipient The address of receiver for fToken or xToken.\n  /// @param baseTokenIn The amount of base token deposited.\n  /// @param fTokenOut The amount of fToken minted.\n  /// @param mintFee The amount of mint fee charged.\n  event MintFToken(\n    address indexed owner,\n    address indexed recipient,\n    uint256 baseTokenIn,\n    uint256 fTokenOut,\n    uint256 mintFee\n  );\n\n  /// @notice Emitted when xToken is minted.\n  /// @param owner The address of base token owner.\n  /// @param recipient The address of receiver for fToken or xToken.\n  /// @param baseTokenIn The amount of base token deposited.\n  /// @param xTokenOut The amount of xToken minted.\n  /// @param bonus The amount of base token as bonus.\n  /// @param mintFee The amount of mint fee charged.\n  event MintXToken(\n    address indexed owner,\n    address indexed recipient,\n    uint256 baseTokenIn,\n    uint256 xTokenOut,\n    uint256 bonus,\n    uint256 mintFee\n  );\n\n  /// @notice Emitted when someone redeem base token with fToken or xToken.\n  /// @param owner The address of fToken and xToken owner.\n  /// @param recipient The address of receiver for base token.\n  /// @param fTokenBurned The amount of fToken burned.\n  /// @param baseTokenOut The amount of base token redeemed.\n  /// @param bonus The amount of base token as bonus.\n  /// @param redeemFee The amount of redeem fee charged.\n  event RedeemFToken(\n    address indexed owner,\n    address indexed recipient,\n    uint256 fTokenBurned,\n    uint256 baseTokenOut,\n    uint256 bonus,\n    uint256 redeemFee\n  );\n\n  /// @notice Emitted when someone redeem base token with fToken or xToken.\n  /// @param owner The address of fToken and xToken owner.\n  /// @param recipient The address of receiver for base token.\n  /// @param xTokenBurned The amount of xToken burned.\n  /// @param baseTokenOut The amount of base token redeemed.\n  /// @param redeemFee The amount of redeem fee charged.\n  event RedeemXToken(\n    address indexed owner,\n    address indexed recipient,\n    uint256 xTokenBurned,\n    uint256 baseTokenOut,\n    uint256 redeemFee\n  );\n\n  /// @notice Emitted when the fee ratio for minting fToken is updated.\n  /// @param defaultFeeRatio The new default fee ratio, multipled by 1e18.\n  /// @param extraFeeRatio The new extra fee ratio, multipled by 1e18.\n  event UpdateMintFeeRatioFToken(uint256 defaultFeeRatio, int256 extraFeeRatio);\n\n  /// @notice Emitted when the fee ratio for minting xToken is updated.\n  /// @param defaultFeeRatio The new default fee ratio, multipled by 1e18.\n  /// @param extraFeeRatio The new extra fee ratio, multipled by 1e18.\n  event UpdateMintFeeRatioXToken(uint256 defaultFeeRatio, int256 extraFeeRatio);\n\n  /// @notice Emitted when the fee ratio for redeeming fToken is updated.\n  /// @param defaultFeeRatio The new default fee ratio, multipled by 1e18.\n  /// @param extraFeeRatio The new extra fee ratio, multipled by 1e18.\n  event UpdateRedeemFeeRatioFToken(uint256 defaultFeeRatio, int256 extraFeeRatio);\n\n  /// @notice Emitted when the fee ratio for redeeming xToken is updated.\n  /// @param defaultFeeRatio The new default fee ratio, multipled by 1e18.\n  /// @param extraFeeRatio The new extra fee ratio, multipled by 1e18.\n  event UpdateRedeemFeeRatioXToken(uint256 defaultFeeRatio, int256 extraFeeRatio);\n\n  /// @notice Emitted when the stability ratio is updated.\n  /// @param oldRatio The previous collateral ratio to enter stability mode, multiplied by 1e18.\n  /// @param newRatio The current collateral ratio to enter stability mode, multiplied by 1e18.\n  event UpdateStabilityRatio(uint256 oldRatio, uint256 newRatio);\n\n  /// @notice Emitted when the platform contract is updated.\n  /// @param oldPlatform The address of previous platform contract.\n  /// @param newPlatform The address of current platform contract.\n  event UpdatePlatform(address indexed oldPlatform, address indexed newPlatform);\n\n  /// @notice Emitted when the  reserve pool contract is updated.\n  /// @param oldReservePool The address of previous reserve pool contract.\n  /// @param newReservePool The address of current reserve pool contract.\n  event UpdateReservePool(address indexed oldReservePool, address indexed newReservePool);\n\n  /// @notice Emitted when the RebalancePoolRegistry contract is updated.\n  /// @param oldRegistry The address of previous RebalancePoolRegistry contract.\n  /// @param newRegistry The address of current RebalancePoolRegistry contract.\n  event UpdateRebalancePoolRegistry(address indexed oldRegistry, address indexed newRegistry);\n\n  /// @notice Pause or unpause mint.\n  /// @param oldStatus The previous status for mint.\n  /// @param newStatus The current status for mint.\n  event UpdateMintStatus(bool oldStatus, bool newStatus);\n\n  /// @notice Pause or unpause redeem.\n  /// @param oldStatus The previous status for redeem.\n  /// @param newStatus The current status for redeem.\n  event UpdateRedeemStatus(bool oldStatus, bool newStatus);\n\n  /// @notice Pause or unpause fToken mint in stability mode.\n  /// @param oldStatus The previous status for mint.\n  /// @param newStatus The current status for mint.\n  event UpdateFTokenMintStatusInStabilityMode(bool oldStatus, bool newStatus);\n\n  /// @notice Pause or unpause xToken redeem in stability mode.\n  /// @param oldStatus The previous status for redeem.\n  /// @param newStatus The current status for redeem.\n  event UpdateXTokenRedeemStatusInStabilityMode(bool oldStatus, bool newStatus);\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the caller if not fUSD contract.\n  error ErrorCallerNotFUSD();\n\n  /// @dev Thrown when token mint is paused.\n  error ErrorMintPaused();\n\n  /// @dev Thrown when fToken mint is paused in stability mode.\n  error ErrorFTokenMintPausedInStabilityMode();\n\n  /// @dev Thrown when mint with zero amount base token.\n  error ErrorMintZeroAmount();\n\n  /// @dev Thrown when the amount of fToken is not enough.\n  error ErrorInsufficientFTokenOutput();\n\n  /// @dev Thrown when the amount of xToken is not enough.\n  error ErrorInsufficientXTokenOutput();\n\n  /// @dev Thrown when token redeem is paused.\n  error ErrorRedeemPaused();\n\n  /// @dev Thrown when xToken redeem is paused in stability mode.\n  error ErrorXTokenRedeemPausedInStabilityMode();\n\n  /// @dev Thrown when redeem with zero amount fToken or xToken.\n  error ErrorRedeemZeroAmount();\n\n  /// @dev Thrown when the amount of base token is not enough.\n  error ErrorInsufficientBaseOutput();\n\n  /// @dev Thrown when the stability ratio is too large.\n  error ErrorStabilityRatioTooLarge();\n\n  /// @dev Thrown when the default fee is too large.\n  error ErrorDefaultFeeTooLarge();\n\n  /// @dev Thrown when the delta fee is too small.\n  error ErrorDeltaFeeTooSmall();\n\n  /// @dev Thrown when the sum of default fee and delta fee is too large.\n  error ErrorTotalFeeTooLarge();\n\n  /// @dev Thrown when the given address is zero.\n  error ErrorZeroAddress();\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice The address of Treasury contract.\n  function treasury() external view returns (address);\n\n  /// @notice Return the address of base token.\n  function baseToken() external view returns (address);\n\n  /// @notice Return the address fractional base token.\n  function fToken() external view returns (address);\n\n  /// @notice Return the address leveraged base token.\n  function xToken() external view returns (address);\n\n  /// @notice Return the address of fxUSD token.\n  function fxUSD() external view returns (address);\n\n  /// @notice Return the collateral ratio to enter stability mode, multiplied by 1e18.\n  function stabilityRatio() external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Mint some fToken with some base token.\n  /// @param baseIn The amount of wrapped value of base token supplied, use `uint256(-1)` to supply all base token.\n  /// @param recipient The address of receiver for fToken.\n  /// @param minFTokenMinted The minimum amount of fToken should be received.\n  /// @return fTokenMinted The amount of fToken should be received.\n  function mintFToken(\n    uint256 baseIn,\n    address recipient,\n    uint256 minFTokenMinted\n  ) external returns (uint256 fTokenMinted);\n\n  /// @notice Mint some xToken with some base token.\n  /// @param baseIn The amount of wrapped value of base token supplied, use `uint256(-1)` to supply all base token.\n  /// @param recipient The address of receiver for xToken.\n  /// @param minXTokenMinted The minimum amount of xToken should be received.\n  /// @return xTokenMinted The amount of xToken should be received.\n  /// @return bonus The amount of wrapped value of base token as bonus.\n  function mintXToken(\n    uint256 baseIn,\n    address recipient,\n    uint256 minXTokenMinted\n  ) external returns (uint256 xTokenMinted, uint256 bonus);\n\n  /// @notice Redeem base token with fToken.\n  /// @param fTokenIn the amount of fToken to redeem, use `uint256(-1)` to redeem all fToken.\n  /// @param recipient The address of receiver for base token.\n  /// @param minBaseOut The minimum amount of wrapped value of base token should be received.\n  /// @return baseOut The amount of wrapped value of base token should be received.\n  /// @return bonus The amount of wrapped value of base token as bonus.\n  function redeemFToken(\n    uint256 fTokenIn,\n    address recipient,\n    uint256 minBaseOut\n  ) external returns (uint256 baseOut, uint256 bonus);\n\n  /// @notice Redeem base token with xToken.\n  /// @param xTokenIn the amount of xToken to redeem, use `uint256(-1)` to redeem all xToken.\n  /// @param recipient The address of receiver for base token.\n  /// @param minBaseOut The minimum amount of wrapped value of base token should be received.\n  /// @return baseOut The amount of wrapped value of base token should be received.\n  function redeemXToken(\n    uint256 xTokenIn,\n    address recipient,\n    uint256 minBaseOut\n  ) external returns (uint256 baseOut);\n}\n"},{"file_path":"@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)\n\npragma solidity ^0.8.20;\n\nimport {Strings} from \"../Strings.sol\";\n\n/**\n * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.\n *\n * The library provides methods for generating a hash of a message that conforms to the\n * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]\n * specifications.\n */\nlibrary MessageHashUtils {\n    /**\n     * @dev Returns the keccak256 digest of an EIP-191 signed data with version\n     * `0x45` (`personal_sign` messages).\n     *\n     * The digest is calculated by prefixing a bytes32 `messageHash` with\n     * `\"\\x19Ethereum Signed Message:\\n32\"` and hashing the result. It corresponds with the\n     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.\n     *\n     * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with\n     * keccak256, although any bytes32 value can be safely used because the final digest will\n     * be re-hashed.\n     *\n     * See {ECDSA-recover}.\n     */\n    function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x00, \"\\x19Ethereum Signed Message:\\n32\") // 32 is the bytes-length of messageHash\n            mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix\n            digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)\n        }\n    }\n\n    /**\n     * @dev Returns the keccak256 digest of an EIP-191 signed data with version\n     * `0x45` (`personal_sign` messages).\n     *\n     * The digest is calculated by prefixing an arbitrary `message` with\n     * `\"\\x19Ethereum Signed Message:\\n\" + len(message)` and hashing the result. It corresponds with the\n     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.\n     *\n     * See {ECDSA-recover}.\n     */\n    function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {\n        return\n            keccak256(bytes.concat(\"\\x19Ethereum Signed Message:\\n\", bytes(Strings.toString(message.length)), message));\n    }\n\n    /**\n     * @dev Returns the keccak256 digest of an EIP-191 signed data with version\n     * `0x00` (data with intended validator).\n     *\n     * The digest is calculated by prefixing an arbitrary `data` with `\"\\x19\\x00\"` and the intended\n     * `validator` address. Then hashing the result.\n     *\n     * See {ECDSA-recover}.\n     */\n    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(hex\"19_00\", validator, data));\n    }\n\n    /**\n     * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).\n     *\n     * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with\n     * `\\x19\\x01` and hashing the result. It corresponds to the hash signed by the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.\n     *\n     * See {ECDSA-recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let ptr := mload(0x40)\n            mstore(ptr, hex\"19_01\")\n            mstore(add(ptr, 0x02), domainSeparator)\n            mstore(add(ptr, 0x22), structHash)\n            digest := keccak256(ptr, 0x42)\n        }\n    }\n}\n"},{"file_path":"contracts/common/EIP2535/upgradeInitializers/DiamondInit.sol","source_code":"// SPDX-License-Identifier: CC0-1.0\npragma solidity ^0.8.0;\n\n/******************************************************************************\\\n* Author: Nick Mudge <nick@perfectabstractions.com>, Twitter/Github: @mudgen\n* EIP-2535 Diamonds\n*\n* Contract used to initialize state variables during deployment or upgrade\n/******************************************************************************/\n\nimport { LibDiamond } from \"../libraries/LibDiamond.sol\";\nimport { IDiamondLoupe } from \"../interfaces/IDiamondLoupe.sol\";\nimport { IDiamondCut } from \"../interfaces/IDiamondCut.sol\";\nimport { IERC173 } from \"../interfaces/IERC173.sol\";\nimport { IERC165 } from \"../interfaces/IERC165.sol\";\n\n// It is expected that this contract is customized if you want to deploy your diamond\n// with data from a deployment script. Use the init function to initialize state variables\n// of your diamond. Add parameters to the init funciton if you need to.\n\n// Adding parameters to the `init` or other functions you add here can make a single deployed\n// DiamondInit contract reusable accross upgrades, and can be used for multiple diamonds.\n\ncontract DiamondInit {\n  // You can add parameters to this function in order to pass in\n  // data to set your own state variables\n  function init() external {\n    // adding ERC165 data\n    LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();\n    ds.supportedInterfaces[type(IERC165).interfaceId] = true;\n    ds.supportedInterfaces[type(IDiamondCut).interfaceId] = true;\n    ds.supportedInterfaces[type(IDiamondLoupe).interfaceId] = true;\n    ds.supportedInterfaces[type(IERC173).interfaceId] = true;\n\n    // add your own state variables\n    // EIP-2535 specifies that the `diamondCut` function takes two optional\n    // arguments: address _init and bytes calldata _calldata\n    // These arguments are used to execute an arbitrary function using delegatecall\n    // in order to set state variables in the diamond during deployment or an upgrade\n    // More info here: https://eips.ethereum.org/EIPS/eip-2535#diamond-interface\n  }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/token/ERC20/extensions/ERC20PermitUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/ERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20PermitUpgradeable.sol\";\nimport \"../ERC20Upgradeable.sol\";\nimport \"../../../utils/cryptography/ECDSAUpgradeable.sol\";\nimport \"../../../utils/cryptography/EIP712Upgradeable.sol\";\nimport \"../../../utils/CountersUpgradeable.sol\";\nimport {Initializable} from \"../../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * _Available since v3.4._\n *\n * @custom:storage-size 51\n */\nabstract contract ERC20PermitUpgradeable is Initializable, ERC20Upgradeable, IERC20PermitUpgradeable, EIP712Upgradeable {\n    using CountersUpgradeable for CountersUpgradeable.Counter;\n\n    mapping(address => CountersUpgradeable.Counter) private _nonces;\n\n    // solhint-disable-next-line var-name-mixedcase\n    bytes32 private constant _PERMIT_TYPEHASH =\n        keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n    /**\n     * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`.\n     * However, to ensure consistency with the upgradeable transpiler, we will continue\n     * to reserve a slot.\n     * @custom:oz-renamed-from _PERMIT_TYPEHASH\n     */\n    // solhint-disable-next-line var-name-mixedcase\n    bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;\n\n    /**\n     * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\"1\"`.\n     *\n     * It's a good idea to use the same `name` that is defined as the ERC20 token name.\n     */\n    function __ERC20Permit_init(string memory name) internal onlyInitializing {\n        __EIP712_init_unchained(name, \"1\");\n    }\n\n    function __ERC20Permit_init_unchained(string memory) internal onlyInitializing {}\n\n    /**\n     * @inheritdoc IERC20PermitUpgradeable\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 override {\n        require(block.timestamp <= deadline, \"ERC20Permit: expired deadline\");\n\n        bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));\n\n        bytes32 hash = _hashTypedDataV4(structHash);\n\n        address signer = ECDSAUpgradeable.recover(hash, v, r, s);\n        require(signer == owner, \"ERC20Permit: invalid signature\");\n\n        _approve(owner, spender, value);\n    }\n\n    /**\n     * @inheritdoc IERC20PermitUpgradeable\n     */\n    function nonces(address owner) public view virtual override returns (uint256) {\n        return _nonces[owner].current();\n    }\n\n    /**\n     * @inheritdoc IERC20PermitUpgradeable\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view override returns (bytes32) {\n        return _domainSeparatorV4();\n    }\n\n    /**\n     * @dev \"Consume a nonce\": return the current value and increment.\n     *\n     * _Available since v4.1._\n     */\n    function _useNonce(address owner) internal virtual returns (uint256 current) {\n        CountersUpgradeable.Counter storage nonce = _nonces[owner];\n        current = nonce.current();\n        nonce.increment();\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"},{"file_path":"contracts/v2/interfaces/IFxBoostableRebalancePool.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IFxBoostableRebalancePool {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when user deposit asset into this contract.\n  /// @param owner The address of asset owner.\n  /// @param reciever The address of receiver of the asset in this contract.\n  /// @param amount The amount of asset deposited.\n  event Deposit(address indexed owner, address indexed reciever, uint256 amount);\n\n  /// @notice Emitted when the amount of deposited asset changed due to liquidation or deposit or unlock.\n  /// @param owner The address of asset owner.\n  /// @param newDeposit The new amount of deposited asset.\n  /// @param loss The amount of asset used by liquidation.\n  event UserDepositChange(address indexed owner, uint256 newDeposit, uint256 loss);\n\n  /// @notice Emitted when user withdraw asset.\n  /// @param owner The address of asset owner.\n  /// @param reciever The address of receiver of the asset.\n  /// @param amount The amount of token to withdraw.\n  event Withdraw(address indexed owner, address indexed reciever, uint256 amount);\n\n  /// @notice Emitted when liquidation happens.\n  /// @param liquidated The amount of asset liquidated.\n  /// @param baseGained The amount of base token gained.\n  event Liquidate(uint256 liquidated, uint256 baseGained);\n\n  /// @notice Emitted when the address of reward wrapper is updated.\n  /// @param oldWrapper The address of previous reward wrapper.\n  /// @param newWrapper The address of current reward wrapper.\n  event UpdateWrapper(address indexed oldWrapper, address indexed newWrapper);\n\n  /// @notice Emitted when the liquidatable collateral ratio is updated.\n  /// @param oldRatio The previous liquidatable collateral ratio.\n  /// @param newRatio The current liquidatable collateral ratio.\n  event UpdateLiquidatableCollateralRatio(uint256 oldRatio, uint256 newRatio);\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown then the src token mismatched.\n  error ErrorWrapperSrcMismatch();\n\n  /// @dev Thrown then the dst token mismatched.\n  error ErrorWrapperDstMismatch();\n\n  /// @dev Thrown when the deposited amount is zero.\n  error DepositZeroAmount();\n\n  /// @dev Thrown when the withdrawn amount is zero.\n  error WithdrawZeroAmount();\n\n  /// @dev Thrown the cannot liquidate.\n  error CannotLiquidate();\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the address of treasury contract.\n  function treasury() external view returns (address);\n\n  /// @notice Return the address of market contract.\n  function market() external view returns (address);\n\n  /// @notice Return the address of base token.\n  function baseToken() external view returns (address);\n\n  /// @notice Return the address of underlying token of this contract.\n  function asset() external view returns (address);\n\n  /// @notice Return the total amount of asset deposited to this contract.\n  function totalSupply() external view returns (uint256);\n\n  /// @notice Return the amount of deposited asset for some specific user.\n  /// @param account The address of user to query.\n  function balanceOf(address account) external view returns (uint256);\n\n  /// @notice Return the current boost ratio for some specific user.\n  /// @param account The address of user to query, multiplied by 1e18.\n  function getBoostRatio(address account) external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Deposit some asset to this contract.\n  /// @dev Use `amount=uint256(-1)` if you want to deposit all asset held.\n  /// @param amount The amount of asset to deposit.\n  /// @param receiver The address of recipient for the deposited asset.\n  function deposit(uint256 amount, address receiver) external;\n\n  /// @notice Withdraw asset from this contract.\n  function withdraw(uint256 amount, address receiver) external;\n\n  /// @notice Liquidate asset for base token.\n  /// @param maxAmount The maximum amount of asset to liquidate.\n  /// @param minBaseOut The minimum amount of base token should receive.\n  /// @return liquidated The amount of asset liquidated.\n  /// @return baseOut The amount of base token received.\n  function liquidate(uint256 maxAmount, uint256 minBaseOut) external returns (uint256 liquidated, uint256 baseOut);\n}\n"},{"file_path":"@openzeppelin/contracts/utils/math/Math.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    /**\n     * @dev Muldiv operation overflow.\n     */\n    error MathOverflowedMulDiv();\n\n    enum Rounding {\n        Floor, // Toward negative infinity\n        Ceil, // Toward positive infinity\n        Trunc, // Toward zero\n        Expand // Away from zero\n    }\n\n    /**\n     * @dev Returns the addition of two unsigned integers, with an overflow flag.\n     */\n    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            uint256 c = a + b;\n            if (c < a) return (false, 0);\n            return (true, c);\n        }\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n     */\n    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b > a) return (false, 0);\n            return (true, a - b);\n        }\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n     */\n    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n            // benefit is lost if 'b' is also tested.\n            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n            if (a == 0) return (true, 0);\n            uint256 c = a * b;\n            if (c / a != b) return (false, 0);\n            return (true, c);\n        }\n    }\n\n    /**\n     * @dev Returns the division of two unsigned integers, with a division by zero flag.\n     */\n    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b == 0) return (false, 0);\n            return (true, a / b);\n        }\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n     */\n    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b == 0) return (false, 0);\n            return (true, a % b);\n        }\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds towards infinity instead\n     * of rounding towards zero.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        if (b == 0) {\n            // Guarantee the same behavior as in a regular Solidity division.\n            return a / b;\n        }\n\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n     * denominator == 0.\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by\n     * Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0 = x * y; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n                // The surrounding unchecked block does not change this fact.\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            if (denominator <= prod1) {\n                revert MathOverflowedMulDiv();\n            }\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.\n\n            uint256 twos = denominator & (0 - denominator);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n            // works in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded\n     * towards zero.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10 ** 64) {\n                value /= 10 ** 64;\n                result += 64;\n            }\n            if (value >= 10 ** 32) {\n                value /= 10 ** 32;\n                result += 32;\n            }\n            if (value >= 10 ** 16) {\n                value /= 10 ** 16;\n                result += 16;\n            }\n            if (value >= 10 ** 8) {\n                value /= 10 ** 8;\n                result += 8;\n            }\n            if (value >= 10 ** 4) {\n                value /= 10 ** 4;\n                result += 4;\n            }\n            if (value >= 10 ** 2) {\n                value /= 10 ** 2;\n                result += 2;\n            }\n            if (value >= 10 ** 1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.\n     */\n    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {\n        return uint8(rounding) % 2 == 1;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/utils/AddressUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     *\n     * Furthermore, `isContract` will also return true if the target contract within\n     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n     * which only has an effect at the end of a transaction.\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n     *\n     * _Available since v4.8._\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        if (success) {\n            if (returndata.length == 0) {\n                // only check isContract if the call was successful and the return data is empty\n                // otherwise we already know that it was a contract\n                require(isContract(target), \"Address: call to non-contract\");\n            }\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason or using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    function _revert(bytes memory returndata, string memory errorMessage) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            /// @solidity memory-safe-assembly\n            assembly {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert(errorMessage);\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/access/Ownable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    /**\n     * @dev The caller account is not authorized to perform an operation.\n     */\n    error OwnableUnauthorizedAccount(address account);\n\n    /**\n     * @dev The owner is not a valid owner account. (eg. `address(0)`)\n     */\n    error OwnableInvalidOwner(address owner);\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n     */\n    constructor(address initialOwner) {\n        if (initialOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(initialOwner);\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        if (owner() != _msgSender()) {\n            revert OwnableUnauthorizedAccount(_msgSender());\n        }\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        if (newOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"},{"file_path":"contracts/v2/interfaces/IFxUSD.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IFxUSD {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when a new market is added.\n  /// @param baseToken The address of base token of the market.\n  /// @param mintCap The mint capacity of the market.\n  event AddMarket(address indexed baseToken, uint256 mintCap);\n\n  /// @notice Emitted when the mint capacity is updated.\n  /// @param baseToken The address of base token of the market.\n  /// @param oldCap The value of previous mint capacity.\n  /// @param newCap The value of current mint capacity.\n  event UpdateMintCap(address indexed baseToken, uint256 oldCap, uint256 newCap);\n\n  /// @notice Emitted when a new rebalance pool is added.\n  /// @param baseToken The address of base token of the market.\n  /// @param pool The address of the rebalance pool.\n  event AddRebalancePool(address indexed baseToken, address indexed pool);\n\n  /// @notice Emitted when a new rebalance pool is removed.\n  /// @param baseToken The address of base token of the market.\n  /// @param pool The address of the rebalance pool.\n  event RemoveRebalancePool(address indexed baseToken, address indexed pool);\n\n  /// @notice Emitted when someone wrap fToken as fxUSD.\n  /// @param baseToken The address of base token of the market.\n  /// @param owner The address of fToken owner.\n  /// @param receiver The address of fxUSD recipient.\n  /// @param amount The amount of fxUSD minted.\n  event Wrap(address indexed baseToken, address indexed owner, address indexed receiver, uint256 amount);\n\n  /// @notice Emitted when someone unwrap fxUSD as fToken.\n  /// @param baseToken The address of base token of the market.\n  /// @param owner The address of fxUSD owner.\n  /// @param receiver The address of base token recipient.\n  /// @param amount The amount of fxUSD burned.\n  event Unwrap(address indexed baseToken, address indexed owner, address indexed receiver, uint256 amount);\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when someone tries to interact with unsupported market.\n  error ErrorUnsupportedMarket();\n\n  /// @dev Thrown when someone tries to interact with unsupported rebalance pool.\n  error ErrorUnsupportedRebalancePool();\n\n  /// @dev Thrown when someone tries to interact with market in stability mode.\n  error ErrorMarketInStabilityMode();\n\n  /// @dev Thrown when someone tries to interact with market has invalid price.\n  error ErrorMarketWithInvalidPrice();\n\n  /// @dev Thrown when someone tries to add a supported market.\n  error ErrorMarketAlreadySupported();\n\n  /// @dev Thrown when the total supply of fToken exceed mint capacity.\n  error ErrorExceedMintCap();\n\n  /// @dev Thrown when the amount of fToken is not enough for redeem.\n  error ErrorInsufficientLiquidity();\n\n  /// @dev Thrown when current is under collateral.\n  error ErrorUnderCollateral();\n\n  /// @dev Thrown when the length of two arrays is mismatch.\n  error ErrorLengthMismatch();\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the list of supported markets.\n  function getMarkets() external view returns (address[] memory);\n\n  /// @notice Return the list of supported rebalance pools.\n  function getRebalancePools() external view returns (address[] memory);\n\n  /// @notice Return the nav of fxUSD.\n  function nav() external view returns (uint256);\n\n  /// @notice Return whether the system is under collateral.\n  function isUnderCollateral() external view returns (bool);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Wrap fToken to fxUSD.\n  /// @param baseToken The address of corresponding base token.\n  /// @param amount The amount of fToken to wrap.\n  /// @param receiver The address of fxUSD recipient.\n  function wrap(\n    address baseToken,\n    uint256 amount,\n    address receiver\n  ) external;\n\n  /// @notice Unwrap fxUSD to fToken.\n  /// @param baseToken The address of corresponding base token.\n  /// @param amount The amount of fxUSD to unwrap.\n  /// @param receiver The address of fToken recipient.\n  function unwrap(\n    address baseToken,\n    uint256 amount,\n    address receiver\n  ) external;\n\n  /// @notice Wrap fToken from rebalance pool to fxUSD.\n  /// @param pool The address of rebalance pool.\n  /// @param amount The amount of fToken to wrap.\n  /// @param receiver The address of fxUSD recipient.\n  function wrapFrom(\n    address pool,\n    uint256 amount,\n    address receiver\n  ) external;\n\n  /// @notice Mint fxUSD with base token.\n  /// @param baseToken The address of the base token.\n  /// @param amountIn The amount of base token to use.\n  /// @param receiver The address of fxUSD recipient.\n  /// @param minOut The minimum amount of fxUSD should receive.\n  /// @return amountOut The amount of fxUSD received by the receiver.\n  function mint(\n    address baseToken,\n    uint256 amountIn,\n    address receiver,\n    uint256 minOut\n  ) external returns (uint256 amountOut);\n\n  /// @notice Deposit fxUSD to rebalance pool.\n  /// @param pool The address of rebalance pool.\n  /// @param amount The amount of fxUSD to use.\n  /// @param receiver The address of rebalance pool share recipient.\n  function earn(\n    address pool,\n    uint256 amount,\n    address receiver\n  ) external;\n\n  /// @notice Mint fxUSD with base token and deposit to rebalance pool.\n  /// @param pool The address of rebalance pool.\n  /// @param amountIn The amount of base token to use.\n  /// @param receiver The address of rebalance pool recipient.\n  /// @param minOut The minimum amount of rebalance pool shares should receive.\n  /// @return amountOut The amount of rebalance pool shares received by the receiver.\n  function mintAndEarn(\n    address pool,\n    uint256 amountIn,\n    address receiver,\n    uint256 minOut\n  ) external returns (uint256 amountOut);\n\n  /// @notice Redeem fxUSD to base token.\n  /// @param baseToken The address of the base token.\n  /// @param amountIn The amount of fxUSD to redeem.\n  /// @param receiver The address of base token recipient.\n  /// @param minOut The minimum amount of base token should receive.\n  /// @return amountOut The amount of base token received by the receiver.\n  /// @return bonusOut The amount of bonus base token received by the receiver.\n  function redeem(\n    address baseToken,\n    uint256 amountIn,\n    address receiver,\n    uint256 minOut\n  ) external returns (uint256 amountOut, uint256 bonusOut);\n\n  /// @notice Redeem fToken from rebalance pool to base token.\n  /// @param amountIn The amount of fxUSD to redeem.\n  /// @param receiver The address of base token recipient.\n  /// @param minOut The minimum amount of base token should receive.\n  /// @return amountOut The amount of base token received by the receiver.\n  /// @return bonusOut The amount of bonus base token received by the receiver.\n  function redeemFrom(\n    address pool,\n    uint256 amountIn,\n    address receiver,\n    uint256 minOut\n  ) external returns (uint256 amountOut, uint256 bonusOut);\n\n  /// @notice Redeem fxUSD to base token optimally.\n  /// @param amountIn The amount of fxUSD to redeem.\n  /// @param receiver The address of base token recipient.\n  /// @param minOuts The list of minimum amount of base token should receive.\n  /// @return baseTokens The list of base token received by the receiver.\n  /// @return amountOuts The list of amount of base token received by the receiver.\n  /// @return bonusOuts The list of amount of bonus base token received by the receiver.\n  function autoRedeem(\n    uint256 amountIn,\n    address receiver,\n    uint256[] memory minOuts\n  )\n    external\n    returns (\n      address[] memory baseTokens,\n      uint256[] memory amountOuts,\n      uint256[] memory bonusOuts\n    );\n}\n"},{"file_path":"contracts/interfaces/Curve/ICurvePoolOracle.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n// solhint-disable func-name-mixedcase\n\ninterface ICurvePoolOracle {\n  /********************\n   * Common Functions *\n   ********************/\n\n  function ma_exp_time() external view returns (uint256);\n\n  function ma_last_time() external view returns (uint256);\n\n  /***************************\n   * Functions of Plain Pool *\n   ***************************/\n\n  function get_p() external view returns (uint256);\n\n  function last_price() external view returns (uint256);\n\n  function last_prices() external view returns (uint256);\n\n  function ema_price() external view returns (uint256);\n\n  function price_oracle() external view returns (uint256);\n\n  /************************\n   * Functions of NG Pool *\n   ************************/\n\n  function get_p(uint256 index) external view returns (uint256);\n\n  /// @notice Returns last price of the coin at index `k` w.r.t the coin\n  ///         at index 0.\n  /// @dev last_prices returns the quote by the AMM for an infinitesimally small swap\n  ///      after the last trade. It is not equivalent to the last traded price, and\n  ///      is computed by taking the partial differential of `x` w.r.t `y`. The\n  ///      derivative is calculated in `get_p` and then multiplied with price_scale\n  ///      to give last_prices.\n  /// @param index The index of the coin.\n  /// @return uint256 Last logged price of coin.\n  function last_price(uint256 index) external view returns (uint256);\n\n  function last_prices(uint256 index) external view returns (uint256);\n\n  function ema_price(uint256 index) external view returns (uint256);\n\n  function price_oracle(uint256 index) external view returns (uint256);\n}\n"},{"file_path":"contracts/helpers/RevenuePool.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n// copy from: https://github.com/AladdinDAO/aladdin-v3-contracts/blob/main/contracts/helpers/PlatformFeeSpliter.sol\ncontract RevenuePool is Ownable {\n  using SafeERC20 for IERC20;\n\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when the address of staker contract is updated.\n  /// @param staker The address of new staker contract.\n  event UpdateStaker(address staker);\n\n  /// @notice Emitted when the address of treasury contract is updated.\n  /// @param treasury The address of new treasury contract.\n  event UpdateTreasury(address treasury);\n\n  /// @notice Emitted when the address of ecosystem contract is updated.\n  /// @param ecosystem The address of new ecosystem contract.\n  event UpdateEcosystem(address ecosystem);\n\n  /// @notice Emitted when a new reward token is added.\n  /// @param token The address of reward token.\n  /// @param burner The address of token burner contract.\n  /// @param stakerRatio The ratio of token distributed to liquidity stakers, multipled by 1e9.\n  /// @param treasuryRatio The ratio of token distributed to treasury, multipled by 1e9.\n  /// @param lockerRatio The ratio of token distributed to ve token lockers, multipled by 1e9.\n  event AddRewardToken(address token, address burner, uint256 stakerRatio, uint256 treasuryRatio, uint256 lockerRatio);\n\n  /// @notice Emitted when the percentage is updated for existing reward token.\n  /// @param token The address of reward token.\n  /// @param stakerRatio The ratio of token distributed to liquidity stakers, multipled by 1e9.\n  /// @param treasuryRatio The ratio of token distributed to treasury, multipled by 1e9.\n  /// @param lockerRatio The ratio of token distributed to ve token lockers, multipled by 1e9.\n  event UpdateRewardTokenRatio(address token, uint256 stakerRatio, uint256 treasuryRatio, uint256 lockerRatio);\n\n  /// @notice Emitted when the address of token burner is updated.\n  /// @param token The address of reward token.\n  /// @param burner The address of token burner contract.\n  event UpdateRewardTokenBurner(address token, address burner);\n\n  /// @notice Emitted when a reward token is removed.\n  /// @param token The address of reward token.\n  event RemoveRewardToken(address token);\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The fee denominator used for ratio calculation.\n  uint256 private constant FEE_PRECISION = 1e9;\n\n  /***********\n   * Structs *\n   ***********/\n\n  struct RewardInfo {\n    // The address of reward token.\n    address token;\n    // The ratio of token distributed to liquidity stakers, multipled by 1e9.\n    uint32 stakerRatio;\n    // The ratio of token distributed to treasury, multipled by 1e9.\n    uint32 treasuryRatio;\n    // The ratio of token distributed to ve token lockers, multipled by 1e9.\n    uint32 lockerRatio;\n    // @note The rest token will transfer to ecosystem fund for future usage.\n  }\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @notice The address of contract used to hold treasury fund.\n  address public treasury;\n\n  /// @notice The address of contract used to hold ecosystem fund.\n  address public ecosystem;\n\n  /// @notice The address of contract used to distribute incentive for liquidity stakers.\n  address public staker;\n\n  /// @notice The list of rewards token.\n  RewardInfo[] public rewards;\n\n  /// @notice Mapping from reward token address to corresponding token burner.\n  mapping(address => address) public burners;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(\n    address _treasury,\n    address _ecosystem,\n    address _staker\n  ) Ownable(_msgSender()) {\n    _ensureNonZeroAddress(_treasury, \"treasury\");\n    _ensureNonZeroAddress(_ecosystem, \"ecosystem\");\n    _ensureNonZeroAddress(_staker, \"staker\");\n\n    treasury = _treasury;\n    ecosystem = _ecosystem;\n    staker = _staker;\n  }\n\n  /// @notice Return the number of reward tokens.\n  function getRewardCount() external view returns (uint256) {\n    return rewards.length;\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Claim and distribute pending rewards to staker/treasury/locker/ecosystem contract.\n  /// @dev The function can only be called by staker contract.\n  function claim() external {\n    address _staker = staker;\n    require(msg.sender == _staker, \"not staker\");\n\n    address _treasury = treasury;\n    address _ecosystem = ecosystem;\n\n    uint256 _length = rewards.length;\n    for (uint256 i = 0; i < _length; i++) {\n      RewardInfo memory _reward = rewards[i];\n      uint256 _balance = IERC20(_reward.token).balanceOf(address(this));\n      if (_balance > 0) {\n        uint256 _stakerAmount = (_reward.stakerRatio * _balance) / FEE_PRECISION;\n        uint256 _treasuryAmount = (_reward.treasuryRatio * _balance) / FEE_PRECISION;\n        uint256 _lockerAmount = (_reward.lockerRatio * _balance) / FEE_PRECISION;\n        uint256 _ecosystemAmount = _balance - _stakerAmount - _treasuryAmount - _lockerAmount;\n\n        if (_stakerAmount > 0) {\n          IERC20(_reward.token).safeTransfer(_staker, _stakerAmount);\n        }\n        if (_treasuryAmount > 0) {\n          IERC20(_reward.token).safeTransfer(_treasury, _treasuryAmount);\n        }\n        if (_lockerAmount > 0) {\n          IERC20(_reward.token).safeTransfer(burners[_reward.token], _lockerAmount);\n        }\n        if (_ecosystemAmount > 0) {\n          IERC20(_reward.token).safeTransfer(_ecosystem, _ecosystemAmount);\n        }\n      }\n    }\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Update the address of treasury contract.\n  /// @param _treasury The address of new treasury contract.\n  function updateTreasury(address _treasury) external onlyOwner {\n    _ensureNonZeroAddress(_treasury, \"treasury\");\n\n    treasury = _treasury;\n\n    emit UpdateTreasury(_treasury);\n  }\n\n  /// @notice Update the address of ecosystem contract.\n  /// @param _ecosystem The address of new ecosystem contract.\n  function updateEcosystem(address _ecosystem) external onlyOwner {\n    _ensureNonZeroAddress(_ecosystem, \"ecosystem\");\n\n    ecosystem = _ecosystem;\n\n    emit UpdateEcosystem(_ecosystem);\n  }\n\n  /// @notice Update the address of staker contract.\n  /// @param _staker The address of new staker contract.\n  function updateStaker(address _staker) external onlyOwner {\n    _ensureNonZeroAddress(_staker, \"staker\");\n\n    staker = _staker;\n\n    emit UpdateStaker(_staker);\n  }\n\n  /// @notice Add a new reward token.\n  /// @param _token The address of reward token.\n  /// @param _burner The address of corresponding token burner.\n  /// @param _stakerRatio The ratio of token distributed to liquidity stakers, multipled by 1e9.\n  /// @param _treasuryRatio The ratio of token distributed to treasury, multipled by 1e9.\n  /// @param _lockerRatio The ratio of token distributed to ve token lockers, multipled by 1e9.\n  function addRewardToken(\n    address _token,\n    address _burner,\n    uint32 _stakerRatio,\n    uint32 _treasuryRatio,\n    uint32 _lockerRatio\n  ) external onlyOwner {\n    _checkRatioRange(_stakerRatio, _treasuryRatio, _lockerRatio);\n    _ensureNonZeroAddress(_burner, \"burner\");\n\n    require(burners[_token] == address(0), \"duplicated reward token\");\n    burners[_token] = _burner;\n\n    rewards.push(RewardInfo(_token, _stakerRatio, _treasuryRatio, _lockerRatio));\n\n    emit AddRewardToken(_token, _burner, _stakerRatio, _treasuryRatio, _lockerRatio);\n  }\n\n  /// @notice Update reward ratio of existing reward token.\n  /// @param _index The index of reward token.\n  /// @param _stakerRatio The ratio of token distributed to liquidity stakers, multipled by 1e9.\n  /// @param _treasuryRatio The ratio of token distributed to treasury, multipled by 1e9.\n  /// @param _lockerRatio The ratio of token distributed to ve token lockers, multipled by 1e9.\n  function updateRewardTokenRatio(\n    uint256 _index,\n    uint32 _stakerRatio,\n    uint32 _treasuryRatio,\n    uint32 _lockerRatio\n  ) external onlyOwner {\n    _checkRatioRange(_stakerRatio, _treasuryRatio, _lockerRatio);\n    require(_index < rewards.length, \"index out of range\");\n\n    RewardInfo memory _info = rewards[_index];\n    _info.stakerRatio = _stakerRatio;\n    _info.treasuryRatio = _treasuryRatio;\n    _info.lockerRatio = _lockerRatio;\n\n    rewards[_index] = _info;\n    emit UpdateRewardTokenRatio(_info.token, _stakerRatio, _treasuryRatio, _lockerRatio);\n  }\n\n  /// @notice Update the token burner of existing reward token.\n  /// @param _token The address of the reward token.\n  /// @param _burner The address of corresponding token burner.\n  function updateRewardTokenBurner(address _token, address _burner) external onlyOwner {\n    _ensureNonZeroAddress(_burner, \"new burner\");\n    _ensureNonZeroAddress(burners[_token], \"old burner\");\n\n    burners[_token] = _burner;\n\n    emit UpdateRewardTokenBurner(_token, _burner);\n  }\n\n  /// @notice Remove an existing reward token.\n  /// @param _index The index of reward token.\n  function removeRewardToken(uint256 _index) external onlyOwner {\n    uint256 _length = rewards.length;\n    require(_index < _length, \"index out of range\");\n\n    address _token = rewards[_index].token;\n    if (_index != _length - 1) {\n      rewards[_index] = rewards[_length - 1];\n    }\n    rewards.pop();\n\n    burners[_token] = address(0);\n\n    emit RemoveRewardToken(_token);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  function _checkRatioRange(\n    uint32 _stakerRatio,\n    uint32 _treasuryRatio,\n    uint32 _lockerRatio\n  ) internal pure {\n    require(_stakerRatio <= FEE_PRECISION, \"staker ratio too large\");\n    require(_treasuryRatio <= FEE_PRECISION, \"treasury ratio too large\");\n    require(_lockerRatio <= FEE_PRECISION, \"locker ratio too large\");\n    require(_stakerRatio + _treasuryRatio + _lockerRatio <= FEE_PRECISION, \"ecosystem ratio too small\");\n  }\n\n  function _ensureNonZeroAddress(address _addr, string memory _name) internal pure {\n    require(_addr != address(0), string(abi.encodePacked(_name, \" address should not be zero\")));\n  }\n}"},{"file_path":"contracts/core/FlashLoans.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.25;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { ReentrancyGuardUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol\";\n\nimport { IERC3156FlashBorrower } from \"../common/ERC3156/IERC3156FlashBorrower.sol\";\nimport { IERC3156FlashLender } from \"../common/ERC3156/IERC3156FlashLender.sol\";\n\nimport { ProtocolFees } from \"./ProtocolFees.sol\";\n\ncontract FlashLoans is ProtocolFees, ReentrancyGuardUpgradeable, IERC3156FlashLender {\n  using SafeERC20 for IERC20;\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the returned balance after flash loan is not enough.\n  error ErrorInsufficientFlashLoanReturn();\n\n  /// @dev Thrown when the returned value of `ERC3156Callback` is wrong.\n  error ErrorERC3156CallbackFailed();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The correct value of the return value of `ERC3156FlashBorrower.onFlashLoan`.\n  bytes32 private constant CALLBACK_SUCCESS = keccak256(\"ERC3156FlashBorrower.onFlashLoan\");\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @dev Slots for future use.\n  uint256[50] private _gap;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  function __FlashLoans_init() internal onlyInitializing {}\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @inheritdoc IERC3156FlashLender\n  function maxFlashLoan(address token) external view override returns (uint256) {\n    return IERC20(token).balanceOf(address(this));\n  }\n\n  /// @inheritdoc IERC3156FlashLender\n  function flashFee(address /*token*/, uint256 amount) public view returns (uint256) {\n    return (amount * getFlashLoanFeeRatio()) / FEE_PRECISION;\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc IERC3156FlashLender\n  function flashLoan(\n    IERC3156FlashBorrower receiver,\n    address token,\n    uint256 amount,\n    bytes calldata data\n  ) external nonReentrant returns (bool) {\n    // save the current balance\n    uint256 prevBalance = IERC20(token).balanceOf(address(this));\n    uint256 fee = flashFee(token, amount);\n\n    // transfer token to receiver\n    IERC20(token).safeTransfer(address(receiver), amount);\n\n    // invoke the recipient's callback\n    if (receiver.onFlashLoan(_msgSender(), token, amount, fee, data) != CALLBACK_SUCCESS) {\n      revert ErrorERC3156CallbackFailed();\n    }\n\n    // ensure that the tokens + fee have been deposited back to the network\n    uint256 returnedAmount = IERC20(token).balanceOf(address(this)) - prevBalance;\n    if (returnedAmount < amount + fee) {\n      revert ErrorInsufficientFlashLoanReturn();\n    }\n\n    if (fee > 0) {\n      IERC20(token).safeTransfer(treasury, fee);\n    }\n\n    return true;\n  }\n}\n"},{"file_path":"contracts/mocks/MockAggregatorV3Interface.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { AggregatorV3Interface } from \"../interfaces/Chainlink/AggregatorV3Interface.sol\";\n\ncontract MockAggregatorV3Interface is AggregatorV3Interface {\n  uint8 public immutable decimals;\n\n  int256 public price;\n\n  constructor(uint8 _decimals, int256 _price) {\n    decimals = _decimals;\n    price = _price;\n  }\n\n  function setPrice(int256 _price) external {\n    price = _price;\n  }\n\n  function description() external view override returns (string memory) {}\n\n  function version() external view override returns (uint256) {}\n\n  function latestAnswer() external view override returns (uint256) {\n    return uint256(price);\n  }\n\n  function getRoundData(\n    uint80\n  )\n    external\n    view\n    override\n    returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)\n  {\n    roundId = 0;\n    answer = price;\n    startedAt = block.timestamp;\n    updatedAt = block.timestamp;\n    answeredInRound = 0;\n  }\n\n  function latestRoundData()\n    external\n    view\n    override\n    returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)\n  {\n    roundId = 0;\n    answer = price;\n    startedAt = block.timestamp;\n    updatedAt = block.timestamp;\n    answeredInRound = 0;\n  }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.20;\n\nimport {IAccessControl} from \"@openzeppelin/contracts/access/IAccessControl.sol\";\nimport {ContextUpgradeable} from \"../utils/ContextUpgradeable.sol\";\nimport {ERC165Upgradeable} from \"../utils/introspection/ERC165Upgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n *     require(hasRole(MY_ROLE, msg.sender));\n *     ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {\n    struct RoleData {\n        mapping(address account => bool) hasRole;\n        bytes32 adminRole;\n    }\n\n    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n\n    /// @custom:storage-location erc7201:openzeppelin.storage.AccessControl\n    struct AccessControlStorage {\n        mapping(bytes32 role => RoleData) _roles;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.AccessControl\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;\n\n    function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {\n        assembly {\n            $.slot := AccessControlStorageLocation\n        }\n    }\n\n    /**\n     * @dev Modifier that checks that an account has a specific role. Reverts\n     * with an {AccessControlUnauthorizedAccount} error including the required role.\n     */\n    modifier onlyRole(bytes32 role) {\n        _checkRole(role);\n        _;\n    }\n\n    function __AccessControl_init() internal onlyInitializing {\n    }\n\n    function __AccessControl_init_unchained() internal onlyInitializing {\n    }\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        return $._roles[role].hasRole[account];\n    }\n\n    /**\n     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n     */\n    function _checkRole(bytes32 role) internal view virtual {\n        _checkRole(role, _msgSender());\n    }\n\n    /**\n     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n     * is missing `role`.\n     */\n    function _checkRole(bytes32 role, address account) internal view virtual {\n        if (!hasRole(role, account)) {\n            revert AccessControlUnauthorizedAccount(account, role);\n        }\n    }\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        return $._roles[role].adminRole;\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n        _grantRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n        _revokeRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been revoked `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `callerConfirmation`.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n        if (callerConfirmation != _msgSender()) {\n            revert AccessControlBadConfirmation();\n        }\n\n        _revokeRole(role, callerConfirmation);\n    }\n\n    /**\n     * @dev Sets `adminRole` as ``role``'s admin role.\n     *\n     * Emits a {RoleAdminChanged} event.\n     */\n    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        bytes32 previousAdminRole = getRoleAdmin(role);\n        $._roles[role].adminRole = adminRole;\n        emit RoleAdminChanged(role, previousAdminRole, adminRole);\n    }\n\n    /**\n     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        if (!hasRole(role, account)) {\n            $._roles[role].hasRole[account] = true;\n            emit RoleGranted(role, account, _msgSender());\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        if (hasRole(role, account)) {\n            $._roles[role].hasRole[account] = false;\n            emit RoleRevoked(role, account, _msgSender());\n            return true;\n        } else {\n            return false;\n        }\n    }\n}\n"},{"file_path":"contracts/voting-escrow/interfaces/ILiquidityGauge.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n// solhint-disable func-name-mixedcase\n\ninterface ILiquidityGauge {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when user deposit staking token to this contract.\n  /// @param owner The address of token owner.\n  /// @param receiver The address of recipient for the pool share.\n  /// @param amount The amount of staking token deposited.\n  event Deposit(address indexed owner, address indexed receiver, uint256 amount);\n\n  /// @notice Emitted when user withdraw staking token from this contract.\n  /// @param owner The address of token owner.\n  /// @param receiver The address of recipient for the staking token\n  /// @param amount The amount of staking token withdrawn.\n  event Withdraw(address indexed owner, address indexed receiver, uint256 amount);\n\n  /// @notice Emitted then the working balance is updated.\n  /// @param account The address of user updated.\n  /// @param originalBalance The original pool share of the user.\n  /// @param originalSupply The original total pool share of the contract.\n  /// @param workingBalance The current working balance of the user.\n  /// @param workingSupply The current working supply of the contract.\n  event UpdateLiquidityLimit(\n    address indexed account,\n    uint256 originalBalance,\n    uint256 originalSupply,\n    uint256 workingBalance,\n    uint256 workingSupply\n  );\n\n  /// @notice Emitted when the address of liquidity manager is updated.\n  /// @param oldLiquidityManager The address of previous liquidity manager contract.\n  /// @param newLiquidityManager The address of current liquidity manager contract.\n  event UpdateLiquidityManager(address indexed oldLiquidityManager, address indexed newLiquidityManager);\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when someone deposit zero amount staking token.\n  error DepositZeroAmount();\n\n  /// @dev Thrown when someone withdraw zero amount staking token.\n  error WithdrawZeroAmount();\n\n  /// @dev Thrown when some unauthorized user call `user_checkpoint`.\n  error UnauthorizedCaller();\n\n  /// @dev Throw when someone try to kick user who has no changes on their ve balance.\n  error KickNotAllowed();\n\n  /// @dev Thrown when someone try to do unnecessary kick.\n  error KickNotNeeded();\n\n  /// @dev Thrown when try to remove an active liquidity manager.\n  error LiquidityManagerIsActive();\n\n  /// @dev Thrown when try to add an inactive liquidity manager.\n  error LiquidityManagerIsNotActive();\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return whether the gauge is active.\n  function isActive() external view returns (bool);\n\n  /// @notice Return the address of staking token.\n  function stakingToken() external view returns (address);\n\n  /// @notice Return the amount of working supply.\n  function workingSupply() external view returns (uint256);\n\n  /// @notice Return the amount of working balance of some user.\n  /// @param account The address of user to query.\n  function workingBalanceOf(address account) external view returns (uint256);\n\n  /// @notice Return the governance token reward integrate for some user.\n  ///\n  /// @dev This is used in TokenMinter.\n  ///\n  /// @param account The address of user to query.\n  function integrate_fraction(address account) external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Initialize the state of LiquidityGauge.\n  ///\n  /// @param _stakingToken The address of staking token.\n  function initialize(address _stakingToken) external;\n\n  /// @notice Deposit some staking token to this contract.\n  ///\n  /// @dev Use `amount = type(uint256).max`, if caller wants to deposit all held staking tokens.\n  ///\n  /// @param amount The amount of staking token to deposit.\n  function deposit(uint256 amount) external;\n\n  /// @notice Deposit some staking token to this contract and transfer the share to others.\n  ///\n  /// @dev Use `amount = type(uint256).max`, if caller wants to deposit all held staking tokens.\n  ///\n  /// @param amount The amount of staking token to deposit.\n  /// @param receiver The address of the pool share recipient.\n  function deposit(uint256 amount, address receiver) external;\n\n  /// @notice Deposit some staking token to this contract and transfer the share to others.\n  ///\n  /// @dev Use `amount = type(uint256).max`, if caller wants to deposit all held staking tokens.\n  ///\n  /// @param amount The amount of staking token to deposit.\n  /// @param receiver The address of the pool share recipient.\n  /// @param manage The parameter passed to possible `LiquidityManager`.\n  function deposit(\n    uint256 amount,\n    address receiver,\n    bool manage\n  ) external;\n\n  /// @notice Withdraw some staking token from this contract.\n  ///\n  /// @dev Use `amount = type(uint256).max`, if caller wants to deposit all held staking tokens.\n  ///\n  /// @param amount The amount of staking token to withdraw.\n  function withdraw(uint256 amount) external;\n\n  /// @notice Withdraw some staking token from this contract and transfer the token to others.\n  ///\n  /// @dev Use `amount = type(uint256).max`, if caller wants to deposit all held staking tokens.\n  ///\n  /// @param amount The amount of staking token to withdraw.\n  /// @param receiver The address of the staking token recipient.\n  function withdraw(uint256 amount, address receiver) external;\n\n  /// @notice Update the snapshot for some user.\n  ///\n  /// @dev This is used in TokenMinter.\n  ///\n  /// @param account The address of user to update.\n  function user_checkpoint(address account) external returns (bool);\n\n  /// @notice Kick some user for abusing their boost.\n  ///\n  /// @dev Only if either they had another voting event, or their voting escrow lock expired.\n  ///\n  /// @param account The address of user to kick.\n  function kick(address account) external;\n}\n"},{"file_path":"contracts/core/pool/AaveFundingPool.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IAaveV3Pool } from \"../../interfaces/Aave/IAaveV3Pool.sol\";\nimport { IAaveFundingPool } from \"../../interfaces/IAaveFundingPool.sol\";\nimport { IPegKeeper } from \"../../interfaces/IPegKeeper.sol\";\n\nimport { WordCodec } from \"../../common/codec/WordCodec.sol\";\nimport { Math } from \"../../libraries/Math.sol\";\nimport { BasePool } from \"./BasePool.sol\";\n\ncontract AaveFundingPool is BasePool, IAaveFundingPool {\n  using WordCodec for bytes32;\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The offset of *open ratio* in `fundingMiscData`.\n  uint256 private constant OPEN_RATIO_OFFSET = 0;\n\n  /// @dev The offset of *open ratio step* in `fundingMiscData`.\n  uint256 private constant OPEN_RATIO_STEP_OFFSET = 30;\n\n  /// @dev The offset of *close fee ratio* in `fundingMiscData`.\n  uint256 private constant CLOSE_FEE_RATIO_OFFSET = 90;\n\n  /// @dev The offset of *funding ratio* in `fundingMiscData`.\n  uint256 private constant FUNDING_RATIO_OFFSET = 120;\n\n  /// @dev The offset of *interest rate* in `fundingMiscData`.\n  uint256 private constant INTEREST_RATE_OFFSET = 152;\n\n  /// @dev The offset of *timestamp* in `fundingMiscData`.\n  uint256 private constant TIMESTAMP_OFFSET = 220;\n\n  /// @dev The maximum value of *funding ratio*.\n  uint256 private constant MAX_FUNDING_RATIO = 4294967295;\n\n  /// @dev The minimum Aave borrow index snapshot delay.\n  uint256 private constant MIN_SNAPSHOT_DELAY = 30 minutes;\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @dev The address of Aave V3 `LendingPool` contract.\n  address private immutable lendingPool;\n\n  /// @dev The address of asset used for interest calculation.\n  address private immutable baseAsset;\n\n  /***********\n   * Structs *\n   ***********/\n\n  /// @dev The struct for AAVE borrow rate snapshot.\n  /// @param borrowIndex The current borrow index of AAVE, multiplied by 1e27.\n  /// @param lastInterestRate The last recorded interest rate, multiplied by 1e18.\n  /// @param timestamp The timestamp when the snapshot is taken.\n  struct BorrowRateSnapshot {\n    // The initial value of `borrowIndex` is `10^27`, it is very unlikely this value will exceed `2^128`.\n    uint128 borrowIndex;\n    uint80 lastInterestRate;\n    uint48 timestamp;\n  }\n\n  /*********************\n   * Storage Variables *\n   *********************/\n\n  /// @dev `fundingMiscData` is a storage slot that can be used to store unrelated pieces of information.\n  ///\n  /// - The *open ratio* is the fee ratio for opening position, multiplied by 1e9.\n  /// - The *open ratio step* is the fee ratio step for opening position, multiplied by 1e18.\n  /// - The *close fee ratio* is the fee ratio for closing position, multiplied by 1e9.\n  /// - The *funding ratio* is the scalar for funding rate, multiplied by 1e9.\n  ///   The maximum value is `4.294967296`.\n  ///\n  /// [ open ratio | open ratio step | close fee ratio | funding ratio | reserved ]\n  /// [  30  bits  |     60 bits     |     30 bits     |    32 bits    | 104 bits ]\n  /// [ MSB                                                                   LSB ]\n  bytes32 private fundingMiscData;\n\n  /// @notice The snapshot for AAVE borrow rate.\n  BorrowRateSnapshot public borrowRateSnapshot;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _poolManager, address _lendingPool, address _baseAsset) BasePool(_poolManager) {\n    _checkAddressNotZero(_lendingPool);\n    _checkAddressNotZero(_baseAsset);\n\n    lendingPool = _lendingPool;\n    baseAsset = _baseAsset;\n  }\n\n  function initialize(\n    address admin,\n    string memory name_,\n    string memory symbol_,\n    address _collateralToken,\n    address _priceOracle\n  ) external initializer {\n    __Context_init();\n    __ERC165_init();\n    __ERC721_init(name_, symbol_);\n    __AccessControl_init();\n\n    __PoolStorage_init(_collateralToken, _priceOracle);\n    __TickLogic_init();\n    __PositionLogic_init();\n    __BasePool_init();\n\n    _grantRole(DEFAULT_ADMIN_ROLE, admin);\n\n    _updateOpenRatio(1000000, 50000000000000000); // 0.1% and 5%\n    _updateCloseFeeRatio(1000000); // 0.1%\n\n    uint256 borrowIndex = IAaveV3Pool(lendingPool).getReserveNormalizedVariableDebt(baseAsset);\n    IAaveV3Pool.ReserveDataLegacy memory reserveData = IAaveV3Pool(lendingPool).getReserveData(baseAsset);\n    _updateInterestRate(borrowIndex, reserveData.currentVariableBorrowRate / 1e9);\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Get open fee ratio related parameters.\n  /// @return ratio The value of open ratio, multiplied by 1e9.\n  /// @return step The value of open ratio step, multiplied by 1e18.\n  function getOpenRatio() external view returns (uint256 ratio, uint256 step) {\n    return _getOpenRatio();\n  }\n\n  /// @notice Return the value of funding ratio, multiplied by 1e9.\n  function getFundingRatio() external view returns (uint256) {\n    return _getFundingRatio();\n  }\n\n  /// @notice Return the fee ratio for opening position, multiplied by 1e9.\n  function getOpenFeeRatio() public view returns (uint256) {\n    (uint256 openRatio, uint256 openRatioStep) = _getOpenRatio();\n    (, uint256 rate) = _getAverageInterestRate(borrowRateSnapshot);\n    unchecked {\n      uint256 aaveRatio = rate <= openRatioStep ? 1 : (rate - 1) / openRatioStep;\n      return aaveRatio * openRatio;\n    }\n  }\n\n  /// @notice Return the fee ratio for closing position, multiplied by 1e9.\n  function getCloseFeeRatio() external view returns (uint256) {\n    return _getCloseFeeRatio();\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Update the fee ratio for opening position.\n  /// @param ratio The open ratio value, multiplied by 1e9.\n  /// @param step The open ratio step value, multiplied by 1e18.\n  function updateOpenRatio(uint256 ratio, uint256 step) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateOpenRatio(ratio, step);\n  }\n\n  /// @notice Update the fee ratio for closing position.\n  /// @param ratio The close ratio value, multiplied by 1e9.\n  function updateCloseFeeRatio(uint256 ratio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateCloseFeeRatio(ratio);\n  }\n\n  /// @notice Update the funding ratio.\n  /// @param ratio The funding ratio value, multiplied by 1e9.\n  function updateFundingRatio(uint256 ratio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateFundingRatio(ratio);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to get open ratio and open ratio step.\n  /// @return ratio The value of open ratio, multiplied by 1e9.\n  /// @return step The value of open ratio step, multiplied by 1e18.\n  function _getOpenRatio() internal view returns (uint256 ratio, uint256 step) {\n    bytes32 data = fundingMiscData;\n    ratio = data.decodeUint(OPEN_RATIO_OFFSET, 30);\n    step = data.decodeUint(OPEN_RATIO_STEP_OFFSET, 60);\n  }\n\n  /// @dev Internal function to update the fee ratio for opening position.\n  /// @param ratio The open ratio value, multiplied by 1e9.\n  /// @param step The open ratio step value, multiplied by 1e18.\n  function _updateOpenRatio(uint256 ratio, uint256 step) internal {\n    _checkValueTooLarge(ratio, FEE_PRECISION);\n    _checkValueTooLarge(step, PRECISION);\n\n    bytes32 data = fundingMiscData;\n    data = data.insertUint(ratio, OPEN_RATIO_OFFSET, 30);\n    fundingMiscData = data.insertUint(step, OPEN_RATIO_STEP_OFFSET, 60);\n\n    emit UpdateOpenRatio(ratio, step);\n  }\n\n  /// @dev Internal function to get the value of close ratio, multiplied by 1e9.\n  function _getCloseFeeRatio() internal view returns (uint256) {\n    return fundingMiscData.decodeUint(CLOSE_FEE_RATIO_OFFSET, 30);\n  }\n\n  /// @dev Internal function to update the fee ratio for closing position.\n  /// @param newRatio The close fee ratio value, multiplied by 1e9.\n  function _updateCloseFeeRatio(uint256 newRatio) internal {\n    _checkValueTooLarge(newRatio, FEE_PRECISION);\n\n    bytes32 data = fundingMiscData;\n    uint256 oldRatio = data.decodeUint(CLOSE_FEE_RATIO_OFFSET, 30);\n    fundingMiscData = data.insertUint(newRatio, CLOSE_FEE_RATIO_OFFSET, 30);\n\n    emit UpdateCloseFeeRatio(oldRatio, newRatio);\n  }\n\n  /// @dev Internal function to get the value of funding ratio, multiplied by 1e9.\n  function _getFundingRatio() internal view returns (uint256) {\n    return fundingMiscData.decodeUint(FUNDING_RATIO_OFFSET, 32);\n  }\n\n  /// @dev Internal function to update the funding ratio.\n  /// @param newRatio The funding ratio value, multiplied by 1e9.\n  function _updateFundingRatio(uint256 newRatio) internal {\n    _checkValueTooLarge(newRatio, MAX_FUNDING_RATIO);\n\n    bytes32 data = fundingMiscData;\n    uint256 oldRatio = data.decodeUint(FUNDING_RATIO_OFFSET, 32);\n    fundingMiscData = data.insertUint(newRatio, FUNDING_RATIO_OFFSET, 32);\n\n    emit UpdateFundingRatio(oldRatio, newRatio);\n  }\n\n  /// @dev Internal function to return interest rate snapshot.\n  /// @param snapshot The previous borrow index snapshot.\n  /// @return newBorrowIndex The current borrow index, multiplied by 1e27.\n  /// @return rate The annual interest rate, multiplied by 1e18.\n  function _getAverageInterestRate(\n    BorrowRateSnapshot memory snapshot\n  ) internal view returns (uint256 newBorrowIndex, uint256 rate) {\n    uint256 prevBorrowIndex = snapshot.borrowIndex;\n    newBorrowIndex = IAaveV3Pool(lendingPool).getReserveNormalizedVariableDebt(baseAsset);\n    // absolute rate change is (new - prev) / prev\n    // annual interest rate is (new - prev) / prev / duration * 365 days\n    uint256 duration = block.timestamp - snapshot.timestamp;\n    if (duration < MIN_SNAPSHOT_DELAY) {\n      rate = snapshot.lastInterestRate;\n    } else {\n      rate = ((newBorrowIndex - prevBorrowIndex) * 365 days * PRECISION) / (prevBorrowIndex * duration);\n      if (rate == 0) rate = snapshot.lastInterestRate;\n    }\n  }\n\n  /// @dev Internal function to update interest rate snapshot.\n  function _updateInterestRate(uint256 newBorrowIndex, uint256 lastInterestRate) internal {\n    BorrowRateSnapshot memory snapshot = borrowRateSnapshot;\n    // don't update snapshot when the duration is too small.\n    if (snapshot.timestamp > 0 && block.timestamp - snapshot.timestamp < MIN_SNAPSHOT_DELAY) return;\n\n    snapshot.borrowIndex = uint128(newBorrowIndex);\n    snapshot.lastInterestRate = uint80(lastInterestRate);\n    snapshot.timestamp = uint48(block.timestamp);\n    borrowRateSnapshot = snapshot;\n\n    emit SnapshotAaveBorrowIndex(newBorrowIndex, block.timestamp);\n  }\n\n  /// @inheritdoc BasePool\n  function _updateCollAndDebtIndex() internal virtual override returns (uint256 newCollIndex, uint256 newDebtIndex) {\n    (newDebtIndex, newCollIndex) = _getDebtAndCollateralIndex();\n\n    BorrowRateSnapshot memory snapshot = borrowRateSnapshot;\n    uint256 duration = block.timestamp - snapshot.timestamp;\n    if (duration > 0) {\n      (uint256 borrowIndex, uint256 interestRate) = _getAverageInterestRate(snapshot);\n      if (IPegKeeper(pegKeeper).isFundingEnabled()) {\n        (, uint256 totalColls) = _getDebtAndCollateralShares();\n        uint256 totalRawColls = _convertToRawColl(totalColls, newCollIndex, Math.Rounding.Down);\n        uint256 funding = (totalRawColls * interestRate * duration) / (365 days * PRECISION);\n        funding = ((funding * _getFundingRatio()) / FEE_PRECISION);\n\n        // update collateral index with funding costs\n        newCollIndex = (newCollIndex * totalRawColls) / (totalRawColls - funding);\n        _updateCollateralIndex(newCollIndex);\n      }\n\n      // update interest snapshot\n      _updateInterestRate(borrowIndex, interestRate);\n    }\n  }\n\n  /// @inheritdoc BasePool\n  function _deductProtocolFees(int256 rawColl) internal view virtual override returns (uint256) {\n    if (rawColl > 0) {\n      // open position or add collateral\n      uint256 feeRatio = getOpenFeeRatio();\n      if (feeRatio > FEE_PRECISION) feeRatio = FEE_PRECISION;\n      return (uint256(rawColl) * feeRatio) / FEE_PRECISION;\n    } else {\n      // close position or remove collateral\n      return (uint256(-rawColl) * _getCloseFeeRatio()) / FEE_PRECISION;\n    }\n  }\n}\n"},{"file_path":"contracts/core/PoolManager.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\n\nimport { IFxUSDRegeneracy } from \"../interfaces/IFxUSDRegeneracy.sol\";\nimport { IPool } from \"../interfaces/IPool.sol\";\nimport { IPoolManager } from \"../interfaces/IPoolManager.sol\";\nimport { IReservePool } from \"../interfaces/IReservePool.sol\";\nimport { IRewardSplitter } from \"../interfaces/IRewardSplitter.sol\";\nimport { IFxUSDBasePool } from \"../interfaces/IFxUSDBasePool.sol\";\nimport { IRateProvider } from \"../rate-provider/interfaces/IRateProvider.sol\";\n\nimport { WordCodec } from \"../common/codec/WordCodec.sol\";\nimport { AssetManagement } from \"../fund/AssetManagement.sol\";\nimport { FlashLoans } from \"./FlashLoans.sol\";\nimport { ProtocolFees } from \"./ProtocolFees.sol\";\n\ncontract PoolManager is ProtocolFees, FlashLoans, AssetManagement, IPoolManager {\n  using EnumerableSet for EnumerableSet.AddressSet;\n  using SafeERC20 for IERC20;\n  using WordCodec for bytes32;\n\n  /**********\n   * Errors *\n   **********/\n\n  error ErrorCollateralExceedCapacity();\n\n  error ErrorDebtExceedCapacity();\n\n  error ErrorPoolNotRegistered();\n\n  error ErrorInvalidPool();\n\n  error ErrorCallerNotFxUSDSave();\n\n  error ErrorRedeemExceedBalance();\n\n  error ErrorInsufficientRedeemedCollateral();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The precision for token rate.\n  uint256 internal constant PRECISION = 1e18;\n\n  /// @dev The precision for token rate.\n  int256 internal constant PRECISION_I256 = 1e18;\n\n  bytes32 private constant OPERATOR_ROLE = keccak256(\"OPERATOR_ROLE\");\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @inheritdoc IPoolManager\n  address public immutable fxUSD;\n\n  /// @inheritdoc IPoolManager\n  address public immutable fxBASE;\n\n  /// @inheritdoc IPoolManager\n  address public immutable pegKeeper;\n\n  /***********\n   * Structs *\n   ***********/\n\n  /// @dev The struct for pool information.\n  /// @param collateralData The data for collateral.\n  ///   ```text\n  ///   * Field                     Bits    Index       Comments\n  ///   * collateral capacity       85      0           The maximum allowed amount of collateral tokens.\n  ///   * collateral balance        85      85          The amount of collateral tokens deposited.\n  ///   * raw collateral balance    86      170         The amount of raw collateral tokens (without token rate) managed in pool.\n  ///   ```\n  /// @param debtData The data for debt.\n  ///   ```text\n  ///   * Field             Bits    Index       Comments\n  ///   * debt capacity     96      0           The maximum allowed amount of debt tokens.\n  ///   * debt balance      96      96          The amount of debt tokens borrowed.\n  ///   * reserved          64      192         Reserved data.\n  ///   ```\n  struct PoolStruct {\n    bytes32 collateralData;\n    bytes32 debtData;\n  }\n\n  /// @dev The struct for token rate information.\n  /// @param scalar The token scalar to reach 18 decimals.\n  /// @param rateProvider The address of token rate provider.\n  struct TokenRate {\n    uint96 scalar;\n    address rateProvider;\n  }\n\n  /// @dev Memory variables for liquidate or rebalance.\n  /// @param stablePrice The USD price of stable token (with scalar).\n  /// @param scalingFactor The scaling factor for collateral token.\n  /// @param collateralToken The address of collateral token.\n  /// @param rawColls The amount of raw collateral tokens liquidated or rebalanced, including bonus.\n  /// @param bonusRawColls The amount of raw collateral tokens used as bonus.\n  /// @param rawDebts The amount of raw debt tokens liquidated or rebalanced.\n  struct LiquidateOrRebalanceMemoryVar {\n    uint256 stablePrice;\n    uint256 scalingFactor;\n    address collateralToken;\n    uint256 rawColls;\n    uint256 bonusRawColls;\n    uint256 rawDebts;\n  }\n\n  /*********************\n   * Storage Variables *\n   *********************/\n\n  /// @dev The list of registered pools.\n  EnumerableSet.AddressSet private pools;\n\n  /// @notice Mapping to pool address to pool struct.\n  mapping(address => PoolStruct) private poolInfo;\n\n  /// @notice Mapping from pool address to rewards splitter.\n  mapping(address => address) public rewardSplitter;\n\n  /// @notice Mapping from token address to token rate struct.\n  mapping(address => TokenRate) public tokenRates;\n\n  /// @notice The threshold for permissioned liquidate or rebalance.\n  uint256 public permissionedLiquidationThreshold;\n\n  /*************\n   * Modifiers *\n   *************/\n\n  modifier onlyRegisteredPool(address pool) {\n    if (!pools.contains(pool)) revert ErrorPoolNotRegistered();\n    _;\n  }\n\n  modifier onlyFxUSDSave() {\n    if (_msgSender() != fxBASE) {\n      // allow permissonless rebalance or liquidate when insufficient fxUSD/USDC in fxBASE.\n      uint256 totalYieldToken = IFxUSDBasePool(fxBASE).totalYieldToken();\n      uint256 totalStableToken = IFxUSDBasePool(fxBASE).totalStableToken();\n      uint256 price = IFxUSDBasePool(fxBASE).getStableTokenPriceWithScale();\n      if (totalYieldToken + (totalStableToken * price) / PRECISION >= permissionedLiquidationThreshold) {\n        revert ErrorCallerNotFxUSDSave();\n      }\n    }\n    _;\n  }\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _fxUSD, address _fxBASE, address _pegKeeper) {\n    fxUSD = _fxUSD;\n    fxBASE = _fxBASE;\n    pegKeeper = _pegKeeper;\n  }\n\n  function initialize(\n    address admin,\n    uint256 _expenseRatio,\n    uint256 _harvesterRatio,\n    uint256 _flashLoanFeeRatio,\n    address _treasury,\n    address _revenuePool,\n    address _reservePool\n  ) external initializer {\n    __Context_init();\n    __AccessControl_init();\n    __ERC165_init();\n\n    _grantRole(DEFAULT_ADMIN_ROLE, admin);\n\n    __ProtocolFees_init(_expenseRatio, _harvesterRatio, _flashLoanFeeRatio, _treasury, _revenuePool, _reservePool);\n    __FlashLoans_init();\n\n    // default 10000 fxUSD\n    _updateThreshold(10000 ether);\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the pool information.\n  /// @param pool The address of pool to query.\n  /// @return collateralCapacity The maximum allowed amount of collateral tokens.\n  /// @return collateralBalance The amount of collateral tokens deposited.\n  /// @return debtCapacity The maximum allowed amount of debt tokens.\n  /// @return debtBalance The amount of debt tokens borrowed.\n  function getPoolInfo(\n    address pool\n  )\n    external\n    view\n    returns (uint256 collateralCapacity, uint256 collateralBalance, uint256 debtCapacity, uint256 debtBalance)\n  {\n    bytes32 data = poolInfo[pool].collateralData;\n    collateralCapacity = data.decodeUint(0, 85);\n    collateralBalance = data.decodeUint(85, 85);\n    data = poolInfo[pool].debtData;\n    debtCapacity = data.decodeUint(0, 96);\n    debtBalance = data.decodeUint(96, 96);\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc IPoolManager\n  function operate(\n    address pool,\n    uint256 positionId,\n    int256 newColl,\n    int256 newDebt\n  ) external onlyRegisteredPool(pool) onlyRole(OPERATOR_ROLE) nonReentrant returns (uint256) {\n    address collateralToken = IPool(pool).collateralToken();\n    uint256 scalingFactor = _getTokenScalingFactor(collateralToken);\n\n    int256 newRawColl = newColl;\n    if (newRawColl != type(int256).min) {\n      newRawColl = _scaleUp(newRawColl, scalingFactor);\n    }\n\n    uint256 rawProtocolFees;\n    // the `newRawColl` is the result without `protocolFees`\n    (positionId, newRawColl, newDebt, rawProtocolFees) = IPool(pool).operate(\n      positionId,\n      newRawColl,\n      newDebt,\n      _msgSender()\n    );\n\n    newColl = _scaleDown(newRawColl, scalingFactor);\n    uint256 protocolFees = _scaleDown(rawProtocolFees, scalingFactor);\n    _accumulatePoolFee(pool, protocolFees);\n    _changePoolDebts(pool, newDebt);\n    if (newRawColl > 0) {\n      _changePoolCollateral(pool, newColl, newRawColl);\n      IERC20(collateralToken).safeTransferFrom(_msgSender(), address(this), uint256(newColl) + protocolFees);\n    } else if (newRawColl < 0) {\n      _changePoolCollateral(pool, newColl - int256(protocolFees), newRawColl - int256(rawProtocolFees));\n      IERC20(collateralToken).safeTransfer(_msgSender(), uint256(-newColl));\n    }\n\n    if (newDebt > 0) {\n      IFxUSDRegeneracy(fxUSD).mint(_msgSender(), uint256(newDebt));\n    } else if (newDebt < 0) {\n      IFxUSDRegeneracy(fxUSD).burn(_msgSender(), uint256(-newDebt));\n    }\n\n    emit Operate(pool, positionId, newColl, newDebt, protocolFees);\n\n    return positionId;\n  }\n\n  /// @inheritdoc IPoolManager\n  function redeem(\n    address pool,\n    uint256 debts,\n    uint256 minColls\n  ) external onlyRegisteredPool(pool) nonReentrant returns (uint256 colls) {\n    if (debts > IERC20(fxUSD).balanceOf(_msgSender())) {\n      revert ErrorRedeemExceedBalance();\n    }\n\n    uint256 rawColls = IPool(pool).redeem(debts);\n\n    address collateralToken = IPool(pool).collateralToken();\n    uint256 scalingFactor = _getTokenScalingFactor(collateralToken);\n    colls = _scaleDown(rawColls, scalingFactor);\n\n    _changePoolCollateral(pool, -int256(colls), -int256(rawColls));\n    _changePoolDebts(pool, -int256(debts));\n\n    uint256 protocolFees = (colls * getRedeemFeeRatio()) / FEE_PRECISION;\n    _accumulatePoolFee(pool, protocolFees);\n    colls -= protocolFees;\n    if (colls < minColls) revert ErrorInsufficientRedeemedCollateral();\n\n    IERC20(collateralToken).safeTransfer(_msgSender(), colls);\n    IFxUSDRegeneracy(fxUSD).burn(_msgSender(), debts);\n\n    emit Redeem(pool, colls, debts, protocolFees);\n  }\n\n  /// @inheritdoc IPoolManager\n  function rebalance(\n    address pool,\n    address receiver,\n    int16 tick,\n    uint256 maxFxUSD,\n    uint256 maxStable\n  )\n    external\n    onlyRegisteredPool(pool)\n    nonReentrant\n    onlyFxUSDSave\n    returns (uint256 colls, uint256 fxUSDUsed, uint256 stableUsed)\n  {\n    LiquidateOrRebalanceMemoryVar memory op = _beforeRebalanceOrLiquidate(pool);\n    IPool.RebalanceResult memory result = IPool(pool).rebalance(tick, maxFxUSD + _scaleUp(maxStable, op.stablePrice));\n    op.rawColls = result.rawColls + result.bonusRawColls;\n    op.bonusRawColls = result.bonusRawColls;\n    op.rawDebts = result.rawDebts;\n    (colls, fxUSDUsed, stableUsed) = _afterRebalanceOrLiquidate(pool, maxFxUSD, op, receiver);\n\n    emit RebalanceTick(pool, tick, colls, fxUSDUsed, stableUsed);\n  }\n\n  /// @inheritdoc IPoolManager\n  function rebalance(\n    address pool,\n    address receiver,\n    uint32 position,\n    uint256 maxFxUSD,\n    uint256 maxStable\n  )\n    external\n    onlyRegisteredPool(pool)\n    nonReentrant\n    onlyFxUSDSave\n    returns (uint256 colls, uint256 fxUSDUsed, uint256 stableUsed)\n  {\n    LiquidateOrRebalanceMemoryVar memory op = _beforeRebalanceOrLiquidate(pool);\n    IPool.RebalanceResult memory result = IPool(pool).rebalance(\n      position,\n      maxFxUSD + _scaleUp(maxStable, op.stablePrice)\n    );\n    op.rawColls = result.rawColls + result.bonusRawColls;\n    op.bonusRawColls = result.bonusRawColls;\n    op.rawDebts = result.rawDebts;\n    (colls, fxUSDUsed, stableUsed) = _afterRebalanceOrLiquidate(pool, maxFxUSD, op, receiver);\n\n    emit RebalancePosition(pool, position, colls, fxUSDUsed, stableUsed);\n  }\n\n  /// @inheritdoc IPoolManager\n  function liquidate(\n    address pool,\n    address receiver,\n    uint32 position,\n    uint256 maxFxUSD,\n    uint256 maxStable\n  )\n    external\n    onlyRegisteredPool(pool)\n    nonReentrant\n    onlyFxUSDSave\n    returns (uint256 colls, uint256 fxUSDUsed, uint256 stableUsed)\n  {\n    LiquidateOrRebalanceMemoryVar memory op = _beforeRebalanceOrLiquidate(pool);\n    {\n      IPool.LiquidateResult memory result;\n      uint256 reservedRawColls = IReservePool(reservePool).getBalance(op.collateralToken);\n      reservedRawColls = _scaleUp(reservedRawColls, op.scalingFactor);\n      result = IPool(pool).liquidate(position, maxFxUSD + _scaleUp(maxStable, op.stablePrice), reservedRawColls);\n      op.rawColls = result.rawColls + result.bonusRawColls;\n      op.bonusRawColls = result.bonusRawColls;\n      op.rawDebts = result.rawDebts;\n\n      // take bonus from reserve pool\n      uint256 bonusFromReserve = result.bonusFromReserve;\n      if (bonusFromReserve > 0) {\n        bonusFromReserve = _scaleDown(result.bonusFromReserve, op.scalingFactor);\n        IReservePool(reservePool).requestBonus(IPool(pool).collateralToken(), address(this), bonusFromReserve);\n\n        // increase pool reserve first\n        _changePoolCollateral(pool, int256(bonusFromReserve), int256(result.bonusFromReserve));\n      }\n    }\n\n    (colls, fxUSDUsed, stableUsed) = _afterRebalanceOrLiquidate(pool, maxFxUSD, op, receiver);\n\n    emit LiquidatePosition(pool, position, colls, fxUSDUsed, stableUsed);\n  }\n\n  /// @inheritdoc IPoolManager\n  function harvest(\n    address pool\n  ) external onlyRegisteredPool(pool) nonReentrant returns (uint256 amountRewards, uint256 amountFunding) {\n    address collateralToken = IPool(pool).collateralToken();\n    uint256 scalingFactor = _getTokenScalingFactor(collateralToken);\n\n    uint256 collateralRecorded;\n    uint256 rawCollateralRecorded;\n    {\n      bytes32 data = poolInfo[pool].collateralData;\n      collateralRecorded = data.decodeUint(85, 85);\n      rawCollateralRecorded = data.decodeUint(170, 86);\n    }\n    uint256 performanceFee;\n    uint256 harvestBounty;\n    uint256 pendingRewards;\n    // compute funding\n    uint256 rawCollateral = IPool(pool).getTotalRawCollaterals();\n    if (rawCollateralRecorded > rawCollateral) {\n      unchecked {\n        amountFunding = _scaleDown(rawCollateralRecorded - rawCollateral, scalingFactor);\n        _changePoolCollateral(pool, -int256(amountFunding), -int256(rawCollateralRecorded - rawCollateral));\n\n        performanceFee = (getFundingExpenseRatio() * amountFunding) / FEE_PRECISION;\n        harvestBounty = (getHarvesterRatio() * amountFunding) / FEE_PRECISION;\n        pendingRewards = amountFunding - harvestBounty - performanceFee;\n      }\n    }\n    // compute rewards\n    rawCollateral = _scaleUp(collateralRecorded, scalingFactor);\n    if (rawCollateral > rawCollateralRecorded) {\n      unchecked {\n        amountRewards = _scaleDown(rawCollateral - rawCollateralRecorded, scalingFactor);\n        _changePoolCollateral(pool, -int256(amountRewards), -int256(rawCollateral - rawCollateralRecorded));\n\n        uint256 performanceFeeRewards = (getRewardsExpenseRatio() * amountRewards) / FEE_PRECISION;\n        uint256 harvestBountyRewards = (getHarvesterRatio() * amountRewards) / FEE_PRECISION;\n        pendingRewards += amountRewards - harvestBountyRewards - performanceFeeRewards;\n        performanceFee += performanceFeeRewards;\n        harvestBounty += harvestBountyRewards;\n      }\n    }\n\n    // transfer performance fee to treasury\n    if (performanceFee > 0) {\n      IERC20(collateralToken).safeTransfer(treasury, performanceFee);\n    }\n    // transfer various fees to revenue pool\n    _takeAccumulatedPoolFee(pool);\n    // transfer harvest bounty\n    if (harvestBounty > 0) {\n      IERC20(collateralToken).safeTransfer(_msgSender(), harvestBounty);\n    }\n    // transfer rewards for fxBASE\n    if (pendingRewards > 0) {\n      address splitter = rewardSplitter[pool];\n      IERC20(collateralToken).safeTransfer(splitter, pendingRewards);\n      IRewardSplitter(splitter).split(collateralToken);\n    }\n\n    emit Harvest(_msgSender(), pool, amountRewards, amountFunding, performanceFee, harvestBounty);\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Register a new pool with reward splitter.\n  /// @param pool The address of pool.\n  /// @param splitter The address of reward splitter.\n  function registerPool(\n    address pool,\n    address splitter,\n    uint96 collateralCapacity,\n    uint96 debtCapacity\n  ) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    if (fxUSD != IPool(pool).fxUSD()) revert ErrorInvalidPool();\n\n    if (pools.add(pool)) {\n      emit RegisterPool(pool);\n\n      _updateRewardSplitter(pool, splitter);\n      _updatePoolCapacity(pool, collateralCapacity, debtCapacity);\n    }\n  }\n\n  /// @notice Update rate provider for the given token.\n  /// @param token The address of the token.\n  /// @param provider The address of corresponding rate provider.\n  function updateRateProvider(address token, address provider) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    uint256 scale = 10 ** (18 - IERC20Metadata(token).decimals());\n    tokenRates[token] = TokenRate(uint96(scale), provider);\n\n    emit UpdateTokenRate(token, scale, provider);\n  }\n\n  /// @notice Update the address of reward splitter for the given pool.\n  /// @param pool The address of the pool.\n  /// @param newSplitter The address of reward splitter.\n  function updateRewardSplitter(\n    address pool,\n    address newSplitter\n  ) external onlyRole(DEFAULT_ADMIN_ROLE) onlyRegisteredPool(pool) {\n    _updateRewardSplitter(pool, newSplitter);\n  }\n\n  /// @notice Update the pool capacity.\n  /// @param pool The address of fx pool.\n  /// @param collateralCapacity The capacity for collateral token.\n  /// @param debtCapacity The capacity for debt token.\n  function updatePoolCapacity(\n    address pool,\n    uint96 collateralCapacity,\n    uint96 debtCapacity\n  ) external onlyRole(DEFAULT_ADMIN_ROLE) onlyRegisteredPool(pool) {\n    _updatePoolCapacity(pool, collateralCapacity, debtCapacity);\n  }\n\n  /// @notice Update threshold for permissionless liquidation.\n  /// @param newThreshold The value of new threshold.\n  function updateThreshold(uint256 newThreshold) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateThreshold(newThreshold);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to update the address of reward splitter for the given pool.\n  /// @param pool The address of the pool.\n  /// @param newSplitter The address of reward splitter.\n  function _updateRewardSplitter(address pool, address newSplitter) internal {\n    address oldSplitter = rewardSplitter[pool];\n    rewardSplitter[pool] = newSplitter;\n\n    emit UpdateRewardSplitter(pool, oldSplitter, newSplitter);\n  }\n\n  /// @dev Internal function to update the pool capacity.\n  /// @param pool The address of fx pool.\n  /// @param collateralCapacity The capacity for collateral token.\n  /// @param debtCapacity The capacity for debt token.\n  function _updatePoolCapacity(address pool, uint96 collateralCapacity, uint96 debtCapacity) internal {\n    poolInfo[pool].collateralData = poolInfo[pool].collateralData.insertUint(collateralCapacity, 0, 96);\n    poolInfo[pool].debtData = poolInfo[pool].debtData.insertUint(debtCapacity, 0, 96);\n\n    emit UpdatePoolCapacity(pool, collateralCapacity, debtCapacity);\n  }\n\n  /// @dev Internal function to update threshold for permissionless liquidation.\n  /// @param newThreshold The value of new threshold.\n  function _updateThreshold(uint256 newThreshold) internal {\n    uint256 oldThreshold = permissionedLiquidationThreshold;\n    permissionedLiquidationThreshold = newThreshold;\n\n    emit UpdatePermissionedLiquidationThreshold(oldThreshold, newThreshold);\n  }\n\n  /// @dev Internal function to scaler up for `uint256`.\n  function _scaleUp(uint256 value, uint256 scale) internal pure returns (uint256) {\n    return (value * scale) / PRECISION;\n  }\n\n  /// @dev Internal function to scaler up for `int256`.\n  function _scaleUp(int256 value, uint256 scale) internal pure returns (int256) {\n    return (value * int256(scale)) / PRECISION_I256;\n  }\n\n  /// @dev Internal function to scaler down for `uint256`, rounding down.\n  function _scaleDown(uint256 value, uint256 scale) internal pure returns (uint256) {\n    return (value * PRECISION) / scale;\n  }\n\n  /// @dev Internal function to scaler down for `uint256`, rounding up.\n  function _scaleDownRoundingUp(uint256 value, uint256 scale) internal pure returns (uint256) {\n    return (value * PRECISION + scale - 1) / scale;\n  }\n\n  /// @dev Internal function to scaler down for `int256`.\n  function _scaleDown(int256 value, uint256 scale) internal pure returns (int256) {\n    return (value * PRECISION_I256) / int256(scale);\n  }\n\n  /// @dev Internal function to prepare variables before rebalance or liquidate.\n  /// @param pool The address of pool to liquidate or rebalance.\n  function _beforeRebalanceOrLiquidate(address pool) internal view returns (LiquidateOrRebalanceMemoryVar memory op) {\n    op.stablePrice = IFxUSDBasePool(fxBASE).getStableTokenPriceWithScale();\n    op.collateralToken = IPool(pool).collateralToken();\n    op.scalingFactor = _getTokenScalingFactor(op.collateralToken);\n  }\n\n  /// @dev Internal function to do actions after rebalance or liquidate.\n  /// @param pool The address of pool to liquidate or rebalance.\n  /// @param maxFxUSD The maximum amount of fxUSD can be used.\n  /// @param op The memory helper variable.\n  /// @param receiver The address collateral token receiver.\n  /// @return colls The actual amount of collateral token rebalanced or liquidated.\n  /// @return fxUSDUsed The amount of fxUSD used.\n  /// @return stableUsed The amount of stable token (a.k.a USDC) used.\n  function _afterRebalanceOrLiquidate(\n    address pool,\n    uint256 maxFxUSD,\n    LiquidateOrRebalanceMemoryVar memory op,\n    address receiver\n  ) internal returns (uint256 colls, uint256 fxUSDUsed, uint256 stableUsed) {\n    colls = _scaleDown(op.rawColls, op.scalingFactor);\n    _changePoolCollateral(pool, -int256(colls), -int256(op.rawColls));\n    _changePoolDebts(pool, -int256(op.rawDebts));\n\n    // burn fxUSD or transfer USDC\n    fxUSDUsed = op.rawDebts;\n    if (fxUSDUsed > maxFxUSD) {\n      // rounding up here\n      stableUsed = _scaleDownRoundingUp(fxUSDUsed - maxFxUSD, op.stablePrice);\n      fxUSDUsed = maxFxUSD;\n    }\n    if (fxUSDUsed > 0) {\n      IFxUSDRegeneracy(fxUSD).burn(_msgSender(), fxUSDUsed);\n    }\n    if (stableUsed > 0) {\n      IERC20(IFxUSDBasePool(fxBASE).stableToken()).safeTransferFrom(_msgSender(), fxUSD, stableUsed);\n      IFxUSDRegeneracy(fxUSD).onRebalanceWithStable(stableUsed, op.rawDebts - maxFxUSD);\n    }\n\n    // transfer collateral\n    uint256 protocolRevenue = (_scaleDown(op.bonusRawColls, op.scalingFactor) * getLiquidationExpenseRatio()) /\n      FEE_PRECISION;\n    _accumulatePoolFee(pool, protocolRevenue);\n    unchecked {\n      colls -= protocolRevenue;\n    }\n    IERC20(op.collateralToken).safeTransfer(receiver, colls);\n  }\n\n  /// @dev Internal function to update collateral balance.\n  function _changePoolCollateral(address pool, int256 delta, int256 rawDelta) internal {\n    bytes32 data = poolInfo[pool].collateralData;\n    uint256 capacity = data.decodeUint(0, 85);\n    uint256 balance = uint256(int256(data.decodeUint(85, 85)) + delta);\n    if (balance > capacity) revert ErrorCollateralExceedCapacity();\n    data = data.insertUint(balance, 85, 85);\n    balance = uint256(int256(data.decodeUint(170, 86)) + rawDelta);\n    poolInfo[pool].collateralData = data.insertUint(balance, 170, 86);\n  }\n\n  /// @dev Internal function to update debt balance.\n  function _changePoolDebts(address pool, int256 delta) internal {\n    bytes32 data = poolInfo[pool].debtData;\n    uint256 capacity = data.decodeUint(0, 96);\n    uint256 balance = uint256(int256(data.decodeUint(96, 96)) + delta);\n    if (balance > capacity) revert ErrorDebtExceedCapacity();\n    poolInfo[pool].debtData = data.insertUint(balance, 96, 96);\n  }\n\n  /// @dev Internal function to get token scaling factor.\n  function _getTokenScalingFactor(address token) internal view returns (uint256 value) {\n    TokenRate memory rate = tokenRates[token];\n    value = rate.scalar;\n    unchecked {\n      if (rate.rateProvider != address(0)) {\n        value *= IRateProvider(rate.rateProvider).getRate();\n      } else {\n        value *= PRECISION;\n      }\n    }\n  }\n}\n"},{"file_path":"contracts/mocks/MockCurveStableSwapNG.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\ncontract MockCurveStableSwapNG {\n    mapping(uint256 => address) public coins;\n\n    mapping(uint256 => uint256) public price_oracle;\n\n    function setCoin(uint256 index, address token) external {\n        coins[index] = token;\n    }\n\n    function setPriceOracle(uint256 index, uint256 value) external {\n        price_oracle[index] = value;\n    }\n}"},{"file_path":"@openzeppelin/contracts-upgradeable-v4/utils/math/SignedMathUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard signed math utilities missing in the Solidity language.\n */\nlibrary SignedMathUpgradeable {\n    /**\n     * @dev Returns the largest of two signed numbers.\n     */\n    function max(int256 a, int256 b) internal pure returns (int256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two signed numbers.\n     */\n    function min(int256 a, int256 b) internal pure returns (int256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two signed numbers without overflow.\n     * The result is rounded towards zero.\n     */\n    function average(int256 a, int256 b) internal pure returns (int256) {\n        // Formula from the book \"Hacker's Delight\"\n        int256 x = (a & b) + ((a ^ b) >> 1);\n        return x + (int256(uint256(x) >> 255) & (a ^ b));\n    }\n\n    /**\n     * @dev Returns the absolute unsigned value of a signed value.\n     */\n    function abs(int256 n) internal pure returns (uint256) {\n        unchecked {\n            // must be unchecked in order to support `n = type(int256).min`\n            return uint256(n >= 0 ? n : -n);\n        }\n    }\n}\n"},{"file_path":"contracts/price-oracle/interfaces/IPriceOracle.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IPriceOracle {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when the value of maximum price deviation is updated.\n  /// @param oldValue The value of the previous maximum price deviation.\n  /// @param newValue The value of the current maximum price deviation.\n  event UpdateMaxPriceDeviation(uint256 oldValue, uint256 newValue);\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the oracle price with 18 decimal places.\n  /// @return anchorPrice The anchor price for this asset, multiplied by 1e18. It should be hard to manipulate,\n  ///         like time-weighted average price or chainlink spot price.\n  /// @return minPrice The minimum oracle price among all available price sources (including twap), multiplied by 1e18.\n  /// @return maxPrice The maximum oracle price among all available price sources (including twap), multiplied by 1e18.\n  function getPrice() external view returns (uint256 anchorPrice, uint256 minPrice, uint256 maxPrice);\n}\n"},{"file_path":"contracts/interfaces/Balancer/IFlashLoanRecipient.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IFlashLoanRecipient {\n  /**\n   * @dev When `flashLoan` is called on the Vault, it invokes the `receiveFlashLoan` hook on the recipient.\n   *\n   * At the time of the call, the Vault will have transferred `amounts` for `tokens` to the recipient. Before this\n   * call returns, the recipient must have transferred `amounts` plus `feeAmounts` for each token back to the\n   * Vault, or else the entire flash loan will revert.\n   *\n   * `userData` is the same value passed in the `IVault.flashLoan` call.\n   */\n  function receiveFlashLoan(\n    address[] memory tokens,\n    uint256[] memory amounts,\n    uint256[] memory feeAmounts,\n    bytes memory userData\n  ) external;\n}\n"},{"file_path":"contracts/v2/interfaces/IFxRebalancePoolRegistry.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IFxRebalancePoolRegistry {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when a new rebalance pool is added.\n  /// @param pool The address of the rebalance pool.\n  event RegisterPool(address indexed pool);\n\n  /// @notice Emitted when an exsited rebalance pool is removed.\n  /// @param pool The address of the rebalance pool.\n  event DeregisterPool(address indexed pool);\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the address list of all registered RebalancePool.\n  function getPools() external view returns (address[] memory pools);\n\n  /// @notice Return the total amount of asset managed by all registered RebalancePool.\n  function totalSupply() external view returns (uint256);\n}\n"},{"file_path":"@openzeppelin/contracts-v4/interfaces/draft-IERC1822.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\n * proxy whose upgrades are fully controlled by the current implementation.\n */\ninterface IERC1822Proxiable {\n    /**\n     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\n     * address.\n     *\n     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\n     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\n     * function revert if invoked through a proxy.\n     */\n    function proxiableUUID() external view returns (bytes32);\n}\n"},{"file_path":"contracts/common/rewards/distributor/LinearReward.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\n// solhint-disable not-rely-on-time\n\nlibrary LinearReward {\n  using SafeCast for uint256;\n\n  /// @dev Compiler will pack this into single `uint256`.\n  /// Usually, we assume the amount of rewards won't exceed `uint96.max`.\n  /// In such case, the rate won't exceed `uint80.max`, since `periodLength` is at least `86400`.\n  /// Also `uint40.max` is enough for timestamp, which is about 30000 years.\n  struct RewardData {\n    // The amount of rewards pending to distribute.\n    uint96 queued;\n    // The current reward rate per second.\n    uint80 rate;\n    // The last timestamp when the reward is distributed.\n    uint40 lastUpdate;\n    // The timestamp when this period will finish.\n    uint40 finishAt;\n  }\n\n  /// @dev Add new rewards to current one. It is possible that the rewards will not distribute immediately.\n  /// The rewards will be only distributed when current period is end or the current increase or\n  /// decrease no more than 10%.\n  ///\n  /// @param _data The struct of reward data, will be modified inplace.\n  /// @param _periodLength The length of a period, caller should make sure it is at least `86400`.\n  /// @param _amount The amount of new rewards to distribute.\n  function increase(\n    RewardData memory _data,\n    uint256 _periodLength,\n    uint256 _amount\n  ) internal view {\n    _amount = _amount + _data.queued;\n    _data.queued = 0;\n\n    if (block.timestamp >= _data.finishAt) {\n      // period finished, distribute to next period\n      _data.rate = (_amount / _periodLength).toUint80();\n      _data.queued = uint96(_amount - (_data.rate * _periodLength)); // keep rounding error\n      _data.lastUpdate = uint40(block.timestamp);\n      _data.finishAt = uint40(block.timestamp + _periodLength);\n    } else {\n      uint256 _elapsed = block.timestamp - (_data.finishAt - _periodLength);\n      uint256 _distributed = uint256(_data.rate) * _elapsed;\n      if (_distributed * 9 <= _amount * 10) {\n        // APR increase or drop no more than 10%, distribute\n        _amount = _amount + uint256(_data.rate) * (_data.finishAt - _data.lastUpdate);\n        _data.rate = (_amount / _periodLength).toUint80();\n        _data.queued = uint96(_amount - (_data.rate * _periodLength)); // keep rounding error\n        _data.lastUpdate = uint40(block.timestamp);\n        _data.finishAt = uint40(block.timestamp + _periodLength);\n        _data.lastUpdate = uint40(block.timestamp);\n      } else {\n        // APR drop more than 10%, wait for more rewards\n        _data.queued = _amount.toUint96();\n      }\n    }\n  }\n\n  /// @dev Return the amount of pending distributed rewards in current period.\n  ///\n  /// @param _data The struct of reward data.\n  function pending(RewardData memory _data) internal view returns (uint256, uint256) {\n    uint256 _elapsed;\n    uint256 _left;\n    if (block.timestamp > _data.finishAt) {\n      // finishAt >= lastUpdate will happen, if `_notifyReward` is not called during current period.\n      _elapsed = _data.finishAt >= _data.lastUpdate ? _data.finishAt - _data.lastUpdate : 0;\n    } else {\n      unchecked {\n        _elapsed = block.timestamp - _data.lastUpdate;\n        _left = uint256(_data.finishAt) - block.timestamp;\n      }\n    }\n\n    return (uint256(_data.rate) * _elapsed, uint256(_data.rate) * _left);\n  }\n}\n"},{"file_path":"contracts/common/EIP2535/facets/DiamondCutFacet.sol","source_code":"// SPDX-License-Identifier: CC0-1.0\npragma solidity ^0.8.0;\n\n/******************************************************************************\\\n* Author: Nick Mudge <nick@perfectabstractions.com>, Twitter/Github: @mudgen\n* EIP-2535 Diamonds\n/******************************************************************************/\n\nimport { IDiamondCut } from \"../interfaces/IDiamondCut.sol\";\nimport { LibDiamond } from \"../libraries/LibDiamond.sol\";\n\n// Remember to add the loupe functions from DiamondLoupeFacet to the diamond.\n// The loupe functions are required by the EIP2535 Diamonds standard\n\ncontract DiamondCutFacet is IDiamondCut {\n  /// @notice Add/replace/remove any number of functions and optionally execute\n  ///         a function with delegatecall\n  /// @param _diamondCut Contains the facet addresses and function selectors\n  /// @param _init The address of the contract or facet to execute _calldata\n  /// @param _calldata A function call, including function selector and arguments\n  ///                  _calldata is executed with delegatecall on _init\n  function diamondCut(\n    FacetCut[] calldata _diamondCut,\n    address _init,\n    bytes calldata _calldata\n  ) external override {\n    LibDiamond.enforceIsContractOwner();\n    LibDiamond.diamondCut(_diamondCut, _init, _calldata);\n  }\n}\n"},{"file_path":"@openzeppelin/contracts/utils/introspection/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"address","name":"_logic","type":"address"},{"internalType":"address","name":"admin_","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"stateMutability":"payable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"stateMutability":"payable","type":"fallback"},{"stateMutability":"payable","type":"receive"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":"000000000000000000000000387568e1ea4ff4d003b8147739db69d87325e206000000000000000000000000d41d29fc53fe5ce9f0fb2328e54d35a2a03a324b00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000"}