{"file_path":"src/periphery/Accountant.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: GNU AGPLv3\npragma solidity >=0.8.18;\n\nimport {IVault} from \"@yearn-vaults/interfaces/IVault.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/// @title Accountant.\n/// @notice A simplified accountant that (1) hardcodes performance fee to 100% and (2) only takes fee if there's no loss.\n/// @dev Will charge fees and run health check on any reported\n///     gains or losses during a strategy's report.\ncontract Accountant {\n\n    using SafeERC20 for ERC20;\n\n    /// @notice An event emitted when a vault is added or removed.\n    event VaultChanged(address indexed vault, ChangeType change);\n\n    /// @notice An event emitted when the default fee configuration is updated.\n    event UpdateDefaultFeeConfig(Fee defaultFeeConfig);\n\n    /// @notice An event emitted when the future fee manager is set.\n    event SetFutureFeeManager(address indexed futureFeeManager);\n\n    /// @notice An event emitted when a new fee manager is accepted.\n    event NewFeeManager(address indexed feeManager);\n\n    /// @notice An event emitted when a new vault manager is set.\n    event UpdateVaultManager(address indexed newVaultManager);\n\n    /// @notice An event emitted when the fee recipient is updated.\n    event UpdateFeeRecipient(address indexed oldFeeRecipient, address indexed newFeeRecipient);\n\n    /// @notice An event emitted when a custom fee configuration is updated.\n    event UpdateCustomFeeConfig(address indexed vault, Fee custom_config);\n\n    /// @notice An event emitted when a custom fee configuration is removed.\n    event RemovedCustomFeeConfig(address indexed vault);\n\n    /// @notice An event emitted when the `maxLoss` parameter is updated.\n    event UpdateMaxLoss(uint256 maxLoss);\n\n    /// @notice An event emitted when rewards are distributed.\n    event DistributeRewards(address indexed token, uint256 rewards);\n\n    /// @notice Enum defining change types (added or removed).\n    enum ChangeType {\n        NULL,\n        ADDED,\n        REMOVED\n    }\n\n    /// @notice Struct representing fee details.\n    struct Fee {\n        uint16 maxGain; // Max percent gain a strategy can report.\n        uint16 maxLoss; // Max percent loss a strategy can report.\n        bool custom; // Flag to set for custom configs.\n    }\n\n    modifier onlyFeeManager() {\n        _checkFeeManager();\n        _;\n    }\n\n    modifier onlyVaultOrFeeManager() {\n        _checkVaultOrFeeManager();\n        _;\n    }\n\n    modifier onlyFeeManagerOrRecipient() {\n        _checkFeeManagerOrRecipient();\n        _;\n    }\n\n    modifier onlyAddedVaults() {\n        _checkVaultIsAdded();\n        _;\n    }\n\n    function _checkFeeManager() internal view virtual {\n        require(msg.sender == feeManager, \"!fee manager\");\n    }\n\n    function _checkVaultOrFeeManager() internal view virtual {\n        require(msg.sender == feeManager || msg.sender == vaultManager, \"!vault manager\");\n    }\n\n    function _checkFeeManagerOrRecipient() internal view virtual {\n        require(msg.sender == feeRecipient || msg.sender == feeManager, \"!recipient\");\n    }\n\n    function _checkVaultIsAdded() internal view virtual {\n        require(vaults[msg.sender], \"vault not added\");\n    }\n\n    /// @notice Constant defining the maximum basis points.\n    uint256 internal constant MAX_BPS = 10_000;\n\n    /// @notice The amount of max loss to use when redeeming from vaults.\n    uint256 public maxLoss;\n\n    /// @notice The address of the fee manager.\n    address public feeManager;\n\n    /// @notice The address of the fee recipient.\n    address public feeRecipient;\n\n    /// @notice An address that can add or remove vaults.\n    address public vaultManager;\n\n    /// @notice The address of the future fee manager.\n    address public futureFeeManager;\n\n    /// @notice The default fee configuration.\n    Fee public defaultConfig;\n\n    /// @notice Mapping to track added vaults.\n    mapping(address => bool) public vaults;\n\n    /// @notice Mapping vault => custom Fee config if any.\n    mapping(address => Fee) public customConfig;\n\n    /// @notice Mapping vault => strategy => flag for one time healthcheck skips.\n    mapping(address => mapping(address => bool)) skipHealthCheck;\n\n    constructor(address _feeManager, address _feeRecipient, uint16 defaultMaxGain, uint16 defaultMaxLoss) {\n        require(_feeManager != address(0), \"ZERO ADDRESS\");\n        require(_feeRecipient != address(0), \"ZERO ADDRESS\");\n\n        feeManager = _feeManager;\n        feeRecipient = _feeRecipient;\n\n        _updateDefaultConfig(defaultMaxGain, defaultMaxLoss);\n    }\n\n    /**\n     * @notice Called by a vault when a `strategy` is reporting.\n     * @dev The msg.sender must have been added to the `vaults` mapping.\n     * @param strategy Address of the strategy reporting.\n     * @param gain Amount of the gain if any.\n     * @param loss Amount of the loss if any.\n     * @return totalFees if any to charge.\n     * @return totalRefunds if any for the vault to pull.\n     */\n    function report(\n        address strategy,\n        uint256 gain,\n        uint256 loss\n    ) public virtual onlyAddedVaults returns (uint256 totalFees, uint256 /* totalRefunds */ ) {\n        // Declare the config to use as the custom.\n        Fee memory fee = customConfig[msg.sender];\n\n        // Check if there is a custom config to use.\n        if (!fee.custom) {\n            // Otherwise use the default.\n            fee = defaultConfig;\n        }\n\n        // Retrieve the strategy's params from the vault.\n        IVault vault = IVault(msg.sender);\n        IVault.StrategyParams memory strategyParams = vault.strategies(strategy);\n\n        // Only charge performance fees if there is a gain.\n        if (gain > 0) {\n            // If we are skipping the healthcheck this report\n            if (skipHealthCheck[msg.sender][strategy]) {\n                // Make sure it is reset for the next one.\n                skipHealthCheck[msg.sender][strategy] = false;\n\n                // Setting `maxGain` to 0 will disable the healthcheck on profits.\n            } else if (fee.maxGain > 0) {\n                require(gain <= (strategyParams.current_debt * (fee.maxGain)) / MAX_BPS, \"too much gain\");\n            }\n\n            // 100% performance fee\n            totalFees = gain;\n\n            // Only take fee if there's no loss.\n            uint256 supply = vault.totalSupply();\n            uint256 assets = vault.totalAssets();\n            if (assets < supply) {\n                uint256 needed = supply - assets;\n                totalFees = gain < needed ? 0 : gain - needed;\n            }\n        } else {\n            // If we are skipping the healthcheck this report\n            if (skipHealthCheck[msg.sender][strategy]) {\n                // Make sure it is reset for the next one.\n                skipHealthCheck[msg.sender][strategy] = false;\n\n                // Setting `maxLoss` to 10_000 will disable the healthcheck on losses.\n            } else if (fee.maxLoss < MAX_BPS) {\n                require(loss <= (strategyParams.current_debt * (fee.maxLoss)) / MAX_BPS, \"too much loss\");\n            }\n        }\n\n        return (totalFees, 0);\n    }\n\n    /**\n     * @notice Function to add a new vault for this accountant to charge fees for.\n     * @dev This is not used to set any of the fees for the specific vault or strategy. Each fee will be set separately.\n     * @param vault The address of a vault to allow to use this accountant.\n     */\n    function addVault(\n        address vault\n    ) external virtual onlyVaultOrFeeManager {\n        // Ensure the vault has not already been added.\n        require(!vaults[vault], \"already added\");\n\n        vaults[vault] = true;\n\n        emit VaultChanged(vault, ChangeType.ADDED);\n    }\n\n    /**\n     * @notice Function to remove a vault from this accountant's fee charging list.\n     * @param vault The address of the vault to be removed from this accountant.\n     */\n    function removeVault(\n        address vault\n    ) external virtual onlyVaultOrFeeManager {\n        // Ensure the vault has been previously added.\n        require(vaults[vault], \"not added\");\n\n        address asset = IVault(vault).asset();\n        // Remove any allowances left.\n        if (ERC20(asset).allowance(address(this), vault) != 0) {\n            // slither-disable-next-line reentrancy-no-eth\n            ERC20(asset).safeApprove(vault, 0);\n        }\n\n        vaults[vault] = false;\n\n        emit VaultChanged(vault, ChangeType.REMOVED);\n    }\n\n    /**\n     * @notice Function to update the default fee configuration used for\n     *     all strategies that don't have a custom config set.\n     * @param defaultMaxGain Default max percent gain a strategy can report.\n     * @param defaultMaxLoss Default max percent loss a strategy can report.\n     */\n    function updateDefaultConfig(uint16 defaultMaxGain, uint16 defaultMaxLoss) external virtual onlyFeeManager {\n        _updateDefaultConfig(defaultMaxGain, defaultMaxLoss);\n    }\n\n    /**\n     * @dev Updates the Accountant's default fee config.\n     *   Is used during deployment and during any future updates.\n     */\n    function _updateDefaultConfig(uint16 defaultMaxGain, uint16 defaultMaxLoss) internal virtual {\n        // Check for threshold and limit conditions.\n        require(defaultMaxLoss <= MAX_BPS, \"too high\");\n\n        // Update the default fee configuration.\n        defaultConfig = Fee({maxGain: defaultMaxGain, maxLoss: defaultMaxLoss, custom: false});\n\n        emit UpdateDefaultFeeConfig(defaultConfig);\n    }\n\n    /**\n     * @notice Function to set a custom fee configuration for a specific vault.\n     * @param vault The vault the strategy is hooked up to.\n     * @param customMaxGain Custom max percent gain a strategy can report.\n     * @param customMaxLoss Custom max percent loss a strategy can report.\n     */\n    function setCustomConfig(\n        address vault,\n        uint16 customMaxGain,\n        uint16 customMaxLoss\n    ) external virtual onlyFeeManager {\n        // Ensure the vault has been added.\n        require(vaults[vault], \"vault not added\");\n        // Check for threshold and limit conditions.\n        require(customMaxLoss <= MAX_BPS, \"too high\");\n\n        // Create the vault's custom config.\n        Fee memory _config = Fee({maxGain: customMaxGain, maxLoss: customMaxLoss, custom: true});\n\n        // Store the config.\n        customConfig[vault] = _config;\n\n        emit UpdateCustomFeeConfig(vault, _config);\n    }\n\n    /**\n     * @notice Function to remove a previously set custom fee configuration for a vault.\n     * @param vault The vault to remove custom setting for.\n     */\n    function removeCustomConfig(\n        address vault\n    ) external virtual onlyFeeManager {\n        // Ensure custom fees are set for the specified vault.\n        require(customConfig[vault].custom, \"No custom fees set\");\n\n        // Set all the vaults's custom fees to 0.\n        delete customConfig[vault];\n\n        // Emit relevant event.\n        emit RemovedCustomFeeConfig(vault);\n    }\n\n    /**\n     * @notice Turn off the health check for a specific `vault` `strategy` combo.\n     * @dev This will only last for one report and get automatically turned back on.\n     * @param vault Address of the vault.\n     * @param strategy Address of the strategy.\n     */\n    function turnOffHealthCheck(address vault, address strategy) external virtual onlyFeeManager {\n        // Ensure the vault has been added.\n        require(vaults[vault], \"vault not added\");\n\n        skipHealthCheck[vault][strategy] = true;\n    }\n\n    /**\n     * @notice Public getter to check for custom setting.\n     * @dev We use uint256 for the flag since its cheaper so this\n     *   will convert it to a bool for easy view functions.\n     *\n     * @param vault Address of the vault.\n     * @return If a custom fee config is set.\n     */\n    function useCustomConfig(\n        address vault\n    ) external view virtual returns (bool) {\n        return customConfig[vault].custom;\n    }\n\n    /**\n     * @notice Get the full config used for a specific `vault`.\n     * @param vault Address of the vault.\n     * @return fee The config that would be used during the report.\n     */\n    function getVaultConfig(\n        address vault\n    ) external view returns (Fee memory fee) {\n        fee = customConfig[vault];\n\n        // Check if there is a custom config to use.\n        if (!fee.custom) {\n            // Otherwise use the default.\n            fee = defaultConfig;\n        }\n    }\n\n    /**\n     * @notice Sets the `maxLoss` parameter to be used on redeems.\n     * @param _maxLoss The amount in basis points to set as the maximum loss.\n     */\n    function setMaxLoss(\n        uint256 _maxLoss\n    ) external virtual onlyFeeManager {\n        // Ensure that the provided `maxLoss` does not exceed 100% (in basis points).\n        require(_maxLoss <= MAX_BPS, \"higher than 100%\");\n\n        maxLoss = _maxLoss;\n\n        // Emit an event to signal the update of the `maxLoss` parameter.\n        emit UpdateMaxLoss(_maxLoss);\n    }\n\n    /**\n     * @notice Function to distribute all accumulated fees to the designated recipient.\n     * @param token The token to distribute.\n     */\n    function distribute(\n        address token\n    ) external virtual {\n        distribute(token, ERC20(token).balanceOf(address(this)));\n    }\n\n    /**\n     * @notice Function to distribute accumulated fees to the designated recipient.\n     * @param token The token to distribute.\n     * @param amount amount of token to distribute.\n     */\n    function distribute(address token, uint256 amount) public virtual onlyFeeManagerOrRecipient {\n        ERC20(token).safeTransfer(feeRecipient, amount);\n\n        emit DistributeRewards(token, amount);\n    }\n\n    /**\n     * @notice Function to set a future fee manager address.\n     * @param _futureFeeManager The address to set as the future fee manager.\n     */\n    function setFutureFeeManager(\n        address _futureFeeManager\n    ) external virtual onlyFeeManager {\n        // Ensure the futureFeeManager is not a zero address.\n        require(_futureFeeManager != address(0), \"ZERO ADDRESS\");\n        futureFeeManager = _futureFeeManager;\n\n        emit SetFutureFeeManager(_futureFeeManager);\n    }\n\n    /**\n     * @notice Function to accept the role change and become the new fee manager.\n     * @dev This function allows the future fee manager to accept the role change and become the new fee manager.\n     */\n    function acceptFeeManager() external virtual {\n        // Make sure the sender is the future fee manager.\n        require(msg.sender == futureFeeManager, \"not future fee manager\");\n        feeManager = futureFeeManager;\n        futureFeeManager = address(0);\n\n        emit NewFeeManager(msg.sender);\n    }\n\n    /**\n     * @notice Function to set a new vault manager.\n     * @param newVaultManager Address to add or remove vaults.\n     */\n    function setVaultManager(\n        address newVaultManager\n    ) external virtual onlyFeeManager {\n        vaultManager = newVaultManager;\n\n        emit UpdateVaultManager(newVaultManager);\n    }\n\n    /**\n     * @notice Function to set a new address to receive distributed rewards.\n     * @param newFeeRecipient Address to receive distributed fees.\n     */\n    function setFeeRecipient(\n        address newFeeRecipient\n    ) external virtual onlyFeeManager {\n        // Ensure the newFeeRecipient is not a zero address.\n        require(newFeeRecipient != address(0), \"ZERO ADDRESS\");\n        address oldRecipient = feeRecipient;\n        feeRecipient = newFeeRecipient;\n\n        emit UpdateFeeRecipient(oldRecipient, newFeeRecipient);\n    }\n\n}\n","deployed_bytecode":"0x608060405234801561000f575f80fd5b5060043610610156575f3560e01c80639b3b6955116100c1578063d0fb02031161007a578063d0fb0203146103b1578063de1eb9a3146103cf578063e0aacb20146103ff578063e74b981b1461041b578063f94c53c714610437578063fb9321081461044157610156565b80639b3b6955146102dd5780639e09ed5f146102f9578063a622ee7c14610319578063b543503e14610349578063c7c504b914610365578063ceb68c231461039557610156565b80635efbccdd116101135780635efbccdd1461020857806363453ae11461022457806367bee7e9146102405780637b5d7b651461025c5780638a4adf241461028e578063921f8a8f146102ac57610156565b8063015cf1501461015a57806324be662814610178578063256b5a021461019457806346904840146101b05780635783fe39146101ce5780635cece03a146101ec575b5f80fd5b61016261045d565b60405161016f91906123d4565b60405180910390f35b610192600480360381019061018d919061242d565b610482565b005b6101ae60048036038101906101a99190612482565b61050f565b005b6101b8610648565b6040516101c591906123d4565b60405180910390f35b6101d661066d565b6040516101e391906124bc565b60405180910390f35b610206600480360381019061020191906124d5565b610672565b005b610222600480360381019061021d919061254a565b610797565b005b61023e60048036038101906102399190612482565b610990565b005b61025a60048036038101906102559190612482565b610a14565b005b61027660048036038101906102719190612482565b610b68565b604051610285939291906125c3565b60405180910390f35b610296610bb4565b6040516102a391906123d4565b60405180910390f35b6102c660048036038101906102c191906125f8565b610bd9565b6040516102d4929190612648565b60405180910390f35b6102f760048036038101906102f29190612482565b6111db565b005b6103016112d7565b604051610310939291906125c3565b60405180910390f35b610333600480360381019061032e9190612482565b611314565b604051610340919061266f565b60405180910390f35b610363600480360381019061035e9190612482565b611331565b005b61037f600480360381019061037a9190612482565b6113bf565b60405161038c919061266f565b60405180910390f35b6103af60048036038101906103aa9190612482565b611414565b005b6103b9611668565b6040516103c691906123d4565b60405180910390f35b6103e960048036038101906103e49190612482565b61168d565b6040516103f691906126e6565b60405180910390f35b610419600480360381019061041491906126ff565b6117ab565b005b61043560048036038101906104309190612482565b6117c1565b005b61043f6118fa565b005b61045b6004803603810190610456919061273d565b611a6f565b005b60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61048a611b15565b6127108111156104cf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104c6906127d5565b60405180910390fd5b805f819055507f18182e268b61d2aada98f23ade23b0ea133d5b0b6712dbfa682dc6da29941c228160405161050491906124bc565b60405180910390a150565b610517611ba6565b60065f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16156105a1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105989061283d565b60405180910390fd5b600160065f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508073ffffffffffffffffffffffffffffffffffffffff167fce96c4db32686d3f0011df1abea0ab6c5794b848868dcbece79961fef7e8198d600160405161063d91906128ce565b60405180910390a250565b60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f5481565b61067a611b15565b60065f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16610703576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106fa90612931565b60405180910390fd5b600160085f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055505050565b61079f611b15565b60065f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16610828576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161081f90612931565b60405180910390fd5b6127108161ffff161115610871576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161086890612999565b60405180910390fd5b5f60405180606001604052808461ffff1681526020018361ffff1681526020016001151581525090508060075f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f820151815f015f6101000a81548161ffff021916908361ffff1602179055506020820151815f0160026101000a81548161ffff021916908361ffff1602179055506040820151815f0160046101000a81548160ff0219169083151502179055509050508373ffffffffffffffffffffffffffffffffffffffff167f914adca64de965e53de3931c288ec0cf1e24208efad234e9f8d969f533a9f0648260405161098291906126e6565b60405180910390a250505050565b610a11818273ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016109cd91906123d4565b602060405180830381865afa1580156109e8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a0c91906129cb565b611a6f565b50565b610a1c611b15565b60075f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160049054906101000a900460ff16610aa8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9f90612a40565b60405180910390fd5b60075f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8082015f6101000a81549061ffff02191690555f820160026101000a81549061ffff02191690555f820160046101000a81549060ff021916905550508073ffffffffffffffffffffffffffffffffffffffff167f3e6648a1d6918f893e09d7f2a385f04bdafbf8ad899b255b7f40e02c967b558760405160405180910390a250565b6007602052805f5260405f205f91509050805f015f9054906101000a900461ffff1690805f0160029054906101000a900461ffff1690805f0160049054906101000a900460ff16905083565b60035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f80610be3611c8e565b5f60075f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206040518060600160405290815f82015f9054906101000a900461ffff1661ffff1661ffff1681526020015f820160029054906101000a900461ffff1661ffff1661ffff1681526020015f820160049054906101000a900460ff16151515158152505090508060400151610cf55760056040518060600160405290815f82015f9054906101000a900461ffff1661ffff1661ffff1681526020015f820160029054906101000a900461ffff1661ffff1661ffff1681526020015f820160049054906101000a900460ff16151515158152505090505b5f3390505f8173ffffffffffffffffffffffffffffffffffffffff166339ebf823896040518263ffffffff1660e01b8152600401610d3391906123d4565b608060405180830381865afa158015610d4e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d729190612b5f565b90505f8711156110305760085f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff1615610e9a575f60085f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff021916908315150217905550610f11565b5f835f015161ffff161115610f1057612710835f015161ffff168260400151610ec39190612bb7565b610ecd9190612c25565b871115610f0f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f0690612c9f565b60405180910390fd5b5b5b8694505f8273ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f5e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f8291906129cb565b90505f8373ffffffffffffffffffffffffffffffffffffffff166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fce573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ff291906129cb565b905081811015611029575f81836110099190612cbd565b9050808a1061102357808a61101e9190612cbd565b611025565b5f5b9750505b50506111ca565b60085f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff161561114e575f60085f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055506111c9565b612710836020015161ffff1610156111c857612710836020015161ffff16826040015161117b9190612bb7565b6111859190612c25565b8611156111c7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111be90612d3a565b60405180910390fd5b5b5b5b845f94509450505050935093915050565b6111e3611b15565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611251576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161124890612da2565b60405180910390fd5b8060045f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167fa839c45565e8a86de41783841928f4acde049c2b7160f0ea4d4698220c5af61b60405160405180910390a250565b6005805f015f9054906101000a900461ffff1690805f0160029054906101000a900461ffff1690805f0160049054906101000a900460ff16905083565b6006602052805f5260405f205f915054906101000a900460ff1681565b611339611b15565b8060035f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167fda833a9122ed0b27d5c78c99315bb3758f1b77fb240db484a67fd0f286b263e560405160405180910390a250565b5f60075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160049054906101000a900460ff169050919050565b61141c611ba6565b60065f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff166114a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161149c90612e0a565b60405180910390fd5b5f8173ffffffffffffffffffffffffffffffffffffffff166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114ef573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115139190612e3c565b90505f8173ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e30856040518363ffffffff1660e01b8152600401611551929190612e67565b602060405180830381865afa15801561156c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061159091906129cb565b146115c1576115c0825f8373ffffffffffffffffffffffffffffffffffffffff16611d199092919063ffffffff16565b5b5f60065f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff167fce96c4db32686d3f0011df1abea0ab6c5794b848868dcbece79961fef7e8198d600260405161165c91906128ce565b60405180910390a25050565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61169561236d565b60075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206040518060600160405290815f82015f9054906101000a900461ffff1661ffff1661ffff1681526020015f820160029054906101000a900461ffff1661ffff1661ffff1681526020015f820160049054906101000a900460ff161515151581525050905080604001516117a65760056040518060600160405290815f82015f9054906101000a900461ffff1661ffff1661ffff1681526020015f820160029054906101000a900461ffff1661ffff1661ffff1681526020015f820160049054906101000a900460ff16151515158152505090505b919050565b6117b3611b15565b6117bd8282611e64565b5050565b6117c9611b15565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611837576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161182e90612da2565b60405180910390fd5b5f60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160025f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167fb03f92c8c7ac39710f28b146f754650929499d599a66d51423cbd7f3ceb9aee360405160405180910390a35050565b60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611989576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161198090612ed8565b60405180910390fd5b60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f60045f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff167f772ddcfc9a0f3b1401c0f60000a81999005d9d593b71bb67707c5f326eb7c94d60405160405180910390a2565b611a77611f74565b611ac360025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828473ffffffffffffffffffffffffffffffffffffffff1661205c9092919063ffffffff16565b8173ffffffffffffffffffffffffffffffffffffffff167f962bc326c7b063c70721a63687e0e19450155f93c58eca94769746c0cfb02c5d82604051611b0991906124bc565b60405180910390a25050565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611ba4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b9b90612f40565b60405180910390fd5b565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480611c4d575060035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b611c8c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c8390612fa8565b60405180910390fd5b565b60065f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16611d17576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d0e90612931565b60405180910390fd5b565b5f811480611d9f57505f8373ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e30856040518363ffffffff1660e01b8152600401611d5e929190612e67565b602060405180830381865afa158015611d79573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d9d91906129cb565b145b611dde576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611dd590613036565b60405180910390fd5b611e5f8363095ea7b360e01b8484604051602401611dfd929190613054565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506120e2565b505050565b6127108161ffff161115611ead576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ea490612999565b60405180910390fd5b60405180606001604052808361ffff1681526020018261ffff1681526020015f151581525060055f820151815f015f6101000a81548161ffff021916908361ffff1602179055506020820151815f0160026101000a81548161ffff021916908361ffff1602179055506040820151815f0160046101000a81548160ff0219169083151502179055509050507f3e15ab9cfee468f38606b9afca902d32f69e23eb59832e38d221486c190d13286005604051611f689190613157565b60405180910390a15050565b60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061201b575060015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b61205a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612051906131ba565b60405180910390fd5b565b6120dd8363a9059cbb60e01b848460405160240161207b929190613054565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506120e2565b505050565b5f612143826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166121a89092919063ffffffff16565b90505f815114806121645750808060200190518101906121639190613202565b5b6121a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161219a9061329d565b60405180910390fd5b505050565b60606121b684845f856121bf565b90509392505050565b606082471015612204576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121fb9061332b565b60405180910390fd5b5f808673ffffffffffffffffffffffffffffffffffffffff16858760405161222c91906133b5565b5f6040518083038185875af1925050503d805f8114612266576040519150601f19603f3d011682016040523d82523d5f602084013e61226b565b606091505b509150915061227c87838387612288565b92505050949350505050565b606083156122e9575f8351036122e1576122a1856122fc565b6122e0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122d790613415565b60405180910390fd5b5b8290506122f4565b6122f3838361231e565b5b949350505050565b5f808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b5f825111156123305781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123649190613475565b60405180910390fd5b60405180606001604052805f61ffff1681526020015f61ffff1681526020015f151581525090565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6123be82612395565b9050919050565b6123ce816123b4565b82525050565b5f6020820190506123e75f8301846123c5565b92915050565b5f604051905090565b5f80fd5b5f819050919050565b61240c816123fa565b8114612416575f80fd5b50565b5f8135905061242781612403565b92915050565b5f60208284031215612442576124416123f6565b5b5f61244f84828501612419565b91505092915050565b612461816123b4565b811461246b575f80fd5b50565b5f8135905061247c81612458565b92915050565b5f60208284031215612497576124966123f6565b5b5f6124a48482850161246e565b91505092915050565b6124b6816123fa565b82525050565b5f6020820190506124cf5f8301846124ad565b92915050565b5f80604083850312156124eb576124ea6123f6565b5b5f6124f88582860161246e565b92505060206125098582860161246e565b9150509250929050565b5f61ffff82169050919050565b61252981612513565b8114612533575f80fd5b50565b5f8135905061254481612520565b92915050565b5f805f60608486031215612561576125606123f6565b5b5f61256e8682870161246e565b935050602061257f86828701612536565b925050604061259086828701612536565b9150509250925092565b6125a381612513565b82525050565b5f8115159050919050565b6125bd816125a9565b82525050565b5f6060820190506125d65f83018661259a565b6125e3602083018561259a565b6125f060408301846125b4565b949350505050565b5f805f6060848603121561260f5761260e6123f6565b5b5f61261c8682870161246e565b935050602061262d86828701612419565b925050604061263e86828701612419565b9150509250925092565b5f60408201905061265b5f8301856124ad565b61266860208301846124ad565b9392505050565b5f6020820190506126825f8301846125b4565b92915050565b61269181612513565b82525050565b6126a0816125a9565b82525050565b606082015f8201516126ba5f850182612688565b5060208201516126cd6020850182612688565b5060408201516126e06040850182612697565b50505050565b5f6060820190506126f95f8301846126a6565b92915050565b5f8060408385031215612715576127146123f6565b5b5f61272285828601612536565b925050602061273385828601612536565b9150509250929050565b5f8060408385031215612753576127526123f6565b5b5f6127608582860161246e565b925050602061277185828601612419565b9150509250929050565b5f82825260208201905092915050565b7f686967686572207468616e2031303025000000000000000000000000000000005f82015250565b5f6127bf60108361277b565b91506127ca8261278b565b602082019050919050565b5f6020820190508181035f8301526127ec816127b3565b9050919050565b7f616c7265616479206164646564000000000000000000000000000000000000005f82015250565b5f612827600d8361277b565b9150612832826127f3565b602082019050919050565b5f6020820190508181035f8301526128548161281b565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b600381106128995761289861285b565b5b50565b5f8190506128a982612888565b919050565b5f6128b88261289c565b9050919050565b6128c8816128ae565b82525050565b5f6020820190506128e15f8301846128bf565b92915050565b7f7661756c74206e6f7420616464656400000000000000000000000000000000005f82015250565b5f61291b600f8361277b565b9150612926826128e7565b602082019050919050565b5f6020820190508181035f8301526129488161290f565b9050919050565b7f746f6f20686967680000000000000000000000000000000000000000000000005f82015250565b5f61298360088361277b565b915061298e8261294f565b602082019050919050565b5f6020820190508181035f8301526129b081612977565b9050919050565b5f815190506129c581612403565b92915050565b5f602082840312156129e0576129df6123f6565b5b5f6129ed848285016129b7565b91505092915050565b7f4e6f20637573746f6d20666565732073657400000000000000000000000000005f82015250565b5f612a2a60128361277b565b9150612a35826129f6565b602082019050919050565b5f6020820190508181035f830152612a5781612a1e565b9050919050565b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b612aa882612a62565b810181811067ffffffffffffffff82111715612ac757612ac6612a72565b5b80604052505050565b5f612ad96123ed565b9050612ae58282612a9f565b919050565b5f60808284031215612aff57612afe612a5e565b5b612b096080612ad0565b90505f612b18848285016129b7565b5f830152506020612b2b848285016129b7565b6020830152506040612b3f848285016129b7565b6040830152506060612b53848285016129b7565b60608301525092915050565b5f60808284031215612b7457612b736123f6565b5b5f612b8184828501612aea565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f612bc1826123fa565b9150612bcc836123fa565b9250828202612bda816123fa565b91508282048414831517612bf157612bf0612b8a565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f612c2f826123fa565b9150612c3a836123fa565b925082612c4a57612c49612bf8565b5b828204905092915050565b7f746f6f206d756368206761696e000000000000000000000000000000000000005f82015250565b5f612c89600d8361277b565b9150612c9482612c55565b602082019050919050565b5f6020820190508181035f830152612cb681612c7d565b9050919050565b5f612cc7826123fa565b9150612cd2836123fa565b9250828203905081811115612cea57612ce9612b8a565b5b92915050565b7f746f6f206d756368206c6f7373000000000000000000000000000000000000005f82015250565b5f612d24600d8361277b565b9150612d2f82612cf0565b602082019050919050565b5f6020820190508181035f830152612d5181612d18565b9050919050565b7f5a45524f204144445245535300000000000000000000000000000000000000005f82015250565b5f612d8c600c8361277b565b9150612d9782612d58565b602082019050919050565b5f6020820190508181035f830152612db981612d80565b9050919050565b7f6e6f7420616464656400000000000000000000000000000000000000000000005f82015250565b5f612df460098361277b565b9150612dff82612dc0565b602082019050919050565b5f6020820190508181035f830152612e2181612de8565b9050919050565b5f81519050612e3681612458565b92915050565b5f60208284031215612e5157612e506123f6565b5b5f612e5e84828501612e28565b91505092915050565b5f604082019050612e7a5f8301856123c5565b612e8760208301846123c5565b9392505050565b7f6e6f742066757475726520666565206d616e61676572000000000000000000005f82015250565b5f612ec260168361277b565b9150612ecd82612e8e565b602082019050919050565b5f6020820190508181035f830152612eef81612eb6565b9050919050565b7f21666565206d616e6167657200000000000000000000000000000000000000005f82015250565b5f612f2a600c8361277b565b9150612f3582612ef6565b602082019050919050565b5f6020820190508181035f830152612f5781612f1e565b9050919050565b7f217661756c74206d616e616765720000000000000000000000000000000000005f82015250565b5f612f92600e8361277b565b9150612f9d82612f5e565b602082019050919050565b5f6020820190508181035f830152612fbf81612f86565b9050919050565b7f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f5f8201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000602082015250565b5f61302060368361277b565b915061302b82612fc6565b604082019050919050565b5f6020820190508181035f83015261304d81613014565b9050919050565b5f6040820190506130675f8301856123c5565b61307460208301846124ad565b9392505050565b5f815f1c9050919050565b5f61ffff82169050919050565b5f6130a56130a08361307b565b613086565b9050919050565b5f8160101c9050919050565b5f6130ca6130c5836130ac565b613086565b9050919050565b5f8160201c9050919050565b5f60ff82169050919050565b5f6130fb6130f6836130d1565b6130dd565b9050919050565b606082015f80830154905061311681613093565b6131225f860182612688565b5061312c816130b8565b6131396020860182612688565b50613143816130e9565b6131506040860182612697565b5050505050565b5f60608201905061316a5f830184613102565b92915050565b7f21726563697069656e74000000000000000000000000000000000000000000005f82015250565b5f6131a4600a8361277b565b91506131af82613170565b602082019050919050565b5f6020820190508181035f8301526131d181613198565b9050919050565b6131e1816125a9565b81146131eb575f80fd5b50565b5f815190506131fc816131d8565b92915050565b5f60208284031215613217576132166123f6565b5b5f613224848285016131ee565b91505092915050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e5f8201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b5f613287602a8361277b565b91506132928261322d565b604082019050919050565b5f6020820190508181035f8301526132b48161327b565b9050919050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f5f8201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b5f61331560268361277b565b9150613320826132bb565b604082019050919050565b5f6020820190508181035f83015261334281613309565b9050919050565b5f81519050919050565b5f81905092915050565b5f5b8381101561337a57808201518184015260208101905061335f565b5f8484015250505050565b5f61338f82613349565b6133998185613353565b93506133a981856020860161335d565b80840191505092915050565b5f6133c08284613385565b915081905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000005f82015250565b5f6133ff601d8361277b565b915061340a826133cb565b602082019050919050565b5f6020820190508181035f83015261342c816133f3565b9050919050565b5f81519050919050565b5f61344782613433565b613451818561277b565b935061346181856020860161335d565b61346a81612a62565b840191505092915050565b5f6020820190508181035f83015261348d818461343d565b90509291505056fea26469706673582212209dc05e935b1eb80e572e36fa5d695496822dfc58c16ae93c876efa6ff5746d1264736f6c63430008170033","optimization_enabled":false,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"shanghai","libraries":{},"metadata":{"bytecodeHash":"ipfs"},"optimizer":{"enabled":false,"runs":200},"remappings":[":@openzeppelin/=lib/openzeppelin-contracts/",":@periphery/=lib/tokenized-strategy-periphery/src/",":@tokenized-strategy/=lib/tokenized-strategy/src/",":@vault-periphery/=lib/vault-periphery/src/",":@yearn-vaults/=lib/yearn-vaults-v3/contracts/",":ds-test/=lib/forge-std/lib/ds-test/src/",":erc4626-tests/=lib/tokenized-strategy/lib/erc4626-tests/",":forge-std/=lib/forge-std/src/",":openzeppelin-contracts/=lib/openzeppelin-contracts/",":openzeppelin/=lib/openzeppelin-contracts/contracts/",":tokenized-strategy 2/=lib/tokenized-strategy-periphery/lib/tokenized-strategy 2/src/",":tokenized-strategy-periphery/=lib/tokenized-strategy-periphery/",":tokenized-strategy/=lib/tokenized-strategy/",":vault-periphery/=lib/vault-periphery/",":yearn-vaults-v3 2/=lib/tokenized-strategy-periphery/lib/",":yearn-vaults-v3/=lib/yearn-vaults-v3/"]},"optimization_runs":null,"sourcify_repo_url":"https://repo.sourcify.dev/contracts/full_match/1/0x53acEBB9470Cfc9D231075154f5dcF1586A4c6fa/","decoded_constructor_args":[["0x285E3b1E82f74A99D07D2aD25e159E75382bB43B",{"internalType":"address","name":"_feeManager","type":"address"}],["0x285E3b1E82f74A99D07D2aD25e159E75382bB43B",{"internalType":"address","name":"_feeRecipient","type":"address"}],["0",{"internalType":"uint16","name":"defaultMaxGain","type":"uint16"}],["10000",{"internalType":"uint16","name":"defaultMaxLoss","type":"uint16"}]],"compiler_version":"0.8.23+commit.f704f362","is_verified_via_verifier_alliance":false,"verified_at":"2025-05-26T22:49:39.883293Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x608060405234801562000010575f80fd5b5060405162003ada38038062003ada83398181016040528101906200003691906200036a565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603620000a7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200009e9062000437565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160362000118576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200010f9062000437565b60405180910390fd5b8360015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508260025f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550620001aa8282620001b460201b60201c565b5050505062000601565b6127108161ffff16111562000200576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620001f790620004a5565b60405180910390fd5b60405180606001604052808361ffff1681526020018261ffff1681526020015f151581525060055f820151815f015f6101000a81548161ffff021916908361ffff1602179055506020820151815f0160026101000a81548161ffff021916908361ffff1602179055506040820151815f0160046101000a81548160ff0219169083151502179055509050507f3e15ab9cfee468f38606b9afca902d32f69e23eb59832e38d221486c190d13286005604051620002bd9190620005e6565b60405180910390a15050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f620002f882620002cd565b9050919050565b6200030a81620002ec565b811462000315575f80fd5b50565b5f815190506200032881620002ff565b92915050565b5f61ffff82169050919050565b62000346816200032e565b811462000351575f80fd5b50565b5f8151905062000364816200033b565b92915050565b5f805f8060808587031215620003855762000384620002c9565b5b5f620003948782880162000318565b9450506020620003a78782880162000318565b9350506040620003ba8782880162000354565b9250506060620003cd8782880162000354565b91505092959194509250565b5f82825260208201905092915050565b7f5a45524f204144445245535300000000000000000000000000000000000000005f82015250565b5f6200041f600c83620003d9565b91506200042c82620003e9565b602082019050919050565b5f6020820190508181035f830152620004508162000411565b9050919050565b7f746f6f20686967680000000000000000000000000000000000000000000000005f82015250565b5f6200048d600883620003d9565b91506200049a8262000457565b602082019050919050565b5f6020820190508181035f830152620004be816200047f565b9050919050565b5f815f1c9050919050565b5f61ffff82169050919050565b5f620004f3620004ed83620004c5565b620004d0565b9050919050565b62000505816200032e565b82525050565b5f8160101c9050919050565b5f6200052d62000527836200050b565b620004d0565b9050919050565b5f8160201c9050919050565b5f60ff82169050919050565b5f620005626200055c8362000534565b62000540565b9050919050565b5f8115159050919050565b6200057f8162000569565b82525050565b606082015f8083015490506200059b81620004dd565b620005a95f860182620004fa565b50620005b58162000517565b620005c46020860182620004fa565b50620005d0816200054c565b620005df604086018262000574565b5050505050565b5f606082019050620005fb5f83018462000585565b92915050565b6134cb806200060f5f395ff3fe608060405234801561000f575f80fd5b5060043610610156575f3560e01c80639b3b6955116100c1578063d0fb02031161007a578063d0fb0203146103b1578063de1eb9a3146103cf578063e0aacb20146103ff578063e74b981b1461041b578063f94c53c714610437578063fb9321081461044157610156565b80639b3b6955146102dd5780639e09ed5f146102f9578063a622ee7c14610319578063b543503e14610349578063c7c504b914610365578063ceb68c231461039557610156565b80635efbccdd116101135780635efbccdd1461020857806363453ae11461022457806367bee7e9146102405780637b5d7b651461025c5780638a4adf241461028e578063921f8a8f146102ac57610156565b8063015cf1501461015a57806324be662814610178578063256b5a021461019457806346904840146101b05780635783fe39146101ce5780635cece03a146101ec575b5f80fd5b61016261045d565b60405161016f91906123d4565b60405180910390f35b610192600480360381019061018d919061242d565b610482565b005b6101ae60048036038101906101a99190612482565b61050f565b005b6101b8610648565b6040516101c591906123d4565b60405180910390f35b6101d661066d565b6040516101e391906124bc565b60405180910390f35b610206600480360381019061020191906124d5565b610672565b005b610222600480360381019061021d919061254a565b610797565b005b61023e60048036038101906102399190612482565b610990565b005b61025a60048036038101906102559190612482565b610a14565b005b61027660048036038101906102719190612482565b610b68565b604051610285939291906125c3565b60405180910390f35b610296610bb4565b6040516102a391906123d4565b60405180910390f35b6102c660048036038101906102c191906125f8565b610bd9565b6040516102d4929190612648565b60405180910390f35b6102f760048036038101906102f29190612482565b6111db565b005b6103016112d7565b604051610310939291906125c3565b60405180910390f35b610333600480360381019061032e9190612482565b611314565b604051610340919061266f565b60405180910390f35b610363600480360381019061035e9190612482565b611331565b005b61037f600480360381019061037a9190612482565b6113bf565b60405161038c919061266f565b60405180910390f35b6103af60048036038101906103aa9190612482565b611414565b005b6103b9611668565b6040516103c691906123d4565b60405180910390f35b6103e960048036038101906103e49190612482565b61168d565b6040516103f691906126e6565b60405180910390f35b610419600480360381019061041491906126ff565b6117ab565b005b61043560048036038101906104309190612482565b6117c1565b005b61043f6118fa565b005b61045b6004803603810190610456919061273d565b611a6f565b005b60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61048a611b15565b6127108111156104cf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104c6906127d5565b60405180910390fd5b805f819055507f18182e268b61d2aada98f23ade23b0ea133d5b0b6712dbfa682dc6da29941c228160405161050491906124bc565b60405180910390a150565b610517611ba6565b60065f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16156105a1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105989061283d565b60405180910390fd5b600160065f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508073ffffffffffffffffffffffffffffffffffffffff167fce96c4db32686d3f0011df1abea0ab6c5794b848868dcbece79961fef7e8198d600160405161063d91906128ce565b60405180910390a250565b60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f5481565b61067a611b15565b60065f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16610703576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106fa90612931565b60405180910390fd5b600160085f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055505050565b61079f611b15565b60065f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16610828576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161081f90612931565b60405180910390fd5b6127108161ffff161115610871576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161086890612999565b60405180910390fd5b5f60405180606001604052808461ffff1681526020018361ffff1681526020016001151581525090508060075f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f820151815f015f6101000a81548161ffff021916908361ffff1602179055506020820151815f0160026101000a81548161ffff021916908361ffff1602179055506040820151815f0160046101000a81548160ff0219169083151502179055509050508373ffffffffffffffffffffffffffffffffffffffff167f914adca64de965e53de3931c288ec0cf1e24208efad234e9f8d969f533a9f0648260405161098291906126e6565b60405180910390a250505050565b610a11818273ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016109cd91906123d4565b602060405180830381865afa1580156109e8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a0c91906129cb565b611a6f565b50565b610a1c611b15565b60075f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160049054906101000a900460ff16610aa8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9f90612a40565b60405180910390fd5b60075f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8082015f6101000a81549061ffff02191690555f820160026101000a81549061ffff02191690555f820160046101000a81549060ff021916905550508073ffffffffffffffffffffffffffffffffffffffff167f3e6648a1d6918f893e09d7f2a385f04bdafbf8ad899b255b7f40e02c967b558760405160405180910390a250565b6007602052805f5260405f205f91509050805f015f9054906101000a900461ffff1690805f0160029054906101000a900461ffff1690805f0160049054906101000a900460ff16905083565b60035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f80610be3611c8e565b5f60075f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206040518060600160405290815f82015f9054906101000a900461ffff1661ffff1661ffff1681526020015f820160029054906101000a900461ffff1661ffff1661ffff1681526020015f820160049054906101000a900460ff16151515158152505090508060400151610cf55760056040518060600160405290815f82015f9054906101000a900461ffff1661ffff1661ffff1681526020015f820160029054906101000a900461ffff1661ffff1661ffff1681526020015f820160049054906101000a900460ff16151515158152505090505b5f3390505f8173ffffffffffffffffffffffffffffffffffffffff166339ebf823896040518263ffffffff1660e01b8152600401610d3391906123d4565b608060405180830381865afa158015610d4e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d729190612b5f565b90505f8711156110305760085f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff1615610e9a575f60085f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff021916908315150217905550610f11565b5f835f015161ffff161115610f1057612710835f015161ffff168260400151610ec39190612bb7565b610ecd9190612c25565b871115610f0f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f0690612c9f565b60405180910390fd5b5b5b8694505f8273ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f5e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f8291906129cb565b90505f8373ffffffffffffffffffffffffffffffffffffffff166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fce573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ff291906129cb565b905081811015611029575f81836110099190612cbd565b9050808a1061102357808a61101e9190612cbd565b611025565b5f5b9750505b50506111ca565b60085f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff161561114e575f60085f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055506111c9565b612710836020015161ffff1610156111c857612710836020015161ffff16826040015161117b9190612bb7565b6111859190612c25565b8611156111c7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111be90612d3a565b60405180910390fd5b5b5b5b845f94509450505050935093915050565b6111e3611b15565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611251576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161124890612da2565b60405180910390fd5b8060045f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167fa839c45565e8a86de41783841928f4acde049c2b7160f0ea4d4698220c5af61b60405160405180910390a250565b6005805f015f9054906101000a900461ffff1690805f0160029054906101000a900461ffff1690805f0160049054906101000a900460ff16905083565b6006602052805f5260405f205f915054906101000a900460ff1681565b611339611b15565b8060035f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167fda833a9122ed0b27d5c78c99315bb3758f1b77fb240db484a67fd0f286b263e560405160405180910390a250565b5f60075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160049054906101000a900460ff169050919050565b61141c611ba6565b60065f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff166114a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161149c90612e0a565b60405180910390fd5b5f8173ffffffffffffffffffffffffffffffffffffffff166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114ef573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115139190612e3c565b90505f8173ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e30856040518363ffffffff1660e01b8152600401611551929190612e67565b602060405180830381865afa15801561156c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061159091906129cb565b146115c1576115c0825f8373ffffffffffffffffffffffffffffffffffffffff16611d199092919063ffffffff16565b5b5f60065f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff167fce96c4db32686d3f0011df1abea0ab6c5794b848868dcbece79961fef7e8198d600260405161165c91906128ce565b60405180910390a25050565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61169561236d565b60075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206040518060600160405290815f82015f9054906101000a900461ffff1661ffff1661ffff1681526020015f820160029054906101000a900461ffff1661ffff1661ffff1681526020015f820160049054906101000a900460ff161515151581525050905080604001516117a65760056040518060600160405290815f82015f9054906101000a900461ffff1661ffff1661ffff1681526020015f820160029054906101000a900461ffff1661ffff1661ffff1681526020015f820160049054906101000a900460ff16151515158152505090505b919050565b6117b3611b15565b6117bd8282611e64565b5050565b6117c9611b15565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611837576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161182e90612da2565b60405180910390fd5b5f60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160025f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167fb03f92c8c7ac39710f28b146f754650929499d599a66d51423cbd7f3ceb9aee360405160405180910390a35050565b60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611989576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161198090612ed8565b60405180910390fd5b60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f60045f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff167f772ddcfc9a0f3b1401c0f60000a81999005d9d593b71bb67707c5f326eb7c94d60405160405180910390a2565b611a77611f74565b611ac360025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828473ffffffffffffffffffffffffffffffffffffffff1661205c9092919063ffffffff16565b8173ffffffffffffffffffffffffffffffffffffffff167f962bc326c7b063c70721a63687e0e19450155f93c58eca94769746c0cfb02c5d82604051611b0991906124bc565b60405180910390a25050565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611ba4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b9b90612f40565b60405180910390fd5b565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480611c4d575060035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b611c8c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c8390612fa8565b60405180910390fd5b565b60065f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16611d17576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d0e90612931565b60405180910390fd5b565b5f811480611d9f57505f8373ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e30856040518363ffffffff1660e01b8152600401611d5e929190612e67565b602060405180830381865afa158015611d79573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d9d91906129cb565b145b611dde576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611dd590613036565b60405180910390fd5b611e5f8363095ea7b360e01b8484604051602401611dfd929190613054565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506120e2565b505050565b6127108161ffff161115611ead576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ea490612999565b60405180910390fd5b60405180606001604052808361ffff1681526020018261ffff1681526020015f151581525060055f820151815f015f6101000a81548161ffff021916908361ffff1602179055506020820151815f0160026101000a81548161ffff021916908361ffff1602179055506040820151815f0160046101000a81548160ff0219169083151502179055509050507f3e15ab9cfee468f38606b9afca902d32f69e23eb59832e38d221486c190d13286005604051611f689190613157565b60405180910390a15050565b60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061201b575060015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b61205a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612051906131ba565b60405180910390fd5b565b6120dd8363a9059cbb60e01b848460405160240161207b929190613054565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506120e2565b505050565b5f612143826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166121a89092919063ffffffff16565b90505f815114806121645750808060200190518101906121639190613202565b5b6121a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161219a9061329d565b60405180910390fd5b505050565b60606121b684845f856121bf565b90509392505050565b606082471015612204576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121fb9061332b565b60405180910390fd5b5f808673ffffffffffffffffffffffffffffffffffffffff16858760405161222c91906133b5565b5f6040518083038185875af1925050503d805f8114612266576040519150601f19603f3d011682016040523d82523d5f602084013e61226b565b606091505b509150915061227c87838387612288565b92505050949350505050565b606083156122e9575f8351036122e1576122a1856122fc565b6122e0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122d790613415565b60405180910390fd5b5b8290506122f4565b6122f3838361231e565b5b949350505050565b5f808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b5f825111156123305781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123649190613475565b60405180910390fd5b60405180606001604052805f61ffff1681526020015f61ffff1681526020015f151581525090565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6123be82612395565b9050919050565b6123ce816123b4565b82525050565b5f6020820190506123e75f8301846123c5565b92915050565b5f604051905090565b5f80fd5b5f819050919050565b61240c816123fa565b8114612416575f80fd5b50565b5f8135905061242781612403565b92915050565b5f60208284031215612442576124416123f6565b5b5f61244f84828501612419565b91505092915050565b612461816123b4565b811461246b575f80fd5b50565b5f8135905061247c81612458565b92915050565b5f60208284031215612497576124966123f6565b5b5f6124a48482850161246e565b91505092915050565b6124b6816123fa565b82525050565b5f6020820190506124cf5f8301846124ad565b92915050565b5f80604083850312156124eb576124ea6123f6565b5b5f6124f88582860161246e565b92505060206125098582860161246e565b9150509250929050565b5f61ffff82169050919050565b61252981612513565b8114612533575f80fd5b50565b5f8135905061254481612520565b92915050565b5f805f60608486031215612561576125606123f6565b5b5f61256e8682870161246e565b935050602061257f86828701612536565b925050604061259086828701612536565b9150509250925092565b6125a381612513565b82525050565b5f8115159050919050565b6125bd816125a9565b82525050565b5f6060820190506125d65f83018661259a565b6125e3602083018561259a565b6125f060408301846125b4565b949350505050565b5f805f6060848603121561260f5761260e6123f6565b5b5f61261c8682870161246e565b935050602061262d86828701612419565b925050604061263e86828701612419565b9150509250925092565b5f60408201905061265b5f8301856124ad565b61266860208301846124ad565b9392505050565b5f6020820190506126825f8301846125b4565b92915050565b61269181612513565b82525050565b6126a0816125a9565b82525050565b606082015f8201516126ba5f850182612688565b5060208201516126cd6020850182612688565b5060408201516126e06040850182612697565b50505050565b5f6060820190506126f95f8301846126a6565b92915050565b5f8060408385031215612715576127146123f6565b5b5f61272285828601612536565b925050602061273385828601612536565b9150509250929050565b5f8060408385031215612753576127526123f6565b5b5f6127608582860161246e565b925050602061277185828601612419565b9150509250929050565b5f82825260208201905092915050565b7f686967686572207468616e2031303025000000000000000000000000000000005f82015250565b5f6127bf60108361277b565b91506127ca8261278b565b602082019050919050565b5f6020820190508181035f8301526127ec816127b3565b9050919050565b7f616c7265616479206164646564000000000000000000000000000000000000005f82015250565b5f612827600d8361277b565b9150612832826127f3565b602082019050919050565b5f6020820190508181035f8301526128548161281b565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b600381106128995761289861285b565b5b50565b5f8190506128a982612888565b919050565b5f6128b88261289c565b9050919050565b6128c8816128ae565b82525050565b5f6020820190506128e15f8301846128bf565b92915050565b7f7661756c74206e6f7420616464656400000000000000000000000000000000005f82015250565b5f61291b600f8361277b565b9150612926826128e7565b602082019050919050565b5f6020820190508181035f8301526129488161290f565b9050919050565b7f746f6f20686967680000000000000000000000000000000000000000000000005f82015250565b5f61298360088361277b565b915061298e8261294f565b602082019050919050565b5f6020820190508181035f8301526129b081612977565b9050919050565b5f815190506129c581612403565b92915050565b5f602082840312156129e0576129df6123f6565b5b5f6129ed848285016129b7565b91505092915050565b7f4e6f20637573746f6d20666565732073657400000000000000000000000000005f82015250565b5f612a2a60128361277b565b9150612a35826129f6565b602082019050919050565b5f6020820190508181035f830152612a5781612a1e565b9050919050565b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b612aa882612a62565b810181811067ffffffffffffffff82111715612ac757612ac6612a72565b5b80604052505050565b5f612ad96123ed565b9050612ae58282612a9f565b919050565b5f60808284031215612aff57612afe612a5e565b5b612b096080612ad0565b90505f612b18848285016129b7565b5f830152506020612b2b848285016129b7565b6020830152506040612b3f848285016129b7565b6040830152506060612b53848285016129b7565b60608301525092915050565b5f60808284031215612b7457612b736123f6565b5b5f612b8184828501612aea565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f612bc1826123fa565b9150612bcc836123fa565b9250828202612bda816123fa565b91508282048414831517612bf157612bf0612b8a565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f612c2f826123fa565b9150612c3a836123fa565b925082612c4a57612c49612bf8565b5b828204905092915050565b7f746f6f206d756368206761696e000000000000000000000000000000000000005f82015250565b5f612c89600d8361277b565b9150612c9482612c55565b602082019050919050565b5f6020820190508181035f830152612cb681612c7d565b9050919050565b5f612cc7826123fa565b9150612cd2836123fa565b9250828203905081811115612cea57612ce9612b8a565b5b92915050565b7f746f6f206d756368206c6f7373000000000000000000000000000000000000005f82015250565b5f612d24600d8361277b565b9150612d2f82612cf0565b602082019050919050565b5f6020820190508181035f830152612d5181612d18565b9050919050565b7f5a45524f204144445245535300000000000000000000000000000000000000005f82015250565b5f612d8c600c8361277b565b9150612d9782612d58565b602082019050919050565b5f6020820190508181035f830152612db981612d80565b9050919050565b7f6e6f7420616464656400000000000000000000000000000000000000000000005f82015250565b5f612df460098361277b565b9150612dff82612dc0565b602082019050919050565b5f6020820190508181035f830152612e2181612de8565b9050919050565b5f81519050612e3681612458565b92915050565b5f60208284031215612e5157612e506123f6565b5b5f612e5e84828501612e28565b91505092915050565b5f604082019050612e7a5f8301856123c5565b612e8760208301846123c5565b9392505050565b7f6e6f742066757475726520666565206d616e61676572000000000000000000005f82015250565b5f612ec260168361277b565b9150612ecd82612e8e565b602082019050919050565b5f6020820190508181035f830152612eef81612eb6565b9050919050565b7f21666565206d616e6167657200000000000000000000000000000000000000005f82015250565b5f612f2a600c8361277b565b9150612f3582612ef6565b602082019050919050565b5f6020820190508181035f830152612f5781612f1e565b9050919050565b7f217661756c74206d616e616765720000000000000000000000000000000000005f82015250565b5f612f92600e8361277b565b9150612f9d82612f5e565b602082019050919050565b5f6020820190508181035f830152612fbf81612f86565b9050919050565b7f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f5f8201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000602082015250565b5f61302060368361277b565b915061302b82612fc6565b604082019050919050565b5f6020820190508181035f83015261304d81613014565b9050919050565b5f6040820190506130675f8301856123c5565b61307460208301846124ad565b9392505050565b5f815f1c9050919050565b5f61ffff82169050919050565b5f6130a56130a08361307b565b613086565b9050919050565b5f8160101c9050919050565b5f6130ca6130c5836130ac565b613086565b9050919050565b5f8160201c9050919050565b5f60ff82169050919050565b5f6130fb6130f6836130d1565b6130dd565b9050919050565b606082015f80830154905061311681613093565b6131225f860182612688565b5061312c816130b8565b6131396020860182612688565b50613143816130e9565b6131506040860182612697565b5050505050565b5f60608201905061316a5f830184613102565b92915050565b7f21726563697069656e74000000000000000000000000000000000000000000005f82015250565b5f6131a4600a8361277b565b91506131af82613170565b602082019050919050565b5f6020820190508181035f8301526131d181613198565b9050919050565b6131e1816125a9565b81146131eb575f80fd5b50565b5f815190506131fc816131d8565b92915050565b5f60208284031215613217576132166123f6565b5b5f613224848285016131ee565b91505092915050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e5f8201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b5f613287602a8361277b565b91506132928261322d565b604082019050919050565b5f6020820190508181035f8301526132b48161327b565b9050919050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f5f8201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b5f61331560268361277b565b9150613320826132bb565b604082019050919050565b5f6020820190508181035f83015261334281613309565b9050919050565b5f81519050919050565b5f81905092915050565b5f5b8381101561337a57808201518184015260208101905061335f565b5f8484015250505050565b5f61338f82613349565b6133998185613353565b93506133a981856020860161335d565b80840191505092915050565b5f6133c08284613385565b915081905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000005f82015250565b5f6133ff601d8361277b565b915061340a826133cb565b602082019050919050565b5f6020820190508181035f83015261342c816133f3565b9050919050565b5f81519050919050565b5f61344782613433565b613451818561277b565b935061346181856020860161335d565b61346a81612a62565b840191505092915050565b5f6020820190508181035f83015261348d818461343d565b90509291505056fea26469706673582212209dc05e935b1eb80e572e36fa5d695496822dfc58c16ae93c876efa6ff5746d1264736f6c63430008170033000000000000000000000000285e3b1e82f74a99d07d2ad25e159e75382bb43b000000000000000000000000285e3b1e82f74a99d07d2ad25e159e75382bb43b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002710","name":"Accountant","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"shanghai","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":true,"additional_sources":[{"file_path":"lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4626.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../token/ERC20/IERC20.sol\";\nimport \"../token/ERC20/extensions/IERC20Metadata.sol\";\n\n/**\n * @dev Interface of the ERC4626 \"Tokenized Vault Standard\", as defined in\n * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].\n *\n * _Available since v4.7._\n */\ninterface IERC4626 is IERC20, IERC20Metadata {\n\n    event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n\n    event Withdraw(\n        address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares\n    );\n\n    /**\n     * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n     *\n     * - MUST be an ERC-20 token contract.\n     * - MUST NOT revert.\n     */\n    function asset() external view returns (address assetTokenAddress);\n\n    /**\n     * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n     *\n     * - SHOULD include any compounding that occurs from yield.\n     * - MUST be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT revert.\n     */\n    function totalAssets() external view returns (uint256 totalManagedAssets);\n\n    /**\n     * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n     * scenario where all the conditions are met.\n     *\n     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT show any variations depending on the caller.\n     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n     * - MUST NOT revert.\n     *\n     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n     * from.\n     */\n    function convertToShares(\n        uint256 assets\n    ) external view returns (uint256 shares);\n\n    /**\n     * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n     * scenario where all the conditions are met.\n     *\n     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT show any variations depending on the caller.\n     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n     * - MUST NOT revert.\n     *\n     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n     * from.\n     */\n    function convertToAssets(\n        uint256 shares\n    ) external view returns (uint256 assets);\n\n    /**\n     * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n     * through a deposit call.\n     *\n     * - MUST return a limited value if receiver is subject to some deposit limit.\n     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n     * - MUST NOT revert.\n     */\n    function maxDeposit(\n        address receiver\n    ) external view returns (uint256 maxAssets);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n     * current on-chain conditions.\n     *\n     * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n     *   call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n     *   in the same transaction.\n     * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n     *   deposit would be accepted, regardless if the user has enough tokens approved, etc.\n     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n     */\n    function previewDeposit(\n        uint256 assets\n    ) external view returns (uint256 shares);\n\n    /**\n     * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n     *\n     * - MUST emit the Deposit event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   deposit execution, and are accounted for during deposit.\n     * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n     *   approving enough underlying tokens to the Vault contract, etc).\n     *\n     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n     */\n    function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n    /**\n     * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n     * - MUST return a limited value if receiver is subject to some mint limit.\n     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n     * - MUST NOT revert.\n     */\n    function maxMint(\n        address receiver\n    ) external view returns (uint256 maxShares);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n     * current on-chain conditions.\n     *\n     * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n     *   in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n     *   same transaction.\n     * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n     *   would be accepted, regardless if the user has enough tokens approved, etc.\n     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by minting.\n     */\n    function previewMint(\n        uint256 shares\n    ) external view returns (uint256 assets);\n\n    /**\n     * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n     *\n     * - MUST emit the Deposit event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n     *   execution, and are accounted for during mint.\n     * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n     *   approving enough underlying tokens to the Vault contract, etc).\n     *\n     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n     */\n    function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n    /**\n     * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n     * Vault, through a withdraw call.\n     *\n     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n     * - MUST NOT revert.\n     */\n    function maxWithdraw(\n        address owner\n    ) external view returns (uint256 maxAssets);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n     * given current on-chain conditions.\n     *\n     * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n     *   call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n     *   called\n     *   in the same transaction.\n     * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n     *   the withdrawal would be accepted, regardless if the user has enough shares, etc.\n     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n     */\n    function previewWithdraw(\n        uint256 assets\n    ) external view returns (uint256 shares);\n\n    /**\n     * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n     *\n     * - MUST emit the Withdraw event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   withdraw execution, and are accounted for during withdraw.\n     * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n     *   not having enough shares, etc).\n     *\n     * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n     * Those methods should be performed separately.\n     */\n    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);\n\n    /**\n     * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n     * through a redeem call.\n     *\n     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n     * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n     * - MUST NOT revert.\n     */\n    function maxRedeem(\n        address owner\n    ) external view returns (uint256 maxShares);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n     * given current on-chain conditions.\n     *\n     * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n     *   in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n     *   same transaction.\n     * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n     *   redemption would be accepted, regardless if the user has enough shares, etc.\n     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n     */\n    function previewRedeem(\n        uint256 shares\n    ) external view returns (uint256 assets);\n\n    /**\n     * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n     *\n     * - MUST emit the Withdraw event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   redeem execution, and are accounted for during redeem.\n     * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n     *   not having enough shares, etc).\n     *\n     * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n     * Those methods should be performed separately.\n     */\n    function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);\n\n}\n"},{"file_path":"lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.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 \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.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 ERC20 is Context, IERC20, IERC20Metadata {\n\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    constructor(string memory name_, string memory symbol_) {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the 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(\n        address account\n    ) 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    /**\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"},{"file_path":"lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.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 IERC20 {\n\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\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(\n        address account\n    ) 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}\n"},{"file_path":"lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.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 \"../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    /**\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}\n"},{"file_path":"lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.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 IERC20Permit {\n\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(\n        address owner\n    ) 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}\n"},{"file_path":"lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.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 \"../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\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}\n"},{"file_path":"lib/openzeppelin-contracts/contracts/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    /**\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(\n        address account\n    ) 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) return returndata;\n        else _revert(returndata, errorMessage);\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}\n"},{"file_path":"lib/openzeppelin-contracts/contracts/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\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"},{"file_path":"lib/openzeppelin-contracts/contracts/utils/math/Math.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 Math {\n\n    enum Rounding {\n        Down, // Toward negative infinity\n        Up, // Toward infinity\n        Zero // Toward zero\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 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) result += 1;\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(\n        uint256 a\n    ) internal pure returns (uint256) {\n        if (a == 0) return 0;\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(\n        uint256 value\n    ) 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) result += 1;\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(\n        uint256 value\n    ) 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) result += 1;\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(\n        uint256 value\n    ) 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) result += 1;\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}\n"},{"file_path":"lib/yearn-vaults-v3/contracts/interfaces/IVault.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.18;\n\nimport {IERC4626} from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\n\ninterface IVault is IERC4626 {\n\n    // STRATEGY EVENTS\n    event StrategyChanged(address indexed strategy, uint256 change_type);\n    event StrategyReported(\n        address indexed strategy,\n        uint256 gain,\n        uint256 loss,\n        uint256 current_debt,\n        uint256 protocol_fees,\n        uint256 total_fees,\n        uint256 total_refunds\n    );\n    // DEBT MANAGEMENT EVENTS\n    event DebtUpdated(address indexed strategy, uint256 current_debt, uint256 new_debt);\n    // ROLE UPDATES\n    event RoleSet(address indexed account, uint256 role);\n    event UpdateFutureRoleManager(address indexed future_role_manager);\n    event UpdateRoleManager(address indexed role_manager);\n\n    event UpdateAccountant(address indexed accountant);\n    event UpdateDefaultQueue(address[] new_default_queue);\n    event UpdateUseDefaultQueue(bool use_default_queue);\n    event UpdatedMaxDebtForStrategy(address indexed sender, address indexed strategy, uint256 new_debt);\n    event UpdateAutoAllocate(bool auto_allocate);\n    event UpdateDepositLimit(uint256 deposit_limit);\n    event UpdateMinimumTotalIdle(uint256 minimum_total_idle);\n    event UpdateProfitMaxUnlockTime(uint256 profit_max_unlock_time);\n    event DebtPurchased(address indexed strategy, uint256 amount);\n    event Shutdown();\n\n    struct StrategyParams {\n        uint256 activation;\n        uint256 last_report;\n        uint256 current_debt;\n        uint256 max_debt;\n    }\n\n    function FACTORY() external view returns (uint256);\n\n    function strategies(\n        address\n    ) external view returns (StrategyParams memory);\n\n    function default_queue(\n        uint256\n    ) external view returns (address);\n\n    function use_default_queue() external view returns (bool);\n\n    function auto_allocate() external view returns (bool);\n\n    function minimum_total_idle() external view returns (uint256);\n\n    function deposit_limit() external view returns (uint256);\n\n    function deposit_limit_module() external view returns (address);\n\n    function withdraw_limit_module() external view returns (address);\n\n    function accountant() external view returns (address);\n\n    function roles(\n        address\n    ) external view returns (uint256);\n\n    function role_manager() external view returns (address);\n\n    function future_role_manager() external view returns (address);\n\n    function isShutdown() external view returns (bool);\n\n    function nonces(\n        address\n    ) external view returns (uint256);\n\n    function initialize(address, string memory, string memory, address, uint256) external;\n\n    function setName(\n        string memory\n    ) external;\n\n    function setSymbol(\n        string memory\n    ) external;\n\n    function set_accountant(\n        address new_accountant\n    ) external;\n\n    function set_default_queue(\n        address[] memory new_default_queue\n    ) external;\n\n    function set_use_default_queue(\n        bool\n    ) external;\n\n    function set_auto_allocate(\n        bool\n    ) external;\n\n    function set_deposit_limit(\n        uint256 deposit_limit\n    ) external;\n\n    function set_deposit_limit(uint256 deposit_limit, bool should_override) external;\n\n    function set_deposit_limit_module(\n        address new_deposit_limit_module\n    ) external;\n\n    function set_deposit_limit_module(address new_deposit_limit_module, bool should_override) external;\n\n    function set_withdraw_limit_module(\n        address new_withdraw_limit_module\n    ) external;\n\n    function set_minimum_total_idle(\n        uint256 minimum_total_idle\n    ) external;\n\n    function setProfitMaxUnlockTime(\n        uint256 new_profit_max_unlock_time\n    ) external;\n\n    function set_role(address account, uint256 role) external;\n\n    function add_role(address account, uint256 role) external;\n\n    function remove_role(address account, uint256 role) external;\n\n    function transfer_role_manager(\n        address role_manager\n    ) external;\n\n    function accept_role_manager() external;\n\n    function unlockedShares() external view returns (uint256);\n\n    function pricePerShare() external view returns (uint256);\n\n    function get_default_queue() external view returns (address[] memory);\n\n    function process_report(\n        address strategy\n    ) external returns (uint256, uint256);\n\n    function buy_debt(address strategy, uint256 amount) external;\n\n    function add_strategy(\n        address new_strategy\n    ) external;\n\n    function revoke_strategy(\n        address strategy\n    ) external;\n\n    function force_revoke_strategy(\n        address strategy\n    ) external;\n\n    function update_max_debt_for_strategy(address strategy, uint256 new_max_debt) external;\n\n    function update_debt(address strategy, uint256 target_debt) external returns (uint256);\n\n    function update_debt(address strategy, uint256 target_debt, uint256 max_loss) external returns (uint256);\n\n    function shutdown_vault() external;\n\n    function totalIdle() external view returns (uint256);\n\n    function totalDebt() external view returns (uint256);\n\n    function apiVersion() external view returns (string memory);\n\n    function assess_share_of_unrealised_losses(\n        address strategy,\n        uint256 assets_needed\n    ) external view returns (uint256);\n\n    function profitMaxUnlockTime() external view returns (uint256);\n\n    function fullProfitUnlockDate() external view returns (uint256);\n\n    function profitUnlockingRate() external view returns (uint256);\n\n    function lastProfitUpdate() external view returns (uint256);\n\n    //// NON-STANDARD ERC-4626 FUNCTIONS \\\\\\\\\n\n    function withdraw(uint256 assets, address receiver, address owner, uint256 max_loss) external returns (uint256);\n\n    function withdraw(\n        uint256 assets,\n        address receiver,\n        address owner,\n        uint256 max_loss,\n        address[] memory strategies\n    ) external returns (uint256);\n\n    function redeem(uint256 shares, address receiver, address owner, uint256 max_loss) external returns (uint256);\n\n    function redeem(\n        uint256 shares,\n        address receiver,\n        address owner,\n        uint256 max_loss,\n        address[] memory strategies\n    ) external returns (uint256);\n\n    function maxWithdraw(address owner, uint256 max_loss) external view returns (uint256);\n\n    function maxWithdraw(\n        address owner,\n        uint256 max_loss,\n        address[] memory strategies\n    ) external view returns (uint256);\n\n    function maxRedeem(address owner, uint256 max_loss) external view returns (uint256);\n\n    function maxRedeem(address owner, uint256 max_loss, address[] memory strategies) external view returns (uint256);\n\n    //// NON-STANDARD ERC-20 FUNCTIONS \\\\\\\\\n\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n    function permit(\n        address owner,\n        address spender,\n        uint256 amount,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external returns (bool);\n\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"address","name":"_feeManager","type":"address"},{"internalType":"address","name":"_feeRecipient","type":"address"},{"internalType":"uint16","name":"defaultMaxGain","type":"uint16"},{"internalType":"uint16","name":"defaultMaxLoss","type":"uint16"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewards","type":"uint256"}],"name":"DistributeRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"feeManager","type":"address"}],"name":"NewFeeManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"}],"name":"RemovedCustomFeeConfig","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"futureFeeManager","type":"address"}],"name":"SetFutureFeeManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"components":[{"internalType":"uint16","name":"maxGain","type":"uint16"},{"internalType":"uint16","name":"maxLoss","type":"uint16"},{"internalType":"bool","name":"custom","type":"bool"}],"indexed":false,"internalType":"struct Accountant.Fee","name":"custom_config","type":"tuple"}],"name":"UpdateCustomFeeConfig","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint16","name":"maxGain","type":"uint16"},{"internalType":"uint16","name":"maxLoss","type":"uint16"},{"internalType":"bool","name":"custom","type":"bool"}],"indexed":false,"internalType":"struct Accountant.Fee","name":"defaultFeeConfig","type":"tuple"}],"name":"UpdateDefaultFeeConfig","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldFeeRecipient","type":"address"},{"indexed":true,"internalType":"address","name":"newFeeRecipient","type":"address"}],"name":"UpdateFeeRecipient","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxLoss","type":"uint256"}],"name":"UpdateMaxLoss","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newVaultManager","type":"address"}],"name":"UpdateVaultManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"enum Accountant.ChangeType","name":"change","type":"uint8"}],"name":"VaultChanged","type":"event"},{"inputs":[],"name":"acceptFeeManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"addVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"customConfig","outputs":[{"internalType":"uint16","name":"maxGain","type":"uint16"},{"internalType":"uint16","name":"maxLoss","type":"uint16"},{"internalType":"bool","name":"custom","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultConfig","outputs":[{"internalType":"uint16","name":"maxGain","type":"uint16"},{"internalType":"uint16","name":"maxLoss","type":"uint16"},{"internalType":"bool","name":"custom","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"distribute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"distribute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"futureFeeManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"getVaultConfig","outputs":[{"components":[{"internalType":"uint16","name":"maxGain","type":"uint16"},{"internalType":"uint16","name":"maxLoss","type":"uint16"},{"internalType":"bool","name":"custom","type":"bool"}],"internalType":"struct Accountant.Fee","name":"fee","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLoss","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"removeCustomConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"removeVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"strategy","type":"address"},{"internalType":"uint256","name":"gain","type":"uint256"},{"internalType":"uint256","name":"loss","type":"uint256"}],"name":"report","outputs":[{"internalType":"uint256","name":"totalFees","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"uint16","name":"customMaxGain","type":"uint16"},{"internalType":"uint16","name":"customMaxLoss","type":"uint16"}],"name":"setCustomConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newFeeRecipient","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_futureFeeManager","type":"address"}],"name":"setFutureFeeManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxLoss","type":"uint256"}],"name":"setMaxLoss","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newVaultManager","type":"address"}],"name":"setVaultManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"strategy","type":"address"}],"name":"turnOffHealthCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"defaultMaxGain","type":"uint16"},{"internalType":"uint16","name":"defaultMaxLoss","type":"uint16"}],"name":"updateDefaultConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"useCustomConfig","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"vaults","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":"0x000000000000000000000000285e3b1e82f74a99d07d2ad25e159e75382bb43b000000000000000000000000285e3b1e82f74a99d07d2ad25e159e75382bb43b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002710"}