S Price: $0.067549 (-3.84%)
Gas: 55 Gwei

Contract

0x2461aF27cAb0f586601D8FA1795f4F3CDB050F20

Overview

S Balance

Sonic LogoSonic LogoSonic Logo0 S

S Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

Please try again later

Advanced mode:
Parent Transaction Hash Block From To
View All Internal Transactions
Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
VaultMetadataFacet

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion, MIT license
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../../storage/PetalsStorageLayout.sol";
import "../../00_libraries/types.sol";
import "../../00_libraries/RoleChecker.sol";
import "../../../interfaces/common/ICommonErrors.sol";

/**
 * @title VaultMetadataFacet
 * @author Petals Protocol
 * @notice Manages all vault-specific properties: metadata, UI data, and tags
 * @dev Consolidates vault property management in one place for clean separation of concerns
 * 
 * Architecture:
 * - Vault Metadata: Core vault information (name, symbol, description, risk, category)
 * - Vault UI Metadata: Frontend display data (logos, socials, LP tokens)
 * - Vault Tags: Filtering and discovery labels
 * 
 * Responsibilities:
 * 1. Initialize vault properties during registration (called by ControllerFacet)
 * 2. Update vault properties after registration (called by admins)
 * 3. Manage tag definitions and application
 * 
 * Access Control & Security:
 * - ALL functions require MASTER_ROLE (protocol admin only)
 * - No emergency pause needed - tags/metadata are non-critical
 * - Centralized curation model (no community/strategist access)
 * - Maximum 7 tags per vault to prevent spam/DoS
 * - Strict validation: no duplicates, all tags must exist before use
 * 
 * This facet owns ALL writes to:
 * - s.vaultData[vault].metadata
 * - s.vaultData[vault].ui
 * - s.vaultTags[]
 * - s.vaultsByTag[]
 */
contract VaultMetadataFacet is ICommonErrors {
    
    // ============ Constants ============
    
    /// @notice Maximum number of tags allowed per vault
    uint256 public constant MAX_TAGS_PER_VAULT = 7;
    
    // ============ Access Control ============
    
    modifier onlyRole(uint64 role) {
        if (!RoleChecker.hasRole(role, msg.sender)) {
            revert UnauthorizedUpdate();
        }
        _;
    }
    
    // ============ Custom Errors ============
    
    error InvalidInputArrayLength();
    error TagAlreadyExists();
    error TagNotFound();
    error VaultAlreadyHasTag();
    error VaultDoesNotHaveTag();
    error DuplicateTag();
    error TooManyTags();
    error VaultNotRegistered();
    error IdentityMismatch();
    error StrategyNotSet();
    error VaultNotIndexed();
    
    // ============ Events ============
    
    // Vault property events
    event VaultPropertiesInitialized(address indexed vault, VaultMetadata metadata, bytes32[] initialTags);
    // Note: VaultMetadataUpdated is defined in types.sol (with expanded fields)
    // Note: VaultUIMetadataUpdated is defined in types.sol
    
    // Tag definition events
    event VaultTagRegistered(bytes32 indexed tagId, bytes32 displayName);
    event VaultTagUpdated(bytes32 indexed tagId);
    event VaultTagDeactivated(bytes32 indexed tagId);
    
    // Tag application events
    event TagAppliedToVault(address indexed vault, bytes32 indexed tagId);
    event TagRemovedFromVault(address indexed vault, bytes32 indexed tagId);
    // Note: VaultTagsUpdated is defined in types.sol (with oldTags and newTags)
    
    // ============ VAULT PROPERTY INITIALIZATION (Internal) ============
    
    /**
     * @notice Initialize vault properties during registration (INTERNAL ONLY)
     * @dev This function is ONLY callable via delegatecall from ControllerFacet
     * 
     * ============================================================================
     * SECURITY CRITICAL: DELEGATECALL GUARD
     * ============================================================================
     * The check `msg.sender == address(this)` means:
     * - msg.sender must be the Diamond contract address itself
     * - This is ONLY possible when called via delegatecall from another facet
     * - Direct external calls will fail (msg.sender would be EOA/contract, not Diamond)
     * - This enforces that ONLY ControllerFacet can initialize properties during registration
     * 
     * Call flow:
     * ┌─────────────────────────────────────────────────────────────────────────┐
     * │ 1. User → Diamond.approveDeploymentRegistry() → ControllerFacet         │
     * │    (delegatecall, so msg.sender = user, address(this) = Diamond)        │
     * │                                                                           │
     * │ 2. ControllerFacet → Diamond.initializeVaultProperties()                │
     * │    → VaultMetadataFacet (delegatecall)                                   │
     * │    (msg.sender = Diamond address because of delegatecall chain)          │
     * │                                                                           │
     * │ 3. Check passes: msg.sender == address(this) == Diamond                  │
     * │    Initialization succeeds                                                │
     * └─────────────────────────────────────────────────────────────────────────┘
     * 
     * If someone tries to call this directly:
     * ┌─────────────────────────────────────────────────────────────────────────┐
     * │ Attacker → Diamond.initializeVaultProperties() → VaultMetadataFacet     │
     * │ (msg.sender = Attacker EOA, address(this) = Diamond)                    │
     * │ Check fails: msg.sender ≠ address(this)                                 │
     * │ Reverts with UnauthorizedUpdate()                                        │
     * └─────────────────────────────────────────────────────────────────────────┘
     * 
     * Why not use role checks?
     * - Chicken-egg problem: Can't check roles before vault is registered
     * - Role transfers happen AFTER this initialization in ControllerFacet
     * - This is a one-time initialization during registration, not ongoing access control
     * 
     * After initialization:
     * - External functions like updateVaultMetadata() use role checks (MASTER_ROLE)
     * - This function is never called again for the same vault (double-init prevented)
     * 
     * @param vault Vault address to initialize
     * @param metadata Core vault metadata
     * @param ui UI metadata  
     * @param initialTags Initial tags to apply (can be empty array)
     */
    function initializeVaultProperties(
        address vault,
        VaultMetadata calldata metadata,
        VaultUIMetadata calldata ui,
        bytes32[] calldata initialTags
    ) external {
        // DELEGATECALL GUARD: Only callable from another facet via Diamond
        // msg.sender will be Diamond address if called via delegatecall
        // msg.sender will be EOA/contract if called directly (should fail)
        if (msg.sender != address(this)) revert UnauthorizedUpdate();
        
        PetalsStorageLayout.AppStorage storage s = PetalsStorageLayout.getStorage();
        
        // Initialization lock: Prevent double-initialization
        // Check that core data exists (vault is registered by ControllerFacet)
        if (s.vaultData[vault].identity.vaultAddress == address(0)) revert VaultNotRegistered();
        if (s.vaultData[vault].metadata.name.length != 0) revert AlreadyInitialized(); // Inherited from ICommonErrors
        
        // Verify storage ownership rules (runtime safety checks)
        if (s.vaultData[vault].identity.vaultAddress != vault) revert IdentityMismatch();
        if (s.vaultData[vault].strategy.strategyAddress == address(0)) revert StrategyNotSet();
        if (!s.isVault[vault]) revert VaultNotIndexed();
        
        // Validate tags BEFORE modifying any state
        if (initialTags.length > MAX_TAGS_PER_VAULT) revert TooManyTags();
        
        // Check for duplicate tags and validate all tags exist
        for (uint256 i = 0; i < initialTags.length; i++) {
            // Check if tag exists
            if (s.vaultTags[initialTags[i]].tagId == bytes32(0)) revert TagNotFound();
            
            // Check for duplicates (compare with all subsequent tags)
            for (uint256 j = i + 1; j < initialTags.length; j++) {
                if (initialTags[i] == initialTags[j]) revert DuplicateTag();
            }
        }
        
        // Initialize metadata and UI
        s.vaultData[vault].metadata = metadata;
        s.vaultData[vault].ui = ui;
        
        // Apply initial tags (all validation passed)
        if (initialTags.length > 0) {
            for (uint256 i = 0; i < initialTags.length; i++) {
                s.vaultsByTag[initialTags[i]].push(vault);
            }
            s.vaultData[vault].ui.tags = initialTags;
        }
        
        emit VaultPropertiesInitialized(vault, metadata, initialTags);
    }
    
    // ============ VAULT METADATA MANAGEMENT (External) ============
    
    /**
     * @notice Update vault metadata
     * @dev Updates core vault metadata (name, symbol, description, etc.)
     * @param vault Vault address
     * @param metadata New metadata
     */
    function updateVaultMetadata(address vault, VaultMetadata calldata metadata) 
        external 
        onlyRole(RoleChecker.MASTER_ROLE) 
    {
        PetalsStorageLayout.AppStorage storage s = PetalsStorageLayout.getStorage();
        
        if (!s.isVault[vault]) revert VaultNotFound();
        
        s.vaultData[vault].metadata = metadata;
        
        emit VaultMetadataUpdated(
            vault,
            metadata.name,
            metadata.protocol,
            metadata.category,
            metadata.riskLevel
        );
    }
    
    /**
     * @notice Set vault UI metadata
     * @dev Updates UI-specific metadata for frontend display
     * @param vault Vault address
     * @param ui UI metadata struct
     */
    function setVaultUIMetadata(address vault, VaultUIMetadata calldata ui) 
        external 
        onlyRole(RoleChecker.MASTER_ROLE) 
    {
        PetalsStorageLayout.AppStorage storage s = PetalsStorageLayout.getStorage();
        
        if (!s.isVault[vault]) revert VaultNotFound();
        
        s.vaultData[vault].ui = ui;
        
        emit VaultUIMetadataUpdated(vault, ui);
    }
    
    /**
     * @notice Set vault UI metadata for multiple vaults
     * @dev Batch operation for gas efficiency
     * @param vaults Array of vault addresses
     * @param uiData Array of UI metadata structs
     */
    function setVaultUIMetadataBatch(
        address[] calldata vaults,
        VaultUIMetadata[] calldata uiData
    ) external onlyRole(RoleChecker.MASTER_ROLE) {
        if (vaults.length != uiData.length) revert InvalidInputArrayLength();
        
        PetalsStorageLayout.AppStorage storage s = PetalsStorageLayout.getStorage();
        
        for (uint256 i = 0; i < vaults.length; i++) {
            if (!s.isVault[vaults[i]]) revert VaultNotFound();
            
            s.vaultData[vaults[i]].ui = uiData[i];
            
            emit VaultUIMetadataUpdated(vaults[i], uiData[i]);
        }
    }
    
    /**
     * @notice Auto-populate vault UI metadata from token registry
     * @dev Helper function to auto-fill logos and symbols from token registry
     * @param vault Vault address to populate
     */
    function autoPopulateVaultUI(address vault) 
        external 
        onlyRole(RoleChecker.MASTER_ROLE) 
    {
        PetalsStorageLayout.AppStorage storage s = PetalsStorageLayout.getStorage();
        
        if (!s.isVault[vault]) revert VaultNotFound();
        
        VaultStoredData storage vaultData = s.vaultData[vault];
        
        // Initialize empty UI metadata
        VaultUIMetadata memory ui;
        ui.socials = new bytes[](4); // Empty social links array
        ui.lpTokens = new address[](0);
        ui.lpTokenSymbols = new bytes32[](0);
        ui.lpTokenLogos = new bytes[](0);
        ui.tags = vaultData.ui.tags; // Preserve existing tags
        
        // Look up protocol logo from UniversalFactory
        bytes32 baseProtocol = vaultData.metadata.protocol;
        ProtocolRegistration storage protocolReg = s.universalFactoryProtocols[baseProtocol];
        ui.protocolLogoURI = protocolReg.logoURI;
        
        // Look up token metadata if registered
        address underlyingAsset = vaultData.strategy.underlyingAsset;
        TokenMetadata storage tokenMeta = s.tokenMetadata[underlyingAsset];
        if (tokenMeta.tokenAddress != address(0)) {
            ui.vaultLogoURI = tokenMeta.logoURI;
        }
        
        s.vaultData[vault].ui = ui;
        
        emit VaultUIMetadataUpdated(vault, ui);
    }
    
    // ============ TAG DEFINITION MANAGEMENT ============
    
    /**
     * @notice Register a new vault tag
     * @dev MASTER_ROLE can create new tags for vault categorization
     * @param tag Tag information struct
     */
    function registerVaultTag(VaultTagInfo calldata tag) 
        external 
        onlyRole(RoleChecker.MASTER_ROLE) 
    {
        PetalsStorageLayout.AppStorage storage s = PetalsStorageLayout.getStorage();
        
        if (tag.tagId == bytes32(0)) revert ZeroAddress();
        if (s.vaultTags[tag.tagId].tagId != bytes32(0)) revert TagAlreadyExists();
        
        s.vaultTags[tag.tagId] = tag;
        s.registeredTags.push(tag.tagId);
        
        emit VaultTagRegistered(tag.tagId, tag.displayName);
    }

    /**
     * @notice Update an existing vault tag
     * @param tagId Tag ID to update
     * @param tag Updated tag information
     */
    function updateVaultTag(bytes32 tagId, VaultTagInfo calldata tag) 
        external 
        onlyRole(RoleChecker.MASTER_ROLE) 
    {
        PetalsStorageLayout.AppStorage storage s = PetalsStorageLayout.getStorage();
        
        if (s.vaultTags[tagId].tagId == bytes32(0)) revert TagNotFound();
        
        s.vaultTags[tagId] = tag;
        
        emit VaultTagUpdated(tagId);
    }

    /**
     * @notice Deactivate a vault tag
     * @param tagId Tag ID to deactivate
     */
    function deactivateVaultTag(bytes32 tagId) 
        external 
        onlyRole(RoleChecker.MASTER_ROLE) 
    {
        PetalsStorageLayout.AppStorage storage s = PetalsStorageLayout.getStorage();
        
        if (s.vaultTags[tagId].tagId == bytes32(0)) revert TagNotFound();
        
        s.vaultTags[tagId].isActive = false;
        
        emit VaultTagDeactivated(tagId);
    }

    // ============ TAG APPLICATION MANAGEMENT ============

    /**
     * @notice Set tags for a vault (replaces existing tags)
     * @dev MASTER_ROLE can apply tags to vaults for filtering
     *      Validates all tags exist and checks for duplicates before modifying state
     * @param vault Vault address
     * @param tagIds Array of tag IDs to apply
     */
    function setVaultTags(address vault, bytes32[] calldata tagIds) 
        external 
        onlyRole(RoleChecker.MASTER_ROLE) 
    {
        PetalsStorageLayout.AppStorage storage s = PetalsStorageLayout.getStorage();
        
        if (!s.isVault[vault]) revert VaultNotFound();
        if (tagIds.length > MAX_TAGS_PER_VAULT) revert TooManyTags();
        
        // VALIDATE ALL TAGS FIRST (before modifying any state)
        for (uint256 i = 0; i < tagIds.length; i++) {
            // Check if tag exists
            if (s.vaultTags[tagIds[i]].tagId == bytes32(0)) revert TagNotFound();
            
            // Check for duplicates (compare with all subsequent tags)
            for (uint256 j = i + 1; j < tagIds.length; j++) {
                if (tagIds[i] == tagIds[j]) revert DuplicateTag();
            }
        }
        
        // All validation passed - now safe to modify state
        
        // Remove vault from old tag indexes
        bytes32[] memory oldTags = s.vaultData[vault].ui.tags;
        for (uint256 i = 0; i < oldTags.length; i++) {
            _removeVaultFromTag(vault, oldTags[i]);
        }
        
        // Add vault to new tag indexes
        for (uint256 i = 0; i < tagIds.length; i++) {
            s.vaultsByTag[tagIds[i]].push(vault);
        }
        
        // Update vault tags
        s.vaultData[vault].ui.tags = tagIds;
        
        emit VaultTagsUpdated(vault, oldTags, tagIds);
    }

    /**
     * @notice Add a single tag to a vault
     * @param vault Vault address
     * @param tagId Tag ID to add
     */
    function addVaultTag(address vault, bytes32 tagId) 
        external 
        onlyRole(RoleChecker.MASTER_ROLE) 
    {
        PetalsStorageLayout.AppStorage storage s = PetalsStorageLayout.getStorage();
        
        if (!s.isVault[vault]) revert VaultNotFound();
        if (s.vaultTags[tagId].tagId == bytes32(0)) revert TagNotFound();
        
        // Check if vault already has this tag
        bytes32[] storage vaultTags = s.vaultData[vault].ui.tags;
        if (vaultTags.length >= MAX_TAGS_PER_VAULT) revert TooManyTags();
        
        for (uint256 i = 0; i < vaultTags.length; i++) {
            if (vaultTags[i] == tagId) revert VaultAlreadyHasTag();
        }
        
        // Add tag
        vaultTags.push(tagId);
        s.vaultsByTag[tagId].push(vault);
        
        emit TagAppliedToVault(vault, tagId);
    }

    /**
     * @notice Remove a tag from a vault
     * @param vault Vault address
     * @param tagId Tag ID to remove
     */
    function removeVaultTag(address vault, bytes32 tagId) 
        external 
        onlyRole(RoleChecker.MASTER_ROLE) 
    {
        PetalsStorageLayout.AppStorage storage s = PetalsStorageLayout.getStorage();
        
        if (!s.isVault[vault]) revert VaultNotFound();
        
        // Remove from vault's tag array
        bytes32[] storage vaultTags = s.vaultData[vault].ui.tags;
        bool found = false;
        for (uint256 i = 0; i < vaultTags.length; i++) {
            if (vaultTags[i] == tagId) {
                vaultTags[i] = vaultTags[vaultTags.length - 1];
                vaultTags.pop();
                found = true;
                break;
            }
        }
        
        if (!found) revert VaultDoesNotHaveTag();
        
        // Remove from tag's vault array
        _removeVaultFromTag(vault, tagId);
        
        emit TagRemovedFromVault(vault, tagId);
    }

    // ============ TAG QUERY FUNCTIONS ============

    /**
     * @notice Get tag information
     * @param tagId Tag ID
     * @return Tag information struct
     */
    function getVaultTag(bytes32 tagId) external view returns (VaultTagInfo memory) {
        PetalsStorageLayout.AppStorage storage s = PetalsStorageLayout.getStorage();
        return s.vaultTags[tagId];
    }

    /**
     * @notice Get all registered vault tags
     * @return Array of tag information structs
     */
    function getAllVaultTags() external view returns (VaultTagInfo[] memory) {
        PetalsStorageLayout.AppStorage storage s = PetalsStorageLayout.getStorage();
        
        uint256 length = s.registeredTags.length;
        VaultTagInfo[] memory tags = new VaultTagInfo[](length);
        
        for (uint256 i = 0; i < length; i++) {
            tags[i] = s.vaultTags[s.registeredTags[i]];
        }
        
        return tags;
    }

    /**
     * @notice Get all tags for a vault
     * @dev Returns ALL tags regardless of active status.
     *      Frontend should filter by calling getVaultTag(tagId).isActive
     *      to display only active tags.
     * @param vault Vault address
     * @return Array of tag IDs (includes deactivated tags)
     */
    function getVaultTags(address vault) external view returns (bytes32[] memory) {
        PetalsStorageLayout.AppStorage storage s = PetalsStorageLayout.getStorage();
        
        if (!s.isVault[vault]) revert VaultNotFound();
        
        return s.vaultData[vault].ui.tags;
    }

    // ============ INTERNAL HELPER FUNCTIONS ============

    /**
     * @notice Internal helper to remove vault from tag's vault array
     * @param vault Vault address
     * @param tagId Tag ID
     */
    function _removeVaultFromTag(address vault, bytes32 tagId) private {
        PetalsStorageLayout.AppStorage storage s = PetalsStorageLayout.getStorage();
        
        address[] storage vaults = s.vaultsByTag[tagId];
        for (uint256 i = 0; i < vaults.length; i++) {
            if (vaults[i] == vault) {
                vaults[i] = vaults[vaults.length - 1];
                vaults.pop();
                break;
            }
        }
    }
}

File 2 of 7 : PetalsStorageLayout.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../00_libraries/types.sol";
import "../../interfaces/common/IStrategyFactory.sol";
import "../../interfaces/routing/RouterTypes.sol";

/**
 * @title PetalsStorageLayout
 * @notice Storage layout library for the upgradeable PetalsVaultController
 * @dev This library defines the storage layout that will be used by all versions
 * of the controller implementation. It uses the diamond storage pattern to
 * prevent storage collisions and ensure upgrade compatibility.
 */
library PetalsStorageLayout {
    /// @notice Unique storage slot identifier to prevent collisions
    /// @dev Using a unique namespace for this protocol's storage
    bytes32 constant STORAGE_SLOT = keccak256("com.petals.protocol.storage.main");

    /**
     * @notice Complete storage layout for the Petals Protocol
     * @dev All state variables from PetalsVaultController are defined here
     * This struct represents the entire persistent state of the protocol
     * that will be preserved across all logic contract upgrades
     */
    struct AppStorage {
        // ============ Strategy Registry ============
        
        /// @notice Mapping from strategy to vault (reverse lookup)
        /// @dev Forward lookup (vault => strategy) is in vaultData[vault].strategy.strategyAddress
        mapping(address => address) strategyToVault;

        // ============ Access Control & Permission Registry ============
        /// @notice Contract-specific role assignments: contractAddr => role => account => hasRole
        mapping(address => mapping(uint64 => mapping(address => bool))) contractRoles;
        
        // ============ Core Infrastructure ============
        
        /// @notice The master vault implementation used for all vault clones
        address masterVault;
        
        /// @notice The data provider contract for aggregated queries
        address dataProvider;
        
        /// @notice Price oracle contract for USD valuations
        address priceOracle;
        
        /// @notice Wrapped native token address for this chain
        address wrappedNativeToken;
        
        /// @notice Fee manager contract for all fee-related operations
        address feeManager;
        
        /// @notice Access manager contract for all permission-related operations
        address accessManager;

        /// @notice The master address that receives ownership of registered vaults and strategies
        address masterAddress;
        
        /// @notice Timelock controller for critical operations (optional, address(0) = no timelock)
        address timelockController;

        // ============ Vault Registry ============
        
        /// @notice Array of all deployed vault addresses
        address[] allVaults;
        
        /// @notice Quick lookup to verify if an address is a registered vault
        mapping(address => bool) isVault;
        
        /// @notice Comprehensive data storage for each vault
        /// @dev Stores all persistent vault data (identity, metadata, metrics, strategy, UI)
        mapping(address => VaultStoredData) vaultData;

        // ============ Indexing System ============
        
        /// @notice Vaults organized by underlying asset for efficient discovery
        mapping(address => address[]) vaultsByAsset;
        
            /// @notice Vaults organized by fee recipient for management interfaces
        mapping(address => address[]) vaultsByFeeRecipient;

        /// @notice Array of retired vault addresses for archiving
        address[] retiredVaults;
        /// @notice Quick check if a vault is retired
        mapping(address => bool) isRetired;

        // ============ Performance Tracking ============
        
        /// @notice Running count of total vaults deployed through this controller
        uint256 totalVaultsDeployed;

        // ============ Duplicate Prevention ============
        
        /// @notice Prevents duplicate registrations of the same asset+strategyType combination
        /// @dev Key: [asset][strategyType] → vault
        /// @dev Allows multiple strategy types per asset (e.g., USDC with Shadow-V1, Shadow-V2, Aave)
        mapping(address => mapping(bytes32 => address)) assetStrategyTypeVault;

        // ============ Protocol-Wide Operations ============
        
        /// @notice Direct mapping from base protocol to all vaults using it
        /// @dev Enables O(1) protocol-wide operations (panic, analytics)
        mapping(bytes32 => address[]) vaultsByProtocol;
        
        /// @notice Index mapping for efficient vault removal from protocol array
        mapping(bytes32 => mapping(address => uint256)) vaultsByProtocolIndex;

        // ============ Deployment Management ============
        
        /// @notice Vault deployments queued for admin approval before registration
        /// @dev Mapping-only design (no array) to prevent DOS attacks via queue spam
        /// @dev Admin discovers vaults via off-chain events/indexer, approves by direct address lookup
        /// @dev Multiple vaults can queue for same asset - admin chooses best during approval
        mapping(address => VaultStoredData) queuedVaults;


        
        // ============ Configurable Protocol Constants ============
        
        /// @notice Standard basis points denominator (configurable)
        uint256 basisPoints;
        
        /// @notice Maximum slippage tolerance for strategy operations (configurable)
        uint256 maxSlippage;
        
        /// @notice Minimum delay between harvests (configurable)
        uint256 minHarvestDelay;
        
        /// @notice Default performance fee for new vaults (configurable)
        uint256 defaultPerformanceFee;
        
        /// @notice Default slippage tolerance for strategies (configurable)
        uint256 defaultSlippageTolerance;
        uint256 defaultCollateralFactor; // Default collateral factor for lending strategies in basis points

        // ============ Essential Indexing System ============
        mapping(address => uint256) allVaultsIndex;
        mapping(address => mapping(address => uint256)) vaultsByAssetIndex;  // asset => vault => index

        // ============ Fee Config Storage ============
        /// @notice Vault-specific fee configurations stored in the diamond
        mapping(address => VaultFeeConfig) vaultFeeConfigs;
        /// @notice Universal fee configuration used as default when no override
        UniversalFeeConfig universalFeeConfig;
        
        /// @notice Claimable fees per recipient address
        /// @dev Fees accumulate here instead of direct transfer for better composability
        mapping(address => uint256) claimableFees;

        // ============ Routing System ============
        /// @notice Registry of router libraries: RouterType => library address
        mapping(RouterType => address) routerLibraries;
        
        /// @notice Centralized fees library for all strategies
        address feesLibrary;
        
        /// @notice Last route change timestamp per strategy
        mapping(address => uint256) strategyLastRouteChange;
        
        /// @notice Total route updates per strategy
        mapping(address => uint256) strategyRouteUpdateCount;

        // ============ Metadata Registry (NEW) ============
        
        /// @notice Chain metadata for this deployment (single static struct)
        ChainMetadata chainMetadata;
        
        /// @notice Token category information (dynamic registry)
        mapping(bytes32 => TokenCategoryInfo) tokenCategories;
        bytes32[] registeredCategories;
        
        /// @notice Token metadata registry for UI display
        mapping(address => TokenMetadata) tokenMetadata;
        address[] registeredTokens;
        
        /// @notice Tokens organized by category for filtering
        mapping(bytes32 => address[]) tokensByCategory; // categoryId => tokens[]

        // ============ Vault Tag Registry ============
        
        /// @notice Vault tag definitions
        mapping(bytes32 => VaultTagInfo) vaultTags;
        bytes32[] registeredTags;
        
        /// @notice Reverse index: tagId => vault addresses (for filtering)
        mapping(bytes32 => address[]) vaultsByTag;

        // ============ Universal Factory Registry ============
        
        /// @notice Protocol registry: baseProtocol => registration data
        /// @dev Primary access by bytes32 name (stable, readable API)
        mapping(bytes32 => ProtocolRegistration) universalFactoryProtocols;
        
        /// @notice All registered protocols (for enumeration)
        /// @dev Array indices match ProtocolRegistration.protocolIndex
        bytes32[] universalFactoryRegisteredProtocols;
        
        /// @notice Strategy type registry: baseProtocol => strategyType => registration data
        /// @dev Two-level mapping for protocol → type hierarchy
        mapping(bytes32 => mapping(bytes32 => StrategyTypeRegistration)) universalFactoryStrategyTypes;
        
        /// @notice Protocol strategy types (for enumeration): baseProtocol => strategyType[]
        /// @dev Array indices match StrategyTypeRegistration.typeIndex
        mapping(bytes32 => bytes32[]) universalFactoryProtocolStrategyTypes;
        
        /// @notice Tracks all strategies deployed by UniversalFactory for O(1) validation
        /// @dev Only UniversalFactory can set this to true, making it unspoofable
        mapping(address => bool) universalFactoryDeployedStrategies;

        // ============ Oracle Storage ============
        
        /// @notice Chainlink price feeds: asset => feed address
        mapping(address => address) chainlinkFeeds;
        
        /// @notice DEX routers with their types for price discovery
        OracleRouterInfo[] dexRouters;
        mapping(address => bool) approvedRouters;
        
        /// @notice Base tokens for routing (USDC, WETH, etc.)
        address[] baseTokens;
        mapping(address => bool) isBaseToken;
        mapping(address => uint256) baseTokenPriority;
        
        /// @notice Cached price data: asset => PriceData
        mapping(address => PriceData) cachedPrices;
        
        /// @notice LP token detection cache
        mapping(address => bool) isLPTokenCache;
        mapping(address => bool) isLPTokenSet;
        
        /// @notice Manual price overrides (emergency)
        mapping(address => PriceData) manualPrices;
        mapping(address => bool) useManualPrice;
        
        /// @notice Custom price staleness per asset
        mapping(address => uint256) maxPriceAge;

        // ============ Asset Registry Storage ============
        
        /// @notice Asset metadata registry (LP tokens, complex assets)
        /// @dev Populated by ChainRegistryFacet, queried by OracleFacet and ControllerFacet
        mapping(address => AssetMetadata) assetRegistry;
        
        /// @notice Quick lookup: Is this address a registered asset?
        mapping(address => bool) isRegisteredAsset;
        
        /// @notice Enumeration: All registered assets
        address[] registeredAssets;
        
        /// @notice Index by RouterType (for Oracle optimization)
        /// @dev Allows O(1) lookup of all assets for a given DEX type
        mapping(RouterType => address[]) assetsByRouterType;

        // ============ Storage Gap ============
        /// @notice Storage gap for future upgrades - reserves 100 slots
        /// @dev This prevents storage collisions when adding new state variables in future versions
        /// @dev Increased to 100 for better long-term flexibility
        uint256[100] __gap;
    }

    /**
     * @notice Get a storage pointer to the AppStorage struct
     * @dev Uses assembly to return a storage pointer at the designated slot
     * This is the standard diamond storage pattern for upgradeable contracts
     * @return s Storage pointer to the AppStorage struct
     */
    function getStorage() internal pure returns (AppStorage storage s) {
        bytes32 slot = STORAGE_SLOT;
        assembly {
            s.slot := slot
        }
    }
}

File 3 of 7 : types.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../../interfaces/common/IStrategyFactory.sol";
import "../../interfaces/routing/RouterTypes.sol";

/**
 * ╔══════════════════════════════════════════════════════════════════════════════╗
 * ║                     PETALS PROTOCOL DATA ARCHITECTURE                        ║
 * ╚══════════════════════════════════════════════════════════════════════════════╝
 * 
 * This file defines the complete data structure hierarchy for the Petals Protocol.
 * 
 * ┌─────────────────────────────────────────────────────────────────────────────┐
 * │                          TWO MAIN DATA STRUCTURES                           │
 * └─────────────────────────────────────────────────────────────────────────────┘
 * 
 * 1. VaultRowData
 *    ├─ Purpose: Lightweight data for vault list display (/vaults page)
 *    ├─ Usage: Batch queries of 500+ vaults
 *    ├─ Contains: Essential metrics + UI branding
 *    └─ Returned by: DataProviderFacet.getVaultRowsBatch()
 * 
 * 2. VaultCompleteData
 *    ├─ Purpose: Complete vault data for detail pages (/vaults/[id])
 *    ├─ Usage: Single vault detailed view
 *    ├─ Contains: ALL vault data in one call (stored + computed + derived)
 *    └─ Returned by: DataProviderFacet.getVaultData()
 * 
 * ┌─────────────────────────────────────────────────────────────────────────────┐
 * │                        DATA LAYER ORGANIZATION                              │
 * └─────────────────────────────────────────────────────────────────────────────┘
 * 
 * LAYER 1: STORED DATA (Persisted in Diamond Storage)
 * ────────────────────────────────────────────────────
 * VaultStoredData
 *  ├─ VaultIdentity      → Who/what/when (addresses, timestamps)
 *  ├─ VaultMetadata      → Name, protocol, category, branding
 *  ├─ VaultMetrics       → Performance history (APY, harvests)
 *  ├─ StrategyData       → Strategy configuration
 *  └─ VaultUIMetadata    → Logos, links, LP token info
 * 
 * LAYER 2: COMPUTED DATA (Calculated On-Demand from Contracts)
 * ────────────────────────────────────────────────────────────
 *  ├─ VaultStateData     → Real-time vault state (totalAssets, sharePrice)
 *  ├─ UserPortfolioData  → User-specific balances and allowances
 *  ├─ VaultFeeData       → Fee configuration from FeeManager
 *  └─ HarvestData        → Harvest readiness and pending rewards
 * 
 * LAYER 3: DERIVED DATA (Computed from Logic)
 * ────────────────────────────────────────────
 *  └─ VaultStatus        → Active/Paused/Retired (enum)
 * 
 * ┌─────────────────────────────────────────────────────────────────────────────┐
 * │                           DATA FLOW DIAGRAM                                 │
 * └─────────────────────────────────────────────────────────────────────────────┘
 * 
 * Diamond Storage: vaultData[address] → VaultStoredData
 *                                           │
 *                                           ├─► VaultIdentity
 *                                           ├─► VaultMetadata
 *                                           ├─► VaultMetrics
 *                                           ├─► StrategyData
 *                                           └─► VaultUIMetadata
 *                                           
 * DataProviderFacet._getVaultCompleteData() reads storage + computes real-time:
 *                                           
 * VaultCompleteData
 *  ├─ [STORED] identity, metadata, metrics, strategy, ui
 *  ├─ [COMPUTED] state ──────► Query vault.totalAssets(), vault.totalSupply()
 *  ├─ [COMPUTED] user ───────► Query vault.balanceOf(user), asset.balanceOf(user)
 *  ├─ [COMPUTED] fees ───────► Query feeManager.getVaultFeeConfig(vault)
 *  ├─ [COMPUTED] harvest ────► Query strategy.totalRewardsAvailable()
 *  └─ [DERIVED] status ──────► Compute from vault.active() + strategy.paused()
 * 
 * ┌─────────────────────────────────────────────────────────────────────────────┐
 * │                         FRONTEND USAGE GUIDE                                │
 * └─────────────────────────────────────────────────────────────────────────────┘
 * 
 * For Vault List Page (/vaults):
 * ────────────────────────────────
 * const rows = await dataProvider.getVaultRowsBatch(vaults, user);
 * // Access: row.name, row.protocol, row.estAPY, row.vaultLogoURI
 * 
 * For Vault Detail Page (/vaults/[id]):
 * ───────────────────────────────────────
 * const data = await dataProvider.getVaultData(vault, user);
 * // Access all fields:
 * // - data.identity.vaultAddress
 * // - data.metadata.name
 * // - data.ui.vaultLogoURI, data.ui.websiteURI
 * // - data.state.totalAssets, data.state.sharePrice
 * // - data.user.userBalance
 * // - data.harvest.canHarvest
 */

// ════════════════════════════════════════════════════════════════════════════════
// MAIN DATA STRUCTURES
// ════════════════════════════════════════════════════════════════════════════════

/**
 * @notice Lightweight vault data optimized for list display
 * @dev Used by: Frontend /vaults page for displaying 500+ vaults efficiently
 * @dev Returned by: DataProviderFacet.getVaultRowsBatch()
 * 
 * Contains:
 * - Essential identification (address, name, protocol)
 * - Key metrics (APY, TVL, risk level)
 * - User portfolio (balances)
 * - UI branding (logos)
 * - Status indicator
 */
struct VaultRowData {
    // === IDENTITY ===
    address vaultAddress;        // Vault contract address
    bytes name;                  // Vault name (full length, no truncation)
    bytes32 protocol;            // Protocol name (e.g., "Shadow", "Aave")
    bytes32 category;            // Category (e.g., "Stable", "Volatile")
    
    // === KEY METRICS ===
    uint256 estAPY;              // Last APY in basis points (10000 = 100%)
    uint256 tvlUSD;              // TVL estimate in USD (6 decimals)
    uint8 riskLevel;             // Risk level 1-10
    uint8 status;                // 0=Active, 1=Paused, 2=Retired
    
    // === USER PORTFOLIO ===
    uint256 userAvailable;       // User's underlying asset balance
    uint256 userHoldings;        // User's vault share balance
    uint256 userPositionUSD;     // User's vault position in USD (6 decimals) - 0 if unavailable
    uint256 userAvailableUSD;    // User's available balance in USD (6 decimals) - 0 if unavailable
    
    // === USD PRICING ===
    uint256 assetPriceUSD;       // Asset price in USD (18 decimals) - 0 if unavailable
    uint8 priceConfidence;       // Oracle confidence (0-100) - 0 if no oracle
    
    // === UI METADATA ===
    bytes vaultLogoURI;          // Vault logo (IPFS/HTTP) - bytes for gas efficiency
    bytes protocolLogoURI;       // Protocol logo (IPFS/HTTP) - bytes for gas efficiency
}

/**
 * @notice Complete vault data with all information in a single structure
 * @dev Used by: Frontend /vaults/[id] detail page
 * @dev Returned by: DataProviderFacet.getVaultData()
 * 
 * Architecture:
 * ├─ STORED DATA (from Diamond storage - VaultStoredData)
 * │  ├─ identity: Basic vault identity
 * │  ├─ metadata: Name, description, branding
 * │  ├─ metrics: Performance history
 * │  ├─ strategy: Strategy configuration
 * │  └─ ui: Logos, links, LP token info
 * │
 * ├─ COMPUTED DATA (from contracts - calculated on-demand)
 * │  ├─ state: Real-time vault state
 * │  ├─ user: User-specific portfolio data
 * │  ├─ fees: Fee configuration
 * │  └─ harvest: Harvest readiness
 * │
 * └─ DERIVED DATA (from logic)
 *    └─ status: Active/Paused/Retired
 */
struct VaultCompleteData {
    // ═══════════════════════════════════════════════════════════════════════════
    // STORED DATA (Persisted in Diamond Storage)
    // ═══════════════════════════════════════════════════════════════════════════
    
    /// @notice Basic vault identity (addresses, IDs, timestamps)
    VaultIdentity identity;
    
    /// @notice Vault metadata (name, protocol, category, descriptions)
    VaultMetadata metadata;
    
    /// @notice Performance metrics (APY history, harvest counts)
    VaultMetrics metrics;
    
    /// @notice Strategy configuration
    StrategyData strategy;
    
    /// @notice UI metadata (logos, links, LP token info)
    VaultUIMetadata ui;
    
    // ═══════════════════════════════════════════════════════════════════════════
    // COMPUTED DATA (Calculated On-Demand from Contracts)
    // ═══════════════════════════════════════════════════════════════════════════
    
    /// @notice Real-time vault state (totalAssets, sharePrice, etc.)
    VaultStateData state;
    
    /// @notice User-specific portfolio data (balances, allowances)
    UserPortfolioData user;
    
    /// @notice Fee configuration (performance, withdrawal, deposit fees)
    VaultFeeData fees;
    
    /// @notice Harvest data (pending rewards, readiness)
    HarvestData harvest;
    
    // ═══════════════════════════════════════════════════════════════════════════
    // DERIVED DATA (Computed from Logic)
    // ═══════════════════════════════════════════════════════════════════════════
    
    /// @notice Computed vault status
    VaultStatus status;
}

// ════════════════════════════════════════════════════════════════════════════════
// STORED SUB-STRUCTURES (Layer 1: Persisted in Diamond Storage)
// ════════════════════════════════════════════════════════════════════════════════

/**
 * @notice Complete stored vault data (what's actually in Diamond storage)
 * @dev This is what gets stored in: PetalsStorageLayout.vaultData[address]
 * @dev Contains all persistent vault information that survives between transactions
 * 
 * Used internally by:
 * - ControllerFacet (for registration and updates)
 * - DataProviderFacet (for reading and building VaultCompleteData)
 * 
 * ┌──────────────────────────────────────────────────────────────────────────────┐
 * │ STORAGE OWNERSHIP - CRITICAL: DO NOT VIOLATE THIS SEPARATION                │
 * ├──────────────┬───────────────────────┬────────────────────────────────────────┤
 * │ Field        │ Written By            │ When                                   │
 * ├──────────────┼───────────────────────┼────────────────────────────────────────┤
 * │ identity     │ ControllerFacet       │ Registration (once)                    │
 * │ metadata     │ VaultMetadataFacet  │ Initialization & updates               │
 * │ metrics      │ ControllerFacet       │ Registration + after harvests          │
 * │ strategy     │ ControllerFacet       │ Registration (once)                    │
 * │ ui           │ VaultMetadataFacet  │ Initialization & updates               │
 * └──────────────┴───────────────────────┴────────────────────────────────────────┘
 * 
 * IMPORTANT RULES:
 * 1. ControllerFacet writes: identity, strategy (immutable after registration)
 * 2. ControllerFacet writes: metrics (updated after harvests)
 * 3. VaultMetadataFacet writes: metadata, ui (mutable, admin-controlled)
 * 4. NO OTHER FACETS should write to these fields
 * 5. Initialization order: ControllerFacet (core) → VaultMetadataFacet (properties)
 * 
 * Violating this can cause:
 * - Data corruption (two facets writing same field)
 * - Broken initialization (properties set before core data)
 * - Audit failures (unclear ownership boundaries)
 */
struct VaultStoredData {
    VaultIdentity identity;      // ControllerFacet ONLY - immutable after registration
    VaultMetadata metadata;      // VaultMetadataFacet ONLY - mutable
    VaultMetrics metrics;        // ControllerFacet ONLY - updated after harvests
    StrategyData strategy;       // ControllerFacet ONLY - immutable after registration
    VaultUIMetadata ui;          // VaultMetadataFacet ONLY - mutable
}

/**
 * @notice Basic vault identity information
 * @dev Core identification fields for vault tracking
 */
struct VaultIdentity {
    address vaultAddress;        // Vault contract address
    bytes32 vaultId;             // Unique vault identifier
    uint256 createdAt;           // Vault creation timestamp
    uint256 registeredAt;        // Registration timestamp in controller
    address deployer;            // Address that deployed the vault
}

/**
 * @notice Vault metadata for display and categorization
 * @dev Human-readable information about the vault
 */
struct VaultMetadata {
    bytes name;                  // Vault name - dynamic length for complex multi-token pools (e.g., "BeethovenX USDC-DAI-USDT Stable Pool")
    bytes32 symbol;              // Vault symbol (e.g., "P-wS-SHADOW") - always short, keep bytes32
    bytes32 protocol;            // Protocol name (e.g., "Shadow", "Aave") - always short, keep bytes32
    bytes32 category;            // Category (e.g., "Stable", "Volatile", "Blue-chip") - always short, keep bytes32
    uint8 riskLevel;             // Risk level 1-10
    bytes description;           // Vault description
    bytes strategyDescription;   // Strategy description
}

/**
 * @notice Performance metrics tracked over time
 * @dev Updated after each harvest to maintain historical performance data
 */
struct VaultMetrics {
    uint256 lastAPY;             // APY from most recent harvest (basis points)
    uint256 totalHarvests;       // Total number of harvests executed
    uint64 lastHarvest;          // Timestamp of last harvest
    uint256 supplyApy;           // Supply APY for lending strategies
    uint256 borrowApy;           // Borrow APY for lending strategies
    uint256 _reserved1;          // Reserved for future metrics
    uint256 _reserved2;          // Reserved for future metrics
}

/**
 * @notice Strategy configuration and deployment info
 * @dev Static information about the strategy contract
 */
struct StrategyData {
    address strategyAddress;     // Strategy contract address
    address underlyingAsset;     // Asset the strategy manages
    bytes32 strategyType;        // Strategy type identifier (e.g., "Shadow-Volatile-V1")
    uint64 registeredAt;         // When strategy was registered
    address deployer;            // Who deployed the strategy
    uint256 collateralFactor;    // Collateral factor for lending (basis points)
    uint16 slippageTolerance;    // Slippage tolerance in basis points (0-1000 = 0-10%)
}

/**
 * @notice UI metadata for frontend display
 * @dev All data needed for rich vault UI (logos, links, LP token info)
 * @dev Uses bytes instead of string for gas efficiency (~50% savings)
 * @dev Frontend decodes with ethers.toUtf8String(bytesData)
 * 
 * Contains:
 * - Branding: Vault and protocol logos
 * - Links: Website, docs, social media (in socials array)
 * - LP Info: Underlying token addresses and metadata (supports N tokens for Curve/Balancer/BeethovenX)
 * 
 * Use Cases:
 * - Display vault branding on list and detail pages
 * - Provide direct links to protocol websites/docs
 * - Show LP token composition without additional RPC calls
 * - Enable token selection dropdowns with proper symbols and logos
 * - Support multi-token pools (2+ tokens)
 * 
 * Socials Array Convention:
 * - socials[0] = website
 * - socials[1] = docs
 * - socials[2] = discord
 * - socials[3] = twitter
 * 
 * Multi-Token Pool Support:
 * - For UniV2/Solidly pairs: lpTokens.length = 2
 * - For Curve 3pool: lpTokens.length = 3
 * - For Balancer weighted pools: lpTokens.length = 2-8
 * - Arrays are parallel: lpTokens[i], lpTokenSymbols[i], lpTokenLogos[i]
 */
struct VaultUIMetadata {
    // === BRANDING ===
    bytes vaultLogoURI;          // Vault-specific logo (IPFS/HTTP)
    bytes protocolLogoURI;       // Protocol logo
    
    // === LINKS (Array for gas efficiency) ===
    bytes[] socials;             // [website, docs, discord, twitter]
    
    // === LP TOKEN INFO (flexible for multi-token pools) ===
    address[] lpTokens;          // Underlying token addresses (2+ for multi-token pools)
    bytes32[] lpTokenSymbols;    // Cached symbols (parallel to lpTokens)
    bytes[] lpTokenLogos;        // Logo URIs (parallel to lpTokens)
    
    // === TAGS (for filtering and discovery) ===
    bytes32[] tags;              // Tag IDs applied to this vault (e.g., [TAG_LP_STRATEGY, TAG_AUDITED])
}

// ════════════════════════════════════════════════════════════════════════════════
// COMPUTED SUB-STRUCTURES (Layer 2: Calculated On-Demand from Contracts)
// ════════════════════════════════════════════════════════════════════════════════

/**
 * @notice Real-time vault state data
 * @dev Computed by querying vault and strategy contracts
 * @dev NOT stored - calculated fresh on each DataProviderFacet.getVaultData() call
 * 
 * Data Sources:
 * - vault.totalAssets()
 * - vault.totalSupply()
 * - strategy.totalAssets()
 * - vault.maxDeposit(user)
 * - oracle.getPrice(asset)
 */
struct VaultStateData {
    uint256 totalAssets;         // Total assets in vault (underlying asset)
    uint256 totalSupply;         // Total vault token supply
    uint256 strategyBalance;     // Assets deployed in strategy
    uint256 sharePrice;          // Current share price (18 decimals)
    uint256 tvlEstimateUSD;      // Oracle-based TVL estimate (6 decimals)
    uint256 maxDeposit;          // Maximum deposit allowed (ERC4626)
    uint256 maxWithdraw;         // Maximum withdrawal allowed (ERC4626)
    uint256 maxRedeem;           // Maximum redemption allowed (ERC4626)
    bytes32 assetSymbol;         // Asset symbol (gas-efficient bytes32)
    uint8 assetDecimals;         // Asset decimal places
    bool vaultActive;            // Vault operational status
    bool strategyPaused;         // Strategy pause status
    uint256 assetPriceUSD;       // Asset price in USD (18 decimals) - 0 if unavailable
    uint8 priceConfidence;       // Oracle confidence level (0-100) - 0 if no oracle
}

/**
 * @notice User-specific portfolio data
 * @dev Computed by querying vault and asset contracts for user balances
 * @dev Pass address(0) to skip user-specific data
 * 
 * Data Sources:
 * - vault.balanceOf(user)
 * - asset.balanceOf(user)
 * - asset.allowance(user, vault)
 */
struct UserPortfolioData {
    uint256 userBalance;         // User's vault share balance
    uint256 userAssetBalance;    // User's underlying asset balance
    uint256 userAllowance;       // User's asset allowance to vault
    uint256 positionValueUSD;    // User's vault position value in USD (6 decimals) - 0 if unavailable
    uint256 availableValueUSD;   // User's available asset balance in USD (6 decimals) - 0 if unavailable
}

/**
 * @notice Fee configuration data
 * @dev Computed by querying fee configuration from Diamond storage
 * @dev Only performance fees are charged - deposit/withdrawal fees removed
 * 
 * Data Sources:
 * - s.vaultFeeConfigs[vault] or s.universalFeeConfig
 * - controller.defaultPerformanceFee (fallback)
 */
struct VaultFeeData {
    uint256 performanceFee;      // Performance fee in basis points (only fee charged)
    uint256 supplyApy;           // Supply APY for lending strategies
    uint256 borrowApy;           // Borrow APY for lending strategies
    uint256 collateralFactor;    // Collateral factor for lending (basis points)
}

/**
 * @notice Harvest readiness and reward data
 * @dev Computed by querying strategy contract for pending rewards
 * @dev Used to determine if harvest() can be called profitably
 * 
 * Data Sources:
 * - strategy.totalRewardsAvailable()
 * - strategy.lastHarvest()
 * - strategy.paused()
 */
struct HarvestData {
    uint256 pendingRewards;      // Total pending rewards available
    uint256 lastHarvestTime;     // Timestamp of last harvest
    uint256 timeSinceLastHarvest; // Calculated time since last harvest
    uint256 totalHarvests;       // Total number of harvests executed
    address[] rewardTokens;      // Array of reward token addresses
    uint256[] rewardAmounts;     // Array of pending reward amounts
    bool canHarvest;             // Whether harvest can be called now
    uint256 callRewardValueUSD;  // Harvester reward value in USD (6 decimals) - 0 if unavailable
    uint256 pendingRewardsValueUSD; // Total pending rewards value in USD (6 decimals) - 0 if unavailable
}

// ════════════════════════════════════════════════════════════════════════════════
// DERIVED DATA (Layer 3: Computed from Logic)
// ════════════════════════════════════════════════════════════════════════════════

/**
 * @notice Vault status enumeration
 * @dev Computed from vault.active() and strategy.paused()
 */
enum VaultStatus {
    Active,    // Vault is active and strategy is not paused
    Paused,    // Strategy is paused (deposits/withdrawals may be restricted)
    Retired    // Vault is retired (no longer operational)
}

// ════════════════════════════════════════════════════════════════════════════════
// METADATA REGISTRY STRUCTURES
// ════════════════════════════════════════════════════════════════════════════════

/**
 * @notice Chain metadata for the current deployment
 * @dev Each Diamond deployment is chain-specific, so only one ChainMetadata per deployment
 * @dev Stored once per chain, provides UI with chain-specific information
 * 
 * Use Cases:
 * - Display chain name and logo in UI
 * - Provide explorer links for contract addresses
 * - Enable wallet RPC configuration
 */
struct ChainMetadata {
    uint256 chainId;             // Chain ID (e.g., 146 for Sonic)
    bytes32 name;                // Chain name (e.g., "Sonic")
    bytes32 nativeCurrency;      // Native currency symbol (e.g., "S")
    bytes logoURI;               // Chain logo (IPFS/HTTP)
    bytes explorerBaseURL;       // Block explorer base URL (e.g., "https://sonicscan.org")
    bytes rpcURL;                // RPC endpoint for wallet connections
    bool isSet;                  // Whether metadata has been configured
}

/**
 * @notice Dynamic token category information
 * @dev Replaces enum to allow runtime category management
 * @dev Categories can be added/updated without contract redeployment
 * 
 * Use Cases:
 * - Filter tokens by category in UI
 * - Organize token selection dropdowns
 * - Display category-specific metadata
 */
struct TokenCategoryInfo {
    bytes32 categoryId;          // Unique identifier (e.g., keccak256("STABLECOIN"))
    bytes32 displayName;         // UI display name (e.g., "Stablecoin")
    bytes description;           // Category description for UI
    bool isActive;               // Whether category is active
    uint256 createdAt;           // Creation timestamp
}

/**
 * @notice Complete token metadata for UI display
 * @dev Stored per token address in MetadataRegistry
 * @dev Uses bytes instead of string for gas efficiency
 * 
 * Use Cases:
 * - Display token symbols and logos in vault list
 * - Enable "Create Vault" UI with token dropdowns
 * - Show rich token information in AssetsTab
 * - Filter tokens by category
 */
struct TokenMetadata {
    address tokenAddress;        // Token contract address
    bytes32 symbol;              // Token symbol (e.g., "USDC") - bytes32 for gas efficiency
    bytes32 name;                // Token name (e.g., "USD Coin")
    uint8 decimals;              // Token decimals
    bytes32 category;            // References TokenCategoryInfo.categoryId
    bytes logoURI;               // Token logo (IPFS/HTTP) - bytes for flexibility
    bytes description;           // Rich description for AssetsTab (supports markdown)
    bool isActive;               // Whether token is active for new vaults
    uint256 addedAt;             // Timestamp when token was registered
}

// Default category constants for initialization
bytes32 constant CATEGORY_STABLECOIN = keccak256("STABLECOIN");
bytes32 constant CATEGORY_GOVERNANCE = keccak256("GOVERNANCE");
bytes32 constant CATEGORY_LP_TOKEN = keccak256("LP_TOKEN");
bytes32 constant CATEGORY_WRAPPED_NATIVE = keccak256("WRAPPED_NATIVE");
bytes32 constant CATEGORY_YIELD_BEARING = keccak256("YIELD_BEARING");
bytes32 constant CATEGORY_BRIDGE_TOKEN = keccak256("BRIDGE_TOKEN");

/**
 * @notice Vault tag information for filtering and discovery
 * @dev Tags are dynamic, reusable labels that can be applied to multiple vaults
 * @dev Examples: "LP Strategy", "Single Asset", "Lending"
 * 
 * Use Cases:
 * - Filter vaults by strategy type
 * - Display strategy badges in UI
 * - Group vaults by characteristics
 * - Enable advanced search and discovery
 */
struct VaultTagInfo {
    bytes32 tagId;               // Unique identifier (e.g., keccak256("LP_STRATEGY"))
    bytes32 displayName;         // UI display name (e.g., "LP Strategy")
    bytes description;           // Tag description for tooltips
    bool isActive;               // Whether tag is active
}

// Minimal tag constants for auto-tagging logic (used by ControllerFacet)
bytes32 constant TAG_LP_STRATEGY = keccak256("LP_STRATEGY");
bytes32 constant TAG_SINGLE_ASSET = keccak256("SINGLE_ASSET");
bytes32 constant TAG_LENDING = keccak256("LENDING");

// ════════════════════════════════════════════════════════════════════════════════
// FEE SYSTEM STRUCTURES
// ════════════════════════════════════════════════════════════════════════════════

/**
 * @notice Fee configuration for a specific vault
 * @dev Simplified to only performance fees - deposit/withdrawal fees removed (unused)
 */
struct VaultFeeConfig {
    uint16 performanceFee;       // Performance fee in basis points (only fee charged)
    address[] recipients;        // Fee recipients
    uint256[] ratios;            // Fee ratios (basis points, should sum to 10000)
    bytes32[] labels;            // Labels for identification
    uint256 lastUpdated;         // Last update timestamp
    bool isOverride;             // Whether this overrides universal config
}

/**
 * @notice Universal fee configuration (default for all vaults)
 * @dev Used when vault doesn't have a specific fee override
 */
struct UniversalFeeConfig {
    address[] recipients;        // Fee recipients
    uint256[] ratios;            // Fee ratios (basis points, should sum to 10000)
    bytes32[] labels;            // Labels for identification
    uint256 lastUpdated;         // Last update timestamp
}

// Note: ProtocolInfo struct removed - use UniversalFactory instead
// Migration: UniversalFactoryFacet.getProtocolRegistration(baseProtocol)

// ════════════════════════════════════════════════════════════════════════════════
// SHARED EVENTS
// ════════════════════════════════════════════════════════════════════════════════

/// @notice Vault operations
event VaultDeployed(
    address indexed vault,
    address indexed strategy,
    address indexed asset,
    bytes name,  // Full-length name (no truncation)
    bytes32 symbol,
    bytes32 strategyType,
    bytes32 baseProtocol
);

event VaultUpdated(address indexed vault, uint256 indexed updateType, bytes data);

event HarvestExecuted(address indexed vault, address indexed harvester, uint256 yield, uint256 lastAPY, uint256 totalAssets);

event FeeConfigUpdated(address indexed vault, VaultFeeConfig config, bool isUniversal);

event ProtocolConfigured(
    bytes32 indexed protocolType, address indexed factory, address indexed implementation, bool isActive
);

event ProtocolConstantsUpdated(
    uint256 basisPoints, uint256 maxSlippage, uint256 minHarvestDelay, uint256 defaultPerformanceFee, uint256 defaultSlippageTolerance
);

event RolesTransferredOnRegistration(
    address indexed vault, address indexed strategy, bool managerRole, bool emergencyRole
);

event VaultUIMetadataUpdated(address indexed vault, VaultUIMetadata uiMetadata);

event VaultMetadataUpdated(
    address indexed vault,
    bytes name,
    bytes32 protocol,
    bytes32 category,
    uint8 riskLevel
);

event VaultTagsUpdated(address indexed vault, bytes32[] oldTags, bytes32[] newTags);

/// @notice Strategy operations
event StrategyUpdated(address indexed newStrategy);
event StrategyConfigUpdated(uint8 indexed updateType, bytes data);

event StrategyDeployed(address indexed strategy, bytes32 indexed protocolType, address indexed deployer);
event StrategyDeployedDetailed(
    address indexed strategy,
    address indexed vault,
    bytes32 indexed strategyType,
    address deployer,
    address asset,
    uint256 timestamp
);

/// @notice Deployment queue operations
event DeploymentQueued(address indexed vault, address indexed strategy, address indexed asset, address deployer);

event DeploymentConfirmed(address indexed vault, bool managerRoleTransferred, bool emergencyRoleTransferred);

event DeploymentRejected(address indexed vault, address indexed strategy, address indexed asset);

/// @notice Permission system
event RoleCacheUpdated(bytes32 indexed role, address indexed account, bool granted);

    event FeeRecipientUpdated(address indexed previousFeeRecipient, address indexed newFeeRecipient);

/// @notice Rewards and routing
event RewardTokensSet(address[] rewardTokens);

event RewardConfigurationUpdated(address[] rewardTokens, address[][] routes);

event NativeToLp0RouteSet(address[] route);

event NativeToLp1RouteSet(address[] route);

event EmergencyWithdrawFailed(bytes reason);

// ════════════════════════════════════════════════════════════════════════════════
// SHARED ERRORS
// ════════════════════════════════════════════════════════════════════════════════

/// @notice General errors
error ZeroAddress();
error InvalidAsset();
error InvalidRouter();
error InvalidStrategy(address strategy);
error InvalidVault(address vault);
error InvalidShadowToken();
error InvalidRecipient();
error OnlyVault();
error VaultNotFound(address vault);
error StrategyNotFound();
error ProtocolNotFound(bytes32 protocol);
error ProtocolInactive(bytes32 protocol);
error AlreadyInitialized();
error UnauthorizedUpdate();
error EmptyArray();
error NoRewardTokens();
error NativeTokenNotConfigured();

/// @notice Fee system errors
error FeeTooHigh(uint256 fee, uint256 maxFee);
error TotalFeesExceeded(uint256 totalFees, uint256 maxFees);
error InvalidConfiguration();

/// @notice Registration errors
error VaultAlreadyRegistered();
error VaultNotConnectedToStrategy();
error StrategyOwnershipTransferFailed();
error DuplicateRegistration(address asset, bytes32 strategyType);

/// @notice Queue system errors
error DeploymentAlreadyQueued();
error DeploymentNotQueued();
error DeploymentAlreadyRegistered();
error NotValidDeployment();

// ============================================================================
// UNIVERSAL FACTORY TYPES
// ============================================================================

/// @notice Protocol registration in UniversalFactory
struct ProtocolRegistration {
    bytes32 baseProtocol;          // Protocol identifier (e.g., "Shadow")
    uint256 protocolIndex;         // Index in enumeration array
    bytes description;             // Protocol description
    bool isActive;                 // Whether protocol accepts new deployments
    bool exists;                   // Whether protocol is registered
    uint256 registeredAt;          // Registration timestamp
    uint256 totalDeployments;      // Total strategies deployed across all types
    bytes logoURI;                 // Protocol logo (IPFS/HTTP) for UI display
    bytes[] socials;               // Social links [website, docs, discord, twitter]
}

/// @notice Strategy type registration in UniversalFactory
struct StrategyTypeRegistration {
    bytes32 strategyType;          // Strategy type identifier (e.g., "Shadow-Volatile")
    uint256 typeIndex;             // Index within protocol's strategy types
    address implementation;        // Master implementation address
    bytes name;                    // Human-readable name
    bytes description;             // Strategy description
    bool isActive;                 // Whether type accepts new deployments
    bool exists;                   // Whether type is registered
    uint256 registeredAt;          // Registration timestamp
    uint256 deployCount;           // Number of strategies deployed
}

// ============================================================================
// ORACLE TYPES
// ============================================================================

/// @notice Price data with metadata
struct PriceData {
    uint256 price;          // Price in USD (18 decimals)
    uint8 confidence;       // Confidence level (0-100)
    uint256 lastUpdate;     // Last update timestamp
    bytes32 method;         // Pricing method used
}

/// @notice Router info for Oracle price queries
struct OracleRouterInfo {
    address routerAddress;  // DEX router address
    RouterType routerType;  // Router type (SOLIDLY, UNISWAP_V2, etc.)
}

/// @notice LP token data structure (supports multi-token pools)
/// @dev Uses arrays to support 2-token pairs AND multi-token pools (Balancer, Curve)
struct LPTokenData {
    bool isLP;              // Is this an LP token?
    address[] tokens;       // ALL tokens (2 for UniV2/Solidly, 3+ for Balancer/Curve)
    uint256[] reserves;     // ALL reserves (parallel to tokens array)
    uint256 totalSupply;    // Total LP token supply
    bool isStable;          // Stable vs volatile pool
    bytes metadata;         // Protocol-specific data (poolId, fees, etc.)
}

/// @notice Asset type classification
enum AssetType {
    STANDALONE_TOKEN,    // Regular ERC20 (USDC, WETH, SHADOW)
    LP_TOKEN_2,          // 2-token LP (UniswapV2, Solidly pairs)
    LP_TOKEN_MULTI,      // Multi-token LP (Balancer, Curve pools with 3+ tokens)
    YIELD_BEARING        // Yield-bearing tokens (aUSDC, cDAI - future support)
}

/// @notice Complete asset metadata for registry
/// @dev Used by ChainRegistryFacet for explicit asset registration
struct AssetMetadata {
    address assetAddress;        // Asset contract address
    AssetType assetType;         // Type classification
    RouterType routerType;       // For LP tokens: which DEX/router type
    
    // Composition (for LP tokens)
    address[] componentTokens;   // Underlying tokens (e.g., [SHADOW, wSONIC])
    
    // Display metadata
    bytes32 symbol;              // Asset symbol (e.g., "SHADOW-wSONIC-LP")
    bytes name;                  // Full name for UI display
    bytes logoURI;               // Asset logo URI (IPFS/HTTP)
    
    // Categorization & Status
    bytes32 category;            // Category ID (references TokenCategoryInfo)
    bool isActive;               // Whether asset can be used for new vaults
    uint256 registeredAt;        // Registration timestamp
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../storage/PetalsStorageLayout.sol";

/**
 * @title RoleChecker
 * @author Petals Protocol
 * @notice Shared access control library for all Diamond facets
 * @dev Provides centralized role checking logic to avoid duplication across facets
 * 
 * Named RoleChecker (not AccessControl) to avoid conflicts with OpenZeppelin's AccessControl contract
 * 
 * Usage:
 *   import "../../00_libraries/RoleChecker.sol";
 *   
 *   modifier onlyRole(uint64 role) {
 *       if (!RoleChecker.hasRole(role, msg.sender)) {
 *           revert UnauthorizedUpdate();
 *       }
 *       _;
 *   }
 */
library RoleChecker {
    
    /// @notice Master role constant (admin/owner role)
    uint64 internal constant MASTER_ROLE = 0;
    
    /// @notice Strategist role constant
    uint64 internal constant STRATEGIST_ROLE = 1;
    
    /// @notice Guardian role constant (protocol-wide emergency powers)
    uint64 internal constant GUARDIAN_ROLE = 2;
    
    /**
     * @notice Check if an account has a specific role
     * @dev Checks in order:
     *      1. Is account the master address for MASTER_ROLE?
     *      2. Does account have role on this contract (address(this))?
     *      3. Does account have global role (address(0))?
     * @param role Role ID to check
     * @param account Account address to check
     * @return Whether account has the role
     */
    function hasRole(uint64 role, address account) internal view returns (bool) {
        PetalsStorageLayout.AppStorage storage s = PetalsStorageLayout.getStorage();
        
        // Master address always has MASTER_ROLE
        if (role == MASTER_ROLE && account == s.masterAddress) return true;
        
        // Check contract-specific role
        if (s.contractRoles[address(this)][role][account]) return true;
        
        // Check global role (address(0) = all contracts)
        if (s.contractRoles[address(0)][role][account]) return true;
        
        return false;
    }
    
    // Note: requireRole() function removed - use hasRole() with custom errors instead
    // Example: if (!RoleChecker.hasRole(role, msg.sender)) revert UnauthorizedUpdate();
}

File 5 of 7 : ICommonErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title ICommonErrors
/// @notice Common error definitions used across multiple contracts
/// @dev Inherit this interface to access common errors and reduce code duplication
interface ICommonErrors {
    // ============ COMMON ERRORS ============

    error ZeroAddress();
    error UnauthorizedUpdate();
    error AlreadyInitialized();
    error InvalidStrategy(address strategy);
    error VaultNotFound();
    error EmptyArray();
    error InvalidAsset();
    error InvalidRouter();
    error NoRewardTokens();
    error NativeTokenNotConfigured();
    error InsufficientBalance();

    // ============ COMMON ACCESS ERRORS ============
    error OnlyVault();
    error InvalidRecipient();
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @notice Strategy factory interface for clone deployment
/// @dev Extended to support multi-type factories and Universal Factory pattern
interface IStrategyFactory {
    // ============ DEPLOYMENT ============
    
    /**
     * @notice Deploy a strategy clone with custom configuration
     * @param config ABI-encoded configuration (format depends on factory implementation)
     * @param owner Strategy owner address
     * @return strategy Deployed strategy address
     */
    function createStrategy(bytes calldata config, address owner) external returns (address strategy);
    
    // ============ LEGACY FUNCTIONS (for backward compatibility) ============
    
    /**
     * @notice Get master implementation address
     * @dev For single-type factories, returns the implementation
     * @dev For multi-type factories, may return address(0) or primary implementation
     * @return Implementation address
     */
    function implementation() external view returns (address);
    
    /**
     * @notice Get estimated gas cost for strategy deployment
     * @return Estimated gas cost
     */
    function getStrategyCreationGas() external view returns (uint256);
    
    // ============ MULTI-TYPE FACTORY SUPPORT (NEW) ============
    
    /**
     * @notice Get base protocol this factory serves
     * @dev Used by Universal Factory pattern to identify factory type
     * @return baseProtocol Base protocol identifier (e.g., bytes32("Shadow"))
     */
    function getBaseProtocol() external view returns (bytes32 baseProtocol);
    
    /**
     * @notice Get all strategy types this factory can deploy
     * @dev Used for enumeration and UI display
     * @return strategyTypes Array of strategy type identifiers
     */
    function getSupportedStrategyTypes() external view returns (bytes32[] memory strategyTypes);
}

File 7 of 7 : RouterTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title RouterTypes
 * @notice Shared type definitions for the extensible routing system
 * @dev Enums and structs used across routing libraries and facets
 */

/// @notice Supported router types for different DEX protocols
enum RouterType {
    SOLIDLY,      // Shadow, Velodrome, Aerodrome, Thena (Solidly forks)
    UNIV2,        // UniswapV2, SushiSwap, PancakeSwap
    UNIV3,        // UniswapV3, PancakeSwap V3
    UNIVERSAL,    // Uniswap Universal Router
    CURVE,        // Curve Finance
    BALANCER      // Balancer
}

/// @notice Metadata about a route configuration update
struct RouteUpdateMetadata {
    uint256 timestamp;      // When the routes were last updated
    address updatedBy;      // Who updated the routes
    uint256 updateCount;    // Number of times routes have been updated
}

Settings
{
  "remappings": [
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": true
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"DuplicateTag","type":"error"},{"inputs":[],"name":"EmptyArray","type":"error"},{"inputs":[],"name":"IdentityMismatch","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidAsset","type":"error"},{"inputs":[],"name":"InvalidInputArrayLength","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidRouter","type":"error"},{"inputs":[{"internalType":"address","name":"strategy","type":"address"}],"name":"InvalidStrategy","type":"error"},{"inputs":[],"name":"NativeTokenNotConfigured","type":"error"},{"inputs":[],"name":"NoRewardTokens","type":"error"},{"inputs":[],"name":"OnlyVault","type":"error"},{"inputs":[],"name":"StrategyNotSet","type":"error"},{"inputs":[],"name":"TagAlreadyExists","type":"error"},{"inputs":[],"name":"TagNotFound","type":"error"},{"inputs":[],"name":"TooManyTags","type":"error"},{"inputs":[],"name":"UnauthorizedUpdate","type":"error"},{"inputs":[],"name":"VaultAlreadyHasTag","type":"error"},{"inputs":[],"name":"VaultDoesNotHaveTag","type":"error"},{"inputs":[],"name":"VaultNotFound","type":"error"},{"inputs":[],"name":"VaultNotIndexed","type":"error"},{"inputs":[],"name":"VaultNotRegistered","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"bytes32","name":"tagId","type":"bytes32"}],"name":"TagAppliedToVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"bytes32","name":"tagId","type":"bytes32"}],"name":"TagRemovedFromVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"bytes","name":"name","type":"bytes"},{"indexed":false,"internalType":"bytes32","name":"protocol","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"category","type":"bytes32"},{"indexed":false,"internalType":"uint8","name":"riskLevel","type":"uint8"}],"name":"VaultMetadataUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"components":[{"internalType":"bytes","name":"name","type":"bytes"},{"internalType":"bytes32","name":"symbol","type":"bytes32"},{"internalType":"bytes32","name":"protocol","type":"bytes32"},{"internalType":"bytes32","name":"category","type":"bytes32"},{"internalType":"uint8","name":"riskLevel","type":"uint8"},{"internalType":"bytes","name":"description","type":"bytes"},{"internalType":"bytes","name":"strategyDescription","type":"bytes"}],"indexed":false,"internalType":"struct VaultMetadata","name":"metadata","type":"tuple"},{"indexed":false,"internalType":"bytes32[]","name":"initialTags","type":"bytes32[]"}],"name":"VaultPropertiesInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"tagId","type":"bytes32"}],"name":"VaultTagDeactivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"tagId","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"displayName","type":"bytes32"}],"name":"VaultTagRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"tagId","type":"bytes32"}],"name":"VaultTagUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"bytes32[]","name":"oldTags","type":"bytes32[]"},{"indexed":false,"internalType":"bytes32[]","name":"newTags","type":"bytes32[]"}],"name":"VaultTagsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"components":[{"internalType":"bytes","name":"vaultLogoURI","type":"bytes"},{"internalType":"bytes","name":"protocolLogoURI","type":"bytes"},{"internalType":"bytes[]","name":"socials","type":"bytes[]"},{"internalType":"address[]","name":"lpTokens","type":"address[]"},{"internalType":"bytes32[]","name":"lpTokenSymbols","type":"bytes32[]"},{"internalType":"bytes[]","name":"lpTokenLogos","type":"bytes[]"},{"internalType":"bytes32[]","name":"tags","type":"bytes32[]"}],"indexed":false,"internalType":"struct VaultUIMetadata","name":"uiMetadata","type":"tuple"}],"name":"VaultUIMetadataUpdated","type":"event"},{"inputs":[],"name":"MAX_TAGS_PER_VAULT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"bytes32","name":"tagId","type":"bytes32"}],"name":"addVaultTag","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"autoPopulateVaultUI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"tagId","type":"bytes32"}],"name":"deactivateVaultTag","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllVaultTags","outputs":[{"components":[{"internalType":"bytes32","name":"tagId","type":"bytes32"},{"internalType":"bytes32","name":"displayName","type":"bytes32"},{"internalType":"bytes","name":"description","type":"bytes"},{"internalType":"bool","name":"isActive","type":"bool"}],"internalType":"struct VaultTagInfo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"tagId","type":"bytes32"}],"name":"getVaultTag","outputs":[{"components":[{"internalType":"bytes32","name":"tagId","type":"bytes32"},{"internalType":"bytes32","name":"displayName","type":"bytes32"},{"internalType":"bytes","name":"description","type":"bytes"},{"internalType":"bool","name":"isActive","type":"bool"}],"internalType":"struct VaultTagInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"getVaultTags","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"components":[{"internalType":"bytes","name":"name","type":"bytes"},{"internalType":"bytes32","name":"symbol","type":"bytes32"},{"internalType":"bytes32","name":"protocol","type":"bytes32"},{"internalType":"bytes32","name":"category","type":"bytes32"},{"internalType":"uint8","name":"riskLevel","type":"uint8"},{"internalType":"bytes","name":"description","type":"bytes"},{"internalType":"bytes","name":"strategyDescription","type":"bytes"}],"internalType":"struct VaultMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes","name":"vaultLogoURI","type":"bytes"},{"internalType":"bytes","name":"protocolLogoURI","type":"bytes"},{"internalType":"bytes[]","name":"socials","type":"bytes[]"},{"internalType":"address[]","name":"lpTokens","type":"address[]"},{"internalType":"bytes32[]","name":"lpTokenSymbols","type":"bytes32[]"},{"internalType":"bytes[]","name":"lpTokenLogos","type":"bytes[]"},{"internalType":"bytes32[]","name":"tags","type":"bytes32[]"}],"internalType":"struct VaultUIMetadata","name":"ui","type":"tuple"},{"internalType":"bytes32[]","name":"initialTags","type":"bytes32[]"}],"name":"initializeVaultProperties","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"tagId","type":"bytes32"},{"internalType":"bytes32","name":"displayName","type":"bytes32"},{"internalType":"bytes","name":"description","type":"bytes"},{"internalType":"bool","name":"isActive","type":"bool"}],"internalType":"struct VaultTagInfo","name":"tag","type":"tuple"}],"name":"registerVaultTag","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"bytes32","name":"tagId","type":"bytes32"}],"name":"removeVaultTag","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"bytes32[]","name":"tagIds","type":"bytes32[]"}],"name":"setVaultTags","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"components":[{"internalType":"bytes","name":"vaultLogoURI","type":"bytes"},{"internalType":"bytes","name":"protocolLogoURI","type":"bytes"},{"internalType":"bytes[]","name":"socials","type":"bytes[]"},{"internalType":"address[]","name":"lpTokens","type":"address[]"},{"internalType":"bytes32[]","name":"lpTokenSymbols","type":"bytes32[]"},{"internalType":"bytes[]","name":"lpTokenLogos","type":"bytes[]"},{"internalType":"bytes32[]","name":"tags","type":"bytes32[]"}],"internalType":"struct VaultUIMetadata","name":"ui","type":"tuple"}],"name":"setVaultUIMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"vaults","type":"address[]"},{"components":[{"internalType":"bytes","name":"vaultLogoURI","type":"bytes"},{"internalType":"bytes","name":"protocolLogoURI","type":"bytes"},{"internalType":"bytes[]","name":"socials","type":"bytes[]"},{"internalType":"address[]","name":"lpTokens","type":"address[]"},{"internalType":"bytes32[]","name":"lpTokenSymbols","type":"bytes32[]"},{"internalType":"bytes[]","name":"lpTokenLogos","type":"bytes[]"},{"internalType":"bytes32[]","name":"tags","type":"bytes32[]"}],"internalType":"struct VaultUIMetadata[]","name":"uiData","type":"tuple[]"}],"name":"setVaultUIMetadataBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"components":[{"internalType":"bytes","name":"name","type":"bytes"},{"internalType":"bytes32","name":"symbol","type":"bytes32"},{"internalType":"bytes32","name":"protocol","type":"bytes32"},{"internalType":"bytes32","name":"category","type":"bytes32"},{"internalType":"uint8","name":"riskLevel","type":"uint8"},{"internalType":"bytes","name":"description","type":"bytes"},{"internalType":"bytes","name":"strategyDescription","type":"bytes"}],"internalType":"struct VaultMetadata","name":"metadata","type":"tuple"}],"name":"updateVaultMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"tagId","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"tagId","type":"bytes32"},{"internalType":"bytes32","name":"displayName","type":"bytes32"},{"internalType":"bytes","name":"description","type":"bytes"},{"internalType":"bool","name":"isActive","type":"bool"}],"internalType":"struct VaultTagInfo","name":"tag","type":"tuple"}],"name":"updateVaultTag","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608080604052346015576137b1908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c8063150c12d61461226e5780634a6ef80a146120e55780636170563514611ee55780636eeaad1314611e5c5780637b8d9fa81461187857806381c6a2bf146114f457806399bb34ec14610d7f578063a48763fa14610c31578063befd706814610a11578063c1bfdb1d146108cd578063cb0985e314610877578063d1b9ace11461034a578063d3aac175146102c1578063eb35061f146100dd5763ecca1e1e146100be575f80fd5b346100d9575f3660031901126100d957602060405160078152f35b5f80fd5b346100d95760403660031901126100d9576004356024356001600160401b0381116100d9578060040190608060031982360301126100d95761011e3361358e565b156102b257825f525f8051602061375c83398151915260205260405f2054156102a357825f525f8051602061375c83398151915260205260405f2091803583556024820135600184015561017a60028401916044840190612f1c565b906001600160401b03821161028f5761019d826101978554612ed4565b85612f64565b5f90601f83116001146102275791806101d09260649695945f9261021c575b50508160011b915f199060031b1c19161790565b90555b013580151581036100d95760036101f692019060ff801983541691151516179055565b7f41bda51eb37a72d2962c6138c65a18d88e119fec679f94b36e87ca0b2529aff25f80a2005b0135905088806101bc565b601f19831691845f5260205f20925f5b81811061027757509160019391856064989796941061025e575b505050811b0190556101d3565b01355f19600384901b60f8161c19169055878080610251565b91936020600181928787013581550195019201610237565b634e487b7160e01b5f52604160045260245ffd5b6318b4935f60e21b5f5260045ffd5b634f1f214760e01b5f5260045ffd5b346100d95760203660031901126100d9576102da613227565b506004355f525f8051602061375c83398151915260205261034660405f2060ff600360405192610309846131d4565b80548452600181015460208501526103236002820161325f565b604085015201541615156060820152604051918291602083526020830190612db3565b0390f35b346100d95761035836612de9565b906103623361358e565b156102b25760ff61037282612e9c565b5416156108685761038281612e64565b601981016103908480612f1c565b906001600160401b03821161028f576103ad826101978554612ed4565b5f90601f8311600114610804576103da92915f91836107955750508160011b915f199060031b1c19161790565b90555b601a81016103ee6020850185612f1c565b906001600160401b03821161028f5761040b826101978554612ed4565b5f90601f83116001146107a05761043892915f91836107955750508160011b915f199060031b1c19161790565b90555b601b810161044c6040850185612fb7565b90916104588282612fec565b5f9081526020812092805b8383106106c057878787601c810161047e6060850185612fb7565b91906001600160401b03831161028f57610498838361307d565b905f5260205f205f5b8381106106a55750505050601d81016104bd6080850185612fb7565b91906001600160401b03831161028f576104d783836130c3565b905f5260205f205f5b8381106106915750505050601e81016104fc60a0850185612fb7565b90916105088282612fec565b5f9081526020812092805b8383106105ab578787601f880161052d60c0840184612fb7565b91906001600160401b03831161028f5761054783836130c3565b905f5260205f205f5b838110610597576040516001600160a01b038616907f49c1d9936f48c9c75cbd236bafc985f0f64a883ca72bef48535b52e7664168fa90806105928a826133fa565b0390a2005b600190602084359401938184015501610550565b6105b58183612f1c565b906001600160401b03821161028f576105d8826105d28954612ed4565b89612f64565b5f90601f8311600114610627579261060d836001959460209487965f9261061c5750508160011b915f199060031b1c19161790565b88555b01950192019193610513565b013590508e806101bc565b601f19831691885f5260205f20925f5b8181106106795750936020936001969387969383889510610660575b505050811b018855610610565b01355f19600384901b60f8161c191690558d8080610653565b91936020600181928787013581550195019201610637565b6001906020843594019381840155016104e0565b60019060206106b3856130af565b94019381840155016104a1565b6106ca8183612f1c565b906001600160401b03821161028f576106e7826105d28954612ed4565b5f90601f831160011461072b579261071c836001959460209487965f9261061c5750508160011b915f199060031b1c19161790565b88555b01950192019193610463565b601f19831691885f5260205f20925f5b81811061077d5750936020936001969387969383889510610764575b505050811b01885561071f565b01355f19600384901b60f8161c191690558d8080610757565b9193602060018192878701358155019501920161073b565b0135905087806101bc565b601f19831691845f5260205f20925f5b8181106107ec57509084600195949392106107d3575b505050811b01905561043b565b01355f19600384901b60f8161c191690558680806107c6565b919360206001819287870135815501950192016107b0565b601f19831691845f5260205f20925f5b8181106108505750908460019594939210610837575b505050811b0190556103dd565b01355f19600384901b60f8161c1916905586808061082a565b91936020600181928787013581550195019201610814565b63dee790fb60e01b5f5260045ffd5b346100d95760203660031901126100d957610890612d49565b60ff61089b82612e9c565b541615610868576108b9601f6108b361034693612e64565b016132fd565b604051918291602083526020830190612e31565b346100d95760403660031901126100d9576108e6612d49565b602435906108f33361358e565b156102b25760ff61090382612e9c565b54161561086857815f525f8051602061375c83398151915260205260405f2054156102a357601f61093382612e64565b0180546007811015610a02575f5b8181106109d45750508054600160401b81101561028f5761096c818593600161098294018155613103565b819391549060031b91821b915f19901b19161790565b9055815f525f8051602061373c8339815191526020526109a58160405f20613118565b6001600160a01b03167ff8f1580e9ec67ec505d45da2ba4b7979bde4ebed64e14f75281cf7448322e3e15f80a3005b846109df8285613103565b90549060031b1c146109f357600101610941565b63538cc66760e01b5f5260045ffd5b63ee39e85560e01b5f5260045ffd5b346100d95760203660031901126100d9576004356001600160401b0381116100d95780600401608060031983360301126100d957610a4e3361358e565b156102b2578035918215610c2257825f525f8051602061375c83398151915260205260405f2054610c1357825f525f8051602061375c83398151915260205260405f2090838255602481013592836001840155610ab360028401916044840190612f1c565b906001600160401b03821161028f57610ad0826101978554612ed4565b5f90601f8311600114610bab579180610b029260649695945f92610ba05750508160011b915f199060031b1c19161790565b90555b013580151581036100d9576003610b2892019060ff801983541691151516179055565b5f8051602061371c83398151915254600160401b81101561028f577fb8700687a3120fabaeae7b5aa476a8e4ea300c84d68eec9e5f83a05f49e4c1bc9183610b9561096c846001602096015f8051602061371c833981519152555f8051602061371c833981519152613103565b9055604051908152a2005b0135905089806101bc565b601f19831691845f5260205f20925f5b818110610bfb575091600193918560649897969410610be2575b505050811b019055610b05565b01355f19600384901b60f8161c19169055888080610bd5565b91936020600181928787013581550195019201610bbb565b63346120b160e01b5f5260045ffd5b63d92e233d60e01b5f5260045ffd5b346100d95760403660031901126100d957610c4a612d49565b60243590610c573361358e565b156102b25760ff610c6782612e9c565b54161561086857601f610c7982612e64565b01905f915f5b815480821015610d765785610c948385613103565b90549060031b1c14610ca95750600101610c7f565b92935090915f198101908111610d625761096c610cc9610cd79285613103565b90549060031b1c9284613103565b905580548015610d4e575f190190610cef8282613103565b8154905f199060031b1b191690555560015b15610d3f57610d10828261365f565b6001600160a01b03167f77122549c5cea9920e43154e5a3125b27c24066e99e509084fad39f05b624b205f80a3005b63d09daa2b60e01b5f5260045ffd5b634e487b7160e01b5f52603160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b50505090610d01565b346100d95760203660031901126100d957610d98612d49565b610da13361358e565b156102b25760ff610db182612e9c565b54161561086857610dc181612e64565b9060405160e081018181106001600160401b0382111761028f5760405260608152602081019060608252604081016060815260608201906060825260606080840152606060a0840152606060c08401526001600160401b0360041161028f5760405160a0610e2f81836131ef565b60048252601f19015f5b8181106114e35750508152602095604051610e5488826131ef565b5f81525f3681378352604051610e6a88826131ef565b5f81525f3681376080850152604051610e8388826131ef565b5f8152601f198801885f5b8281106114d45750505060a0850152610ea9601f82016132fd565b60c085015260078101545f527f4a095d6cb9b93a0f83522807df8d2f3070c21f3a0a4ca97d86925974cbbfd3c98752610ee7600660405f200161325f565b8552601401546001600160a01b039081165f9081527f4a095d6cb9b93a0f83522807df8d2f3070c21f3a0a4ca97d86925974cbbfd3c388526040902080549091166114c0575b50610f3785612e64565b6019810184518051906001600160401b03821161028f57610f5c826101978554612ed4565b8990601f831160011461145d57610f8992915f91836113ef5750508160011b915f199060031b1c19161790565b90555b601a810185518051906001600160401b03821161028f57610fb1826101978554612ed4565b8990601f83116001146113fa57610fde92915f91836113ef5750508160011b915f199060031b1c19161790565b90555b601b8101825188815191610ff58385612fec565b01915f52885f205f925b8284106113165750505050601c81018351908151916001600160401b03831161028f57899061102e848461307d565b01905f52885f205f5b8381106112fb5750505050601d81016080850151908151916001600160401b03831161028f57899061106984846130c3565b01905f52885f205f5b8381106112e95750505050601e810160a0850151888151916110948385612fec565b01915f52885f205f925b8284106111ff5750505050601f0160c0840151908151916001600160401b03831161028f57978094986110d184846130c3565b01905f52835f205f5b8381106111ed575050505061112f9061111c60405195848752611109865160e0878a0152610100890190612d8f565b9051878203601f19016040890152612d8f565b9051858203601f19016060870152613536565b9451838603601f19016080850152805180875295820195908201915f5b8281106111d05750857f49c1d9936f48c9c75cbd236bafc985f0f64a883ca72bef48535b52e7664168fa86806105928860c06111b061119b8f6080850151601f198883030160a0890152612e31565b60a0840151868203601f190184880152613536565b910151838203601f190160e08501526001600160a01b0390961695612e31565b83516001600160a01b03168852968101969281019260010161114c565b825182820155918501916001016110da565b80519081516001600160401b03811161028f578c92611228826112228754612ed4565b87612f64565b8390601f831160011461127557826001959386959361125b935f9261126a5750508160011b915f199060031b1c19161790565b85555b0192019301929061109e565b015190505f806101bc565b90855f95949552835f20915f5b601f19851681106112ca5750926001959286959492869383601f198116106112b2575b505050811b01855561125e565b01515f1960f88460031b161c191690555f80806112a5565b9294600183959683948394015181550194019201908f94939291611282565b825182820155918a0191600101611072565b82516001600160a01b031682820155918a0191600101611037565b80519081516001600160401b03811161028f578c92611339826112228754612ed4565b8390601f831160011461137b57826001959386959361136c935f9261126a5750508160011b915f199060031b1c19161790565b85555b01920193019290610fff565b90855f95949552835f20915f5b601f19851681106113d05750926001959286959492869383601f198116106113b8575b505050811b01855561136f565b01515f1960f88460031b161c191690555f80806113ab565b9294600183959683948394015181550194019201908f94939291611388565b015190508b806101bc565b90601f19831691845f528b5f20925f5b8d82821061144757505090846001959493921061142f575b505050811b019055610fe1565b01515f1960f88460031b161c191690558a8080611422565b600185968293968601518155019501930161140a565b90601f19831691845f528b5f20925f5b8d8282106114aa575050908460019594939210611492575b505050811b019055610f8c565b01515f1960f88460031b161c191690558a8080611485565b600185968293968601518155019501930161146d565b60056114cc910161325f565b835286610f2d565b60608482018301528101610e8e565b806060602080938601015201610e39565b346100d95761150236612de9565b9061150c3361358e565b156102b25760ff61151c82612e9c565b5416156108685761152c81612e64565b6005810161153a8480612f1c565b906001600160401b03821161028f57611557826101978554612ed4565b5f90601f83116001146118145761158492915f91836107955750508160011b915f199060031b1c19161790565b90555b6020830135600682015560408301359182600783015560608401358060088401556009830192608086019360ff6115bd86612fa9565b1660ff19825416179055600a81016115d860a0880188612f1c565b906001600160401b03821161028f576115f5826101978554612ed4565b5f90601f83116001146117ac57918061162792600b9695945f926117a15750508160011b915f199060031b1c19161790565b90555b019461163960c0820182612f1c565b6001600160401b03819892981161028f5761165e816116588454612ed4565b84612f64565b5f601f821160011461170f57926116ca9594926116b9836116c29460ff977fbeb1c8c3497666cb271f5ddb01175499ac40bf04395542caab4c3c85c8f76ab39c9d5f926117045750508160011b915f199060031b1c19161790565b90555b80612f1c565b949095612fa9565b906116e2604051968796608088526080880191613190565b602086019890985260408501521660608301526001600160a01b0316930390a2005b013590508d806101bc565b601f19821690835f5260205f20915f5b81811061178957508360ff96937fbeb1c8c3497666cb271f5ddb01175499ac40bf04395542caab4c3c85c8f76ab39b9c6116ca9a9997946116c29760019510611770575b505050811b0190556116bc565b01355f19600384901b60f8161c191690558c8080611763565b9192602060018192868f01358155019401920161171f565b013590508b806101bc565b601f19831691845f5260205f20925f5b8181106117fc5750916001939185600b98979694106117e3575b505050811b01905561162a565b01355f19600384901b60f8161c191690558a80806117d6565b919360206001819287870135815501950192016117bc565b601f19831691845f5260205f20925f5b8181106118605750908460019594939210611847575b505050811b019055611587565b01355f19600384901b60f8161c1916905586808061183a565b91936020600181928787013581550195019201611824565b346100d95760403660031901126100d9576004356001600160401b0381116100d9576118a8903690600401612d5f565b6024356001600160401b0381116100d9576118c7903690600401612d5f565b6118d03361358e565b156102b257808303611e4d575f5b8381106118e757005b60ff6119046118ff6118fa84888a612f0c565b6130af565b612e9c565b54161561086857611916818385613345565b61192c6119276118fa84888a612f0c565b612e64565b6019810161193a8380612f1c565b906001600160401b03821161028f57611957826101978554612ed4565b5f90601f8311600114611de95761198492915f91836117a15750508160011b915f199060031b1c19161790565b90555b601a81016119986020840184612f1c565b906001600160401b03821161028f576119b5826101978554612ed4565b5f90601f8311600114611d85576119e292915f91836117a15750508160011b915f199060031b1c19161790565b90555b601b81016119f66040840184612fb7565b9091611a028282612fec565b5f9081526020812092805b838310611ca4575050505050601c8101611a2a6060840184612fb7565b91906001600160401b03831161028f57611a44838361307d565b905f5260205f205f5b838110611c7d5750505050601d8101611a696080840184612fb7565b91906001600160401b03831161028f57611a8383836130c3565b905f5260205f205f5b838110611c695750505050601e8101611aa860a0840184612fb7565b9091611ab48282612fec565b5f9081526020812092805b838310611b7d575050505050601f611add91019160c0810190612fb7565b91906001600160401b03831161028f57611af783836130c3565b905f5260205f205f5b838110611b69575050505080611b1c6118fa6001938789612f0c565b7f49c1d9936f48c9c75cbd236bafc985f0f64a883ca72bef48535b52e7664168fa611b60611b4b848789613345565b92604051918291878060a01b031694826133fa565b0390a2016118de565b823582820155602090920191600101611b00565b611b8d81839d989d9c999c612f1c565b906001600160401b03821161028f57611baa826105d28954612ed4565b5f90601f8311600114611bff5792611bdf836001959460209487965f92611bf45750508160011b915f199060031b1c19161790565b88555b019501920191939a959a999699611abf565b013590505f806101bc565b601f19831691885f5260205f20925f5b818110611c515750936020936001969387969383889510611c38575b505050811b018855611be2565b01355f19600384901b60f8161c191690555f8080611c2b565b91936020600181928787013581550195019201611c0f565b823581830155602090920191600101611a8c565b6001906020611c91859d989d9c999c6130af565b9401938184015501999499989598611a4d565b611cb481839d989d9c999c612f1c565b906001600160401b03821161028f57611cd1826105d28954612ed4565b5f90601f8311600114611d1b5792611d06836001959460209487965f92611bf45750508160011b915f199060031b1c19161790565b88555b019501920191939a959a999699611a0d565b601f19831691885f5260205f20925f5b818110611d6d5750936020936001969387969383889510611d54575b505050811b018855611d09565b01355f19600384901b60f8161c191690555f8080611d47565b91936020600181928787013581550195019201611d2b565b601f19831691845f5260205f20925f5b818110611dd15750908460019594939210611db8575b505050811b0190556119e5565b01355f19600384901b60f8161c191690558a8080611dab565b83830135855560019094019360209283019201611d95565b601f19831691845f5260205f20925f5b818110611e355750908460019594939210611e1c575b505050811b019055611987565b01355f19600384901b60f8161c191690558a8080611e0f565b83830135855560019094019360209283019201611df9565b63a7b682d760e01b5f5260045ffd5b346100d95760203660031901126100d957600435611e793361358e565b156102b257805f525f8051602061375c83398151915260205260405f2054156102a357805f525f8051602061375c833981519152602052600360405f200160ff1981541690557ff49bbaee82f6020a8b109958fb96cf0a256ad35e735148db9a22b1e209283cc05f80a2005b346100d95760403660031901126100d957611efe612d49565b6024356001600160401b0381116100d957611f1d903690600401612d5f565b9091611f283361358e565b156102b25760ff611f3882612e9c565b5416156108685760078211610a02575f5b82811061206c5750611f5f601f6108b383612e64565b925f5b8451811015611f885780611f82611f7b6001938861324b565b518561365f565b01611f62565b5092915f5b8181106120375750601f611fa083612e64565b016001600160401b03821161028f57611fb982826130c3565b84905f5260205f20905f5b83811061202357867f092317661db809ddb59ab04dcb02024ebeb4b868848f76de1550705c8942e1e261200a886105928989604051948594604086526040860190612e31565b84810360208601526001600160a01b03909216966131b0565b600190602083359301928185015501611fc4565b806120456001928488612f0c565b355f525f8051602061373c8339815191526020526120668460405f20613118565b01611f8d565b612077818486612f0c565b355f525f8051602061375c83398151915260205260405f2054156102a35760018101808211610d62575b8381106120b15750600101611f49565b6120bc828587612f0c565b356120c8828688612f0c565b35146120d6576001016120a1565b631a3abfc960e31b5f5260045ffd5b346100d9575f3660031901126100d9575f8051602061371c8339815191525461210d81613210565b9061211b60405192836131ef565b808252601f1961212a82613210565b015f5b8181106122575750505f8051602061371c833981519152545f5b8281106121b557836040518091602082016020835281518091526040830190602060408260051b8601019301915f905b82821061218657505050500390f35b919360019193955060206121a58192603f198a82030186528851612db3565b9601920192018594939192612177565b81811015612243576001905f8051602061371c8339815191525f528060205f2001545f525f8051602061375c83398151915260205260405f2060ff6003604051926121ff846131d4565b805484528581015460208501526122186002820161325f565b604085015201541615156060820152612231828761324b565b5261223c818661324b565b5001612147565b634e487b7160e01b5f52603260045260245ffd5b602090612262613227565b8282870101520161212d565b346100d95760803660031901126100d957612287612d49565b6001600160401b03602435116100d95760e0602435360360031901126100d9576001600160401b03604435116100d95760e0604435360360031901126100d9576064356001600160401b0381116100d9576122e6903690600401612d5f565b903033036102b2576001600160a01b036122ff84612e64565b541615612d3a5761231b600561231485612e64565b0154612ed4565b612d2c576001600160a01b0361233084612e64565b546001600160a01b038516949116849003612d1d576001600160a01b03601361235883612e64565b01541615612d0e5760ff61236b82612e9c565b541615612cff5760078311610a02575f5b838110612c95575061238d81612e64565b600581016123a060046024350180612f1c565b906001600160401b03821161028f576123bd826101978554612ed4565b5f90601f8311600114612c31576123ea92915f9183610ba05750508160011b915f199060031b1c19161790565b90555b60248035013560068201556044602435013560078201556064602435013560088201556009810160ff612424608460243501612fa9565b1660ff1982541617905561244260a460243501602435600401612f1c565b906001600160401b03821161028f5761246b82612462600a860154612ed4565b600a8601612f64565b5f90601f8311600114612bc257918061249c92600b95945f92610ba05750508160011b915f199060031b1c19161790565b600a8201555b019060c460243501916124ba83602435600401612f1c565b906001600160401b03821161028f576124d7826101978554612ed4565b5f90601f8311600114612b5e5761250492915f9183610ba05750508160011b915f199060031b1c19161790565b90555b61251081612e64565b6019810161252360046044350180612f1c565b906001600160401b03821161028f57612540826101978554612ed4565b5f90601f8311600114612afa5761256d92915f9183612a8b5750508160011b915f199060031b1c19161790565b90555b601a8101612588602460443501604435600401612f1c565b906001600160401b03821161028f576125a5826101978554612ed4565b5f90601f8311600114612a96576125d292915f9183612a8b5750508160011b915f199060031b1c19161790565b90555b601b81016125ec6044803501604435600401612fb7565b90916125f88282612fec565b5f9081526020812092805b8383106129b6575050505050601c8101612627606460443501604435600401612fb7565b91906001600160401b03831161028f57612641838361307d565b905f5260205f205f5b83811061299b5750505050601d810161266d608460443501604435600401612fb7565b91906001600160401b03831161028f5761268783836130c3565b905f5260205f205f5b8381106129875750505050601e81016126b360a460443501604435600401612fb7565b90916126bf8282612fec565b5f9081526020812092805b8383106128b2575050505050601f016126ed60c460443501604435600401612fb7565b91906001600160401b03831161028f5761270783836130c3565b905f5260205f205f5b83811061289e57505050508361280e575b50604080519081529161274e61273c6004602435018061315f565b60e06040870152610120860191613190565b9060248035013560608501526044602435013560808501526064602435013560a0850152608460243501359460ff86168096036100d95761280085946127ed6127e1610592967f90439a4e9252f0b43d7942ba9c0b7aa7f3eedea3e96f5ee786fb60b241eb8f219a60c08a01526127cf60a46024350160243560040161315f565b8a8303603f190160e08c015290613190565b9160243560040161315f565b878303603f190161010089015290613190565b9184830360208601526131b0565b5f5b8481106128695750612823601f91612e64565b016001600160401b03841161028f5761283c84826130c3565b82905f5260205f20905f5b858110612855575050612721565b600190602083359301928185015501612847565b806128776001928787612f0c565b355f525f8051602061373c8339815191526020526128988360405f20613118565b01612810565b600190602084359401938184015501612710565b6128bc8183612f1c565b906001600160401b03821161028f576128d9826105d28954612ed4565b5f90601f831160011461291d579261290e836001959460209487965f92611bf45750508160011b915f199060031b1c19161790565b88555b019501920191936126ca565b601f19831691885f5260205f20925f5b81811061296f5750936020936001969387969383889510612956575b505050811b018855612911565b01355f19600384901b60f8161c191690555f8080612949565b9193602060018192878701358155019501920161292d565b600190602084359401938184015501612690565b60019060206129a9856130af565b940193818401550161264a565b6129c08183612f1c565b906001600160401b03821161028f576129dd826105d28954612ed4565b5f90601f8311600114612a215792612a12836001959460209487965f92611bf45750508160011b915f199060031b1c19161790565b88555b01950192019193612603565b601f19831691885f5260205f20925f5b818110612a735750936020936001969387969383889510612a5a575b505050811b018855612a15565b01355f19600384901b60f8161c191690555f8080612a4d565b91936020600181928787013581550195019201612a31565b013590508a806101bc565b601f19831691845f5260205f20925f5b818110612ae25750908460019594939210612ac9575b505050811b0190556125d5565b01355f19600384901b60f8161c19169055898080612abc565b91936020600181928787013581550195019201612aa6565b601f19831691845f5260205f20925f5b818110612b465750908460019594939210612b2d575b505050811b019055612570565b01355f19600384901b60f8161c19169055898080612b20565b91936020600181928787013581550195019201612b0a565b601f19831691845f5260205f20925f5b818110612baa5750908460019594939210612b91575b505050811b019055612507565b01355f19600384901b60f8161c19169055888080612b84565b91936020600181928787013581550195019201612b6e565b600a84015f5260205f20915f5b601f1985168110612c195750918391600193600b9695601f19811610612c00575b505050811b01600a8201556124a2565b01355f19600384901b60f8161c19169055888080612bf0565b90926020600181928686013581550194019101612bcf565b601f19831691845f5260205f20925f5b818110612c7d5750908460019594939210612c64575b505050811b0190556123ed565b01355f19600384901b60f8161c19169055888080612c57565b91936020600181928787013581550195019201612c41565b612ca0818585612f0c565b355f525f8051602061375c83398151915260205260405f2054156102a35760018101808211610d62575b848110612cda575060010161237c565b612ce5828686612f0c565b35612cf1828787612f0c565b35146120d657600101612cca565b631c1be0cd60e01b5f5260045ffd5b630fb1a74560e41b5f5260045ffd5b63b2f0dc1f60e01b5f5260045ffd5b62dc149f60e41b5f5260045ffd5b63775a7b0960e11b5f5260045ffd5b600435906001600160a01b03821682036100d957565b9181601f840112156100d9578235916001600160401b0383116100d9576020808501948460051b0101116100d957565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b908151815260208201516020820152606080612dde6040850151608060408601526080850190612d8f565b930151151591015290565b9060406003198301126100d9576004356001600160a01b03811681036100d95791602435906001600160401b0382116100d95760e09082900360031901126100d95760040190565b90602080835192838152019201905f5b818110612e4e5750505090565b8251845260209384019390920191600101612e41565b6001600160a01b03165f9081527f4a095d6cb9b93a0f83522807df8d2f3070c21f3a0a4ca97d86925974cbbfd39e6020526040902090565b6001600160a01b03165f9081527f4a095d6cb9b93a0f83522807df8d2f3070c21f3a0a4ca97d86925974cbbfd39d6020526040902090565b90600182811c92168015612f02575b6020831014612eee57565b634e487b7160e01b5f52602260045260245ffd5b91607f1691612ee3565b91908110156122435760051b0190565b903590601e19813603018212156100d957018035906001600160401b0382116100d9576020019181360383136100d957565b818110612f59575050565b5f8155600101612f4e565b9190601f8111612f7357505050565b612f9d925f5260205f20906020601f840160051c83019310612f9f575b601f0160051c0190612f4e565b565b9091508190612f90565b3560ff811681036100d95790565b903590601e19813603018212156100d957018035906001600160401b0382116100d957602001918160051b360383136100d957565b90600160401b811161028f5781549181815582821061300a57505050565b5f5260205f2091820191015b818110613021575050565b8061302e60019254612ed4565b8061303b575b5001613016565b601f8111831461305057505f81555b5f613034565b61306c90825f5283601f60205f20920160051c82019101612f4e565b805f525f602081208183555561304a565b90600160401b811161028f5781549080835581811061309b57505050565b612f9d925f5260205f209182019101612f4e565b356001600160a01b03811681036100d95790565b90600160401b811161028f578154918181558282106130e157505050565b5f5260205f2091820191015b8181106130f8575050565b5f81556001016130ed565b8054821015612243575f5260205f2001905f90565b90815491600160401b83101561028f578261313b916001612f9d95018155613103565b81546001600160a01b0393841660039290921b91821b9390911b1916919091179055565b9035601e19823603018112156100d95701602081359101916001600160401b0382116100d95781360383136100d957565b908060209392818452848401375f828201840152601f01601f1916010190565b81835290916001600160fb1b0383116100d95760209260051b809284830137010190565b608081019081106001600160401b0382111761028f57604052565b90601f801991011681019081106001600160401b0382111761028f57604052565b6001600160401b03811161028f5760051b60200190565b60405190613234826131d4565b5f6060838281528260208201528160408201520152565b80518210156122435760209160051b010190565b9060405191825f82549261327284612ed4565b80845293600181169081156132db5750600114613297575b50612f9d925003836131ef565b90505f9291925260205f20905f915b8183106132bf575050906020612f9d928201015f61328a565b60209193508060019154838589010152019101909184926132a6565b905060209250612f9d94915060ff191682840152151560051b8201015f61328a565b90604051918281549182825260208201905f5260205f20925f5b81811061332c575050612f9d925003836131ef565b8454835260019485019487945060209093019201613317565b91908110156122435760051b8101359060de19813603018212156100d9570190565b9035601e19823603018112156100d95701602081359101916001600160401b0382116100d9578160051b360383136100d957565b90602083828152019260208260051b82010193835f925b8484106133c25750505050505090565b9091929394956020806133ea600193601f198682030188526133e48b8861315f565b90613190565b98019401940192949391906133b2565b919060208352613463613444613425613413848061315f565b60e06020890152610100880191613190565b613432602085018561315f565b878303601f1901604089015290613190565b6134516040840184613367565b868303601f190160608801529061339b565b9260206134736060840184613367565b838703601f1901608085015280875295909101945f905b808210613500575050506134eb6134e06134c16134fd95966134af6080870187613367565b868303601f190160a0880152906131b0565b6134ce60a0860186613367565b858303601f190160c08701529061339b565b9260c0810190613367565b9160e0601f19828603019101526131b0565b90565b91959091908635906001600160a01b03821682036100d9576001600160a01b03909116815260209081019601916001019061348a565b9080602083519182815201916020808360051b8301019401925f915b83831061356157505050505090565b909192939460208061357f600193601f198682030187528951612d8f565b97019301930191939290613552565b7f4a095d6cb9b93a0f83522807df8d2f3070c21f3a0a4ca97d86925974cbbfd39a546001600160a01b0382811691161461365957305f9081527f4a095d6cb9b93a0f83522807df8d2f3070c21f3a0a4ca97d86925974cbbfd3936020908152604080832083805282528083206001600160a01b038516845290915290205460ff16613659576001600160a01b03165f9081527f577ffbf32e3154d879602fc33c6c618fd87b4f6285b5b7d95589de65fd7269d2602052604090205460ff16613654575f90565b600190565b50600190565b905f525f8051602061373c83398151915260205260405f205f5b8154808210156137155761368d8284613103565b905460039190911b1c6001600160a01b03908116908516146136b25750600101613679565b9192505f198201918211610d625761313b6136d06136e99385613103565b905460039190911b1c6001600160a01b03169184613103565b80548015610d4e575f1901906136ff8282613103565b81549060018060a01b039060031b1b1916905555565b5050505056fe4a095d6cb9b93a0f83522807df8d2f3070c21f3a0a4ca97d86925974cbbfd3c74a095d6cb9b93a0f83522807df8d2f3070c21f3a0a4ca97d86925974cbbfd3c84a095d6cb9b93a0f83522807df8d2f3070c21f3a0a4ca97d86925974cbbfd3c6a2646970667358221220b334eb4134d409e83b46be2236130c8bf8a3eacf562dfad3f1a42ea9693bf61064736f6c634300081a0033

Deployed Bytecode

0x60806040526004361015610011575f80fd5b5f3560e01c8063150c12d61461226e5780634a6ef80a146120e55780636170563514611ee55780636eeaad1314611e5c5780637b8d9fa81461187857806381c6a2bf146114f457806399bb34ec14610d7f578063a48763fa14610c31578063befd706814610a11578063c1bfdb1d146108cd578063cb0985e314610877578063d1b9ace11461034a578063d3aac175146102c1578063eb35061f146100dd5763ecca1e1e146100be575f80fd5b346100d9575f3660031901126100d957602060405160078152f35b5f80fd5b346100d95760403660031901126100d9576004356024356001600160401b0381116100d9578060040190608060031982360301126100d95761011e3361358e565b156102b257825f525f8051602061375c83398151915260205260405f2054156102a357825f525f8051602061375c83398151915260205260405f2091803583556024820135600184015561017a60028401916044840190612f1c565b906001600160401b03821161028f5761019d826101978554612ed4565b85612f64565b5f90601f83116001146102275791806101d09260649695945f9261021c575b50508160011b915f199060031b1c19161790565b90555b013580151581036100d95760036101f692019060ff801983541691151516179055565b7f41bda51eb37a72d2962c6138c65a18d88e119fec679f94b36e87ca0b2529aff25f80a2005b0135905088806101bc565b601f19831691845f5260205f20925f5b81811061027757509160019391856064989796941061025e575b505050811b0190556101d3565b01355f19600384901b60f8161c19169055878080610251565b91936020600181928787013581550195019201610237565b634e487b7160e01b5f52604160045260245ffd5b6318b4935f60e21b5f5260045ffd5b634f1f214760e01b5f5260045ffd5b346100d95760203660031901126100d9576102da613227565b506004355f525f8051602061375c83398151915260205261034660405f2060ff600360405192610309846131d4565b80548452600181015460208501526103236002820161325f565b604085015201541615156060820152604051918291602083526020830190612db3565b0390f35b346100d95761035836612de9565b906103623361358e565b156102b25760ff61037282612e9c565b5416156108685761038281612e64565b601981016103908480612f1c565b906001600160401b03821161028f576103ad826101978554612ed4565b5f90601f8311600114610804576103da92915f91836107955750508160011b915f199060031b1c19161790565b90555b601a81016103ee6020850185612f1c565b906001600160401b03821161028f5761040b826101978554612ed4565b5f90601f83116001146107a05761043892915f91836107955750508160011b915f199060031b1c19161790565b90555b601b810161044c6040850185612fb7565b90916104588282612fec565b5f9081526020812092805b8383106106c057878787601c810161047e6060850185612fb7565b91906001600160401b03831161028f57610498838361307d565b905f5260205f205f5b8381106106a55750505050601d81016104bd6080850185612fb7565b91906001600160401b03831161028f576104d783836130c3565b905f5260205f205f5b8381106106915750505050601e81016104fc60a0850185612fb7565b90916105088282612fec565b5f9081526020812092805b8383106105ab578787601f880161052d60c0840184612fb7565b91906001600160401b03831161028f5761054783836130c3565b905f5260205f205f5b838110610597576040516001600160a01b038616907f49c1d9936f48c9c75cbd236bafc985f0f64a883ca72bef48535b52e7664168fa90806105928a826133fa565b0390a2005b600190602084359401938184015501610550565b6105b58183612f1c565b906001600160401b03821161028f576105d8826105d28954612ed4565b89612f64565b5f90601f8311600114610627579261060d836001959460209487965f9261061c5750508160011b915f199060031b1c19161790565b88555b01950192019193610513565b013590508e806101bc565b601f19831691885f5260205f20925f5b8181106106795750936020936001969387969383889510610660575b505050811b018855610610565b01355f19600384901b60f8161c191690558d8080610653565b91936020600181928787013581550195019201610637565b6001906020843594019381840155016104e0565b60019060206106b3856130af565b94019381840155016104a1565b6106ca8183612f1c565b906001600160401b03821161028f576106e7826105d28954612ed4565b5f90601f831160011461072b579261071c836001959460209487965f9261061c5750508160011b915f199060031b1c19161790565b88555b01950192019193610463565b601f19831691885f5260205f20925f5b81811061077d5750936020936001969387969383889510610764575b505050811b01885561071f565b01355f19600384901b60f8161c191690558d8080610757565b9193602060018192878701358155019501920161073b565b0135905087806101bc565b601f19831691845f5260205f20925f5b8181106107ec57509084600195949392106107d3575b505050811b01905561043b565b01355f19600384901b60f8161c191690558680806107c6565b919360206001819287870135815501950192016107b0565b601f19831691845f5260205f20925f5b8181106108505750908460019594939210610837575b505050811b0190556103dd565b01355f19600384901b60f8161c1916905586808061082a565b91936020600181928787013581550195019201610814565b63dee790fb60e01b5f5260045ffd5b346100d95760203660031901126100d957610890612d49565b60ff61089b82612e9c565b541615610868576108b9601f6108b361034693612e64565b016132fd565b604051918291602083526020830190612e31565b346100d95760403660031901126100d9576108e6612d49565b602435906108f33361358e565b156102b25760ff61090382612e9c565b54161561086857815f525f8051602061375c83398151915260205260405f2054156102a357601f61093382612e64565b0180546007811015610a02575f5b8181106109d45750508054600160401b81101561028f5761096c818593600161098294018155613103565b819391549060031b91821b915f19901b19161790565b9055815f525f8051602061373c8339815191526020526109a58160405f20613118565b6001600160a01b03167ff8f1580e9ec67ec505d45da2ba4b7979bde4ebed64e14f75281cf7448322e3e15f80a3005b846109df8285613103565b90549060031b1c146109f357600101610941565b63538cc66760e01b5f5260045ffd5b63ee39e85560e01b5f5260045ffd5b346100d95760203660031901126100d9576004356001600160401b0381116100d95780600401608060031983360301126100d957610a4e3361358e565b156102b2578035918215610c2257825f525f8051602061375c83398151915260205260405f2054610c1357825f525f8051602061375c83398151915260205260405f2090838255602481013592836001840155610ab360028401916044840190612f1c565b906001600160401b03821161028f57610ad0826101978554612ed4565b5f90601f8311600114610bab579180610b029260649695945f92610ba05750508160011b915f199060031b1c19161790565b90555b013580151581036100d9576003610b2892019060ff801983541691151516179055565b5f8051602061371c83398151915254600160401b81101561028f577fb8700687a3120fabaeae7b5aa476a8e4ea300c84d68eec9e5f83a05f49e4c1bc9183610b9561096c846001602096015f8051602061371c833981519152555f8051602061371c833981519152613103565b9055604051908152a2005b0135905089806101bc565b601f19831691845f5260205f20925f5b818110610bfb575091600193918560649897969410610be2575b505050811b019055610b05565b01355f19600384901b60f8161c19169055888080610bd5565b91936020600181928787013581550195019201610bbb565b63346120b160e01b5f5260045ffd5b63d92e233d60e01b5f5260045ffd5b346100d95760403660031901126100d957610c4a612d49565b60243590610c573361358e565b156102b25760ff610c6782612e9c565b54161561086857601f610c7982612e64565b01905f915f5b815480821015610d765785610c948385613103565b90549060031b1c14610ca95750600101610c7f565b92935090915f198101908111610d625761096c610cc9610cd79285613103565b90549060031b1c9284613103565b905580548015610d4e575f190190610cef8282613103565b8154905f199060031b1b191690555560015b15610d3f57610d10828261365f565b6001600160a01b03167f77122549c5cea9920e43154e5a3125b27c24066e99e509084fad39f05b624b205f80a3005b63d09daa2b60e01b5f5260045ffd5b634e487b7160e01b5f52603160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b50505090610d01565b346100d95760203660031901126100d957610d98612d49565b610da13361358e565b156102b25760ff610db182612e9c565b54161561086857610dc181612e64565b9060405160e081018181106001600160401b0382111761028f5760405260608152602081019060608252604081016060815260608201906060825260606080840152606060a0840152606060c08401526001600160401b0360041161028f5760405160a0610e2f81836131ef565b60048252601f19015f5b8181106114e35750508152602095604051610e5488826131ef565b5f81525f3681378352604051610e6a88826131ef565b5f81525f3681376080850152604051610e8388826131ef565b5f8152601f198801885f5b8281106114d45750505060a0850152610ea9601f82016132fd565b60c085015260078101545f527f4a095d6cb9b93a0f83522807df8d2f3070c21f3a0a4ca97d86925974cbbfd3c98752610ee7600660405f200161325f565b8552601401546001600160a01b039081165f9081527f4a095d6cb9b93a0f83522807df8d2f3070c21f3a0a4ca97d86925974cbbfd3c388526040902080549091166114c0575b50610f3785612e64565b6019810184518051906001600160401b03821161028f57610f5c826101978554612ed4565b8990601f831160011461145d57610f8992915f91836113ef5750508160011b915f199060031b1c19161790565b90555b601a810185518051906001600160401b03821161028f57610fb1826101978554612ed4565b8990601f83116001146113fa57610fde92915f91836113ef5750508160011b915f199060031b1c19161790565b90555b601b8101825188815191610ff58385612fec565b01915f52885f205f925b8284106113165750505050601c81018351908151916001600160401b03831161028f57899061102e848461307d565b01905f52885f205f5b8381106112fb5750505050601d81016080850151908151916001600160401b03831161028f57899061106984846130c3565b01905f52885f205f5b8381106112e95750505050601e810160a0850151888151916110948385612fec565b01915f52885f205f925b8284106111ff5750505050601f0160c0840151908151916001600160401b03831161028f57978094986110d184846130c3565b01905f52835f205f5b8381106111ed575050505061112f9061111c60405195848752611109865160e0878a0152610100890190612d8f565b9051878203601f19016040890152612d8f565b9051858203601f19016060870152613536565b9451838603601f19016080850152805180875295820195908201915f5b8281106111d05750857f49c1d9936f48c9c75cbd236bafc985f0f64a883ca72bef48535b52e7664168fa86806105928860c06111b061119b8f6080850151601f198883030160a0890152612e31565b60a0840151868203601f190184880152613536565b910151838203601f190160e08501526001600160a01b0390961695612e31565b83516001600160a01b03168852968101969281019260010161114c565b825182820155918501916001016110da565b80519081516001600160401b03811161028f578c92611228826112228754612ed4565b87612f64565b8390601f831160011461127557826001959386959361125b935f9261126a5750508160011b915f199060031b1c19161790565b85555b0192019301929061109e565b015190505f806101bc565b90855f95949552835f20915f5b601f19851681106112ca5750926001959286959492869383601f198116106112b2575b505050811b01855561125e565b01515f1960f88460031b161c191690555f80806112a5565b9294600183959683948394015181550194019201908f94939291611282565b825182820155918a0191600101611072565b82516001600160a01b031682820155918a0191600101611037565b80519081516001600160401b03811161028f578c92611339826112228754612ed4565b8390601f831160011461137b57826001959386959361136c935f9261126a5750508160011b915f199060031b1c19161790565b85555b01920193019290610fff565b90855f95949552835f20915f5b601f19851681106113d05750926001959286959492869383601f198116106113b8575b505050811b01855561136f565b01515f1960f88460031b161c191690555f80806113ab565b9294600183959683948394015181550194019201908f94939291611388565b015190508b806101bc565b90601f19831691845f528b5f20925f5b8d82821061144757505090846001959493921061142f575b505050811b019055610fe1565b01515f1960f88460031b161c191690558a8080611422565b600185968293968601518155019501930161140a565b90601f19831691845f528b5f20925f5b8d8282106114aa575050908460019594939210611492575b505050811b019055610f8c565b01515f1960f88460031b161c191690558a8080611485565b600185968293968601518155019501930161146d565b60056114cc910161325f565b835286610f2d565b60608482018301528101610e8e565b806060602080938601015201610e39565b346100d95761150236612de9565b9061150c3361358e565b156102b25760ff61151c82612e9c565b5416156108685761152c81612e64565b6005810161153a8480612f1c565b906001600160401b03821161028f57611557826101978554612ed4565b5f90601f83116001146118145761158492915f91836107955750508160011b915f199060031b1c19161790565b90555b6020830135600682015560408301359182600783015560608401358060088401556009830192608086019360ff6115bd86612fa9565b1660ff19825416179055600a81016115d860a0880188612f1c565b906001600160401b03821161028f576115f5826101978554612ed4565b5f90601f83116001146117ac57918061162792600b9695945f926117a15750508160011b915f199060031b1c19161790565b90555b019461163960c0820182612f1c565b6001600160401b03819892981161028f5761165e816116588454612ed4565b84612f64565b5f601f821160011461170f57926116ca9594926116b9836116c29460ff977fbeb1c8c3497666cb271f5ddb01175499ac40bf04395542caab4c3c85c8f76ab39c9d5f926117045750508160011b915f199060031b1c19161790565b90555b80612f1c565b949095612fa9565b906116e2604051968796608088526080880191613190565b602086019890985260408501521660608301526001600160a01b0316930390a2005b013590508d806101bc565b601f19821690835f5260205f20915f5b81811061178957508360ff96937fbeb1c8c3497666cb271f5ddb01175499ac40bf04395542caab4c3c85c8f76ab39b9c6116ca9a9997946116c29760019510611770575b505050811b0190556116bc565b01355f19600384901b60f8161c191690558c8080611763565b9192602060018192868f01358155019401920161171f565b013590508b806101bc565b601f19831691845f5260205f20925f5b8181106117fc5750916001939185600b98979694106117e3575b505050811b01905561162a565b01355f19600384901b60f8161c191690558a80806117d6565b919360206001819287870135815501950192016117bc565b601f19831691845f5260205f20925f5b8181106118605750908460019594939210611847575b505050811b019055611587565b01355f19600384901b60f8161c1916905586808061183a565b91936020600181928787013581550195019201611824565b346100d95760403660031901126100d9576004356001600160401b0381116100d9576118a8903690600401612d5f565b6024356001600160401b0381116100d9576118c7903690600401612d5f565b6118d03361358e565b156102b257808303611e4d575f5b8381106118e757005b60ff6119046118ff6118fa84888a612f0c565b6130af565b612e9c565b54161561086857611916818385613345565b61192c6119276118fa84888a612f0c565b612e64565b6019810161193a8380612f1c565b906001600160401b03821161028f57611957826101978554612ed4565b5f90601f8311600114611de95761198492915f91836117a15750508160011b915f199060031b1c19161790565b90555b601a81016119986020840184612f1c565b906001600160401b03821161028f576119b5826101978554612ed4565b5f90601f8311600114611d85576119e292915f91836117a15750508160011b915f199060031b1c19161790565b90555b601b81016119f66040840184612fb7565b9091611a028282612fec565b5f9081526020812092805b838310611ca4575050505050601c8101611a2a6060840184612fb7565b91906001600160401b03831161028f57611a44838361307d565b905f5260205f205f5b838110611c7d5750505050601d8101611a696080840184612fb7565b91906001600160401b03831161028f57611a8383836130c3565b905f5260205f205f5b838110611c695750505050601e8101611aa860a0840184612fb7565b9091611ab48282612fec565b5f9081526020812092805b838310611b7d575050505050601f611add91019160c0810190612fb7565b91906001600160401b03831161028f57611af783836130c3565b905f5260205f205f5b838110611b69575050505080611b1c6118fa6001938789612f0c565b7f49c1d9936f48c9c75cbd236bafc985f0f64a883ca72bef48535b52e7664168fa611b60611b4b848789613345565b92604051918291878060a01b031694826133fa565b0390a2016118de565b823582820155602090920191600101611b00565b611b8d81839d989d9c999c612f1c565b906001600160401b03821161028f57611baa826105d28954612ed4565b5f90601f8311600114611bff5792611bdf836001959460209487965f92611bf45750508160011b915f199060031b1c19161790565b88555b019501920191939a959a999699611abf565b013590505f806101bc565b601f19831691885f5260205f20925f5b818110611c515750936020936001969387969383889510611c38575b505050811b018855611be2565b01355f19600384901b60f8161c191690555f8080611c2b565b91936020600181928787013581550195019201611c0f565b823581830155602090920191600101611a8c565b6001906020611c91859d989d9c999c6130af565b9401938184015501999499989598611a4d565b611cb481839d989d9c999c612f1c565b906001600160401b03821161028f57611cd1826105d28954612ed4565b5f90601f8311600114611d1b5792611d06836001959460209487965f92611bf45750508160011b915f199060031b1c19161790565b88555b019501920191939a959a999699611a0d565b601f19831691885f5260205f20925f5b818110611d6d5750936020936001969387969383889510611d54575b505050811b018855611d09565b01355f19600384901b60f8161c191690555f8080611d47565b91936020600181928787013581550195019201611d2b565b601f19831691845f5260205f20925f5b818110611dd15750908460019594939210611db8575b505050811b0190556119e5565b01355f19600384901b60f8161c191690558a8080611dab565b83830135855560019094019360209283019201611d95565b601f19831691845f5260205f20925f5b818110611e355750908460019594939210611e1c575b505050811b019055611987565b01355f19600384901b60f8161c191690558a8080611e0f565b83830135855560019094019360209283019201611df9565b63a7b682d760e01b5f5260045ffd5b346100d95760203660031901126100d957600435611e793361358e565b156102b257805f525f8051602061375c83398151915260205260405f2054156102a357805f525f8051602061375c833981519152602052600360405f200160ff1981541690557ff49bbaee82f6020a8b109958fb96cf0a256ad35e735148db9a22b1e209283cc05f80a2005b346100d95760403660031901126100d957611efe612d49565b6024356001600160401b0381116100d957611f1d903690600401612d5f565b9091611f283361358e565b156102b25760ff611f3882612e9c565b5416156108685760078211610a02575f5b82811061206c5750611f5f601f6108b383612e64565b925f5b8451811015611f885780611f82611f7b6001938861324b565b518561365f565b01611f62565b5092915f5b8181106120375750601f611fa083612e64565b016001600160401b03821161028f57611fb982826130c3565b84905f5260205f20905f5b83811061202357867f092317661db809ddb59ab04dcb02024ebeb4b868848f76de1550705c8942e1e261200a886105928989604051948594604086526040860190612e31565b84810360208601526001600160a01b03909216966131b0565b600190602083359301928185015501611fc4565b806120456001928488612f0c565b355f525f8051602061373c8339815191526020526120668460405f20613118565b01611f8d565b612077818486612f0c565b355f525f8051602061375c83398151915260205260405f2054156102a35760018101808211610d62575b8381106120b15750600101611f49565b6120bc828587612f0c565b356120c8828688612f0c565b35146120d6576001016120a1565b631a3abfc960e31b5f5260045ffd5b346100d9575f3660031901126100d9575f8051602061371c8339815191525461210d81613210565b9061211b60405192836131ef565b808252601f1961212a82613210565b015f5b8181106122575750505f8051602061371c833981519152545f5b8281106121b557836040518091602082016020835281518091526040830190602060408260051b8601019301915f905b82821061218657505050500390f35b919360019193955060206121a58192603f198a82030186528851612db3565b9601920192018594939192612177565b81811015612243576001905f8051602061371c8339815191525f528060205f2001545f525f8051602061375c83398151915260205260405f2060ff6003604051926121ff846131d4565b805484528581015460208501526122186002820161325f565b604085015201541615156060820152612231828761324b565b5261223c818661324b565b5001612147565b634e487b7160e01b5f52603260045260245ffd5b602090612262613227565b8282870101520161212d565b346100d95760803660031901126100d957612287612d49565b6001600160401b03602435116100d95760e0602435360360031901126100d9576001600160401b03604435116100d95760e0604435360360031901126100d9576064356001600160401b0381116100d9576122e6903690600401612d5f565b903033036102b2576001600160a01b036122ff84612e64565b541615612d3a5761231b600561231485612e64565b0154612ed4565b612d2c576001600160a01b0361233084612e64565b546001600160a01b038516949116849003612d1d576001600160a01b03601361235883612e64565b01541615612d0e5760ff61236b82612e9c565b541615612cff5760078311610a02575f5b838110612c95575061238d81612e64565b600581016123a060046024350180612f1c565b906001600160401b03821161028f576123bd826101978554612ed4565b5f90601f8311600114612c31576123ea92915f9183610ba05750508160011b915f199060031b1c19161790565b90555b60248035013560068201556044602435013560078201556064602435013560088201556009810160ff612424608460243501612fa9565b1660ff1982541617905561244260a460243501602435600401612f1c565b906001600160401b03821161028f5761246b82612462600a860154612ed4565b600a8601612f64565b5f90601f8311600114612bc257918061249c92600b95945f92610ba05750508160011b915f199060031b1c19161790565b600a8201555b019060c460243501916124ba83602435600401612f1c565b906001600160401b03821161028f576124d7826101978554612ed4565b5f90601f8311600114612b5e5761250492915f9183610ba05750508160011b915f199060031b1c19161790565b90555b61251081612e64565b6019810161252360046044350180612f1c565b906001600160401b03821161028f57612540826101978554612ed4565b5f90601f8311600114612afa5761256d92915f9183612a8b5750508160011b915f199060031b1c19161790565b90555b601a8101612588602460443501604435600401612f1c565b906001600160401b03821161028f576125a5826101978554612ed4565b5f90601f8311600114612a96576125d292915f9183612a8b5750508160011b915f199060031b1c19161790565b90555b601b81016125ec6044803501604435600401612fb7565b90916125f88282612fec565b5f9081526020812092805b8383106129b6575050505050601c8101612627606460443501604435600401612fb7565b91906001600160401b03831161028f57612641838361307d565b905f5260205f205f5b83811061299b5750505050601d810161266d608460443501604435600401612fb7565b91906001600160401b03831161028f5761268783836130c3565b905f5260205f205f5b8381106129875750505050601e81016126b360a460443501604435600401612fb7565b90916126bf8282612fec565b5f9081526020812092805b8383106128b2575050505050601f016126ed60c460443501604435600401612fb7565b91906001600160401b03831161028f5761270783836130c3565b905f5260205f205f5b83811061289e57505050508361280e575b50604080519081529161274e61273c6004602435018061315f565b60e06040870152610120860191613190565b9060248035013560608501526044602435013560808501526064602435013560a0850152608460243501359460ff86168096036100d95761280085946127ed6127e1610592967f90439a4e9252f0b43d7942ba9c0b7aa7f3eedea3e96f5ee786fb60b241eb8f219a60c08a01526127cf60a46024350160243560040161315f565b8a8303603f190160e08c015290613190565b9160243560040161315f565b878303603f190161010089015290613190565b9184830360208601526131b0565b5f5b8481106128695750612823601f91612e64565b016001600160401b03841161028f5761283c84826130c3565b82905f5260205f20905f5b858110612855575050612721565b600190602083359301928185015501612847565b806128776001928787612f0c565b355f525f8051602061373c8339815191526020526128988360405f20613118565b01612810565b600190602084359401938184015501612710565b6128bc8183612f1c565b906001600160401b03821161028f576128d9826105d28954612ed4565b5f90601f831160011461291d579261290e836001959460209487965f92611bf45750508160011b915f199060031b1c19161790565b88555b019501920191936126ca565b601f19831691885f5260205f20925f5b81811061296f5750936020936001969387969383889510612956575b505050811b018855612911565b01355f19600384901b60f8161c191690555f8080612949565b9193602060018192878701358155019501920161292d565b600190602084359401938184015501612690565b60019060206129a9856130af565b940193818401550161264a565b6129c08183612f1c565b906001600160401b03821161028f576129dd826105d28954612ed4565b5f90601f8311600114612a215792612a12836001959460209487965f92611bf45750508160011b915f199060031b1c19161790565b88555b01950192019193612603565b601f19831691885f5260205f20925f5b818110612a735750936020936001969387969383889510612a5a575b505050811b018855612a15565b01355f19600384901b60f8161c191690555f8080612a4d565b91936020600181928787013581550195019201612a31565b013590508a806101bc565b601f19831691845f5260205f20925f5b818110612ae25750908460019594939210612ac9575b505050811b0190556125d5565b01355f19600384901b60f8161c19169055898080612abc565b91936020600181928787013581550195019201612aa6565b601f19831691845f5260205f20925f5b818110612b465750908460019594939210612b2d575b505050811b019055612570565b01355f19600384901b60f8161c19169055898080612b20565b91936020600181928787013581550195019201612b0a565b601f19831691845f5260205f20925f5b818110612baa5750908460019594939210612b91575b505050811b019055612507565b01355f19600384901b60f8161c19169055888080612b84565b91936020600181928787013581550195019201612b6e565b600a84015f5260205f20915f5b601f1985168110612c195750918391600193600b9695601f19811610612c00575b505050811b01600a8201556124a2565b01355f19600384901b60f8161c19169055888080612bf0565b90926020600181928686013581550194019101612bcf565b601f19831691845f5260205f20925f5b818110612c7d5750908460019594939210612c64575b505050811b0190556123ed565b01355f19600384901b60f8161c19169055888080612c57565b91936020600181928787013581550195019201612c41565b612ca0818585612f0c565b355f525f8051602061375c83398151915260205260405f2054156102a35760018101808211610d62575b848110612cda575060010161237c565b612ce5828686612f0c565b35612cf1828787612f0c565b35146120d657600101612cca565b631c1be0cd60e01b5f5260045ffd5b630fb1a74560e41b5f5260045ffd5b63b2f0dc1f60e01b5f5260045ffd5b62dc149f60e41b5f5260045ffd5b63775a7b0960e11b5f5260045ffd5b600435906001600160a01b03821682036100d957565b9181601f840112156100d9578235916001600160401b0383116100d9576020808501948460051b0101116100d957565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b908151815260208201516020820152606080612dde6040850151608060408601526080850190612d8f565b930151151591015290565b9060406003198301126100d9576004356001600160a01b03811681036100d95791602435906001600160401b0382116100d95760e09082900360031901126100d95760040190565b90602080835192838152019201905f5b818110612e4e5750505090565b8251845260209384019390920191600101612e41565b6001600160a01b03165f9081527f4a095d6cb9b93a0f83522807df8d2f3070c21f3a0a4ca97d86925974cbbfd39e6020526040902090565b6001600160a01b03165f9081527f4a095d6cb9b93a0f83522807df8d2f3070c21f3a0a4ca97d86925974cbbfd39d6020526040902090565b90600182811c92168015612f02575b6020831014612eee57565b634e487b7160e01b5f52602260045260245ffd5b91607f1691612ee3565b91908110156122435760051b0190565b903590601e19813603018212156100d957018035906001600160401b0382116100d9576020019181360383136100d957565b818110612f59575050565b5f8155600101612f4e565b9190601f8111612f7357505050565b612f9d925f5260205f20906020601f840160051c83019310612f9f575b601f0160051c0190612f4e565b565b9091508190612f90565b3560ff811681036100d95790565b903590601e19813603018212156100d957018035906001600160401b0382116100d957602001918160051b360383136100d957565b90600160401b811161028f5781549181815582821061300a57505050565b5f5260205f2091820191015b818110613021575050565b8061302e60019254612ed4565b8061303b575b5001613016565b601f8111831461305057505f81555b5f613034565b61306c90825f5283601f60205f20920160051c82019101612f4e565b805f525f602081208183555561304a565b90600160401b811161028f5781549080835581811061309b57505050565b612f9d925f5260205f209182019101612f4e565b356001600160a01b03811681036100d95790565b90600160401b811161028f578154918181558282106130e157505050565b5f5260205f2091820191015b8181106130f8575050565b5f81556001016130ed565b8054821015612243575f5260205f2001905f90565b90815491600160401b83101561028f578261313b916001612f9d95018155613103565b81546001600160a01b0393841660039290921b91821b9390911b1916919091179055565b9035601e19823603018112156100d95701602081359101916001600160401b0382116100d95781360383136100d957565b908060209392818452848401375f828201840152601f01601f1916010190565b81835290916001600160fb1b0383116100d95760209260051b809284830137010190565b608081019081106001600160401b0382111761028f57604052565b90601f801991011681019081106001600160401b0382111761028f57604052565b6001600160401b03811161028f5760051b60200190565b60405190613234826131d4565b5f6060838281528260208201528160408201520152565b80518210156122435760209160051b010190565b9060405191825f82549261327284612ed4565b80845293600181169081156132db5750600114613297575b50612f9d925003836131ef565b90505f9291925260205f20905f915b8183106132bf575050906020612f9d928201015f61328a565b60209193508060019154838589010152019101909184926132a6565b905060209250612f9d94915060ff191682840152151560051b8201015f61328a565b90604051918281549182825260208201905f5260205f20925f5b81811061332c575050612f9d925003836131ef565b8454835260019485019487945060209093019201613317565b91908110156122435760051b8101359060de19813603018212156100d9570190565b9035601e19823603018112156100d95701602081359101916001600160401b0382116100d9578160051b360383136100d957565b90602083828152019260208260051b82010193835f925b8484106133c25750505050505090565b9091929394956020806133ea600193601f198682030188526133e48b8861315f565b90613190565b98019401940192949391906133b2565b919060208352613463613444613425613413848061315f565b60e06020890152610100880191613190565b613432602085018561315f565b878303601f1901604089015290613190565b6134516040840184613367565b868303601f190160608801529061339b565b9260206134736060840184613367565b838703601f1901608085015280875295909101945f905b808210613500575050506134eb6134e06134c16134fd95966134af6080870187613367565b868303601f190160a0880152906131b0565b6134ce60a0860186613367565b858303601f190160c08701529061339b565b9260c0810190613367565b9160e0601f19828603019101526131b0565b90565b91959091908635906001600160a01b03821682036100d9576001600160a01b03909116815260209081019601916001019061348a565b9080602083519182815201916020808360051b8301019401925f915b83831061356157505050505090565b909192939460208061357f600193601f198682030187528951612d8f565b97019301930191939290613552565b7f4a095d6cb9b93a0f83522807df8d2f3070c21f3a0a4ca97d86925974cbbfd39a546001600160a01b0382811691161461365957305f9081527f4a095d6cb9b93a0f83522807df8d2f3070c21f3a0a4ca97d86925974cbbfd3936020908152604080832083805282528083206001600160a01b038516845290915290205460ff16613659576001600160a01b03165f9081527f577ffbf32e3154d879602fc33c6c618fd87b4f6285b5b7d95589de65fd7269d2602052604090205460ff16613654575f90565b600190565b50600190565b905f525f8051602061373c83398151915260205260405f205f5b8154808210156137155761368d8284613103565b905460039190911b1c6001600160a01b03908116908516146136b25750600101613679565b9192505f198201918211610d625761313b6136d06136e99385613103565b905460039190911b1c6001600160a01b03169184613103565b80548015610d4e575f1901906136ff8282613103565b81549060018060a01b039060031b1b1916905555565b5050505056fe4a095d6cb9b93a0f83522807df8d2f3070c21f3a0a4ca97d86925974cbbfd3c74a095d6cb9b93a0f83522807df8d2f3070c21f3a0a4ca97d86925974cbbfd3c84a095d6cb9b93a0f83522807df8d2f3070c21f3a0a4ca97d86925974cbbfd3c6a2646970667358221220b334eb4134d409e83b46be2236130c8bf8a3eacf562dfad3f1a42ea9693bf61064736f6c634300081a0033

Deployed Bytecode Sourcemap

1413:19458:5:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;1619:1;1413:19458;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;;;;;;;;1730:37;1756:10;1730:37;:::i;:::-;1729:38;1725:96;;1413:19458;;;-1:-1:-1;;;;;;;;;;;1413:19458:5;;;;;;14173:38;14169:64;;1413:19458;;;-1:-1:-1;;;;;;;;;;;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14300:22;1413:19458;14300:22;;1413:19458;;;;;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14169:64;8398:13;;;1413:19458;14220:13;1413:19458;;14220:13;1725:96;7222:20;;;1413:19458;1790:20;1413:19458;;1790:20;1413:19458;;;;;;-1:-1:-1;;1413:19458:5;;;;;;:::i;:::-;;;;;;-1:-1:-1;;;;;;;;;;;1413:19458:5;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;1756:10;1730:37;1756:10;1730:37;:::i;:::-;1729:38;1725:96;;1413:19458;10456:16;;;:::i;:::-;1413:19458;;10455:17;10451:45;;10515:18;;;:::i;:::-;:21;;;1413:19458;;;;:::i;:::-;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;10565:33;;1413:19458;10565:33;1413:19458;;10565:33;:::i;:::-;;;;1413:19458;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10451:45;15456:15;;;1413:19458;10481:15;1413:19458;;10481:15;1413:19458;;;;;;-1:-1:-1;;1413:19458:5;;;;;;:::i;:::-;;20108:16;;;:::i;:::-;1413:19458;;20107:17;20103:45;;1413:19458;20174:26;:18;1413:19458;20174:18;;:::i;:::-;:26;1413:19458;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;1413:19458:5;;;;;;:::i;:::-;;;1756:10;1730:37;1756:10;1730:37;:::i;:::-;1729:38;1725:96;;1413:19458;17001:16;;;:::i;:::-;1413:19458;;17000:17;16996:45;;1413:19458;;;-1:-1:-1;;;;;;;;;;;1413:19458:5;;;;;;17055:38;17051:64;;17211:26;:18;;;:::i;:::-;:26;1413:19458;;1619:1;17251:38;;;17247:64;;1413:19458;17350:20;;;;;;1413:19458;;;;-1:-1:-1;;;1413:19458:5;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;1413:19458:5;;17524:32;1413:19458;;;;17524:32;:::i;:::-;-1:-1:-1;;;;;1413:19458:5;17580:31;1413:19458;;17580:31;1413:19458;17372:3;17395:12;;;;;:::i;:::-;1413:19458;;;;;;17395:21;17391:54;;1413:19458;;17335:13;;17391:54;17425:20;;;1413:19458;17425:20;1413:19458;;17425:20;17247:64;8144:13;;;1413:19458;17298:13;1413:19458;;17298:13;1413:19458;;;;;;-1:-1:-1;;1413:19458:5;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;;;;;;;1730:37;1756:10;1730:37;:::i;:::-;1729:38;1725:96;;1413:19458;;13494:23;;;13490:49;;1413:19458;;;-1:-1:-1;;;;;;;;;;;1413:19458:5;;;;;;13549:73;;1413:19458;;;-1:-1:-1;;;;;;;;;;;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;1413:19458:5;-1:-1:-1;;;1413:19458:5;;;;;13735:46;1413:19458;;;;;;;;;-1:-1:-1;;;;;;;;;;;1413:19458:5;-1:-1:-1;;;;;;;;;;;1413:19458:5;:::i;:::-;;;;;;;;13735:46;1413:19458;;;;;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13549:73;13604:18;;;1413:19458;13604:18;1413:19458;;13604:18;13490:49;13526:13;;;1413:19458;13526:13;1413:19458;;13526:13;1413:19458;;;;;;-1:-1:-1;;1413:19458:5;;;;;;:::i;:::-;;;1756:10;1730:37;1756:10;1730:37;:::i;:::-;1729:38;1725:96;;1413:19458;17981:16;;;:::i;:::-;1413:19458;;17980:17;17976:45;;18111:26;:18;;;:::i;:::-;:26;18147:18;1413:19458;18180:13;1413:19458;18217:3;1413:19458;;18195:20;;;;;;18240:12;;;;;:::i;:::-;1413:19458;;;;;;18240:21;18236:192;;18217:3;1413:19458;;18180:13;;18236:192;1413:19458;;-1:-1:-1;1413:19458:5;;-1:-1:-1;;1413:19458:5;;;;;;;18281:12;18296:31;1413:19458;18296:31;;;:::i;:::-;1413:19458;;;;;;18281:12;;;:::i;1413:19458::-;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;:::i;:::-;;;;;;;;;;;;;;;;18175:263;18460:6;18456:40;;18583:5;;;;:::i;:::-;-1:-1:-1;;;;;1413:19458:5;18613:33;1413:19458;;18613:33;1413:19458;18456:40;18475:21;;;1413:19458;18475:21;1413:19458;;18475:21;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;18195:20;;;;;;;1413:19458;;;;;;-1:-1:-1;;1413:19458:5;;;;;;:::i;:::-;1730:37;1756:10;1730:37;:::i;:::-;1729:38;1725:96;;1413:19458;11883:16;;;:::i;:::-;1413:19458;;11882:17;11878:45;;11978:18;;;:::i;:::-;1413:19458;;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;1413:19458:5;;;;;;;;12090:27;;;;1413:19458;;;;;;;;:::i;:::-;;;;;;;;12155:30;;1413:19458;;;;;;:::i;:::-;;;;;;;;;;;12195:36;1413:19458;;;;;;:::i;:::-;;;;-1:-1:-1;;1413:19458:5;;;-1:-1:-1;1413:19458:5;;;;;;;;;;;;12241:32;1413:19458;;12293:17;;1413:19458;:::i;:::-;;;;12283:27;12433;;;1413:19458;;;12513:27;1413:19458;;;12293:17;1413:19458;;;12585:19;1413:19458;:::i;:::-;12564:40;;12697:34;;1413:19458;-1:-1:-1;;;;;1413:19458:5;;;;;;;12775:15;1413:19458;;;;;;;;;;12817:102;;1413:19458;12937:18;;;;:::i;:::-;12293:12;12937:21;;1413:19458;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;1413:19458:5;;;;;;:::i;:::-;;;;;;-1:-1:-1;;1413:19458:5;;;;;;:::i;:::-;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;12987:33;1413:19458;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;1413:19458:5;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;:::i;:::-;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;12697:34;1413:19458;;;;;;;;;;;;;;12697:34;1413:19458;;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;;12697:34;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;12697:34;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12697:34;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12697:34;1413:19458;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;12697:34;1413:19458;;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;12697:34;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;12697:34;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12697:34;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12697:34;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12697:34;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12697:34;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12697:34;1413:19458;;;;;;;;;;;;;;;;;12817:102;1413:19458;;12891:17;;1413:19458;:::i;:::-;12873:35;;12817:102;;;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1756:10;1730:37;1756:10;1730:37;:::i;:::-;1729:38;1725:96;;1413:19458;9716:16;;;:::i;:::-;1413:19458;;9715:17;9711:45;;9775:18;;;:::i;:::-;:27;;;1413:19458;;;;:::i;:::-;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;9716:9;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;9979:18;1413:19458;;;;;9890:13;1413:19458;;;9837:170;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;9890:13;;:::i;:::-;9979:18;;;;:::i;:::-;1413:19458;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;9837:170;;;1413:19458;;;;;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9837:170;1413:19458;;9979:18;1413:19458;;;;9890:13;1413:19458;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9716:9;1413:19458;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;:::i;:::-;1730:37;1756:10;1730:37;:::i;:::-;1729:38;1725:96;;11005:30;;;11001:68;;1413:19458;11202:17;;;;;;1413:19458;11221:3;1413:19458;11245:20;11255:9;;;;;;:::i;:::-;;:::i;:::-;11245:20;:::i;:::-;1413:19458;;11244:21;11240:49;;11344:9;;;;;:::i;:::-;11316:22;11328:9;;;;;;:::i;:::-;11316:22;:::i;:::-;:25;;;1413:19458;;;;:::i;:::-;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;:::i;:::-;;;;;;;;;;;;;;11408:9;;;;;;;1413:19458;11408:9;;;;:::i;:::-;11385:44;;11419:9;;;;;:::i;:::-;1413:19458;;;;;;;;;;;;11385:44;;;:::i;:::-;;;;1413:19458;11187:13;;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11001:68;11044:25;;;1413:19458;11044:25;1413:19458;;11044:25;1413:19458;;;;;;-1:-1:-1;;1413:19458:5;;;;;;1730:37;1756:10;1730:37;:::i;:::-;1729:38;1725:96;;1413:19458;;;-1:-1:-1;;;;;;;;;;;1413:19458:5;;;;;;14647:38;14643:64;;1413:19458;;;-1:-1:-1;;;;;;;;;;;1413:19458:5;;14726:27;1413:19458;;;14726:27;1413:19458;;;;;;;14785:26;1413:19458;14785:26;;1413:19458;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;:::i;:::-;1756:10;;1730:37;1756:10;1730:37;:::i;:::-;1729:38;1725:96;;1413:19458;15431:16;;;:::i;:::-;1413:19458;;15430:17;15426:45;;1619:1;15485:34;;15481:60;;1413:19458;15644:17;;;;;;16182:18;1413:19458;16182:26;:18;;;:::i;1413:19458::-;16223:13;1413:19458;16258:3;1413:19458;;16238:18;;;;;16304:10;;;15904:1;16304:10;;;:::i;:::-;1413:19458;16304:10;;:::i;:::-;1413:19458;16223:13;;16238:18;;;;1413:19458;16404:17;;;;;;16536:18;16182:26;16536:18;;;:::i;:::-;:26;-1:-1:-1;;;;;1413:19458:5;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;16595:40;1413:19458;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;:::i;:::-;15904:1;1413:19458;;;;;;;;;;;;;;16423:3;16456:9;;15904:1;16456:9;;;;:::i;:::-;1413:19458;;;-1:-1:-1;;;;;;;;;;;1413:19458:5;;16442:36;1413:19458;;;;16442:36;:::i;:::-;1413:19458;16389:13;;15663:3;15733:9;;;;;:::i;:::-;1413:19458;;;-1:-1:-1;;;;;;;;;;;1413:19458:5;;;;;;15721:42;15717:68;;15904:1;1413:19458;;;;;;;15907:17;;;;;;15663:3;15904:1;1413:19458;15629:13;;15926:3;15953:9;;;;;:::i;:::-;1413:19458;15966:9;;;;;:::i;:::-;1413:19458;15953:22;15949:49;;15904:1;1413:19458;15888:17;;15949:49;8625:14;;;1413:19458;15984:14;1413:19458;;15984:14;1413:19458;;;;;;-1:-1:-1;;1413:19458:5;;;;-1:-1:-1;;;;;;;;;;;1413:19458:5;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;-1:-1:-1;;1413:19458:5;;;:::i;:::-;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;1413:19458:5;;19472:10;;;;;;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;19484:3;1413:19458;;;;;;;;-1:-1:-1;;;;;;;;;;;1413:19458:5;;;;;;;;;;-1:-1:-1;;;;;;;;;;;1413:19458:5;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;19503:42;;;;:::i;:::-;;;;;;:::i;:::-;;1413:19458;19457:13;;1413:19458;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;:::i;:::-;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;:::i;:::-;7208:4;;7186:10;:27;7182:60;;-1:-1:-1;;;;;7501:18:5;;;:::i;:::-;1413:19458;;7501:54;7497:87;;1413:19458;7598:27;:18;;;:::i;:::-;:27;1413:19458;;:::i;:::-;7594:77;;-1:-1:-1;;;;;7792:18:5;;;:::i;:::-;1413:19458;-1:-1:-1;;;;;1413:19458:5;;;;;7792:49;;;7788:80;;-1:-1:-1;;;;;7882:27:5;:18;;;:::i;:::-;:27;1413:19458;;7882:57;7878:86;;1413:19458;7979:16;;;:::i;:::-;1413:19458;;7978:17;7974:47;;1619:1;8096:39;;8092:65;;1413:19458;8260:22;;;;;;8720:18;;;;:::i;:::-;7598:27;8720;;1413:19458;;;;;;;:::i;:::-;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1619:1;1413:19458;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;;;;;7979:9;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8768:18;;;:::i;:::-;:21;;;1413:19458;;;;;;;:::i;:::-;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;:::i;:::-;;;;;;;;;;;;;;8871:22;;;;;8867:229;;1413:19458;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9119:56;1413:19458;;;;;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;1413:19458:5;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;-1:-1:-1;;1413:19458:5;;;;;;;:::i;:::-;;;;;;;;;;:::i;8867:229::-;1413:19458;8929:22;;;;;;9045:18;;1413:19458;9045:18;;:::i;:::-;:26;-1:-1:-1;;;;;1413:19458:5;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;8867:229;;;;1413:19458;8530:1;1413:19458;;;;;;;;;;;;;;8953:3;8990:14;;8530:1;8990:14;;;;:::i;:::-;1413:19458;;;-1:-1:-1;;;;;;;;;;;1413:19458:5;;8976:41;1413:19458;;;;8976:41;:::i;:::-;1413:19458;8914:13;;1413:19458;8530:1;1413:19458;;;;;;;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;8530:1;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8530:1;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;8530:1;1413:19458;;;;;;;;;;;;;;;;8530:1;1413:19458;;;;;;;;;;;;;;;8530:1;1413:19458;;;;;:::i;:::-;;;;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;8530:1;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8530:1;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;8530:1;1413:19458;;;;;;;;;;;;;;;;;;;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;8530:1;1413:19458;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;8530:1;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8530:1;1413:19458;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;8530:1;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8530:1;1413:19458;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;8530:1;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;8530:1;1413:19458;7979:9;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;8530:1;1413:19458;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8530:1;1413:19458;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;8530:1;1413:19458;;;;;;;;;;;;;;;8284:3;8354:14;;;;;:::i;:::-;1413:19458;;;-1:-1:-1;;;;;;;;;;;1413:19458:5;;;;;;8342:47;8338:73;;8530:1;1413:19458;;;;;;;8533:22;;;;;;8284:3;8530:1;1413:19458;8245:13;;8557:3;8584:14;;;;;:::i;:::-;1413:19458;8602:14;;;;;:::i;:::-;1413:19458;8584:32;8580:59;;8530:1;1413:19458;8514:17;;7974:47;8004:17;;;1413:19458;8004:17;1413:19458;;8004:17;7878:86;7948:16;;;1413:19458;7948:16;1413:19458;;7948:16;7788:80;7850:18;;;1413:19458;7850:18;1413:19458;;7850:18;7594:77;7651:20;;;1413:19458;7651:20;1413:19458;;7651:20;7497:87;7564:20;;;1413:19458;7564:20;1413:19458;;7564:20;1413:19458;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;:::o;:::-;;;;;;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;1413:19458:5;;;;;;;;-1:-1:-1;;1413:19458:5;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;1413:19458:5;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;-1:-1:-1;;1413:19458:5;;;;;;;:::o;:::-;;;;;;;;;;;;;;-1:-1:-1;1413:19458:5;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;7501:11;1413:19458;;;;;;:::o;:::-;-1:-1:-1;;;;;1413:19458:5;;;;;7979:9;1413:19458;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;;;;:::o;:::-;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;1413:19458:5;;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:::o;:::-;;;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;;;;;;:::o;:::-;;-1:-1:-1;;;1413:19458:5;;;;;;;;;;;;;;;;;;:::o;:::-;-1:-1:-1;1413:19458:5;;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;:::o;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;-1:-1:-1;1413:19458:5;;;;;;;;;;-1:-1:-1;1413:19458:5;;;;-1:-1:-1;1413:19458:5;;;;;;;;;;:::i;:::-;;-1:-1:-1;1413:19458:5;-1:-1:-1;1413:19458:5;;;;;;;;;;;-1:-1:-1;;;1413:19458:5;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;1413:19458:5;;-1:-1:-1;1413:19458:5;;;;;;;:::i;:::-;;-1:-1:-1;;;;;1413:19458:5;;;;;;;:::o;:::-;;-1:-1:-1;;;1413:19458:5;;;;;;;;;;;;;;;;;;:::o;:::-;-1:-1:-1;1413:19458:5;;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;:::o;:::-;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;-1:-1:-1;1413:19458:5;;-1:-1:-1;1413:19458:5;;;-1:-1:-1;1413:19458:5;:::o;:::-;;;;;-1:-1:-1;;;1413:19458:5;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;-1:-1:-1;1413:19458:5;;;;;;;;-1:-1:-1;;1413:19458:5;;;;:::o;:::-;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;:::o;:::-;;;;;;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;:::o;:::-;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;:::o;:::-;;;;;;;:::i;:::-;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;-1:-1:-1;1413:19458:5;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;1413:19458:5;;;;;-1:-1:-1;1413:19458:5;;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1413:19458:5;;-1:-1:-1;1413:19458:5;;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;-1:-1:-1;;1413:19458:5;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;-1:-1:-1;;1413:19458:5;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;1413:19458:5;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;-1:-1:-1;;1413:19458:5;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;:::i;:::-;;:::o;:::-;;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1413:19458:5;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;1429:590:3;1696:15;1413:19458:5;-1:-1:-1;;;;;1413:19458:5;;;;;1685:26:3;1658:66;;1811:4;-1:-1:-1;1413:19458:5;;;1787:15:3;1413:19458:5;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;;;;;;;1783:62:3;;-1:-1:-1;;;;;1413:19458:5;-1:-1:-1;1413:19458:5;;;;;;;;;;;;1922:59:3;;1413:19458:5;1429:590:3;:::o;1922:59::-;1662:19;1970:11;:::o;1783:62::-;1834:11;1662:19;1834:11;:::o;20420:449:5:-;;-1:-1:-1;1413:19458:5;-1:-1:-1;;;;;;;;;;;1413:19458:5;;;-1:-1:-1;1413:19458:5;-1:-1:-1;20687:3:5;1413:19458;;20668:17;;;;;;20710:9;;;;:::i;:::-;1413:19458;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;;;;;20710:18;20706:147;;20687:3;1413:19458;;20653:13;;20706:147;1413:19458;;-1:-1:-1;;;1413:19458:5;;;;;;;20748:9;20760:25;20748:37;20760:25;;;:::i;:::-;1413:19458;;;;;;;;-1:-1:-1;;;;;1413:19458:5;;20748:9;;:::i;:37::-;1413:19458;;;;;;-1:-1:-1;;1413:19458:5;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;20420:449::o;20668:17::-;;;;;20420:449::o

Swarm Source

ipfs://b334eb4134d409e83b46be2236130c8bf8a3eacf562dfad3f1a42ea9693bf610

Block Transaction Gas Used Reward
view all blocks ##produced##

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.