Source Code
Overview
S Balance
S Value
$0.00Cross-Chain Transactions
Loading...
Loading
Contract Name:
VaultMetadataFacet
Compiler Version
v0.8.26+commit.8a97fa7a
Contract Source Code (Solidity Standard Json-Input format)
// 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;
}
}
}
}// 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
}
}
}// 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();
}// 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);
}// 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
}{
"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
- No Contract Security Audit Submitted- Submit Audit Here
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"}]Contract Creation Code
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
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in S
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
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.