creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@openzeppelin/contracts/access/Ownable.sol": {
        "content": "// 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"
      },
      "@openzeppelin/contracts/security/ReentrancyGuard.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\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 ReentrancyGuard {\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    constructor() {\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"
      },
      "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (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 */\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    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"
      },
      "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
        "content": "// 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 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 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"
      },
      "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
        "content": "// 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 \"../IERC20.sol\";\nimport \"../extensions/IERC20Permit.sol\";\nimport \"../../../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 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.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(IERC20 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(IERC20 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(IERC20 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(IERC20 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(IERC20 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        IERC20Permit 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(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, \"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(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\n            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Address.sol": {
        "content": "// 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"
      },
      "@openzeppelin/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (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"
      },
      "contracts/interfaces/IAdapter.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.19;\n\ninterface IAdapter {\n    function initialize(\n        address _wrapper,\n        address _vault,\n        address _admin\n    ) external;\n\n    function wrapper() external returns(address);\n\n    function vault() external returns(address);\n\n    function token0() external returns(address);\n\n    function token1() external returns(address);\n\n    function lpToken() external returns(address);\n\n    function PROTOCOL() external returns(string memory);\n\n    function VERSION() external returns(uint8);\n\n    function PRECISION() external returns(uint256);\n\n    function totalSupply() external view returns(uint256);\n\n    function tokenPerShare() external view returns(uint256 _token0PerShare, uint256 _token1PerShare);\n\n    function pool() external view returns(address);\n\n    function deposit(\n        uint256 _amount0,\n        uint256 _amount1,\n        address _user,\n        bytes calldata _data\n    ) external returns(uint256 _share);\n\n    function withdraw(\n        uint256 _share,\n        address _user,\n        bytes calldata _data\n    ) external returns(uint256 _amount0, uint256 _amount1);\n}"
      },
      "contracts/interfaces/IFarmBooster.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.19;\n\ninterface IFarmBooster {\n    function updatePositionBoostMultiplier(address user) external returns (uint256 _multiplier);\n}"
      },
      "contracts/wrappers/ALMWrapper.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.10;\npragma abicoder v2;\n\nimport {Ownable} from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport {ReentrancyGuard} from \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\n\nimport {IERC20Metadata} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport \"../interfaces/IAdapter.sol\";\n\n// need to call FarmBooster\nimport \"../interfaces/IFarmBooster.sol\";\n\ncontract ALMWrapper is Ownable, ReentrancyGuard {\n    using SafeERC20 for IERC20Metadata;\n    using SafeERC20 for IERC20;\n\n    // The address of the wrapper factory\n    address public immutable WRAPPER_FACTORY;\n\n    // Whether it is initialized\n    bool public isInitialized;\n\n    // Accrued token per share\n    uint256 public accTokenPerShare;\n\n    // The timestamp when reward token mining starts\n    uint256 public startTimestamp;\n\n    // The timestamp when reward token mining ends\n    uint256 public endTimestamp;\n\n    // The timestamp of the last reward token update\n    uint256 public lastRewardTimestamp;\n\n    // reward tokens created per second\n    uint256 public rewardPerSecond;\n\n    // The precision factor\n    uint256 public PRECISION_FACTOR;\n\n    // The staked token\n    IERC20Metadata public stakedToken;\n\n    // The reward token\n    IERC20Metadata public rewardToken;\n\n    // The adapter address\n    address payable public adapterAddr;\n\n    // The contract handles the share boosts.\n    address public boostContract;\n\n    // The total boosted share\n    uint256 public totalBoostedShare;\n\n    // Basic boost factor, none boosted user's boost factor\n    uint256 public constant BOOST_PRECISION = 100 * 1e10;\n    // Hard limit for maximum boost factor, it must greater than BOOST_PRECISION\n    uint256 public constant MAX_BOOST_PRECISION = 300 * 1e10;\n\n    // Info of each user that stakes tokens (stakedToken)\n    mapping(address => UserInfo) public userInfo;\n\n    struct UserInfo {\n        uint256 amount; // How many staked tokens the user has provided\n        uint256 rewardDebt;\n        uint256 boostMultiplier; // currently active multiplier\n        uint256 boostedAmount; // combined boosted amount\n        uint256 unsettledRewards; // rewards haven't been transferred to users but already accounted in rewardDebt\n    }\n\n    event Deposit(address indexed user, uint256 amount);\n    event EmergencyWithdraw(address indexed user, uint256 amount);\n    event NewStartAndEndTimestamp(uint256 oldStartTimestamp, uint256 newStartTimestamp, uint256 oldEndTimestamp, uint256 newEndTimestamp, uint256 rewardPerSecond);\n    event Restart(uint256 startTimestamp, uint256 endTimestamp, uint256 rewardPerSecond);\n    event NewRewardPerSecond(uint256 oldRewardPerSecond, uint256 newRewardPerSecond, uint256 startTimestamp, uint256 endTimestamp);\n    event NewPoolLimit(uint256 poolLimitPerUser);\n    event RewardsStop(uint256 blockNumber);\n    event TokenRecovery(address indexed token, uint256 amount);\n    event Withdraw(address indexed user, uint256 amount);\n    event DepositAndExpend(address indexed user, uint256 amount, uint256 endTimestamp);\n    event MintThenDeposit(address indexed user, uint256 amount, uint256 amount0, uint256 amount1);\n    event WithdrawThenBurn(address indexed user, uint256 amount, uint256 amount0, uint256 amount1);\n    event AdapterUpdated(address indexed user, address indexed newAdapterAddr);\n    event BoostContractUpdated(address indexed boostContract);\n    event BoostMultiplierUpdated(address indexed user, uint256 oldMultiplier, uint256 newMultiplier);\n\n\n    /**\n     * @notice Constructor\n     */\n    constructor() {\n        WRAPPER_FACTORY = msg.sender;\n    }\n\n    /**\n     * @dev Throws if caller is not the boost contract.\n     */\n    modifier onlyBoostContract() {\n        require(boostContract == msg.sender, \"Ownable: caller is not the boost contract\");\n        _;\n    }\n\n    /*\n     * @notice Initialize the contract\n     * @param _stakedToken: staked token address\n     * @param _rewardToken: reward token address\n     * @param _rewardPerSecond: reward per second (in rewardToken)\n     * @param _startTimestamp: start timestamp\n     * @param _endTimestamp: end timestamp\n     * @param _admin: admin address with ownership\n     */\n    function initialize(\n        IERC20Metadata _stakedToken,\n        IERC20Metadata _rewardToken,\n        uint256 _rewardPerSecond,\n        uint256 _startTimestamp,\n        uint256 _endTimestamp,\n        address _admin,\n\t    address _boostContract\n    ) external {\n        require(!isInitialized, \"Already initialized\");\n        require(msg.sender == WRAPPER_FACTORY, \"Not factory\");\n        require(_startTimestamp < _endTimestamp, \"New startTimestamp must be lower than new endTimestamp\");\n        require(block.timestamp < _startTimestamp, \"New startTimestamp must be higher than current timestamp\");\n\n        // Make this contract initialized\n        isInitialized = true;\n\n        stakedToken = _stakedToken;\n        rewardToken = _rewardToken;\n        rewardPerSecond = _rewardPerSecond;\n        startTimestamp = _startTimestamp;\n        endTimestamp = _endTimestamp;\n\t    boostContract = _boostContract;\n\n        uint256 decimalsRewardToken = uint256(rewardToken.decimals());\n        require(decimalsRewardToken < 30, \"Must be inferior to 30\");\n\n        PRECISION_FACTOR = uint256(10**(uint256(30) - decimalsRewardToken));\n        require(PRECISION_FACTOR * rewardPerSecond / (10**decimalsRewardToken) >= 100_000_000, \"rewardPerSecond must be larger\");\n\n        // Set the lastRewardBlock as the startTimestamp\n        lastRewardTimestamp = startTimestamp;\n\n        // Transfer ownership to the admin address who becomes owner of the contract\n        transferOwnership(_admin);\n    }\n\n    /*\n     * @notice Deposit staked tokens and collect reward tokens (if any)\n     * @param _amount: amount to deposit (in stakeToken)\n     * @param _noHarvest: flag for harvest or not\n     */\n    function deposit(uint256 _amount, bool _noHarvest) external nonReentrant {\n        UserInfo storage user = userInfo[msg.sender];\n\n        // always update pool to be safe\n        _updatePool();\n\n        if (user.amount > 0) {\n            // get user unaccounted pending rewards and add to unsettledRewards\n            user.unsettledRewards += _pendingReward(msg.sender);\n\n            // transfer the rewards and clear `unsettledRewards`\n            if (!_noHarvest && user.unsettledRewards > 0) {\n                // SafeTransfer CAKE\n                rewardToken.safeTransfer(msg.sender, user.unsettledRewards);\n\n                // reset accumulative value\n                user.unsettledRewards = 0;\n            }\n        }\n\n        if (_amount > 0) {\n            // get true deposit amount (safe tax/rebase token)\n            uint256 _amountBefore = IERC20Metadata(stakedToken).balanceOf(address(this));\n            stakedToken.safeTransferFrom(msg.sender, address(this), _amount);\n            uint256 _amountAfter = IERC20Metadata(stakedToken).balanceOf(address(this));\n            _amount = _amountAfter - _amountBefore;\n\n            // update user.amount\n            user.amount = user.amount + _amount;\n        }\n\n        // update multiplier\n        _updateBoostMultiplier(msg.sender, 0);\n\n        // update debt\n        user.rewardDebt = (user.boostedAmount * accTokenPerShare) / PRECISION_FACTOR;\n\n        emit Deposit(msg.sender, _amount);\n    }\n\n    /*\n     * @notice Deposit reward tokens and expand end timestamp\n     * @param _amount: amount to deposit (in stakeToken)\n     */\n    function depositRewardAndExpend(uint256 _amount) external nonReentrant {\n        require(block.timestamp < endTimestamp, \"Pool should not ended\");\n\n        uint256 _rewardAmountBefore = IERC20Metadata(rewardToken).balanceOf(address(this));\n        IERC20Metadata(rewardToken).safeTransferFrom(msg.sender, address(this), _amount);\n        uint256 _rewardAmountAfter = IERC20Metadata(rewardToken).balanceOf(address(this));\n        uint256 _rewardAmount = _rewardAmountAfter - _rewardAmountBefore;\n\n        uint256 newEndTimestamp = endTimestamp + _rewardAmount / rewardPerSecond;\n\n        require(endTimestamp < newEndTimestamp, \"New endTimestamp must be larger than old endTimestamp\");\n\n        endTimestamp = newEndTimestamp;\n\n        emit DepositAndExpend(msg.sender, _rewardAmount, endTimestamp);\n    }\n\n    /*\n     * @notice Mint then deposit staked tokens and collect reward tokens (if any)\n     * @param _amount0: token0 amount to deposit (in token0)\n     * @param _amount1: token0 amount to deposit (in token1)\n     * @param _noHarvest: flag for harvest or not\n     * @param _data: payload data from FE side\n     */\n    function mintThenDeposit(uint256 _amount0, uint _amount1, bool _noHarvest, bytes calldata _data) external nonReentrant {\n        require(adapterAddr != address(0), \"Adapter address should not be empty\");\n\n        UserInfo storage user = userInfo[msg.sender];\n\n        // always update pool to be safe\n        _updatePool();\n\n        if (user.amount > 0) {\n            // get user unaccounted pending rewards and add to unsettledRewards\n            user.unsettledRewards += _pendingReward(msg.sender);\n\n            if (!_noHarvest && user.unsettledRewards > 0) {\n                // transfer the rewards and clear `unsettledRewards`\n                rewardToken.safeTransfer(msg.sender, user.unsettledRewards);\n\n                // reset accumulative value\n                user.unsettledRewards = 0;\n            }\n        }\n\n        if (_amount0 > 0) {\n            address token0 = IAdapter(adapterAddr).token0();\n            IERC20(token0).safeTransferFrom(msg.sender, address(this), _amount0);\n            IERC20(token0).forceApprove(adapterAddr, _amount0);\n        }\n\n        if (_amount1 > 0) {\n            address token1 = IAdapter(adapterAddr).token1();\n            IERC20(token1).safeTransferFrom(msg.sender, address(this), _amount1);\n            IERC20(token1).forceApprove(adapterAddr, _amount1);\n        }\n\n        // call adapter\n        uint256 _amountBefore = IERC20Metadata(stakedToken).balanceOf(address(this));\n        IAdapter(adapterAddr).deposit(_amount0, _amount1, msg.sender, _data);\n        uint256 _amountAfter = IERC20Metadata(stakedToken).balanceOf(address(this));\n        uint256 _amount = _amountAfter - _amountBefore;\n\n        if (_amount > 0) {\n            user.amount = user.amount + _amount;\n        }\n\n        // update multiplier\n        _updateBoostMultiplier(msg.sender, 0);\n\n        // update debt\n        user.rewardDebt = (user.boostedAmount * accTokenPerShare) / PRECISION_FACTOR;\n\n        emit MintThenDeposit(msg.sender, _amount, _amount0, _amount1);\n    }\n\n    /*\n     * @notice Withdraw staked tokens and collect reward tokens\n     * @param _amount: amount to withdraw (in rewardToken)\n     * @param _noHarvest: flag for harvest or not\n     */\n    function withdraw(uint256 _amount, bool _noHarvest) external nonReentrant {\n        UserInfo storage user = userInfo[msg.sender];\n        require(user.amount >= _amount, \"Amount to withdraw too high\");\n\n        // always update pool to be safe\n        _updatePool();\n\n        // get user unaccounted pending rewards and add to unsettledRewards\n        user.unsettledRewards += _pendingReward(msg.sender);\n\n        if (_amount > 0) {\n            user.amount = user.amount - _amount;\n            stakedToken.safeTransfer(msg.sender, _amount);\n        }\n\n        // transfer the rewards and clear `unsettledRewards`\n        if (!_noHarvest && user.unsettledRewards > 0) {\n            // SafeTransfer CAKE\n            rewardToken.safeTransfer(msg.sender, user.unsettledRewards);\n\n            // reset accumulative value\n            user.unsettledRewards = 0;\n        }\n\n        // update multiplier\n        _updateBoostMultiplier(msg.sender, 0);\n\n        // update debt\n        user.rewardDebt = (user.boostedAmount * accTokenPerShare) / PRECISION_FACTOR;\n\n        emit Withdraw(msg.sender, _amount);\n    }\n\n    /*\n     * @notice Withdraw then burn staked tokens and collect reward tokens\n     * @param _amount: amount to withdraw (in rewardToken)\n     * @param _noHarvest: flag for harvest or not\n     * @param _data: payload data from FE side\n     */\n    function withdrawThenBurn(uint256 _amount, bool _noHarvest, bytes calldata _data) external nonReentrant {\n        require(adapterAddr != address(0), \"Adapter address should not be empty\");\n\n        UserInfo storage user = userInfo[msg.sender];\n        require(user.amount >= _amount, \"Amount to withdraw too high\");\n\n        // always update pool to be safe\n        _updatePool();\n\n        // get user unaccounted pending rewards and add to unsettledRewards\n        user.unsettledRewards += _pendingReward(msg.sender);\n\n        uint256 _amount0;\n        uint256 _amount1;\n\n        if (_amount > 0) {\n            user.amount = user.amount - _amount;\n\n            IERC20(stakedToken).forceApprove(adapterAddr, _amount);\n\n            // call adapter\n            (_amount0, _amount1) = IAdapter(adapterAddr).withdraw(_amount, msg.sender, _data);\n        }\n\n        if (!_noHarvest && user.unsettledRewards > 0) {\n            // SafeTransfer CAKE\n            rewardToken.safeTransfer(msg.sender, user.unsettledRewards);\n\n            // reset accumulative value\n            user.unsettledRewards = 0;\n        }\n\n        // update multiplier\n        _updateBoostMultiplier(msg.sender, 0);\n\n        // update debt\n        user.rewardDebt = (user.boostedAmount * accTokenPerShare) / PRECISION_FACTOR;\n\n        emit WithdrawThenBurn(msg.sender, _amount, _amount0, _amount1);\n    }\n\n    /*\n     * @notice Withdraw staked tokens without caring about rewards rewards\n     * @dev Needs to be for emergency.\n     */\n    function emergencyWithdraw() external nonReentrant {\n        UserInfo storage user = userInfo[msg.sender];\n        uint256 amountToTransfer = user.amount;\n\n        // remove boosted amount from total share first\n        totalBoostedShare = totalBoostedShare > user.boostedAmount ? totalBoostedShare - user.boostedAmount : 0;\n\n        // reset everything\n        user.amount = 0;\n        user.boostMultiplier = BOOST_PRECISION;\n        user.boostedAmount = 0;\n        user.rewardDebt = 0;\n        // reset accumulative value\n        user.unsettledRewards = 0;\n\n        if (amountToTransfer > 0) {\n            stakedToken.safeTransfer(msg.sender, amountToTransfer);\n        }\n\n        emit EmergencyWithdraw(msg.sender, amountToTransfer);\n    }\n\n    /*\n     * @notice Stop rewards\n     * @dev Only callable by owner. Needs to be for emergency.\n     */\n    function emergencyRewardWithdraw(uint256 _amount) external onlyOwner {\n        rewardToken.safeTransfer(msg.sender, _amount);\n    }\n\n    /**\n    * @notice Allows the owner to recover tokens sent to the contract by mistake\n     * @param _token: token address\n     * @dev Callable by owner\n     */\n    function recoverToken(address _token) external onlyOwner {\n        require(_token != address(stakedToken), \"Operations: Cannot recover staked token\");\n        require(_token != address(rewardToken), \"Operations: Cannot recover reward token\");\n\n        uint256 balance = IERC20Metadata(_token).balanceOf(address(this));\n        require(balance != 0, \"Operations: Cannot recover zero balance\");\n\n        IERC20Metadata(_token).safeTransfer(msg.sender, balance);\n\n        emit TokenRecovery(_token, balance);\n    }\n\n    /*\n     * @notice Stop rewards\n     * @dev Only callable by owner\n     */\n    function stopReward() external onlyOwner {\n        endTimestamp = block.timestamp;\n        emit RewardsStop(endTimestamp);\n    }\n\n    /*\n     * @notice Update reward per block, if campaign is ended, admin can call restart and update rewardPerSecond there\n     * @dev Only callable by owner.\n     * @param _rewardPerSecond: the reward per second\n     */\n    function updateRewardPerSecond(uint256 _rewardPerSecond) external onlyOwner {\n        require(block.timestamp < endTimestamp, \"Pool should not ended\");\n        uint256 decimalsRewardToken = uint256(rewardToken.decimals());\n        require(PRECISION_FACTOR * _rewardPerSecond / (10**decimalsRewardToken) >= 100_000_000, \"rewardPerSecond must be larger\");\n\n        _updatePool();\n\n        emit NewRewardPerSecond(rewardPerSecond, _rewardPerSecond, startTimestamp, endTimestamp);\n\n        rewardPerSecond = _rewardPerSecond;\n    }\n\n    /**\n     * @notice It allows the admin to update start and end blocks\n     * @dev This function is only callable by owner.\n     * @param _startTimestamp: the new start timestamp\n     * @param _endTimestamp: the new end timestamp\n     */\n    function updateStartAndEndTimestamp(uint256 _startTimestamp, uint256 _endTimestamp) external onlyOwner {\n        require(block.timestamp < startTimestamp, \"Pool has started\");\n        require(_startTimestamp < _endTimestamp, \"New startTimestamp must be lower than new endTimestamp\");\n        require(block.timestamp < _startTimestamp, \"New startTimestamp must be higher than current timestamp\");\n\n        emit NewStartAndEndTimestamp(startTimestamp, _startTimestamp, endTimestamp, _endTimestamp, rewardPerSecond);\n\n        startTimestamp = _startTimestamp;\n        endTimestamp = _endTimestamp;\n\n        // Set the lastRewardTimestamp as the startTimestamp\n        lastRewardTimestamp = startTimestamp;\n    }\n\n    /**\n     * @notice It allows the admin to update adapter address\n     * @dev This function is only callable by owner.\n     * @param _adapterAddr: the address of new adapter\n     */\n    function updateAdapterAddress(address _adapterAddr) external onlyOwner {\n        require(_adapterAddr != address(0), \"Adapter address should not be empty\");\n        adapterAddr = payable(_adapterAddr);\n        emit AdapterUpdated(msg.sender, _adapterAddr);\n    }\n\n    /// @notice Update boost contract address and max boost factor.\n    /// @param _newBoostContract The new address for handling all the share boosts.\n    function updateBoostContract(address _newBoostContract) external onlyOwner {\n        require(\n            _newBoostContract != address(0) && _newBoostContract != boostContract,\n            \"New boost contract address must be valid\"\n        );\n\n        boostContract = _newBoostContract;\n        emit BoostContractUpdated(_newBoostContract);\n    }\n\n    /// @notice Update user boost factor from boost contract.\n    /// @param _userAddress The user address for boost factor updates.\n    function updateBoostMultiplierByUser(\n        address _userAddress\n    ) external nonReentrant {\n        UserInfo storage user = userInfo[_userAddress];\n\n        // always update pool to be safe\n        _updatePool();\n\n        if (user.amount > 0) {\n            // get user unaccounted pending rewards and add to unsettledRewards\n            user.unsettledRewards += _pendingReward(_userAddress);\n        }\n\n        // update multiplier based on the latest user.amount\n        _updateBoostMultiplier(_userAddress, 0);\n\n        // update debt\n        user.rewardDebt = (user.boostedAmount * accTokenPerShare) / PRECISION_FACTOR;\n    }\n\n    /// @notice Update user boost factor from boost contract.\n    /// @param _userAddress The user address for boost factor updates.\n    /// @param _newMultiplier The multiplier update to user.\n    function updateBoostMultiplier(\n        address _userAddress,\n        uint256 _newMultiplier\n    ) external onlyBoostContract nonReentrant {\n        UserInfo storage user = userInfo[_userAddress];\n\n        // always update pool to be safe\n        _updatePool();\n\n        if (user.amount > 0) {\n            // get user unaccounted pending rewards and add to unsettledRewards\n            user.unsettledRewards += _pendingReward(_userAddress);\n        }\n\n        // update multiplier based on the latest user.amount\n        _updateBoostMultiplier(_userAddress, _newMultiplier);\n\n        // update debt\n        user.rewardDebt = (user.boostedAmount * accTokenPerShare) / PRECISION_FACTOR;\n    }\n\n    /**\n     * @notice It allows the admin to restart\n     * @dev This function is only callable by owner.\n     * @param _startTimestamp: the new start timestamp\n     * @param _endTimestamp: the new end timestamp\n     * @param _rewardPerSecond: the new rewardPerSecond\n     */\n    function restart(uint256 _startTimestamp, uint256 _endTimestamp, uint256 _rewardPerSecond) external onlyOwner {\n        require(block.timestamp > endTimestamp, \"Pool should be ended\");\n        require(block.timestamp <= _startTimestamp, \"New startTimestamp must be higher than current timestamp\");\n        require(_startTimestamp < _endTimestamp, \"New startTimestamp must be lower than new endTimestamp\");\n\n        // always update pool to be safe\n        _updatePool();\n\n        startTimestamp = _startTimestamp;\n        endTimestamp = _endTimestamp;\n        rewardPerSecond = _rewardPerSecond;\n\n        // Set the lastRewardTimestamp as the startTimestamp\n        lastRewardTimestamp = _startTimestamp;\n\n        emit Restart(_startTimestamp, _endTimestamp, _rewardPerSecond);\n    }\n\n    /*\n     * @notice View function to see total pending reward, including accounted but unsettled \n     * @param _userAddress: user address\n     * @return Pending + Unsettled reward for a given user\n     */\n    function pendingReward(address _userAddress) external view returns (uint256) {\n        UserInfo memory user = userInfo[_userAddress];\n        return user.unsettledRewards + _pendingReward(_userAddress);\n    }\n    \n    /*\n     * @notice View function to see pending reward based on accTokenPerShare&rewardDebt calculation\n     * @param _userAddress: user address\n     * @return Pending reward for a given user\n     */\n    function _pendingReward(address _userAddress) internal view returns (uint256) {\n        UserInfo storage user = userInfo[_userAddress];\n\n        if (block.timestamp > lastRewardTimestamp && totalBoostedShare != 0) {\n            uint256 multiplier = _getMultiplier(lastRewardTimestamp, block.timestamp);\n            uint256 cakeReward = multiplier * rewardPerSecond;\n            uint256 adjustedTokenPerShare = accTokenPerShare + (cakeReward * PRECISION_FACTOR) / totalBoostedShare;\n            return (user.boostedAmount * adjustedTokenPerShare) / PRECISION_FACTOR - user.rewardDebt;\n        } else {\n            return (user.boostedAmount * accTokenPerShare) / PRECISION_FACTOR - user.rewardDebt;\n        }\n    }\n\n    /*\n     * @notice Update reward variables of the given pool to be up-to-date.\n     */\n    function _updatePool() internal {\n        if (block.timestamp <= lastRewardTimestamp) {\n            return;\n        }\n\n        if (totalBoostedShare == 0) {\n            lastRewardTimestamp = block.timestamp;\n            return;\n        }\n\n        uint256 multiplier = _getMultiplier(lastRewardTimestamp, block.timestamp);\n        uint256 cakeReward = multiplier * rewardPerSecond;\n        accTokenPerShare = accTokenPerShare + (cakeReward * PRECISION_FACTOR) / totalBoostedShare;\n        lastRewardTimestamp = block.timestamp;\n    }\n\n    /*\n     * @notice Return reward multiplier over the given _from to _to block.\n     * @param _from: block to start\n     * @param _to: block to finish\n     */\n    function _getMultiplier(uint256 _from, uint256 _to) internal view returns (uint256) {\n        if (_to <= endTimestamp) {\n            return _to - _from;\n        } else if (_from >= endTimestamp) {\n            return 0;\n        } else {\n            return endTimestamp - _from;\n        }\n    }\n\n    /// @notice Update user boost factor.\n    /// @param _userAddress The user address for boost factor updates.\n    /// @param _newMultiplier The multiplier update to user.\n    function _updateBoostMultiplier(\n        address _userAddress,\n        uint256 _newMultiplier\n    ) internal {\n        require(_userAddress != address(0), \"The user address must be valid\");\n\n        UserInfo storage user = userInfo[_userAddress];\n\n        if (_newMultiplier == 0) {\n            _newMultiplier = BOOST_PRECISION;\n\n            if (address(boostContract) != address(0)) {\n                _newMultiplier = IFarmBooster(boostContract).updatePositionBoostMultiplier(_userAddress);\n            }\n        }\n\n        // filter the invalid value\n        if (_newMultiplier < BOOST_PRECISION) {\n            _newMultiplier = BOOST_PRECISION;\n        }\n        if (_newMultiplier > MAX_BOOST_PRECISION) {\n            _newMultiplier = MAX_BOOST_PRECISION;\n        }\n\n        // get current multiplier\n        uint256 _oldMultiplier = user.boostMultiplier;\n        uint256 _oldBoostedAmount = user.boostedAmount;\n\n        // set new multiplier and calculate user's boosted shares\n        user.boostMultiplier = _newMultiplier;\n        user.boostedAmount = user.amount * _newMultiplier / BOOST_PRECISION;\n\n        // add user's new boosted shares to total\n        totalBoostedShare = totalBoostedShare + user.boostedAmount - _oldBoostedAmount;\n        \n        emit BoostMultiplierUpdated(_userAddress, _oldMultiplier, _newMultiplier);\n    }\n\n}\n"
      },
      "contracts/wrappers/ALMWrapperFactory.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.10;\npragma abicoder v2;\n\nimport {Ownable} from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport {IERC20Metadata} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\nimport \"./ALMWrapper.sol\";\n\ncontract ALMWrapperFactory is Ownable {\n    event NewWrapperContract(address indexed wrapper, address indexed stakedToken, address indexed rewardToken, uint256 rewardPerSecond, uint256 startTimestamp, uint256 endTimestamp);\n\n    constructor() {\n        //\n    }\n\n    /*\n     * @notice Deploy the pool\n     * @param _stakedToken: staked token address\n     * @param _rewardToken: reward token address\n     * @param _rewardPerSecond: reward per second (in rewardToken)\n     * @param _startTimestamp: start block timestamp\n     * @param _endTimestamp: end block timestamp\n     * @param _admin: admin address with ownership\n     * @param _boostContract: boost contract address\n     * @return address of new smart chef contract\n     */\n    function deployPool(\n        IERC20Metadata _stakedToken,\n        IERC20Metadata _rewardToken,\n        uint256 _rewardPerSecond,\n        uint256 _startTimestamp,\n        uint256 _endTimestamp,\n        address _admin,\n        address _boostContract\n    ) external onlyOwner {\n        require(_stakedToken.totalSupply() >= 0);\n        require(_rewardToken.totalSupply() >= 0);\n        require(_stakedToken != _rewardToken, \"Tokens must be different\");\n\n        bytes memory bytecode = type(ALMWrapper).creationCode;\n        bytes32 salt = keccak256(abi.encodePacked(_stakedToken, _rewardToken, _startTimestamp));\n        address wrapperAddress;\n\n        assembly {\n            wrapperAddress := create2(0, add(bytecode, 32), mload(bytecode), salt)\n        }\n\n        ALMWrapper(wrapperAddress).initialize(\n            _stakedToken,\n            _rewardToken,\n            _rewardPerSecond,\n            _startTimestamp,\n            _endTimestamp,\n            _admin,\n            _boostContract\n        );\n\n        emit NewWrapperContract(\n            wrapperAddress,\n            address(_stakedToken),\n            address(_rewardToken),\n            _rewardPerSecond,\n            _startTimestamp,\n            _endTimestamp\n        );\n    }\n}"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 10
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}