S Price: $0.47072 (-4.68%)
    /

    Contract Diff Checker

    Contract Name:
    VaultProxy

    Contract Source Code:

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.23;
    
    import "../../core/base/UpgradeableProxy.sol";
    import "../../interfaces/IControllable.sol";
    import "../../interfaces/IPlatform.sol";
    import "../../interfaces/IFactory.sol";
    import "../../interfaces/IVaultProxy.sol";
    
    /// @title EIP1967 Upgradeable proxy implementation for built by factory vaults
    /// @author Alien Deployer (https://github.com/a17)
    contract VaultProxy is UpgradeableProxy, IVaultProxy {
        /// @dev Vault type ID
        bytes32 private constant _TYPE_SLOT = bytes32(uint(keccak256("eip1967.vaultProxy.type")) - 1);
    
        /// @inheritdoc IVaultProxy
        function initProxy(string memory type_) external {
            bytes32 typeHash = keccak256(abi.encodePacked(type_));
            //slither-disable-next-line unused-return
            (, address vaultImplementation,,,) = IFactory(msg.sender).vaultConfig(typeHash);
            _init(vaultImplementation);
            bytes32 slot = _TYPE_SLOT;
            //slither-disable-next-line assembly
            assembly {
                sstore(slot, typeHash)
            }
        }
    
        /// @inheritdoc IVaultProxy
        function upgrade() external {
            if (msg.sender != IPlatform(IControllable(address(this)).platform()).factory()) {
                revert ProxyForbidden();
            }
            bytes32 typeHash;
            bytes32 slot = _TYPE_SLOT;
            //slither-disable-next-line assembly
            assembly {
                typeHash := sload(slot)
            }
            //slither-disable-next-line unused-return
            (, address vaultImplementation,,,) = IFactory(msg.sender).vaultConfig(typeHash);
            _upgradeTo(vaultImplementation);
        }
    
        /// @inheritdoc IVaultProxy
        function implementation() external view returns (address) {
            return _implementation();
        }
    
        /// @inheritdoc IVaultProxy
        function vaultTypeHash() external view returns (bytes32) {
            bytes32 typeHash;
            bytes32 slot = _TYPE_SLOT;
            //slither-disable-next-line assembly
            assembly {
                typeHash := sload(slot)
            }
            return typeHash;
        }
    }

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.23;
    
    /// @title Simple ERC-1967 upgradeable proxy implementation
    abstract contract UpgradeableProxy {
        error ImplementationIsNotContract();
    
        /// @dev This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
        bytes32 private constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
    
        /// @dev Emitted when the implementation is upgraded.
        event Upgraded(address indexed implementation);
    
        constructor() {
            assert(_IMPLEMENTATION_SLOT == bytes32(uint(keccak256("eip1967.proxy.implementation")) - 1));
        }
    
        /// @dev Post deploy initialisation for compatability with EIP-1167 factory
        function _init(address _logic) internal {
            // nosemgrep
            require(_implementation() == address(0), "Already inited");
            _setImplementation(_logic);
        }
    
        /// @dev Returns the current implementation address.
        function _implementation() internal view virtual returns (address impl) {
            bytes32 slot = _IMPLEMENTATION_SLOT;
            // solhint-disable-next-line no-inline-assembly
            //slither-disable-next-line assembly
            assembly {
                impl := sload(slot)
            }
        }
    
        /// @dev Upgrades the proxy to a new implementation.
        function _upgradeTo(address newImplementation) internal virtual {
            _setImplementation(newImplementation);
            emit Upgraded(newImplementation);
        }
    
        /// @dev Stores a new address in the EIP1967 implementation slot.
        function _setImplementation(address newImplementation) private {
            if (newImplementation.code.length == 0) revert ImplementationIsNotContract();
            bytes32 slot = _IMPLEMENTATION_SLOT;
            // solhint-disable-next-line no-inline-assembly
            //slither-disable-next-line assembly
            assembly {
                sstore(slot, newImplementation)
            }
        }
    
        /**
         * @dev Delegates the current call to `implementation`.
         *
         * This function does not return to its internal call site, it will return directly to the external caller.
         */
        function _delegate(address implementation) internal virtual {
            //slither-disable-next-line assembly
            assembly {
                // Copy msg.data. We take full control of memory in this inline assembly
                // block because it will not return to Solidity code. We overwrite the
                // Solidity scratch pad at memory position 0.
                calldatacopy(0, 0, calldatasize())
    
                // Call the implementation.
                // out and outsize are 0 because we don't know the size yet.
                let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
    
                // Copy the returned data.
                returndatacopy(0, 0, returndatasize())
    
                switch result
                // delegatecall returns 0 on error.
                case 0 { revert(0, returndatasize()) }
                default { return(0, returndatasize()) }
            }
        }
    
        /**
         * @dev Delegates the current call to the address returned by `_implementation()`.
         *
         * This function does not return to its internal call site, it will return directly to the external caller.
         */
        function _fallback() internal virtual {
            _delegate(_implementation());
        }
    
        /// @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
        /// function in the contract matches the call data.
        //slither-disable-next-line locked-ether
        fallback() external payable virtual {
            _fallback();
        }
    
        /// @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
        /// is empty.
        //slither-disable-next-line locked-ether
        receive() external payable virtual {
            _fallback();
        }
    }

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.23;
    
    /// @dev Base core interface implemented by most platform contracts.
    ///      Inherited contracts store an immutable Platform proxy address in the storage,
    ///      which provides authorization capabilities and infrastructure contract addresses.
    /// @author Alien Deployer (https://github.com/a17)
    /// @author JodsMigel (https://github.com/JodsMigel)
    interface IControllable {
        //region ----- Custom Errors -----
        error IncorrectZeroArgument();
        error IncorrectMsgSender();
        error NotGovernance();
        error NotMultisig();
        error NotGovernanceAndNotMultisig();
        error NotOperator();
        error NotFactory();
        error NotPlatform();
        error NotVault();
        error IncorrectArrayLength();
        error AlreadyExist();
        error NotExist();
        error NotTheOwner();
        error ETHTransferFailed();
        error IncorrectInitParams();
        //endregion -- Custom Errors -----
    
        event ContractInitialized(address platform, uint ts, uint block);
    
        /// @notice Stability Platform main contract address
        function platform() external view returns (address);
    
        /// @notice Version of contract implementation
        /// @dev SemVer scheme MAJOR.MINOR.PATCH
        //slither-disable-next-line naming-convention
        function VERSION() external view returns (string memory);
    
        /// @notice Block number when contract was initialized
        function createdBlock() external view returns (uint);
    }

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.23;
    
    /// @notice Interface of the main contract and entry point to the platform.
    /// @author Alien Deployer (https://github.com/a17)
    /// @author Jude (https://github.com/iammrjude)
    /// @author JodsMigel (https://github.com/JodsMigel)
    interface IPlatform {
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                       CUSTOM ERRORS                        */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        error AlreadyAnnounced();
        error SameVersion();
        error NoNewVersion();
        error UpgradeTimerIsNotOver(uint TimerTimestamp);
        error IncorrectFee(uint minFee, uint maxFee);
        error NotEnoughAllowedBBToken();
        error TokenAlreadyExistsInSet(address token);
        error AggregatorNotExists(address dexAggRouter);
    
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                           EVENTS                           */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        event PlatformVersion(string version);
        event UpgradeAnnounce(
            string oldVersion, string newVersion, address[] proxies, address[] newImplementations, uint timelock
        );
        event CancelUpgrade(string oldVersion, string newVersion);
        event ProxyUpgraded(
            address indexed proxy, address implementation, string oldContractVersion, string newContractVersion
        );
        event Addresses(
            address multisig_,
            address factory_,
            address priceReader_,
            address swapper_,
            address buildingPermitToken_,
            address vaultManager_,
            address strategyLogic_,
            address aprOracle_,
            address hardWorker,
            address rebalancer,
            address zap,
            address bridge
        );
        event OperatorAdded(address operator);
        event OperatorRemoved(address operator);
        event FeesChanged(uint fee, uint feeShareVaultManager, uint feeShareStrategyLogic, uint feeShareEcosystem);
        event MinInitialBoostChanged(uint minInitialBoostPerDay, uint minInitialBoostDuration);
        event NewAmmAdapter(string id, address proxy);
        event EcosystemRevenueReceiver(address receiver);
        event SetAllowedBBTokenVaults(address bbToken, uint vaultsToBuild, bool firstSet);
        event RemoveAllowedBBToken(address bbToken);
        event AddAllowedBoostRewardToken(address token);
        event RemoveAllowedBoostRewardToken(address token);
        event AddDefaultBoostRewardToken(address token);
        event RemoveDefaultBoostRewardToken(address token);
        event AddBoostTokens(address[] allowedBoostRewardToken, address[] defaultBoostRewardToken);
        event AllowedBBTokenVaultUsed(address bbToken, uint vaultToUse);
        event AddDexAggregator(address router);
        event RemoveDexAggregator(address router);
        event MinTvlForFreeHardWorkChanged(uint oldValue, uint newValue);
        event CustomVaultFee(address vault, uint platformFee);
        event Rebalancer(address rebalancer_);
        event Bridge(address bridge_);
    
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                         DATA TYPES                         */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        struct PlatformUpgrade {
            string newVersion;
            address[] proxies;
            address[] newImplementations;
        }
    
        struct PlatformSettings {
            string networkName;
            bytes32 networkExtra;
            uint fee;
            uint feeShareVaultManager;
            uint feeShareStrategyLogic;
            uint feeShareEcosystem;
            uint minInitialBoostPerDay;
            uint minInitialBoostDuration;
        }
    
        struct AmmAdapter {
            string id;
            address proxy;
        }
    
        struct SetupAddresses {
            address factory;
            address priceReader;
            address swapper;
            address buildingPermitToken;
            address buildingPayPerVaultToken;
            address vaultManager;
            address strategyLogic;
            address aprOracle;
            address targetExchangeAsset;
            address hardWorker;
            address zap;
            address bridge;
            address rebalancer;
        }
    
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                      VIEW FUNCTIONS                        */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        /// @notice Platform version in CalVer scheme: YY.MM.MINOR-tag. Updates on core contract upgrades.
        function platformVersion() external view returns (string memory);
    
        /// @notice Time delay for proxy upgrades of core contracts and changing important platform settings by multisig
        //slither-disable-next-line naming-convention
        function TIME_LOCK() external view returns (uint);
    
        /// @notice DAO governance
        function governance() external view returns (address);
    
        /// @notice Core team multi signature wallet. Development and operations fund
        function multisig() external view returns (address);
    
        /// @notice This NFT allow user to build limited number of vaults per week
        function buildingPermitToken() external view returns (address);
    
        /// @notice This ERC20 token is used as payment token for vault building
        function buildingPayPerVaultToken() external view returns (address);
    
        /// @notice Receiver of ecosystem revenue
        function ecosystemRevenueReceiver() external view returns (address);
    
        /// @dev The best asset in a network for swaps between strategy assets and farms rewards assets
        ///      The target exchange asset is used for finding the best strategy's exchange asset.
        ///      Rhe fewer routes needed to swap to the target exchange asset, the better.
        function targetExchangeAsset() external view returns (address);
    
        /// @notice Platform factory assembling vaults. Stores settings, strategy logic, farms.
        /// Provides the opportunity to upgrade vaults and strategies.
        /// @return Address of Factory proxy
        function factory() external view returns (address);
    
        /// @notice The holders of these NFT receive a share of the vault revenue
        /// @return Address of VaultManager proxy
        function vaultManager() external view returns (address);
    
        /// @notice The holders of these tokens receive a share of the revenue received in all vaults using this strategy logic.
        function strategyLogic() external view returns (address);
    
        /// @notice Combining oracle and DeX spot prices
        /// @return Address of PriceReader proxy
        function priceReader() external view returns (address);
    
        /// @notice Providing underlying assets APRs on-chain
        /// @return Address of AprOracle proxy
        function aprOracle() external view returns (address);
    
        /// @notice On-chain price quoter and swapper
        /// @return Address of Swapper proxy
        function swapper() external view returns (address);
    
        /// @notice HardWork resolver and caller
        /// @return Address of HardWorker proxy
        function hardWorker() external view returns (address);
    
        /// @notice Rebalance resolver
        /// @return Address of Rebalancer proxy
        function rebalancer() external view returns (address);
    
        /// @notice ZAP feature
        /// @return Address of Zap proxy
        function zap() external view returns (address);
    
        /// @notice Stability Bridge
        /// @return Address of Bridge proxy
        function bridge() external view returns (address);
    
        /// @notice Name of current EVM network
        function networkName() external view returns (string memory);
    
        /// @notice Minimal initial boost rewards per day USD amount which needs to create rewarding vault
        function minInitialBoostPerDay() external view returns (uint);
    
        /// @notice Minimal boost rewards vesting duration for initial boost
        function minInitialBoostDuration() external view returns (uint);
    
        /// @notice This function provides the timestamp of the platform upgrade timelock.
        /// @dev This function is an external view function, meaning it doesn't modify the state.
        /// @return uint representing the timestamp of the platform upgrade timelock.
        function platformUpgradeTimelock() external view returns (uint);
    
        /// @dev Extra network data
        /// @return 0-2 bytes - color
        ///         3-5 bytes - background color
        ///         6-31 bytes - free
        function networkExtra() external view returns (bytes32);
    
        /// @notice Pending platform upgrade data
        function pendingPlatformUpgrade() external view returns (PlatformUpgrade memory);
    
        /// @notice Get platform revenue fee settings
        /// @return fee Revenue fee % (between MIN_FEE - MAX_FEE) with DENOMINATOR precision.
        /// @return feeShareVaultManager Revenue fee share % of VaultManager tokenId owner
        /// @return feeShareStrategyLogic Revenue fee share % of StrategyLogic tokenId owner
        /// @return feeShareEcosystem Revenue fee share % of ecosystemFeeReceiver
        function getFees()
            external
            view
            returns (uint fee, uint feeShareVaultManager, uint feeShareStrategyLogic, uint feeShareEcosystem);
    
        /// @notice Get custom vault platform fee
        /// @return fee revenue fee % with DENOMINATOR precision
        function getCustomVaultFee(address vault) external view returns (uint fee);
    
        /// @notice Platform settings
        function getPlatformSettings() external view returns (PlatformSettings memory);
    
        /// @notice AMM adapters of the platform
        function getAmmAdapters() external view returns (string[] memory id, address[] memory proxy);
    
        /// @notice Get AMM adapter data by hash
        /// @param ammAdapterIdHash Keccak256 hash of adapter ID string
        /// @return ID string and proxy address of AMM adapter
        function ammAdapter(bytes32 ammAdapterIdHash) external view returns (AmmAdapter memory);
    
        /// @notice Allowed buy-back tokens for rewarding vaults
        function allowedBBTokens() external view returns (address[] memory);
    
        /// @notice Vaults building limit for buy-back token.
        /// This limit decrements when a vault for BB-token is built.
        /// @param token Allowed buy-back token
        /// @return vaultsLimit Number of vaults that can be built for BB-token
        function allowedBBTokenVaults(address token) external view returns (uint vaultsLimit);
    
        /// @notice Vaults building limits for allowed buy-back tokens.
        /// @return bbToken Allowed buy-back tokens
        /// @return vaultsLimit Number of vaults that can be built for BB-tokens
        function allowedBBTokenVaults() external view returns (address[] memory bbToken, uint[] memory vaultsLimit);
    
        /// @notice Non-zero vaults building limits for allowed buy-back tokens.
        /// @return bbToken Allowed buy-back tokens
        /// @return vaultsLimit Number of vaults that can be built for BB-tokens
        function allowedBBTokenVaultsFiltered()
            external
            view
            returns (address[] memory bbToken, uint[] memory vaultsLimit);
    
        /// @notice Check address for existance in operators list
        /// @param operator Address
        /// @return True if this address is Stability Operator
        function isOperator(address operator) external view returns (bool);
    
        /// @notice Tokens that can be used for boost rewards of rewarding vaults
        /// @return Addresses of tokens
        function allowedBoostRewardTokens() external view returns (address[] memory);
    
        /// @notice Allowed boost reward tokens that used for unmanaged rewarding vaults creation
        /// @return Addresses of tokens
        function defaultBoostRewardTokens() external view returns (address[] memory);
    
        /// @notice Allowed boost reward tokens that used for unmanaged rewarding vaults creation
        /// @param addressToRemove This address will be removed from default boost reward tokens
        /// @return Addresses of tokens
        function defaultBoostRewardTokensFiltered(address addressToRemove) external view returns (address[] memory);
    
        /// @notice Allowed DeX aggregators
        /// @return Addresses of DeX aggregator rounters
        function dexAggregators() external view returns (address[] memory);
    
        /// @notice DeX aggregator router address is allowed to be used in the platform
        /// @param dexAggRouter Address of DeX aggreagator router
        /// @return Can be used
        function isAllowedDexAggregatorRouter(address dexAggRouter) external view returns (bool);
    
        /// @notice Show minimum TVL for compensate if vault has not enough ETH
        /// @return Minimum TVL for compensate.
        function minTvlForFreeHardWork() external view returns (uint);
    
        /// @notice Front-end platform viewer
        /// @return platformAddresses Platform core addresses
        ///        platformAddresses[0] factory
        ///        platformAddresses[1] vaultManager
        ///        platformAddresses[2] strategyLogic
        ///        platformAddresses[3] buildingPermitToken
        ///        platformAddresses[4] buildingPayPerVaultToken
        ///        platformAddresses[5] governance
        ///        platformAddresses[6] multisig
        ///        platformAddresses[7] zap
        ///        platformAddresses[8] bridge
        /// @return bcAssets Blue chip token addresses
        /// @return dexAggregators_ DeX aggregators allowed to be used entire the platform
        /// @return vaultType Vault type ID strings
        /// @return vaultExtra Vault color, background color and other extra data. Index of vault same as in previous array.
        /// @return vaultBulldingPrice Price of creating new vault in buildingPayPerVaultToken. Index of vault same as in previous array.
        /// @return strategyId Strategy logic ID strings
        /// @return isFarmingStrategy True if strategy is farming strategy. Index of strategy same as in previous array.
        /// @return strategyTokenURI StrategyLogic NFT tokenId metadata and on-chain image. Index of strategy same as in previous array.
        /// @return strategyExtra Strategy color, background color and other extra data. Index of strategy same as in previous array.
        function getData()
            external
            view
            returns (
                address[] memory platformAddresses,
                address[] memory bcAssets,
                address[] memory dexAggregators_,
                string[] memory vaultType,
                bytes32[] memory vaultExtra,
                uint[] memory vaultBulldingPrice,
                string[] memory strategyId,
                bool[] memory isFarmingStrategy,
                string[] memory strategyTokenURI,
                bytes32[] memory strategyExtra
            );
    
        // todo add vaultSymbol, vaultName
        /// @notice Front-end balances, prices and vault list viewer
        /// @param yourAccount Address of account to query balances
        /// @return token Tokens supported by the platform
        /// @return tokenPrice USD price of token. Index of token same as in previous array.
        /// @return tokenUserBalance User balance of token. Index of token same as in previous array.
        /// @return vault Deployed vaults
        /// @return vaultSharePrice Price 1.0 vault share. Index of vault same as in previous array.
        /// @return vaultUserBalance User balance of vault. Index of vault same as in previous array.
        /// @return nft Ecosystem NFTs
        ///         nft[0] BuildingPermitToken
        ///         nft[1] VaultManager
        ///         nft[2] StrategyLogic
        /// @return nftUserBalance User balance of NFT. Index of NFT same as in previous array.
        /// @return buildingPayPerVaultTokenBalance User balance of vault creation paying token
        function getBalance(address yourAccount)
            external
            view
            returns (
                address[] memory token,
                uint[] memory tokenPrice,
                uint[] memory tokenUserBalance,
                address[] memory vault,
                uint[] memory vaultSharePrice,
                uint[] memory vaultUserBalance,
                address[] memory nft,
                uint[] memory nftUserBalance,
                uint buildingPayPerVaultTokenBalance
            );
    
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                      WRITE FUNCTIONS                       */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        /// @notice Add platform operator.
        /// Only governance and multisig can add operator.
        /// @param operator Address of new operator
        function addOperator(address operator) external;
    
        /// @notice Remove platform operator.
        /// Only governance and multisig can remove operator.
        /// @param operator Address of operator to remove
        function removeOperator(address operator) external;
    
        /// @notice Announce upgrade of platform proxies implementations
        /// Only governance and multisig can announce platform upgrades.
        /// @param newVersion New platform version. Version must be changed when upgrading.
        /// @param proxies Addresses of core contract proxies
        /// @param newImplementations New implementation for proxy. Index of proxy same as in previous array.
        function announcePlatformUpgrade(
            string memory newVersion,
            address[] memory proxies,
            address[] memory newImplementations
        ) external;
    
        /// @notice Upgrade platform
        /// Only operator (multisig is operator too) can ececute pending platform upgrade
        function upgrade() external;
    
        /// @notice Cancel pending platform upgrade
        /// Only operator (multisig is operator too) can ececute pending platform upgrade
        function cancelUpgrade() external;
    
        /// @notice Register AMM adapter in platform
        /// @param id AMM adapter ID string from AmmAdapterIdLib
        /// @param proxy Address of AMM adapter proxy
        function addAmmAdapter(string memory id, address proxy) external;
    
        // todo Only governance and multisig can set allowed bb-token vaults building limit
        /// @notice Set new vaults building limit for buy-back token
        /// @param bbToken Address of allowed buy-back token
        /// @param vaultsToBuild Number of vaults that can be built for BB-token
        function setAllowedBBTokenVaults(address bbToken, uint vaultsToBuild) external;
    
        // todo Only governance and multisig can add allowed boost reward token
        /// @notice Add new allowed boost reward token
        /// @param token Address of token
        function addAllowedBoostRewardToken(address token) external;
    
        // todo Only governance and multisig can remove allowed boost reward token
        /// @notice Remove allowed boost reward token
        /// @param token Address of allowed boost reward token
        function removeAllowedBoostRewardToken(address token) external;
    
        // todo Only governance and multisig can add default boost reward token
        /// @notice Add default boost reward token
        /// @param token Address of default boost reward token
        function addDefaultBoostRewardToken(address token) external;
    
        // todo Only governance and multisig can remove default boost reward token
        /// @notice Remove default boost reward token
        /// @param token Address of allowed boost reward token
        function removeDefaultBoostRewardToken(address token) external;
    
        // todo Only governance and multisig can add allowed boost reward token
        // todo Only governance and multisig can add default boost reward token
        /// @notice Add new allowed boost reward token
        /// @notice Add default boost reward token
        /// @param allowedBoostRewardToken Address of allowed boost reward token
        /// @param defaultBoostRewardToken Address of default boost reward token
        function addBoostTokens(
            address[] memory allowedBoostRewardToken,
            address[] memory defaultBoostRewardToken
        ) external;
    
        /// @notice Decrease allowed BB-token vault building limit when vault is built
        /// Only Factory can do it.
        /// @param bbToken Address of allowed buy-back token
        function useAllowedBBTokenVault(address bbToken) external;
    
        /// @notice Allow DeX aggregator routers to be used in the platform
        /// @param dexAggRouter Addresses of DeX aggreagator routers
        function addDexAggregators(address[] memory dexAggRouter) external;
    
        /// @notice Remove allowed DeX aggregator router from the platform
        /// @param dexAggRouter Address of DeX aggreagator router
        function removeDexAggregator(address dexAggRouter) external;
    
        /// @notice Change initial boost rewards settings
        /// @param minInitialBoostPerDay_ Minimal initial boost rewards per day USD amount which needs to create rewarding vault
        /// @param minInitialBoostDuration_ Minimal boost rewards vesting duration for initial boost
        function setInitialBoost(uint minInitialBoostPerDay_, uint minInitialBoostDuration_) external;
    
        /// @notice Update new minimum TVL for compensate.
        /// @param value New minimum TVL for compensate.
        function setMinTvlForFreeHardWork(uint value) external;
    
        /// @notice Set custom platform fee for vault
        /// @param vault Vault address
        /// @param platformFee Custom platform fee
        function setCustomVaultFee(address vault, uint platformFee) external;
    
        /// @notice Setup Rebalancer.
        /// Only Goverannce or Multisig can do this when Rebalancer is not set.
        /// @param rebalancer_ Proxy address of Bridge
        function setupRebalancer(address rebalancer_) external;
    
        /// @notice Setup Bridge.
        /// Only Goverannce or Multisig can do this when Bridge is not set.
        /// @param bridge_ Proxy address of Bridge
        function setupBridge(address bridge_) external;
    }

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.23;
    
    import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
    
    /// @notice Creating vaults, upgrading vaults and strategies, vault list, farms and strategy logics management
    /// @author Alien Deployer (https://github.com/a17)
    /// @author Jude (https://github.com/iammrjude)
    /// @author JodsMigel (https://github.com/JodsMigel)
    /// @author HCrypto7 (https://github.com/hcrypto7)
    interface IFactory {
        //region ----- Custom Errors -----
    
        error VaultImplementationIsNotAvailable();
        error VaultNotAllowedToDeploy();
        error StrategyImplementationIsNotAvailable();
        error StrategyLogicNotAllowedToDeploy();
        error YouDontHaveEnoughTokens(uint userBalance, uint requireBalance, address payToken);
        error SuchVaultAlreadyDeployed(bytes32 key);
        error NotActiveVault();
        error UpgradeDenied(bytes32 _hash);
        error AlreadyLastVersion(bytes32 _hash);
        error NotStrategy();
        error BoostDurationTooLow();
        error BoostAmountTooLow();
        error BoostAmountIsZero();
    
        //endregion ----- Custom Errors -----
    
        //region ----- Events -----
    
        event VaultAndStrategy(
            address indexed deployer,
            string vaultType,
            string strategyId,
            address vault,
            address strategy,
            string name,
            string symbol,
            address[] assets,
            bytes32 deploymentKey,
            uint vaultManagerTokenId
        );
        event StrategyProxyUpgraded(address proxy, address oldImplementation, address newImplementation);
        event VaultProxyUpgraded(address proxy, address oldImplementation, address newImplementation);
        event VaultConfigChanged(
            string type_, address implementation, bool deployAllowed, bool upgradeAllowed, bool newVaultType
        );
        event StrategyLogicConfigChanged(
            string id, address implementation, bool deployAllowed, bool upgradeAllowed, bool newStrategy
        );
        event VaultStatus(address indexed vault, uint newStatus);
        event NewFarm(Farm[] farms);
        event UpdateFarm(uint id, Farm farm);
        event SetStrategyAvailableInitParams(string id, address[] initAddresses, uint[] initNums, int24[] initTicks);
        event AliasNameChanged(address indexed operator, address indexed tokenAddress, string newAliasName);
    
        //endregion -- Events -----
    
        //region ----- Data types -----
    
        /// @custom:storage-location erc7201:stability.Factory
        struct FactoryStorage {
            /// @inheritdoc IFactory
            mapping(bytes32 typeHash => VaultConfig) vaultConfig;
            /// @inheritdoc IFactory
            mapping(bytes32 idHash => StrategyLogicConfig) strategyLogicConfig;
            /// @inheritdoc IFactory
            mapping(bytes32 deploymentKey => address vaultProxy) deploymentKey;
            /// @inheritdoc IFactory
            mapping(address vault => uint status) vaultStatus;
            /// @inheritdoc IFactory
            mapping(address address_ => bool isStrategy_) isStrategy;
            EnumerableSet.Bytes32Set vaultTypeHashes;
            EnumerableSet.Bytes32Set strategyLogicIdHashes;
            mapping(uint week => mapping(uint builderPermitTokenId => uint vaultsBuilt)) vaultsBuiltByPermitTokenId;
            address[] deployedVaults;
            Farm[] farms;
            /// @inheritdoc IFactory
            mapping(bytes32 idHash => StrategyAvailableInitParams) strategyAvailableInitParams;
            mapping(address tokenAddress => string aliasName) aliasNames;
        }
    
        struct VaultConfig {
            string vaultType;
            address implementation;
            bool deployAllowed;
            bool upgradeAllowed;
            uint buildingPrice;
        }
    
        struct StrategyLogicConfig {
            string id;
            address implementation;
            bool deployAllowed;
            bool upgradeAllowed;
            bool farming;
            uint tokenId;
        }
    
        struct Farm {
            uint status;
            address pool;
            string strategyLogicId;
            address[] rewardAssets;
            address[] addresses;
            uint[] nums;
            int24[] ticks;
        }
    
        struct StrategyAvailableInitParams {
            address[] initAddresses;
            uint[] initNums;
            int24[] initTicks;
        }
    
        //endregion -- Data types -----
    
        //region ----- View functions -----
    
        /// @notice All vaults deployed by the factory
        /// @return Vault proxy addresses
        function deployedVaults() external view returns (address[] memory);
    
        /// @notice Total vaults deployed
        function deployedVaultsLength() external view returns (uint);
    
        /// @notice Get vault by VaultManager tokenId
        /// @param id Vault array index. Same as tokenId of VaultManager NFT
        /// @return Address of VaultProxy
        function deployedVault(uint id) external view returns (address);
    
        /// @notice All farms known by the factory in current network
        function farms() external view returns (Farm[] memory);
    
        /// @notice Total farms known by the factory in current network
        function farmsLength() external view returns (uint);
    
        /// @notice Farm data by farm index
        /// @param id Index of farm
        function farm(uint id) external view returns (Farm memory);
    
        /// @notice Strategy logic settings
        /// @param idHash keccak256 hash of strategy logic string ID
        /// @return config Strategy logic settings
        function strategyLogicConfig(bytes32 idHash) external view returns (StrategyLogicConfig memory config);
    
        /// @notice All known strategies
        /// @return Array of keccak256 hashes of strategy logic string ID
        function strategyLogicIdHashes() external view returns (bytes32[] memory);
    
        // todo remove, use new function without calculating vault symbol on the fly for not initialized vaults
        // factory required that special functionally only internally, not for interface
        function getStrategyData(
            string memory vaultType,
            address strategyAddress,
            address bbAsset
        )
            external
            view
            returns (
                string memory strategyId,
                address[] memory assets,
                string[] memory assetsSymbols,
                string memory specificName,
                string memory vaultSymbol
            );
    
        /// @dev Get best asset of assets to be strategy exchange asset
        function getExchangeAssetIndex(address[] memory assets) external view returns (uint);
    
        /// @notice Deployment key of created vault
        /// @param deploymentKey_ Hash of concatenated unique vault and strategy initialization parameters
        /// @return Address of deployed vault
        function deploymentKey(bytes32 deploymentKey_) external view returns (address);
    
        /// @notice Calculating deployment key based on unique vault and strategy initialization parameters
        /// @param vaultType Vault type string
        /// @param strategyId Strategy logic Id string
        /// @param vaultInitAddresses Vault initizlization addresses for deployVaultAndStrategy method
        /// @param vaultInitNums Vault initizlization uint numbers for deployVaultAndStrategy method
        /// @param strategyInitAddresses Strategy initizlization addresses for deployVaultAndStrategy method
        /// @param strategyInitNums Strategy initizlization uint numbers for deployVaultAndStrategy method
        /// @param strategyInitTicks Strategy initizlization int24 ticks for deployVaultAndStrategy method
        function getDeploymentKey(
            string memory vaultType,
            string memory strategyId,
            address[] memory vaultInitAddresses,
            uint[] memory vaultInitNums,
            address[] memory strategyInitAddresses,
            uint[] memory strategyInitNums,
            int24[] memory strategyInitTicks
        ) external returns (bytes32);
    
        /// @notice Available variants of new vault for creating.
        /// The structure of the function's output values is complex,
        /// but after parsing them, the front end has all the data to generate a list of vaults to create.
        /// @return desc Descriptions of the strategy for making money
        /// @return vaultType Vault type strings. Output values are matched by index with previous array.
        /// @return strategyId Strategy logic ID strings. Output values are matched by index with previous array.
        /// @return initIndexes Map of start and end indexes in next 5 arrays. Output values are matched by index with previous array.
        ///                 [0] Start index in vaultInitAddresses
        ///                 [1] End index in vaultInitAddresses
        ///                 [2] Start index in vaultInitNums
        ///                 [3] End index in vaultInitNums
        ///                 [4] Start index in strategyInitAddresses
        ///                 [5] End index in strategyInitAddresses
        ///                 [6] Start index in strategyInitNums
        ///                 [7] End index in strategyInitNums
        ///                 [8] Start index in strategyInitTicks
        ///                 [9] End index in strategyInitTicks
        /// @return vaultInitAddresses Vault initizlization addresses for deployVaultAndStrategy method for all building variants.
        /// @return vaultInitNums Vault initizlization uint numbers for deployVaultAndStrategy method for all building variants.
        /// @return strategyInitAddresses Strategy initizlization addresses for deployVaultAndStrategy method for all building variants.
        /// @return strategyInitNums Strategy initizlization uint numbers for deployVaultAndStrategy method for all building variants.
        /// @return strategyInitTicks Strategy initizlization int24 ticks for deployVaultAndStrategy method for all building variants.
        function whatToBuild()
            external
            view
            returns (
                string[] memory desc,
                string[] memory vaultType,
                string[] memory strategyId,
                uint[10][] memory initIndexes,
                address[] memory vaultInitAddresses,
                uint[] memory vaultInitNums,
                address[] memory strategyInitAddresses,
                uint[] memory strategyInitNums,
                int24[] memory strategyInitTicks
            );
    
        /// @notice Governance and multisig can set a vault status other than Active - the default status.
        /// HardWorker only works with active vaults.
        /// @return status Constant from VaultStatusLib
        function vaultStatus(address vault) external view returns (uint status);
    
        /// @notice Check that strategy proxy deployed by the Factory
        /// @param address_ Address of contract
        /// @return This address is our strategy proxy
        function isStrategy(address address_) external view returns (bool);
    
        /// @notice How much vaults was built by builderPermitToken NFT tokenId in week
        /// @param week Week index (timestamp / (86400 * 7))
        /// @param builderPermitTokenId Token ID of buildingPermitToken NFT
        /// @return vaultsBuilt Vaults built
        function vaultsBuiltByPermitTokenId(
            uint week,
            uint builderPermitTokenId
        ) external view returns (uint vaultsBuilt);
    
        /// @notice Data on all factory strategies.
        /// The output values are matched by index in the arrays.
        /// @return id Strategy logic ID strings
        /// @return deployAllowed New vaults can be deployed
        /// @return upgradeAllowed Strategy can be upgraded
        /// @return farming It is farming strategy (earns farming/gauge rewards)
        /// @return tokenId Token ID of StrategyLogic NFT
        /// @return tokenURI StrategyLogic NFT tokenId metadata and on-chain image
        /// @return extra Strategy color, background color and other extra data
        function strategies()
            external
            view
            returns (
                string[] memory id,
                bool[] memory deployAllowed,
                bool[] memory upgradeAllowed,
                bool[] memory farming,
                uint[] memory tokenId,
                string[] memory tokenURI,
                bytes32[] memory extra
            );
    
        /// @notice Get config of vault type
        /// @param typeHash Keccak256 hash of vault type string
        /// @return vaultType Vault type string
        /// @return implementation Vault implementation address
        /// @return deployAllowed New vaults can be deployed
        /// @return upgradeAllowed Vaults can be upgraded
        /// @return buildingPrice Price of building new vault
        function vaultConfig(bytes32 typeHash)
            external
            view
            returns (
                string memory vaultType,
                address implementation,
                bool deployAllowed,
                bool upgradeAllowed,
                uint buildingPrice
            );
    
        /// @notice Data on all factory vault types
        /// The output values are matched by index in the arrays.
        /// @return vaultType Vault type string
        /// @return implementation Address of vault implemented logic
        /// @return deployAllowed New vaults can be deployed
        /// @return upgradeAllowed Vaults can be upgraded
        /// @return buildingPrice  Price of building new vault
        /// @return extra Vault type color, background color and other extra data
        function vaultTypes()
            external
            view
            returns (
                string[] memory vaultType,
                address[] memory implementation,
                bool[] memory deployAllowed,
                bool[] memory upgradeAllowed,
                uint[] memory buildingPrice,
                bytes32[] memory extra
            );
    
        /// @notice Initialization strategy params store
        function strategyAvailableInitParams(bytes32 idHash) external view returns (StrategyAvailableInitParams memory);
    
        /// @notice Retrieves the alias name associated with a given address
        /// @param tokenAddress_ The address to query for its alias name
        /// @return The alias name associated with the provided address
        function getAliasName(address tokenAddress_) external view returns (string memory);
    
        //endregion -- View functions -----
    
        //region ----- Write functions -----
    
        /// @notice Main method of the Factory - new vault creation by user.
        /// @param vaultType Vault type ID string
        /// @param strategyId Strategy logic ID string
        /// Different types of vaults and strategies have different lengths of input arrays.
        /// @param vaultInitAddresses Addresses for vault initialization
        /// @param vaultInitNums Numbers for vault initialization
        /// @param strategyInitAddresses Addresses for strategy initialization
        /// @param strategyInitNums Numbers for strategy initialization
        /// @param strategyInitTicks Ticks for strategy initialization
        /// @return vault Deployed VaultProxy address
        /// @return strategy Deployed StrategyProxy address
        function deployVaultAndStrategy(
            string memory vaultType,
            string memory strategyId,
            address[] memory vaultInitAddresses,
            uint[] memory vaultInitNums,
            address[] memory strategyInitAddresses,
            uint[] memory strategyInitNums,
            int24[] memory strategyInitTicks
        ) external returns (address vault, address strategy);
    
        /// @notice Upgrade vault proxy. Can be called by any address.
        /// @param vault Address of vault proxy for upgrade
        function upgradeVaultProxy(address vault) external;
    
        /// @notice Upgrade strategy proxy. Can be called by any address.
        /// @param strategy Address of strategy proxy for upgrade
        function upgradeStrategyProxy(address strategy) external;
    
        /// @notice Add farm to factory
        /// @param farms_ Settings and data required to work with the farm.
        function addFarms(Farm[] memory farms_) external;
    
        /// @notice Update farm
        /// @param id Farm index
        /// @param farm_ Settings and data required to work with the farm.
        function updateFarm(uint id, Farm memory farm_) external;
    
        /// @notice Initial addition or change of vault type settings.
        /// Operator can add new vault type. Governance or multisig can change existing vault type config.
        /// @param vaultConfig_ Vault type settings
        function setVaultConfig(VaultConfig memory vaultConfig_) external;
    
        /// @notice Initial addition or change of strategy logic settings.
        /// Operator can add new strategy logic. Governance or multisig can change existing logic config.
        /// @param config Strategy logic settings
        /// @param developer Strategy developer is receiver of minted StrategyLogic NFT on initial addition
        function setStrategyLogicConfig(StrategyLogicConfig memory config, address developer) external;
    
        /// @notice Governance and multisig can set a vault status other than Active - the default status.
        /// @param vaults Addresses of vault proxy
        /// @param statuses New vault statuses. Constant from VaultStatusLib
        function setVaultStatus(address[] memory vaults, uint[] memory statuses) external;
    
        /// @notice Initial addition or change of strategy available init params
        /// @param id Strategy ID string
        /// @param initParams Init params variations that will be parsed by strategy
        function setStrategyAvailableInitParams(string memory id, StrategyAvailableInitParams memory initParams) external;
    
        /// @notice Assigns a new alias name to a specific address
        /// @dev This function may require certain permissions to be called successfully.
        /// @param tokenAddress_ The address to assign an alias name to
        /// @param aliasName_ The alias name to assign to the given address
        function setAliasName(address tokenAddress_, string memory aliasName_) external;
    
        //endregion -- Write functions -----
    }

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.23;
    
    /// @dev Interface of proxy contract for a vault implementation
    interface IVaultProxy {
        //region ----- Custom Errors -----
        error ProxyForbidden();
        //endregion -- Custom Errors -----
    
        /// @notice Initialize vault proxy by Factory
        /// @param type_ Vault type ID string
        function initProxy(string memory type_) external;
    
        /// @notice Upgrade vault implementation if available and allowed
        /// Anyone can execute vault upgrade
        function upgrade() external;
    
        /// @notice Current vault implementation
        /// @return Address of vault implementation contract
        function implementation() external view returns (address);
    
        /// @notice Vault type hash
        /// @return keccan256 hash of vault type ID string
        function vaultTypeHash() external view returns (bytes32);
    }

    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
    // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
    
    pragma solidity ^0.8.20;
    
    /**
     * @dev Library for managing
     * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
     * types.
     *
     * Sets have the following properties:
     *
     * - Elements are added, removed, and checked for existence in constant time
     * (O(1)).
     * - Elements are enumerated in O(n). No guarantees are made on the ordering.
     *
     * ```solidity
     * contract Example {
     *     // Add the library methods
     *     using EnumerableSet for EnumerableSet.AddressSet;
     *
     *     // Declare a set state variable
     *     EnumerableSet.AddressSet private mySet;
     * }
     * ```
     *
     * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
     * and `uint256` (`UintSet`) are supported.
     *
     * [WARNING]
     * ====
     * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
     * unusable.
     * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
     *
     * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
     * array of EnumerableSet.
     * ====
     */
    library EnumerableSet {
        // To implement this library for multiple types with as little code
        // repetition as possible, we write it in terms of a generic Set type with
        // bytes32 values.
        // The Set implementation uses private functions, and user-facing
        // implementations (such as AddressSet) are just wrappers around the
        // underlying Set.
        // This means that we can only create new EnumerableSets for types that fit
        // in bytes32.
    
        struct Set {
            // Storage of set values
            bytes32[] _values;
            // Position is the index of the value in the `values` array plus 1.
            // Position 0 is used to mean a value is not in the set.
            mapping(bytes32 value => uint256) _positions;
        }
    
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function _add(Set storage set, bytes32 value) private returns (bool) {
            if (!_contains(set, value)) {
                set._values.push(value);
                // The value is stored at length-1, but we add 1 to all indexes
                // and use 0 as a sentinel value
                set._positions[value] = set._values.length;
                return true;
            } else {
                return false;
            }
        }
    
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function _remove(Set storage set, bytes32 value) private returns (bool) {
            // We cache the value's position to prevent multiple reads from the same storage slot
            uint256 position = set._positions[value];
    
            if (position != 0) {
                // Equivalent to contains(set, value)
                // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
                // the array, and then remove the last element (sometimes called as 'swap and pop').
                // This modifies the order of the array, as noted in {at}.
    
                uint256 valueIndex = position - 1;
                uint256 lastIndex = set._values.length - 1;
    
                if (valueIndex != lastIndex) {
                    bytes32 lastValue = set._values[lastIndex];
    
                    // Move the lastValue to the index where the value to delete is
                    set._values[valueIndex] = lastValue;
                    // Update the tracked position of the lastValue (that was just moved)
                    set._positions[lastValue] = position;
                }
    
                // Delete the slot where the moved value was stored
                set._values.pop();
    
                // Delete the tracked position for the deleted slot
                delete set._positions[value];
    
                return true;
            } else {
                return false;
            }
        }
    
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function _contains(Set storage set, bytes32 value) private view returns (bool) {
            return set._positions[value] != 0;
        }
    
        /**
         * @dev Returns the number of values on the set. O(1).
         */
        function _length(Set storage set) private view returns (uint256) {
            return set._values.length;
        }
    
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function _at(Set storage set, uint256 index) private view returns (bytes32) {
            return set._values[index];
        }
    
        /**
         * @dev Return the entire set in an array
         *
         * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
         * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
         * this function has an unbounded cost, and using it as part of a state-changing function may render the function
         * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
         */
        function _values(Set storage set) private view returns (bytes32[] memory) {
            return set._values;
        }
    
        // Bytes32Set
    
        struct Bytes32Set {
            Set _inner;
        }
    
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
            return _add(set._inner, value);
        }
    
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
            return _remove(set._inner, value);
        }
    
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
            return _contains(set._inner, value);
        }
    
        /**
         * @dev Returns the number of values in the set. O(1).
         */
        function length(Bytes32Set storage set) internal view returns (uint256) {
            return _length(set._inner);
        }
    
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
            return _at(set._inner, index);
        }
    
        /**
         * @dev Return the entire set in an array
         *
         * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
         * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
         * this function has an unbounded cost, and using it as part of a state-changing function may render the function
         * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
         */
        function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
            bytes32[] memory store = _values(set._inner);
            bytes32[] memory result;
    
            /// @solidity memory-safe-assembly
            assembly {
                result := store
            }
    
            return result;
        }
    
        // AddressSet
    
        struct AddressSet {
            Set _inner;
        }
    
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function add(AddressSet storage set, address value) internal returns (bool) {
            return _add(set._inner, bytes32(uint256(uint160(value))));
        }
    
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function remove(AddressSet storage set, address value) internal returns (bool) {
            return _remove(set._inner, bytes32(uint256(uint160(value))));
        }
    
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function contains(AddressSet storage set, address value) internal view returns (bool) {
            return _contains(set._inner, bytes32(uint256(uint160(value))));
        }
    
        /**
         * @dev Returns the number of values in the set. O(1).
         */
        function length(AddressSet storage set) internal view returns (uint256) {
            return _length(set._inner);
        }
    
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function at(AddressSet storage set, uint256 index) internal view returns (address) {
            return address(uint160(uint256(_at(set._inner, index))));
        }
    
        /**
         * @dev Return the entire set in an array
         *
         * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
         * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
         * this function has an unbounded cost, and using it as part of a state-changing function may render the function
         * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
         */
        function values(AddressSet storage set) internal view returns (address[] memory) {
            bytes32[] memory store = _values(set._inner);
            address[] memory result;
    
            /// @solidity memory-safe-assembly
            assembly {
                result := store
            }
    
            return result;
        }
    
        // UintSet
    
        struct UintSet {
            Set _inner;
        }
    
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function add(UintSet storage set, uint256 value) internal returns (bool) {
            return _add(set._inner, bytes32(value));
        }
    
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function remove(UintSet storage set, uint256 value) internal returns (bool) {
            return _remove(set._inner, bytes32(value));
        }
    
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function contains(UintSet storage set, uint256 value) internal view returns (bool) {
            return _contains(set._inner, bytes32(value));
        }
    
        /**
         * @dev Returns the number of values in the set. O(1).
         */
        function length(UintSet storage set) internal view returns (uint256) {
            return _length(set._inner);
        }
    
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function at(UintSet storage set, uint256 index) internal view returns (uint256) {
            return uint256(_at(set._inner, index));
        }
    
        /**
         * @dev Return the entire set in an array
         *
         * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
         * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
         * this function has an unbounded cost, and using it as part of a state-changing function may render the function
         * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
         */
        function values(UintSet storage set) internal view returns (uint256[] memory) {
            bytes32[] memory store = _values(set._inner);
            uint256[] memory result;
    
            /// @solidity memory-safe-assembly
            assembly {
                result := store
            }
    
            return result;
        }
    }

    Contract Name:
    VaultProxy

    Contract Source Code:

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.23;
    
    import "../../core/base/UpgradeableProxy.sol";
    import "../../interfaces/IControllable.sol";
    import "../../interfaces/IPlatform.sol";
    import "../../interfaces/IFactory.sol";
    import "../../interfaces/IVaultProxy.sol";
    
    /// @title EIP1967 Upgradeable proxy implementation for built by factory vaults
    /// @author Alien Deployer (https://github.com/a17)
    contract VaultProxy is UpgradeableProxy, IVaultProxy {
        /// @dev Vault type ID
        bytes32 private constant _TYPE_SLOT = bytes32(uint(keccak256("eip1967.vaultProxy.type")) - 1);
    
        /// @inheritdoc IVaultProxy
        function initProxy(string memory type_) external {
            bytes32 typeHash = keccak256(abi.encodePacked(type_));
            //slither-disable-next-line unused-return
            (, address vaultImplementation,,,) = IFactory(msg.sender).vaultConfig(typeHash);
            _init(vaultImplementation);
            bytes32 slot = _TYPE_SLOT;
            //slither-disable-next-line assembly
            assembly {
                sstore(slot, typeHash)
            }
        }
    
        /// @inheritdoc IVaultProxy
        function upgrade() external {
            if (msg.sender != IPlatform(IControllable(address(this)).platform()).factory()) {
                revert ProxyForbidden();
            }
            bytes32 typeHash;
            bytes32 slot = _TYPE_SLOT;
            //slither-disable-next-line assembly
            assembly {
                typeHash := sload(slot)
            }
            //slither-disable-next-line unused-return
            (, address vaultImplementation,,,) = IFactory(msg.sender).vaultConfig(typeHash);
            _upgradeTo(vaultImplementation);
        }
    
        /// @inheritdoc IVaultProxy
        function implementation() external view returns (address) {
            return _implementation();
        }
    
        /// @inheritdoc IVaultProxy
        function vaultTypeHash() external view returns (bytes32) {
            bytes32 typeHash;
            bytes32 slot = _TYPE_SLOT;
            //slither-disable-next-line assembly
            assembly {
                typeHash := sload(slot)
            }
            return typeHash;
        }
    }

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.23;
    
    /// @title Simple ERC-1967 upgradeable proxy implementation
    abstract contract UpgradeableProxy {
        error ImplementationIsNotContract();
    
        /// @dev This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
        bytes32 private constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
    
        /// @dev Emitted when the implementation is upgraded.
        event Upgraded(address indexed implementation);
    
        constructor() {
            assert(_IMPLEMENTATION_SLOT == bytes32(uint(keccak256("eip1967.proxy.implementation")) - 1));
        }
    
        /// @dev Post deploy initialisation for compatability with EIP-1167 factory
        function _init(address _logic) internal {
            // nosemgrep
            require(_implementation() == address(0), "Already inited");
            _setImplementation(_logic);
        }
    
        /// @dev Returns the current implementation address.
        function _implementation() internal view virtual returns (address impl) {
            bytes32 slot = _IMPLEMENTATION_SLOT;
            // solhint-disable-next-line no-inline-assembly
            //slither-disable-next-line assembly
            assembly {
                impl := sload(slot)
            }
        }
    
        /// @dev Upgrades the proxy to a new implementation.
        function _upgradeTo(address newImplementation) internal virtual {
            _setImplementation(newImplementation);
            emit Upgraded(newImplementation);
        }
    
        /// @dev Stores a new address in the EIP1967 implementation slot.
        function _setImplementation(address newImplementation) private {
            if (newImplementation.code.length == 0) revert ImplementationIsNotContract();
            bytes32 slot = _IMPLEMENTATION_SLOT;
            // solhint-disable-next-line no-inline-assembly
            //slither-disable-next-line assembly
            assembly {
                sstore(slot, newImplementation)
            }
        }
    
        /**
         * @dev Delegates the current call to `implementation`.
         *
         * This function does not return to its internal call site, it will return directly to the external caller.
         */
        function _delegate(address implementation) internal virtual {
            //slither-disable-next-line assembly
            assembly {
                // Copy msg.data. We take full control of memory in this inline assembly
                // block because it will not return to Solidity code. We overwrite the
                // Solidity scratch pad at memory position 0.
                calldatacopy(0, 0, calldatasize())
    
                // Call the implementation.
                // out and outsize are 0 because we don't know the size yet.
                let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
    
                // Copy the returned data.
                returndatacopy(0, 0, returndatasize())
    
                switch result
                // delegatecall returns 0 on error.
                case 0 { revert(0, returndatasize()) }
                default { return(0, returndatasize()) }
            }
        }
    
        /**
         * @dev Delegates the current call to the address returned by `_implementation()`.
         *
         * This function does not return to its internal call site, it will return directly to the external caller.
         */
        function _fallback() internal virtual {
            _delegate(_implementation());
        }
    
        /// @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
        /// function in the contract matches the call data.
        //slither-disable-next-line locked-ether
        fallback() external payable virtual {
            _fallback();
        }
    
        /// @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
        /// is empty.
        //slither-disable-next-line locked-ether
        receive() external payable virtual {
            _fallback();
        }
    }

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.23;
    
    /// @dev Base core interface implemented by most platform contracts.
    ///      Inherited contracts store an immutable Platform proxy address in the storage,
    ///      which provides authorization capabilities and infrastructure contract addresses.
    /// @author Alien Deployer (https://github.com/a17)
    /// @author JodsMigel (https://github.com/JodsMigel)
    interface IControllable {
        //region ----- Custom Errors -----
        error IncorrectZeroArgument();
        error IncorrectMsgSender();
        error NotGovernance();
        error NotMultisig();
        error NotGovernanceAndNotMultisig();
        error NotOperator();
        error NotFactory();
        error NotPlatform();
        error NotVault();
        error IncorrectArrayLength();
        error AlreadyExist();
        error NotExist();
        error NotTheOwner();
        error ETHTransferFailed();
        error IncorrectInitParams();
        //endregion -- Custom Errors -----
    
        event ContractInitialized(address platform, uint ts, uint block);
    
        /// @notice Stability Platform main contract address
        function platform() external view returns (address);
    
        /// @notice Version of contract implementation
        /// @dev SemVer scheme MAJOR.MINOR.PATCH
        //slither-disable-next-line naming-convention
        function VERSION() external view returns (string memory);
    
        /// @notice Block number when contract was initialized
        function createdBlock() external view returns (uint);
    }

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.23;
    
    /// @notice Interface of the main contract and entry point to the platform.
    /// @author Alien Deployer (https://github.com/a17)
    /// @author Jude (https://github.com/iammrjude)
    /// @author JodsMigel (https://github.com/JodsMigel)
    interface IPlatform {
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                       CUSTOM ERRORS                        */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        error AlreadyAnnounced();
        error SameVersion();
        error NoNewVersion();
        error UpgradeTimerIsNotOver(uint TimerTimestamp);
        error IncorrectFee(uint minFee, uint maxFee);
        error NotEnoughAllowedBBToken();
        error TokenAlreadyExistsInSet(address token);
        error AggregatorNotExists(address dexAggRouter);
    
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                           EVENTS                           */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        event PlatformVersion(string version);
        event UpgradeAnnounce(
            string oldVersion, string newVersion, address[] proxies, address[] newImplementations, uint timelock
        );
        event CancelUpgrade(string oldVersion, string newVersion);
        event ProxyUpgraded(
            address indexed proxy, address implementation, string oldContractVersion, string newContractVersion
        );
        event Addresses(
            address multisig_,
            address factory_,
            address priceReader_,
            address swapper_,
            address buildingPermitToken_,
            address vaultManager_,
            address strategyLogic_,
            address aprOracle_,
            address hardWorker,
            address rebalancer,
            address zap,
            address bridge
        );
        event OperatorAdded(address operator);
        event OperatorRemoved(address operator);
        event FeesChanged(uint fee, uint feeShareVaultManager, uint feeShareStrategyLogic, uint feeShareEcosystem);
        event MinInitialBoostChanged(uint minInitialBoostPerDay, uint minInitialBoostDuration);
        event NewAmmAdapter(string id, address proxy);
        event EcosystemRevenueReceiver(address receiver);
        event SetAllowedBBTokenVaults(address bbToken, uint vaultsToBuild, bool firstSet);
        event RemoveAllowedBBToken(address bbToken);
        event AddAllowedBoostRewardToken(address token);
        event RemoveAllowedBoostRewardToken(address token);
        event AddDefaultBoostRewardToken(address token);
        event RemoveDefaultBoostRewardToken(address token);
        event AddBoostTokens(address[] allowedBoostRewardToken, address[] defaultBoostRewardToken);
        event AllowedBBTokenVaultUsed(address bbToken, uint vaultToUse);
        event AddDexAggregator(address router);
        event RemoveDexAggregator(address router);
        event MinTvlForFreeHardWorkChanged(uint oldValue, uint newValue);
        event CustomVaultFee(address vault, uint platformFee);
        event Rebalancer(address rebalancer_);
        event Bridge(address bridge_);
    
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                         DATA TYPES                         */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        struct PlatformUpgrade {
            string newVersion;
            address[] proxies;
            address[] newImplementations;
        }
    
        struct PlatformSettings {
            string networkName;
            bytes32 networkExtra;
            uint fee;
            uint feeShareVaultManager;
            uint feeShareStrategyLogic;
            uint feeShareEcosystem;
            uint minInitialBoostPerDay;
            uint minInitialBoostDuration;
        }
    
        struct AmmAdapter {
            string id;
            address proxy;
        }
    
        struct SetupAddresses {
            address factory;
            address priceReader;
            address swapper;
            address buildingPermitToken;
            address buildingPayPerVaultToken;
            address vaultManager;
            address strategyLogic;
            address aprOracle;
            address targetExchangeAsset;
            address hardWorker;
            address zap;
            address bridge;
            address rebalancer;
        }
    
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                      VIEW FUNCTIONS                        */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        /// @notice Platform version in CalVer scheme: YY.MM.MINOR-tag. Updates on core contract upgrades.
        function platformVersion() external view returns (string memory);
    
        /// @notice Time delay for proxy upgrades of core contracts and changing important platform settings by multisig
        //slither-disable-next-line naming-convention
        function TIME_LOCK() external view returns (uint);
    
        /// @notice DAO governance
        function governance() external view returns (address);
    
        /// @notice Core team multi signature wallet. Development and operations fund
        function multisig() external view returns (address);
    
        /// @notice This NFT allow user to build limited number of vaults per week
        function buildingPermitToken() external view returns (address);
    
        /// @notice This ERC20 token is used as payment token for vault building
        function buildingPayPerVaultToken() external view returns (address);
    
        /// @notice Receiver of ecosystem revenue
        function ecosystemRevenueReceiver() external view returns (address);
    
        /// @dev The best asset in a network for swaps between strategy assets and farms rewards assets
        ///      The target exchange asset is used for finding the best strategy's exchange asset.
        ///      Rhe fewer routes needed to swap to the target exchange asset, the better.
        function targetExchangeAsset() external view returns (address);
    
        /// @notice Platform factory assembling vaults. Stores settings, strategy logic, farms.
        /// Provides the opportunity to upgrade vaults and strategies.
        /// @return Address of Factory proxy
        function factory() external view returns (address);
    
        /// @notice The holders of these NFT receive a share of the vault revenue
        /// @return Address of VaultManager proxy
        function vaultManager() external view returns (address);
    
        /// @notice The holders of these tokens receive a share of the revenue received in all vaults using this strategy logic.
        function strategyLogic() external view returns (address);
    
        /// @notice Combining oracle and DeX spot prices
        /// @return Address of PriceReader proxy
        function priceReader() external view returns (address);
    
        /// @notice Providing underlying assets APRs on-chain
        /// @return Address of AprOracle proxy
        function aprOracle() external view returns (address);
    
        /// @notice On-chain price quoter and swapper
        /// @return Address of Swapper proxy
        function swapper() external view returns (address);
    
        /// @notice HardWork resolver and caller
        /// @return Address of HardWorker proxy
        function hardWorker() external view returns (address);
    
        /// @notice Rebalance resolver
        /// @return Address of Rebalancer proxy
        function rebalancer() external view returns (address);
    
        /// @notice ZAP feature
        /// @return Address of Zap proxy
        function zap() external view returns (address);
    
        /// @notice Stability Bridge
        /// @return Address of Bridge proxy
        function bridge() external view returns (address);
    
        /// @notice Name of current EVM network
        function networkName() external view returns (string memory);
    
        /// @notice Minimal initial boost rewards per day USD amount which needs to create rewarding vault
        function minInitialBoostPerDay() external view returns (uint);
    
        /// @notice Minimal boost rewards vesting duration for initial boost
        function minInitialBoostDuration() external view returns (uint);
    
        /// @notice This function provides the timestamp of the platform upgrade timelock.
        /// @dev This function is an external view function, meaning it doesn't modify the state.
        /// @return uint representing the timestamp of the platform upgrade timelock.
        function platformUpgradeTimelock() external view returns (uint);
    
        /// @dev Extra network data
        /// @return 0-2 bytes - color
        ///         3-5 bytes - background color
        ///         6-31 bytes - free
        function networkExtra() external view returns (bytes32);
    
        /// @notice Pending platform upgrade data
        function pendingPlatformUpgrade() external view returns (PlatformUpgrade memory);
    
        /// @notice Get platform revenue fee settings
        /// @return fee Revenue fee % (between MIN_FEE - MAX_FEE) with DENOMINATOR precision.
        /// @return feeShareVaultManager Revenue fee share % of VaultManager tokenId owner
        /// @return feeShareStrategyLogic Revenue fee share % of StrategyLogic tokenId owner
        /// @return feeShareEcosystem Revenue fee share % of ecosystemFeeReceiver
        function getFees()
            external
            view
            returns (uint fee, uint feeShareVaultManager, uint feeShareStrategyLogic, uint feeShareEcosystem);
    
        /// @notice Get custom vault platform fee
        /// @return fee revenue fee % with DENOMINATOR precision
        function getCustomVaultFee(address vault) external view returns (uint fee);
    
        /// @notice Platform settings
        function getPlatformSettings() external view returns (PlatformSettings memory);
    
        /// @notice AMM adapters of the platform
        function getAmmAdapters() external view returns (string[] memory id, address[] memory proxy);
    
        /// @notice Get AMM adapter data by hash
        /// @param ammAdapterIdHash Keccak256 hash of adapter ID string
        /// @return ID string and proxy address of AMM adapter
        function ammAdapter(bytes32 ammAdapterIdHash) external view returns (AmmAdapter memory);
    
        /// @notice Allowed buy-back tokens for rewarding vaults
        function allowedBBTokens() external view returns (address[] memory);
    
        /// @notice Vaults building limit for buy-back token.
        /// This limit decrements when a vault for BB-token is built.
        /// @param token Allowed buy-back token
        /// @return vaultsLimit Number of vaults that can be built for BB-token
        function allowedBBTokenVaults(address token) external view returns (uint vaultsLimit);
    
        /// @notice Vaults building limits for allowed buy-back tokens.
        /// @return bbToken Allowed buy-back tokens
        /// @return vaultsLimit Number of vaults that can be built for BB-tokens
        function allowedBBTokenVaults() external view returns (address[] memory bbToken, uint[] memory vaultsLimit);
    
        /// @notice Non-zero vaults building limits for allowed buy-back tokens.
        /// @return bbToken Allowed buy-back tokens
        /// @return vaultsLimit Number of vaults that can be built for BB-tokens
        function allowedBBTokenVaultsFiltered()
            external
            view
            returns (address[] memory bbToken, uint[] memory vaultsLimit);
    
        /// @notice Check address for existance in operators list
        /// @param operator Address
        /// @return True if this address is Stability Operator
        function isOperator(address operator) external view returns (bool);
    
        /// @notice Tokens that can be used for boost rewards of rewarding vaults
        /// @return Addresses of tokens
        function allowedBoostRewardTokens() external view returns (address[] memory);
    
        /// @notice Allowed boost reward tokens that used for unmanaged rewarding vaults creation
        /// @return Addresses of tokens
        function defaultBoostRewardTokens() external view returns (address[] memory);
    
        /// @notice Allowed boost reward tokens that used for unmanaged rewarding vaults creation
        /// @param addressToRemove This address will be removed from default boost reward tokens
        /// @return Addresses of tokens
        function defaultBoostRewardTokensFiltered(address addressToRemove) external view returns (address[] memory);
    
        /// @notice Allowed DeX aggregators
        /// @return Addresses of DeX aggregator rounters
        function dexAggregators() external view returns (address[] memory);
    
        /// @notice DeX aggregator router address is allowed to be used in the platform
        /// @param dexAggRouter Address of DeX aggreagator router
        /// @return Can be used
        function isAllowedDexAggregatorRouter(address dexAggRouter) external view returns (bool);
    
        /// @notice Show minimum TVL for compensate if vault has not enough ETH
        /// @return Minimum TVL for compensate.
        function minTvlForFreeHardWork() external view returns (uint);
    
        /// @notice Front-end platform viewer
        /// @return platformAddresses Platform core addresses
        ///        platformAddresses[0] factory
        ///        platformAddresses[1] vaultManager
        ///        platformAddresses[2] strategyLogic
        ///        platformAddresses[3] buildingPermitToken
        ///        platformAddresses[4] buildingPayPerVaultToken
        ///        platformAddresses[5] governance
        ///        platformAddresses[6] multisig
        ///        platformAddresses[7] zap
        ///        platformAddresses[8] bridge
        /// @return bcAssets Blue chip token addresses
        /// @return dexAggregators_ DeX aggregators allowed to be used entire the platform
        /// @return vaultType Vault type ID strings
        /// @return vaultExtra Vault color, background color and other extra data. Index of vault same as in previous array.
        /// @return vaultBulldingPrice Price of creating new vault in buildingPayPerVaultToken. Index of vault same as in previous array.
        /// @return strategyId Strategy logic ID strings
        /// @return isFarmingStrategy True if strategy is farming strategy. Index of strategy same as in previous array.
        /// @return strategyTokenURI StrategyLogic NFT tokenId metadata and on-chain image. Index of strategy same as in previous array.
        /// @return strategyExtra Strategy color, background color and other extra data. Index of strategy same as in previous array.
        function getData()
            external
            view
            returns (
                address[] memory platformAddresses,
                address[] memory bcAssets,
                address[] memory dexAggregators_,
                string[] memory vaultType,
                bytes32[] memory vaultExtra,
                uint[] memory vaultBulldingPrice,
                string[] memory strategyId,
                bool[] memory isFarmingStrategy,
                string[] memory strategyTokenURI,
                bytes32[] memory strategyExtra
            );
    
        // todo add vaultSymbol, vaultName
        /// @notice Front-end balances, prices and vault list viewer
        /// @param yourAccount Address of account to query balances
        /// @return token Tokens supported by the platform
        /// @return tokenPrice USD price of token. Index of token same as in previous array.
        /// @return tokenUserBalance User balance of token. Index of token same as in previous array.
        /// @return vault Deployed vaults
        /// @return vaultSharePrice Price 1.0 vault share. Index of vault same as in previous array.
        /// @return vaultUserBalance User balance of vault. Index of vault same as in previous array.
        /// @return nft Ecosystem NFTs
        ///         nft[0] BuildingPermitToken
        ///         nft[1] VaultManager
        ///         nft[2] StrategyLogic
        /// @return nftUserBalance User balance of NFT. Index of NFT same as in previous array.
        /// @return buildingPayPerVaultTokenBalance User balance of vault creation paying token
        function getBalance(address yourAccount)
            external
            view
            returns (
                address[] memory token,
                uint[] memory tokenPrice,
                uint[] memory tokenUserBalance,
                address[] memory vault,
                uint[] memory vaultSharePrice,
                uint[] memory vaultUserBalance,
                address[] memory nft,
                uint[] memory nftUserBalance,
                uint buildingPayPerVaultTokenBalance
            );
    
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                      WRITE FUNCTIONS                       */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        /// @notice Add platform operator.
        /// Only governance and multisig can add operator.
        /// @param operator Address of new operator
        function addOperator(address operator) external;
    
        /// @notice Remove platform operator.
        /// Only governance and multisig can remove operator.
        /// @param operator Address of operator to remove
        function removeOperator(address operator) external;
    
        /// @notice Announce upgrade of platform proxies implementations
        /// Only governance and multisig can announce platform upgrades.
        /// @param newVersion New platform version. Version must be changed when upgrading.
        /// @param proxies Addresses of core contract proxies
        /// @param newImplementations New implementation for proxy. Index of proxy same as in previous array.
        function announcePlatformUpgrade(
            string memory newVersion,
            address[] memory proxies,
            address[] memory newImplementations
        ) external;
    
        /// @notice Upgrade platform
        /// Only operator (multisig is operator too) can ececute pending platform upgrade
        function upgrade() external;
    
        /// @notice Cancel pending platform upgrade
        /// Only operator (multisig is operator too) can ececute pending platform upgrade
        function cancelUpgrade() external;
    
        /// @notice Register AMM adapter in platform
        /// @param id AMM adapter ID string from AmmAdapterIdLib
        /// @param proxy Address of AMM adapter proxy
        function addAmmAdapter(string memory id, address proxy) external;
    
        // todo Only governance and multisig can set allowed bb-token vaults building limit
        /// @notice Set new vaults building limit for buy-back token
        /// @param bbToken Address of allowed buy-back token
        /// @param vaultsToBuild Number of vaults that can be built for BB-token
        function setAllowedBBTokenVaults(address bbToken, uint vaultsToBuild) external;
    
        // todo Only governance and multisig can add allowed boost reward token
        /// @notice Add new allowed boost reward token
        /// @param token Address of token
        function addAllowedBoostRewardToken(address token) external;
    
        // todo Only governance and multisig can remove allowed boost reward token
        /// @notice Remove allowed boost reward token
        /// @param token Address of allowed boost reward token
        function removeAllowedBoostRewardToken(address token) external;
    
        // todo Only governance and multisig can add default boost reward token
        /// @notice Add default boost reward token
        /// @param token Address of default boost reward token
        function addDefaultBoostRewardToken(address token) external;
    
        // todo Only governance and multisig can remove default boost reward token
        /// @notice Remove default boost reward token
        /// @param token Address of allowed boost reward token
        function removeDefaultBoostRewardToken(address token) external;
    
        // todo Only governance and multisig can add allowed boost reward token
        // todo Only governance and multisig can add default boost reward token
        /// @notice Add new allowed boost reward token
        /// @notice Add default boost reward token
        /// @param allowedBoostRewardToken Address of allowed boost reward token
        /// @param defaultBoostRewardToken Address of default boost reward token
        function addBoostTokens(
            address[] memory allowedBoostRewardToken,
            address[] memory defaultBoostRewardToken
        ) external;
    
        /// @notice Decrease allowed BB-token vault building limit when vault is built
        /// Only Factory can do it.
        /// @param bbToken Address of allowed buy-back token
        function useAllowedBBTokenVault(address bbToken) external;
    
        /// @notice Allow DeX aggregator routers to be used in the platform
        /// @param dexAggRouter Addresses of DeX aggreagator routers
        function addDexAggregators(address[] memory dexAggRouter) external;
    
        /// @notice Remove allowed DeX aggregator router from the platform
        /// @param dexAggRouter Address of DeX aggreagator router
        function removeDexAggregator(address dexAggRouter) external;
    
        /// @notice Change initial boost rewards settings
        /// @param minInitialBoostPerDay_ Minimal initial boost rewards per day USD amount which needs to create rewarding vault
        /// @param minInitialBoostDuration_ Minimal boost rewards vesting duration for initial boost
        function setInitialBoost(uint minInitialBoostPerDay_, uint minInitialBoostDuration_) external;
    
        /// @notice Update new minimum TVL for compensate.
        /// @param value New minimum TVL for compensate.
        function setMinTvlForFreeHardWork(uint value) external;
    
        /// @notice Set custom platform fee for vault
        /// @param vault Vault address
        /// @param platformFee Custom platform fee
        function setCustomVaultFee(address vault, uint platformFee) external;
    
        /// @notice Setup Rebalancer.
        /// Only Goverannce or Multisig can do this when Rebalancer is not set.
        /// @param rebalancer_ Proxy address of Bridge
        function setupRebalancer(address rebalancer_) external;
    
        /// @notice Setup Bridge.
        /// Only Goverannce or Multisig can do this when Bridge is not set.
        /// @param bridge_ Proxy address of Bridge
        function setupBridge(address bridge_) external;
    }

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.23;
    
    import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
    
    /// @notice Creating vaults, upgrading vaults and strategies, vault list, farms and strategy logics management
    /// @author Alien Deployer (https://github.com/a17)
    /// @author Jude (https://github.com/iammrjude)
    /// @author JodsMigel (https://github.com/JodsMigel)
    /// @author HCrypto7 (https://github.com/hcrypto7)
    interface IFactory {
        //region ----- Custom Errors -----
    
        error VaultImplementationIsNotAvailable();
        error VaultNotAllowedToDeploy();
        error StrategyImplementationIsNotAvailable();
        error StrategyLogicNotAllowedToDeploy();
        error YouDontHaveEnoughTokens(uint userBalance, uint requireBalance, address payToken);
        error SuchVaultAlreadyDeployed(bytes32 key);
        error NotActiveVault();
        error UpgradeDenied(bytes32 _hash);
        error AlreadyLastVersion(bytes32 _hash);
        error NotStrategy();
        error BoostDurationTooLow();
        error BoostAmountTooLow();
        error BoostAmountIsZero();
    
        //endregion ----- Custom Errors -----
    
        //region ----- Events -----
    
        event VaultAndStrategy(
            address indexed deployer,
            string vaultType,
            string strategyId,
            address vault,
            address strategy,
            string name,
            string symbol,
            address[] assets,
            bytes32 deploymentKey,
            uint vaultManagerTokenId
        );
        event StrategyProxyUpgraded(address proxy, address oldImplementation, address newImplementation);
        event VaultProxyUpgraded(address proxy, address oldImplementation, address newImplementation);
        event VaultConfigChanged(
            string type_, address implementation, bool deployAllowed, bool upgradeAllowed, bool newVaultType
        );
        event StrategyLogicConfigChanged(
            string id, address implementation, bool deployAllowed, bool upgradeAllowed, bool newStrategy
        );
        event VaultStatus(address indexed vault, uint newStatus);
        event NewFarm(Farm[] farms);
        event UpdateFarm(uint id, Farm farm);
        event SetStrategyAvailableInitParams(string id, address[] initAddresses, uint[] initNums, int24[] initTicks);
        event AliasNameChanged(address indexed operator, address indexed tokenAddress, string newAliasName);
    
        //endregion -- Events -----
    
        //region ----- Data types -----
    
        /// @custom:storage-location erc7201:stability.Factory
        struct FactoryStorage {
            /// @inheritdoc IFactory
            mapping(bytes32 typeHash => VaultConfig) vaultConfig;
            /// @inheritdoc IFactory
            mapping(bytes32 idHash => StrategyLogicConfig) strategyLogicConfig;
            /// @inheritdoc IFactory
            mapping(bytes32 deploymentKey => address vaultProxy) deploymentKey;
            /// @inheritdoc IFactory
            mapping(address vault => uint status) vaultStatus;
            /// @inheritdoc IFactory
            mapping(address address_ => bool isStrategy_) isStrategy;
            EnumerableSet.Bytes32Set vaultTypeHashes;
            EnumerableSet.Bytes32Set strategyLogicIdHashes;
            mapping(uint week => mapping(uint builderPermitTokenId => uint vaultsBuilt)) vaultsBuiltByPermitTokenId;
            address[] deployedVaults;
            Farm[] farms;
            /// @inheritdoc IFactory
            mapping(bytes32 idHash => StrategyAvailableInitParams) strategyAvailableInitParams;
            mapping(address tokenAddress => string aliasName) aliasNames;
        }
    
        struct VaultConfig {
            string vaultType;
            address implementation;
            bool deployAllowed;
            bool upgradeAllowed;
            uint buildingPrice;
        }
    
        struct StrategyLogicConfig {
            string id;
            address implementation;
            bool deployAllowed;
            bool upgradeAllowed;
            bool farming;
            uint tokenId;
        }
    
        struct Farm {
            uint status;
            address pool;
            string strategyLogicId;
            address[] rewardAssets;
            address[] addresses;
            uint[] nums;
            int24[] ticks;
        }
    
        struct StrategyAvailableInitParams {
            address[] initAddresses;
            uint[] initNums;
            int24[] initTicks;
        }
    
        //endregion -- Data types -----
    
        //region ----- View functions -----
    
        /// @notice All vaults deployed by the factory
        /// @return Vault proxy addresses
        function deployedVaults() external view returns (address[] memory);
    
        /// @notice Total vaults deployed
        function deployedVaultsLength() external view returns (uint);
    
        /// @notice Get vault by VaultManager tokenId
        /// @param id Vault array index. Same as tokenId of VaultManager NFT
        /// @return Address of VaultProxy
        function deployedVault(uint id) external view returns (address);
    
        /// @notice All farms known by the factory in current network
        function farms() external view returns (Farm[] memory);
    
        /// @notice Total farms known by the factory in current network
        function farmsLength() external view returns (uint);
    
        /// @notice Farm data by farm index
        /// @param id Index of farm
        function farm(uint id) external view returns (Farm memory);
    
        /// @notice Strategy logic settings
        /// @param idHash keccak256 hash of strategy logic string ID
        /// @return config Strategy logic settings
        function strategyLogicConfig(bytes32 idHash) external view returns (StrategyLogicConfig memory config);
    
        /// @notice All known strategies
        /// @return Array of keccak256 hashes of strategy logic string ID
        function strategyLogicIdHashes() external view returns (bytes32[] memory);
    
        // todo remove, use new function without calculating vault symbol on the fly for not initialized vaults
        // factory required that special functionally only internally, not for interface
        function getStrategyData(
            string memory vaultType,
            address strategyAddress,
            address bbAsset
        )
            external
            view
            returns (
                string memory strategyId,
                address[] memory assets,
                string[] memory assetsSymbols,
                string memory specificName,
                string memory vaultSymbol
            );
    
        /// @dev Get best asset of assets to be strategy exchange asset
        function getExchangeAssetIndex(address[] memory assets) external view returns (uint);
    
        /// @notice Deployment key of created vault
        /// @param deploymentKey_ Hash of concatenated unique vault and strategy initialization parameters
        /// @return Address of deployed vault
        function deploymentKey(bytes32 deploymentKey_) external view returns (address);
    
        /// @notice Calculating deployment key based on unique vault and strategy initialization parameters
        /// @param vaultType Vault type string
        /// @param strategyId Strategy logic Id string
        /// @param vaultInitAddresses Vault initizlization addresses for deployVaultAndStrategy method
        /// @param vaultInitNums Vault initizlization uint numbers for deployVaultAndStrategy method
        /// @param strategyInitAddresses Strategy initizlization addresses for deployVaultAndStrategy method
        /// @param strategyInitNums Strategy initizlization uint numbers for deployVaultAndStrategy method
        /// @param strategyInitTicks Strategy initizlization int24 ticks for deployVaultAndStrategy method
        function getDeploymentKey(
            string memory vaultType,
            string memory strategyId,
            address[] memory vaultInitAddresses,
            uint[] memory vaultInitNums,
            address[] memory strategyInitAddresses,
            uint[] memory strategyInitNums,
            int24[] memory strategyInitTicks
        ) external returns (bytes32);
    
        /// @notice Available variants of new vault for creating.
        /// The structure of the function's output values is complex,
        /// but after parsing them, the front end has all the data to generate a list of vaults to create.
        /// @return desc Descriptions of the strategy for making money
        /// @return vaultType Vault type strings. Output values are matched by index with previous array.
        /// @return strategyId Strategy logic ID strings. Output values are matched by index with previous array.
        /// @return initIndexes Map of start and end indexes in next 5 arrays. Output values are matched by index with previous array.
        ///                 [0] Start index in vaultInitAddresses
        ///                 [1] End index in vaultInitAddresses
        ///                 [2] Start index in vaultInitNums
        ///                 [3] End index in vaultInitNums
        ///                 [4] Start index in strategyInitAddresses
        ///                 [5] End index in strategyInitAddresses
        ///                 [6] Start index in strategyInitNums
        ///                 [7] End index in strategyInitNums
        ///                 [8] Start index in strategyInitTicks
        ///                 [9] End index in strategyInitTicks
        /// @return vaultInitAddresses Vault initizlization addresses for deployVaultAndStrategy method for all building variants.
        /// @return vaultInitNums Vault initizlization uint numbers for deployVaultAndStrategy method for all building variants.
        /// @return strategyInitAddresses Strategy initizlization addresses for deployVaultAndStrategy method for all building variants.
        /// @return strategyInitNums Strategy initizlization uint numbers for deployVaultAndStrategy method for all building variants.
        /// @return strategyInitTicks Strategy initizlization int24 ticks for deployVaultAndStrategy method for all building variants.
        function whatToBuild()
            external
            view
            returns (
                string[] memory desc,
                string[] memory vaultType,
                string[] memory strategyId,
                uint[10][] memory initIndexes,
                address[] memory vaultInitAddresses,
                uint[] memory vaultInitNums,
                address[] memory strategyInitAddresses,
                uint[] memory strategyInitNums,
                int24[] memory strategyInitTicks
            );
    
        /// @notice Governance and multisig can set a vault status other than Active - the default status.
        /// HardWorker only works with active vaults.
        /// @return status Constant from VaultStatusLib
        function vaultStatus(address vault) external view returns (uint status);
    
        /// @notice Check that strategy proxy deployed by the Factory
        /// @param address_ Address of contract
        /// @return This address is our strategy proxy
        function isStrategy(address address_) external view returns (bool);
    
        /// @notice How much vaults was built by builderPermitToken NFT tokenId in week
        /// @param week Week index (timestamp / (86400 * 7))
        /// @param builderPermitTokenId Token ID of buildingPermitToken NFT
        /// @return vaultsBuilt Vaults built
        function vaultsBuiltByPermitTokenId(
            uint week,
            uint builderPermitTokenId
        ) external view returns (uint vaultsBuilt);
    
        /// @notice Data on all factory strategies.
        /// The output values are matched by index in the arrays.
        /// @return id Strategy logic ID strings
        /// @return deployAllowed New vaults can be deployed
        /// @return upgradeAllowed Strategy can be upgraded
        /// @return farming It is farming strategy (earns farming/gauge rewards)
        /// @return tokenId Token ID of StrategyLogic NFT
        /// @return tokenURI StrategyLogic NFT tokenId metadata and on-chain image
        /// @return extra Strategy color, background color and other extra data
        function strategies()
            external
            view
            returns (
                string[] memory id,
                bool[] memory deployAllowed,
                bool[] memory upgradeAllowed,
                bool[] memory farming,
                uint[] memory tokenId,
                string[] memory tokenURI,
                bytes32[] memory extra
            );
    
        /// @notice Get config of vault type
        /// @param typeHash Keccak256 hash of vault type string
        /// @return vaultType Vault type string
        /// @return implementation Vault implementation address
        /// @return deployAllowed New vaults can be deployed
        /// @return upgradeAllowed Vaults can be upgraded
        /// @return buildingPrice Price of building new vault
        function vaultConfig(bytes32 typeHash)
            external
            view
            returns (
                string memory vaultType,
                address implementation,
                bool deployAllowed,
                bool upgradeAllowed,
                uint buildingPrice
            );
    
        /// @notice Data on all factory vault types
        /// The output values are matched by index in the arrays.
        /// @return vaultType Vault type string
        /// @return implementation Address of vault implemented logic
        /// @return deployAllowed New vaults can be deployed
        /// @return upgradeAllowed Vaults can be upgraded
        /// @return buildingPrice  Price of building new vault
        /// @return extra Vault type color, background color and other extra data
        function vaultTypes()
            external
            view
            returns (
                string[] memory vaultType,
                address[] memory implementation,
                bool[] memory deployAllowed,
                bool[] memory upgradeAllowed,
                uint[] memory buildingPrice,
                bytes32[] memory extra
            );
    
        /// @notice Initialization strategy params store
        function strategyAvailableInitParams(bytes32 idHash) external view returns (StrategyAvailableInitParams memory);
    
        /// @notice Retrieves the alias name associated with a given address
        /// @param tokenAddress_ The address to query for its alias name
        /// @return The alias name associated with the provided address
        function getAliasName(address tokenAddress_) external view returns (string memory);
    
        //endregion -- View functions -----
    
        //region ----- Write functions -----
    
        /// @notice Main method of the Factory - new vault creation by user.
        /// @param vaultType Vault type ID string
        /// @param strategyId Strategy logic ID string
        /// Different types of vaults and strategies have different lengths of input arrays.
        /// @param vaultInitAddresses Addresses for vault initialization
        /// @param vaultInitNums Numbers for vault initialization
        /// @param strategyInitAddresses Addresses for strategy initialization
        /// @param strategyInitNums Numbers for strategy initialization
        /// @param strategyInitTicks Ticks for strategy initialization
        /// @return vault Deployed VaultProxy address
        /// @return strategy Deployed StrategyProxy address
        function deployVaultAndStrategy(
            string memory vaultType,
            string memory strategyId,
            address[] memory vaultInitAddresses,
            uint[] memory vaultInitNums,
            address[] memory strategyInitAddresses,
            uint[] memory strategyInitNums,
            int24[] memory strategyInitTicks
        ) external returns (address vault, address strategy);
    
        /// @notice Upgrade vault proxy. Can be called by any address.
        /// @param vault Address of vault proxy for upgrade
        function upgradeVaultProxy(address vault) external;
    
        /// @notice Upgrade strategy proxy. Can be called by any address.
        /// @param strategy Address of strategy proxy for upgrade
        function upgradeStrategyProxy(address strategy) external;
    
        /// @notice Add farm to factory
        /// @param farms_ Settings and data required to work with the farm.
        function addFarms(Farm[] memory farms_) external;
    
        /// @notice Update farm
        /// @param id Farm index
        /// @param farm_ Settings and data required to work with the farm.
        function updateFarm(uint id, Farm memory farm_) external;
    
        /// @notice Initial addition or change of vault type settings.
        /// Operator can add new vault type. Governance or multisig can change existing vault type config.
        /// @param vaultConfig_ Vault type settings
        function setVaultConfig(VaultConfig memory vaultConfig_) external;
    
        /// @notice Initial addition or change of strategy logic settings.
        /// Operator can add new strategy logic. Governance or multisig can change existing logic config.
        /// @param config Strategy logic settings
        /// @param developer Strategy developer is receiver of minted StrategyLogic NFT on initial addition
        function setStrategyLogicConfig(StrategyLogicConfig memory config, address developer) external;
    
        /// @notice Governance and multisig can set a vault status other than Active - the default status.
        /// @param vaults Addresses of vault proxy
        /// @param statuses New vault statuses. Constant from VaultStatusLib
        function setVaultStatus(address[] memory vaults, uint[] memory statuses) external;
    
        /// @notice Initial addition or change of strategy available init params
        /// @param id Strategy ID string
        /// @param initParams Init params variations that will be parsed by strategy
        function setStrategyAvailableInitParams(string memory id, StrategyAvailableInitParams memory initParams) external;
    
        /// @notice Assigns a new alias name to a specific address
        /// @dev This function may require certain permissions to be called successfully.
        /// @param tokenAddress_ The address to assign an alias name to
        /// @param aliasName_ The alias name to assign to the given address
        function setAliasName(address tokenAddress_, string memory aliasName_) external;
    
        //endregion -- Write functions -----
    }

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.23;
    
    /// @dev Interface of proxy contract for a vault implementation
    interface IVaultProxy {
        //region ----- Custom Errors -----
        error ProxyForbidden();
        //endregion -- Custom Errors -----
    
        /// @notice Initialize vault proxy by Factory
        /// @param type_ Vault type ID string
        function initProxy(string memory type_) external;
    
        /// @notice Upgrade vault implementation if available and allowed
        /// Anyone can execute vault upgrade
        function upgrade() external;
    
        /// @notice Current vault implementation
        /// @return Address of vault implementation contract
        function implementation() external view returns (address);
    
        /// @notice Vault type hash
        /// @return keccan256 hash of vault type ID string
        function vaultTypeHash() external view returns (bytes32);
    }

    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
    // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
    
    pragma solidity ^0.8.20;
    
    /**
     * @dev Library for managing
     * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
     * types.
     *
     * Sets have the following properties:
     *
     * - Elements are added, removed, and checked for existence in constant time
     * (O(1)).
     * - Elements are enumerated in O(n). No guarantees are made on the ordering.
     *
     * ```solidity
     * contract Example {
     *     // Add the library methods
     *     using EnumerableSet for EnumerableSet.AddressSet;
     *
     *     // Declare a set state variable
     *     EnumerableSet.AddressSet private mySet;
     * }
     * ```
     *
     * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
     * and `uint256` (`UintSet`) are supported.
     *
     * [WARNING]
     * ====
     * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
     * unusable.
     * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
     *
     * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
     * array of EnumerableSet.
     * ====
     */
    library EnumerableSet {
        // To implement this library for multiple types with as little code
        // repetition as possible, we write it in terms of a generic Set type with
        // bytes32 values.
        // The Set implementation uses private functions, and user-facing
        // implementations (such as AddressSet) are just wrappers around the
        // underlying Set.
        // This means that we can only create new EnumerableSets for types that fit
        // in bytes32.
    
        struct Set {
            // Storage of set values
            bytes32[] _values;
            // Position is the index of the value in the `values` array plus 1.
            // Position 0 is used to mean a value is not in the set.
            mapping(bytes32 value => uint256) _positions;
        }
    
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function _add(Set storage set, bytes32 value) private returns (bool) {
            if (!_contains(set, value)) {
                set._values.push(value);
                // The value is stored at length-1, but we add 1 to all indexes
                // and use 0 as a sentinel value
                set._positions[value] = set._values.length;
                return true;
            } else {
                return false;
            }
        }
    
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function _remove(Set storage set, bytes32 value) private returns (bool) {
            // We cache the value's position to prevent multiple reads from the same storage slot
            uint256 position = set._positions[value];
    
            if (position != 0) {
                // Equivalent to contains(set, value)
                // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
                // the array, and then remove the last element (sometimes called as 'swap and pop').
                // This modifies the order of the array, as noted in {at}.
    
                uint256 valueIndex = position - 1;
                uint256 lastIndex = set._values.length - 1;
    
                if (valueIndex != lastIndex) {
                    bytes32 lastValue = set._values[lastIndex];
    
                    // Move the lastValue to the index where the value to delete is
                    set._values[valueIndex] = lastValue;
                    // Update the tracked position of the lastValue (that was just moved)
                    set._positions[lastValue] = position;
                }
    
                // Delete the slot where the moved value was stored
                set._values.pop();
    
                // Delete the tracked position for the deleted slot
                delete set._positions[value];
    
                return true;
            } else {
                return false;
            }
        }
    
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function _contains(Set storage set, bytes32 value) private view returns (bool) {
            return set._positions[value] != 0;
        }
    
        /**
         * @dev Returns the number of values on the set. O(1).
         */
        function _length(Set storage set) private view returns (uint256) {
            return set._values.length;
        }
    
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function _at(Set storage set, uint256 index) private view returns (bytes32) {
            return set._values[index];
        }
    
        /**
         * @dev Return the entire set in an array
         *
         * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
         * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
         * this function has an unbounded cost, and using it as part of a state-changing function may render the function
         * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
         */
        function _values(Set storage set) private view returns (bytes32[] memory) {
            return set._values;
        }
    
        // Bytes32Set
    
        struct Bytes32Set {
            Set _inner;
        }
    
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
            return _add(set._inner, value);
        }
    
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
            return _remove(set._inner, value);
        }
    
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
            return _contains(set._inner, value);
        }
    
        /**
         * @dev Returns the number of values in the set. O(1).
         */
        function length(Bytes32Set storage set) internal view returns (uint256) {
            return _length(set._inner);
        }
    
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
            return _at(set._inner, index);
        }
    
        /**
         * @dev Return the entire set in an array
         *
         * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
         * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
         * this function has an unbounded cost, and using it as part of a state-changing function may render the function
         * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
         */
        function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
            bytes32[] memory store = _values(set._inner);
            bytes32[] memory result;
    
            /// @solidity memory-safe-assembly
            assembly {
                result := store
            }
    
            return result;
        }
    
        // AddressSet
    
        struct AddressSet {
            Set _inner;
        }
    
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function add(AddressSet storage set, address value) internal returns (bool) {
            return _add(set._inner, bytes32(uint256(uint160(value))));
        }
    
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function remove(AddressSet storage set, address value) internal returns (bool) {
            return _remove(set._inner, bytes32(uint256(uint160(value))));
        }
    
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function contains(AddressSet storage set, address value) internal view returns (bool) {
            return _contains(set._inner, bytes32(uint256(uint160(value))));
        }
    
        /**
         * @dev Returns the number of values in the set. O(1).
         */
        function length(AddressSet storage set) internal view returns (uint256) {
            return _length(set._inner);
        }
    
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function at(AddressSet storage set, uint256 index) internal view returns (address) {
            return address(uint160(uint256(_at(set._inner, index))));
        }
    
        /**
         * @dev Return the entire set in an array
         *
         * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
         * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
         * this function has an unbounded cost, and using it as part of a state-changing function may render the function
         * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
         */
        function values(AddressSet storage set) internal view returns (address[] memory) {
            bytes32[] memory store = _values(set._inner);
            address[] memory result;
    
            /// @solidity memory-safe-assembly
            assembly {
                result := store
            }
    
            return result;
        }
    
        // UintSet
    
        struct UintSet {
            Set _inner;
        }
    
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function add(UintSet storage set, uint256 value) internal returns (bool) {
            return _add(set._inner, bytes32(value));
        }
    
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function remove(UintSet storage set, uint256 value) internal returns (bool) {
            return _remove(set._inner, bytes32(value));
        }
    
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function contains(UintSet storage set, uint256 value) internal view returns (bool) {
            return _contains(set._inner, bytes32(value));
        }
    
        /**
         * @dev Returns the number of values in the set. O(1).
         */
        function length(UintSet storage set) internal view returns (uint256) {
            return _length(set._inner);
        }
    
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function at(UintSet storage set, uint256 index) internal view returns (uint256) {
            return uint256(_at(set._inner, index));
        }
    
        /**
         * @dev Return the entire set in an array
         *
         * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
         * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
         * this function has an unbounded cost, and using it as part of a state-changing function may render the function
         * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
         */
        function values(UintSet storage set) internal view returns (uint256[] memory) {
            bytes32[] memory store = _values(set._inner);
            uint256[] memory result;
    
            /// @solidity memory-safe-assembly
            assembly {
                result := store
            }
    
            return result;
        }
    }

    Context size (optional):