S Price: $0.068289 (-2.51%)

Contract

0x1aa1509523A3DB5F97c744C2674B4c04B1B3fd42

Overview

S Balance

Sonic LogoSonic LogoSonic Logo0 S

S Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Cross-Chain Transactions
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x9585a8A4...169dd653F
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
SolidlyLibrary

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion, MIT license

Contract Source Code (Solidity Standard Json-Input format)

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

import "../../interfaces/routing/IRouterLibrary.sol";
import "../../interfaces/routing/RouterTypes.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

// ============ CUSTOM ERRORS ============

error SolidlyInvalidRouter();
error SolidlyZeroAmount();
error SolidlyZeroAmounts();

/**
 * @title SolidlyLibrary
 * @notice Router library for Solidly-fork protocols (Shadow, Velodrome, Aerodrome, Thena, Equal)
 * @dev Handles validation, encoding/decoding, AND execution of swaps and liquidity operations
 * 
 * Supported DEXes (all use identical Solidly interface):
 * - Shadow (Sonic)
 * - Velodrome (Optimism)
 * - Aerodrome (Base)
 * - Thena (BNB Chain)
 * - Equal (Fantom)
 * 
 * Route Format: (address from, address to, bool stable)
 * - from: Input token address
 * - to: Output token address
 * - stable: Whether to use stable pool (true) or volatile pool (false)
 * 
 * This library eliminates the need for AbstractSolidlyStrategy inheritance.
 * All Solidly-fork strategies delegate to this single library.
 */
contract SolidlyLibrary is IRouterLibrary {
    using SafeERC20 for IERC20;
    
    // ============ TYPE DEFINITIONS ============
    
    /// @notice Single Solidly route (one hop)
    struct SolidlyRoute {
        address from;
        address to;
        bool stable;
    }
    
    /// @notice Complete route configuration for a Solidly strategy
    struct SolidlyRouteData {
        SolidlyRoute[] rewardRoutes;   // Routes to convert rewards to native token
        SolidlyRoute nativeToLp0;      // Route from native to LP token0
        SolidlyRoute nativeToLp1;      // Route from native to LP token1
    }
    
    // ============ IROUTER LIBRARY IMPLEMENTATION ============
    
    /**
     * @notice Returns the router type this library handles
     */
    function getRouterType() external pure override returns (RouterType) {
        return RouterType.SOLIDLY;
    }
    
    /**
     * @notice Validate Solidly route structure
     * @param routeData ABI-encoded SolidlyRouteData
     */
    function validateRoutes(bytes calldata routeData)
        external
        pure
        override
        returns (bool valid, string memory reason)
    {
        // Decode the route data
        SolidlyRouteData memory data = abi.decode(routeData, (SolidlyRouteData));
        
        // Validate reward routes exist
        if (data.rewardRoutes.length == 0) {
            return (false, "Empty reward routes");
        }
        
        // Validate each reward route
        for (uint256 i = 0; i < data.rewardRoutes.length; i++) {
            SolidlyRoute memory route = data.rewardRoutes[i];
            
            if (route.from == address(0)) {
                return (false, "Invalid tokenIn in reward route");
            }
            if (route.to == address(0)) {
                return (false, "Invalid tokenOut in reward route");
            }
            if (route.from == route.to) {
                return (false, "Reward route from == to");
            }
        }
        
        // Validate nativeToLp0 route
        if (data.nativeToLp0.from == address(0)) {
            return (false, "Invalid nativeToLp0 tokenIn");
        }
        if (data.nativeToLp0.to == address(0)) {
            return (false, "Invalid nativeToLp0 tokenOut");
        }
        if (data.nativeToLp0.from == data.nativeToLp0.to) {
            return (false, "NativeToLp0 from == to");
        }
        
        // Validate nativeToLp1 route
        if (data.nativeToLp1.from == address(0)) {
            return (false, "Invalid nativeToLp1 tokenIn");
        }
        if (data.nativeToLp1.to == address(0)) {
            return (false, "Invalid nativeToLp1 tokenOut");
        }
        if (data.nativeToLp1.from == data.nativeToLp1.to) {
            return (false, "NativeToLp1 from == to");
        }
        
        return (true, "");
    }
    
    /**
     * @notice Encode Solidly routes to bytes for storage
     * @param routeData ABI-encoded SolidlyRouteData
     */
    function encodeRoutes(bytes calldata routeData)
        external
        pure
        override
        returns (
            bytes[] memory rewardRoutes,
            bytes memory nativeToLp0,
            bytes memory nativeToLp1
        )
    {
        SolidlyRouteData memory data = abi.decode(routeData, (SolidlyRouteData));
        
        // Encode reward routes
        rewardRoutes = new bytes[](data.rewardRoutes.length);
        for (uint256 i = 0; i < data.rewardRoutes.length; i++) {
            rewardRoutes[i] = abi.encode(
                data.rewardRoutes[i].from,
                data.rewardRoutes[i].to,
                data.rewardRoutes[i].stable
            );
        }
        
        // Encode LP routes
        nativeToLp0 = abi.encode(
            data.nativeToLp0.from,
            data.nativeToLp0.to,
            data.nativeToLp0.stable
        );
        
        nativeToLp1 = abi.encode(
            data.nativeToLp1.from,
            data.nativeToLp1.to,
            data.nativeToLp1.stable
        );
    }
    
    /**
     * @notice Decode Solidly routes from storage bytes
     * @param encodedRewardRoutes Array of encoded reward routes
     * @param encodedNativeToLp0 Encoded native->LP0 route
     * @param encodedNativeToLp1 Encoded native->LP1 route
     */
    function decodeRoutes(
        bytes[] calldata encodedRewardRoutes,
        bytes calldata encodedNativeToLp0,
        bytes calldata encodedNativeToLp1
    ) external pure override returns (bytes memory routeData) {
        SolidlyRouteData memory data;
        
        // Decode reward routes
        data.rewardRoutes = new SolidlyRoute[](encodedRewardRoutes.length);
        for (uint256 i = 0; i < encodedRewardRoutes.length; i++) {
            (address from, address to, bool stable) = abi.decode(
                encodedRewardRoutes[i],
                (address, address, bool)
            );
            data.rewardRoutes[i] = SolidlyRoute({from: from, to: to, stable: stable});
        }
        
        // Decode nativeToLp0
        (address from0, address to0, bool stable0) = abi.decode(
            encodedNativeToLp0,
            (address, address, bool)
        );
        data.nativeToLp0 = SolidlyRoute({from: from0, to: to0, stable: stable0});
        
        // Decode nativeToLp1
        (address from1, address to1, bool stable1) = abi.decode(
            encodedNativeToLp1,
            (address, address, bool)
        );
        data.nativeToLp1 = SolidlyRoute({from: from1, to: to1, stable: stable1});
        
        // Re-encode as SolidlyRouteData for return
        return abi.encode(data);
    }
    
    /**
     * @notice Simulate a Solidly route (not implemented)
     * @dev Simulation would require router interface and on-chain liquidity checks
     */
    function simulateRoute(
        bytes calldata, /* route */
        uint256, /* amountIn */
        address /* router */
    ) external pure override returns (uint256) {
        revert("Simulation not implemented");
    }
    
    // ============ EXECUTION FUNCTIONS ============
    
    /**
     * @notice Execute a swap through any Solidly-fork router
     * @dev Handles approvals, route conversion, and execution for Shadow/Velodrome/Aerodrome/etc.
     * @param router DEX router address (e.g., Shadow: 0x123, Velodrome: 0x456)
     * @param route Encoded route: abi.encode(address from, address to, bool stable)
     * @param amountIn Amount of input tokens to swap
     * @param amountOutMin Minimum amount of output tokens (slippage protection)
     * @param to Recipient address for output tokens
     * @return amountOut Actual amount of output tokens received
     */
    function swap(
        address router,
        bytes calldata route,
        uint256 amountIn,
        uint256 amountOutMin,
        address to
    ) external override returns (uint256 amountOut) {
        if (router == address(0)) revert SolidlyInvalidRouter();
        if (amountIn == 0) revert SolidlyZeroAmount();
        
        // Decode route
        (address tokenIn, address tokenOut, bool stable) = abi.decode(route, (address, address, bool));
        
        // Approve input token to router
        IERC20(tokenIn).forceApprove(router, amountIn);
        
        // Convert to ISolidlyRouter.route format
        ISolidlyRouter.route[] memory routes = new ISolidlyRouter.route[](1);
        routes[0] = ISolidlyRouter.route({
            from: tokenIn,
            to: tokenOut,
            stable: stable
        });
        
        // Execute swap
        uint256[] memory amounts = ISolidlyRouter(router).swapExactTokensForTokens(
            amountIn,
            amountOutMin,
            routes,
            to,
            block.timestamp + 300
        );
        
        return amounts[amounts.length - 1];
    }
    
    /**
     * @notice Add liquidity through any Solidly-fork router
     * @dev Handles approvals and execution for Shadow/Velodrome/Aerodrome/etc.
     * @param router DEX router address
     * @param liquidityData Encoded: abi.encode(address token0, address token1, bool stable)
     * @param amount0 Amount of token0 to add
     * @param amount1 Amount of token1 to add
     * @param minAmount0 Minimum amount of token0 (slippage protection)
     * @param minAmount1 Minimum amount of token1 (slippage protection)
     * @param to Recipient address for LP tokens
     * @return lpReceived Amount of LP tokens received
     */
    function addLiquidity(
        address router,
        bytes calldata liquidityData,
        uint256 amount0,
        uint256 amount1,
        uint256 minAmount0,
        uint256 minAmount1,
        address to
    ) external override returns (uint256 lpReceived) {
        if (router == address(0)) revert SolidlyInvalidRouter();
        if (amount0 == 0 || amount1 == 0) revert SolidlyZeroAmounts();
        
        // Decode liquidity parameters
        (address token0, address token1, bool stable) = abi.decode(liquidityData, (address, address, bool));
        
        // Approve tokens to router
        IERC20(token0).forceApprove(router, amount0);
        IERC20(token1).forceApprove(router, amount1);
        
        // Execute addLiquidity
        (,, uint256 liquidity) = ISolidlyRouter(router).addLiquidity(
            token0,
            token1,
            stable,
            amount0,
            amount1,
            minAmount0,
            minAmount1,
            to,
            block.timestamp + 300
        );
        
        return liquidity;
    }
    
    /**
     * @notice Remove liquidity from a Solidly-fork pool
     * @dev Handles approvals and execution for Shadow/Velodrome/Aerodrome/etc.
     * @param router DEX router address
     * @param liquidityData Encoded: abi.encode(address token0, address token1, bool stable)
     * @param lpAmount Amount of LP tokens to remove
     * @param minAmount0 Minimum amount of token0 to receive
     * @param minAmount1 Minimum amount of token1 to receive
     * @param to Recipient address for tokens
     * @return amount0 Amount of token0 received
     * @return amount1 Amount of token1 received
     */
    function removeLiquidity(
        address router,
        bytes calldata liquidityData,
        uint256 lpAmount,
        uint256 minAmount0,
        uint256 minAmount1,
        address to
    ) external override returns (uint256 amount0, uint256 amount1) {
        if (router == address(0)) revert SolidlyInvalidRouter();
        if (lpAmount == 0) revert SolidlyZeroAmount();
        
        // Decode liquidity parameters
        (address token0, address token1, bool stable) = abi.decode(liquidityData, (address, address, bool));
        
        // Get LP token address
        address lpToken = ISolidlyRouter(router).pairFor(token0, token1, stable);
        
        // Approve LP tokens to router
        IERC20(lpToken).forceApprove(router, lpAmount);
        
        // Execute removeLiquidity
        (amount0, amount1) = ISolidlyRouter(router).removeLiquidity(
            token0,
            token1,
            stable,
            lpAmount,
            minAmount0,
            minAmount1,
            to,
            block.timestamp + 300
        );
    }
    
    // ============ PRICE QUERY (For Oracle Integration) ============
    
    /**
     * @notice Query price from Solidly router (view only)
     * @dev Tries volatile pool first, falls back to stable pool
     * @param router Solidly router address
     * @param tokenIn Input token address
     * @param tokenOut Output token address
     * @param amountIn Amount of input tokens
     * @return amountOut Expected output amount (0 if no route exists)
     */
    function getPrice(
        address router,
        address tokenIn,
        address tokenOut,
        uint256 amountIn
    ) external view override returns (uint256 amountOut) {
        if (router == address(0) || tokenIn == tokenOut) return 0;
        if (amountIn == 0) return 0;
        
        // Try volatile pool first
        address volatilePair = ISolidlyRouter(router).pairFor(tokenIn, tokenOut, false);
        if (volatilePair != address(0)) {
            try ISolidlyPair(volatilePair).getAmountOut(amountIn, tokenIn) returns (uint256 output) {
                if (output > 0) return output;
            } catch {}
        }
        
        // Try stable pool
        address stablePair = ISolidlyRouter(router).pairFor(tokenIn, tokenOut, true);
        if (stablePair != address(0)) {
            try ISolidlyPair(stablePair).getAmountOut(amountIn, tokenIn) returns (uint256 output) {
                if (output > 0) return output;
            } catch {}
        }
        
        return 0;
    }
    
    /**
     * @notice Get complete LP token data for Solidly pairs
     * @dev Returns token composition and reserves for Oracle pricing
     * @param asset Asset address to query
     * @return data Complete LP token data (isLP=false if not a Solidly pair)
     */
    function getLPData(address asset) external view override returns (LPTokenData memory data) {
        // Try to detect if this is a Solidly pair
        try ISolidlyPair(asset).stable() returns (bool stable) {
            try ISolidlyPair(asset).token0() returns (address token0) {
                try ISolidlyPair(asset).token1() returns (address token1) {
                    // It's a Solidly pair - get full data
                    (uint256 reserve0, uint256 reserve1,) = ISolidlyPair(asset).getReserves();
                    uint256 totalSupply = ISolidlyPair(asset).totalSupply();
                    
                    // Build token array (2 tokens for Solidly)
                    address[] memory tokens = new address[](2);
                    tokens[0] = token0;
                    tokens[1] = token1;
                    
                    // Build reserve array
                    uint256[] memory reserves = new uint256[](2);
                    reserves[0] = reserve0;
                    reserves[1] = reserve1;
                    
                    // Return complete data
                    return LPTokenData({
                        isLP: true,
                        tokens: tokens,
                        reserves: reserves,
                        totalSupply: totalSupply,
                        isStable: stable,
                        metadata: ""  // No extra metadata needed for Solidly
                    });
                } catch {}
            } catch {}
        } catch {}
        
        // Not a Solidly pair - return empty data
        return LPTokenData({
            isLP: false,
            tokens: new address[](0),
            reserves: new uint256[](0),
            totalSupply: 0,
            isStable: false,
            metadata: ""
        });
    }
    
    // ============ ROUTE VALIDATION ============
    
    /**
     * @notice Validate Solidly route configuration
     * @dev Ensures routes follow correct format: rewards -> native, native -> lpTokens
     * @param _rewardRoutes Array of encoded reward routes
     * @param _nativeToLp0 Encoded route from native to LP token0
     * @param _nativeToLp1 Encoded route from native to LP token1
     * @param nativeToken Wrapped native token address
     * @param lpToken0 First LP token address
     * @param lpToken1 Second LP token address
     * @return valid Whether all routes are valid
     * @return reason Error message if invalid
     */
    function validateRoutes(
        bytes[] calldata _rewardRoutes,
        bytes calldata _nativeToLp0,
        bytes calldata _nativeToLp1,
        address nativeToken,
        address lpToken0,
        address lpToken1
    ) external pure returns (bool valid, string memory reason) {
        // Validate reward routes end at wrapped native
        for (uint256 i = 0; i < _rewardRoutes.length; i++) {
            (,address to,) = abi.decode(_rewardRoutes[i], (address, address, bool));
            if (to != nativeToken) {
                return (false, "Reward route must end at wrapped native");
            }
        }
        
        // Validate nativeToLp0 route
        (address from0, address to0,) = abi.decode(_nativeToLp0, (address, address, bool));
        if (from0 != nativeToken) {
            return (false, "NativeToLp0 must start at wrapped native");
        }
        if (to0 != lpToken0) {
            return (false, "NativeToLp0 must end at lpToken0");
        }
        
        // Validate nativeToLp1 route
        (address from1, address to1,) = abi.decode(_nativeToLp1, (address, address, bool));
        if (from1 != nativeToken) {
            return (false, "NativeToLp1 must start at wrapped native");
        }
        if (to1 != lpToken1) {
            return (false, "NativeToLp1 must end at lpToken1");
        }
        
        return (true, "");
    }
}

// ============ SOLIDLY ROUTER INTERFACE ============

/**
 * @notice Minimal interface for Solidly-fork routers
 * @dev Used by ALL Solidly forks: Shadow, Velodrome, Aerodrome, Thena, Equal
 */
interface ISolidlyRouter {
    struct route {
        address from;
        address to;
        bool stable;
    }
    
    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        route[] calldata routes,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);
    
    function addLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);
    
    function removeLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB);
    
    function pairFor(
        address tokenA,
        address tokenB,
        bool stable
    ) external view returns (address pair);
}

/**
 * @notice Minimal interface for Solidly-fork pairs
 * @dev Used for price queries and LP data retrieval
 */
interface ISolidlyPair {
    function getAmountOut(uint256 amountIn, address tokenIn) external view returns (uint256);
    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves() external view returns (uint256 reserve0, uint256 reserve1, uint256 blockTimestampLast);
    function totalSupply() external view returns (uint256);
    function stable() external view returns (bool);
}

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

import "./RouterTypes.sol";
import "../../vaults/00_libraries/types.sol";

/**
 * @title IRouterLibrary
 * @notice Standard interface for router-specific encoding/decoding libraries
 * @dev Each router type (Solidly, UniV2, UniV3, etc.) implements this interface
 * 
 * Architecture:
 * - Libraries are external contracts registered in RoutingFacet
 * - Each library handles encoding/decoding for its specific router type
 * - Validation, encoding, and decoding are type-safe and router-specific
 */
interface IRouterLibrary {
    
    /**
     * @notice Get the router type this library handles
     * @return The RouterType enum value
     */
    function getRouterType() external pure returns (RouterType);
    
    /**
     * @notice Validate route structure before encoding
     * @dev Called by RoutingFacet before applying routes
     * @param routeData ABI-encoded route data (library-specific format)
     * @return valid Whether the routes are valid
     * @return reason Error message if invalid
     */
    function validateRoutes(
        bytes calldata routeData
    ) external view returns (bool valid, string memory reason);
    
    /**
     * @notice Encode routes from library-specific format to bytes for storage
     * @dev Called by RoutingFacet after validation
     * @param routeData ABI-encoded route data (library-specific format)
     * @return rewardRoutes Array of encoded reward token routes
     * @return nativeToLp0 Encoded route from native token to LP token0
     * @return nativeToLp1 Encoded route from native token to LP token1
     */
    function encodeRoutes(
        bytes calldata routeData
    ) external pure returns (
        bytes[] memory rewardRoutes,
        bytes memory nativeToLp0,
        bytes memory nativeToLp1
    );
    
    /**
     * @notice Decode routes from storage bytes to library-specific format
     * @dev Called by view functions to return type-safe data to frontend
     * @param rewardRoutes Array of encoded reward routes
     * @param nativeToLp0 Encoded native->LP0 route
     * @param nativeToLp1 Encoded native->LP1 route
     * @return routeData ABI-encoded decoded data (library-specific format)
     */
    function decodeRoutes(
        bytes[] calldata rewardRoutes,
        bytes calldata nativeToLp0,
        bytes calldata nativeToLp1
    ) external pure returns (bytes memory routeData);
    
    /**
     * @notice Simulate a route to estimate output (optional, for advanced validation)
     * @dev May not be implemented by all libraries
     * @param route Single encoded route to simulate
     * @param amountIn Input amount to simulate
     * @param router Router address to query
     * @return expectedOutput Expected output amount
     */
    function simulateRoute(
        bytes calldata route,
        uint256 amountIn,
        address router
    ) external view returns (uint256 expectedOutput);
    
    // ============ EXECUTION FUNCTIONS ============
    
    /**
     * @notice Execute a swap operation through the router
     * @dev Library handles approvals, route conversion, and execution
     * @param router DEX router address (e.g., Shadow, Velodrome, Aerodrome for Solidly type)
     * @param route Encoded route data (library-specific format)
     * @param amountIn Amount of input tokens to swap
     * @param amountOutMin Minimum amount of output tokens (slippage protection)
     * @param to Recipient address for output tokens
     * @return amountOut Actual amount of output tokens received
     */
    function swap(
        address router,
        bytes calldata route,
        uint256 amountIn,
        uint256 amountOutMin,
        address to
    ) external returns (uint256 amountOut);
    
    /**
     * @notice Add liquidity to a pool through the router
     * @dev Library handles approvals, optimal amounts, and execution
     * @param router DEX router address
     * @param liquidityData Encoded liquidity parameters (library-specific format)
     * @param amount0 Amount of token0 to add
     * @param amount1 Amount of token1 to add
     * @param minAmount0 Minimum amount of token0 (slippage protection)
     * @param minAmount1 Minimum amount of token1 (slippage protection)
     * @param to Recipient address for LP tokens
     * @return lpReceived Amount of LP tokens received
     */
    function addLiquidity(
        address router,
        bytes calldata liquidityData,
        uint256 amount0,
        uint256 amount1,
        uint256 minAmount0,
        uint256 minAmount1,
        address to
    ) external returns (uint256 lpReceived);
    
    /**
     * @notice Remove liquidity from a pool through the router
     * @dev Library handles approvals and execution
     * @param router DEX router address
     * @param liquidityData Encoded liquidity parameters (library-specific format)
     * @param lpAmount Amount of LP tokens to remove
     * @param minAmount0 Minimum amount of token0 to receive
     * @param minAmount1 Minimum amount of token1 to receive
     * @param to Recipient address for tokens
     * @return amount0 Amount of token0 received
     * @return amount1 Amount of token1 received
     */
    function removeLiquidity(
        address router,
        bytes calldata liquidityData,
        uint256 lpAmount,
        uint256 minAmount0,
        uint256 minAmount1,
        address to
    ) external returns (uint256 amount0, uint256 amount1);
    
    // ============ PRICE QUERY FUNCTIONS (For Oracle Integration) ============
    
    /**
     * @notice Query price from router (view only, for Oracle)
     * @dev Each library implements router-specific price query logic
     * @param router DEX router address
     * @param tokenIn Input token address
     * @param tokenOut Output token address
     * @param amountIn Amount of input tokens
     * @return amountOut Expected output amount (0 if route doesn't exist)
     */
    function getPrice(
        address router,
        address tokenIn,
        address tokenOut,
        uint256 amountIn
    ) external view returns (uint256 amountOut);
    
    /**
     * @notice Get complete LP token data for Oracle pricing
     * @dev Detects and returns LP token composition with reserves
     * @dev Returns empty/false data if asset is not an LP token for this router type
     * @param asset Asset address to query
     * @return data Complete LP token data (isLP=false if not an LP)
     */
    function getLPData(address asset) external view returns (LPTokenData memory data);
}

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

event VaultUIMetadataUpdated(address indexed vault, VaultUIMetadata uiMetadata);

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

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

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

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

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

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

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

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

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

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

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

event NativeToLp0RouteSet(address[] route);

event NativeToLp1RouteSet(address[] route);

event EmergencyWithdrawFailed(bytes reason);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)

pragma solidity >=0.6.2;

import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}

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

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

File 9 of 11 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)

pragma solidity >=0.4.16;

import {IERC20} from "../token/ERC20/IERC20.sol";

File 10 of 11 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)

pragma solidity >=0.4.16;

import {IERC165} from "../utils/introspection/IERC165.sol";

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SolidlyInvalidRouter","type":"error"},{"inputs":[],"name":"SolidlyZeroAmount","type":"error"},{"inputs":[],"name":"SolidlyZeroAmounts","type":"error"},{"inputs":[{"internalType":"address","name":"router","type":"address"},{"internalType":"bytes","name":"liquidityData","type":"bytes"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"},{"internalType":"uint256","name":"minAmount0","type":"uint256"},{"internalType":"uint256","name":"minAmount1","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"lpReceived","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"encodedRewardRoutes","type":"bytes[]"},{"internalType":"bytes","name":"encodedNativeToLp0","type":"bytes"},{"internalType":"bytes","name":"encodedNativeToLp1","type":"bytes"}],"name":"decodeRoutes","outputs":[{"internalType":"bytes","name":"routeData","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"routeData","type":"bytes"}],"name":"encodeRoutes","outputs":[{"internalType":"bytes[]","name":"rewardRoutes","type":"bytes[]"},{"internalType":"bytes","name":"nativeToLp0","type":"bytes"},{"internalType":"bytes","name":"nativeToLp1","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getLPData","outputs":[{"components":[{"internalType":"bool","name":"isLP","type":"bool"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"reserves","type":"uint256[]"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"bool","name":"isStable","type":"bool"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"internalType":"struct LPTokenData","name":"data","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"getPrice","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRouterType","outputs":[{"internalType":"enum RouterType","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"router","type":"address"},{"internalType":"bytes","name":"liquidityData","type":"bytes"},{"internalType":"uint256","name":"lpAmount","type":"uint256"},{"internalType":"uint256","name":"minAmount0","type":"uint256"},{"internalType":"uint256","name":"minAmount1","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"simulateRoute","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"router","type":"address"},{"internalType":"bytes","name":"route","type":"bytes"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"swap","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"_rewardRoutes","type":"bytes[]"},{"internalType":"bytes","name":"_nativeToLp0","type":"bytes"},{"internalType":"bytes","name":"_nativeToLp1","type":"bytes"},{"internalType":"address","name":"nativeToken","type":"address"},{"internalType":"address","name":"lpToken0","type":"address"},{"internalType":"address","name":"lpToken1","type":"address"}],"name":"validateRoutes","outputs":[{"internalType":"bool","name":"valid","type":"bool"},{"internalType":"string","name":"reason","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"routeData","type":"bytes"}],"name":"validateRoutes","outputs":[{"internalType":"bool","name":"valid","type":"bool"},{"internalType":"string","name":"reason","type":"string"}],"stateMutability":"pure","type":"function"}]

0x60808060405234601557611def908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c80631f19e6af14610bb25780632958884314610a4a578063436b3d99146109a65780636966f521146107ae5780636ea4a2361461076157806373d896ac146106e1578063770b7bf6146106985780639f42c7e4146105ac578063aa5cc163146102f5578063c7abc3ff146100b05763ff7dcd5a14610092575f80fd5b346100ac575f3660031901126100ac5760206040515f8152f35b5f80fd5b346100ac5760203660031901126100ac576004356001600160401b0381116100ac576100e36100eb913690600401610ea1565b810190611580565b805151906100f882610fe3565b916101066040519384610fc2565b808352610115601f1991610fe3565b015f5b8181106102e45750505f5b81519081518110156101d1576001916001600160a01b0390610146908390611049565b5151166101b5838060a01b03602061015f858851611049565b51015116916101a76040610174868951611049565b510151604080516001600160a01b0394851660208201529590931692850192909252901515606084015282906080820190565b03601f198101835282610fc2565b6101bf8286611049565b526101ca8185611049565b5001610123565b505060208181015180518183015160409283015183516001600160a01b039384169581019590955291168383015215156060830152909161021f83608081015b03601f198101855284610fc2565b0151805160208083015160409384015184516001600160a01b039485169381019390935292169281019290925215156060820152916102618360808101610211565b60405191606083016060845282518091526080840190602060808260051b8701019401915f905b8282106102b95786806102b58a6102a78a8a8582036020870152610efe565b908382036040850152610efe565b0390f35b909192946020806102d6600193607f198b82030186528951610efe565b970192019201909291610288565b806060602080938701015201610118565b346100ac5760603660031901126100ac576004356001600160401b0381116100ac57610325903690600401610ece565b906024356001600160401b0381116100ac57610345903690600401610ea1565b92906044356001600160401b0381116100ac57610366903690600401610ea1565b90916040519561037587610f78565b606087526020870195610386610ffa565b87526040880195610395610ffa565b87526103a081610fe3565b6103ad6040519182610fc2565b818152601f196103bc83610fe3565b015f5b81811061059557505089525f5b81811061053657505050816103e89161041a9594930190610f4b565b90604051926103f684610f78565b6001600160a01b039081168452166020830152151560408201528552810190610f4b565b906040519261042884610f78565b60018060a01b0316835260018060a01b0316602083015215156040820152815260405191602080840152610120830193519360e060408501528451809152602061014085019501905f5b8181106104f057835180516001600160a01b039081166060890152602082015116608088015260400151151560a08701526102b5866104dc818a6101a78a5180516001600160a01b0390811660c086015260208201511660e0850152604001511515610100840152565b604051918291602083526020830190610efe565b909195602060608261052b6001948b516040809160018060a01b03815116845260018060a01b03602082015116602085015201511515910152565b019701929101610472565b8061058e8161055361054b6001958789611078565b810190610f4b565b906040519261056184610f78565b60a088901b8890039081168452166020830152151560408201528d51906105888383611049565b52611049565b50016103cc565b6020906105a0610ffa565b828286010152016103bf565b346100ac5760203660031901126100ac576105cd6105c8610e35565b6119ba565b6040516020815260e081019180511515602083015260208101519260c060408401528351809152602061010084019401905f5b81811061067957505050604081015192601f19838203016060840152602080855192838152019401905f5b8181106106635784806102b58860a0886060810151608086015260808101511515828601520151601f198483030160c0850152610efe565b825186526020958601959092019160010161062b565b82516001600160a01b0316865260209586019590920191600101610600565b346100ac5760203660031901126100ac576004356001600160401b0381116100ac576106cb6106d1913690600401610ea1565b90611655565b906102b560405192839283610f22565b346100ac5760603660031901126100ac576004356001600160401b0381116100ac57610711903690600401610ea1565b505061071b610e77565b5060405162461bcd60e51b815260206004820152601a60248201527f53696d756c6174696f6e206e6f7420696d706c656d656e7465640000000000006044820152606490fd5b346100ac5760803660031901126100ac5761077a610e35565b6024356001600160a01b03811681036100ac576020916107a69161079c610e77565b9060643592611310565b604051908152f35b346100ac5760c03660031901126100ac576107c7610e35565b6024356001600160401b0381116100ac576107e6903690600401610ea1565b91604435926107f3610e61565b6001600160a01b0383169390919084156109975785156109885761081991810190610f4b565b60405163260f701f60e11b81526001600160a01b0393841660048201819052929093166024840181905281151560448501529096909491929091906020816064818a5afa91821561093a576108809284925f91610959575b506001600160a01b0316611ca9565b61012c42019485421161094557604095610104945f938851998a98899763037b79b160e21b895260048901526024880152151560448701526064860152606435608486015260843560a486015260018060a01b031660c485015260e48401525af1801561093a575f905f90610900575b6040809350519182526020820152f35b50506040813d604011610932575b8161091b60409383610fc2565b810103126100ac57806020604092519101516108f0565b3d915061090e565b6040513d5f823e3d90fd5b634e487b7160e01b5f52601160045260245ffd5b61097b915060203d602011610981575b6109738183610fc2565b8101906112f1565b8a610871565b503d610969565b63628d981160e11b5f5260045ffd5b634c83788f60e11b5f5260045ffd5b346100ac5760c03660031901126100ac576004356001600160401b0381116100ac576109d6903690600401610ece565b906024356001600160401b0381116100ac576109f6903690600401610ea1565b6044939193356001600160401b0381116100ac57610a18903690600401610ea1565b606435929091906001600160a01b03841684036100ac576106d196610a3b610e4b565b95610a44610e61565b976110b9565b346100ac5760e03660031901126100ac57610a63610e35565b6024356001600160401b0381116100ac57610a82903690600401610ea1565b9160c4356001600160a01b0381169260643591604435908590036100ac576001600160a01b03841680156109975781158015610baa575b610b9c57610ace83610af29886950190610f4b565b986001600160a01b0391821697919092169490610aec858288611ca9565b87611ca9565b61012c420180421161094557606096610124955f946040519a8b998a98635a47ddc360e01b8a5260048a01526024890152151560448801526064870152608486015260843560a486015260a43560c486015260e48501526101048401525af1801561093a576020915f91610b6a575b50604051908152f35b610b8c915060603d606011610b95575b610b848183610fc2565b81019061105d565b91505082610b61565b503d610b7a565b62b784c960e41b5f5260045ffd5b508315610ab9565b346100ac5760a03660031901126100ac57610bcb610e35565b6024356001600160401b0381116100ac57610bea903690600401610ea1565b909160443592610bf8610e4b565b6001600160a01b03831692831561099757851561098857610c2083610c389688950190610f4b565b9690946001600160a01b039092169290919083611ca9565b604094855193610c488786610fc2565b60018552601f1987015f5b818110610e1e575050865192610c6884610f78565b83526001600160a01b03166020830152151585820152610c8783611018565b52610c9182611018565b5061012c420190814211610945579491908451958693631e82ecdb60e31b855260a48501906004860152606435602486015260a060448601528351809152602060c486019401905f5b818110610dd0575050506001600160a01b0316606484015260848301525f929082900390829084905af1918215610dc6575f92610d35575b5081515f1981019290831161094557602092610d2d91611049565b519051908152f35b9091503d805f833e610d478183610fc2565b8101906020818303126100ac578051906001600160401b0382116100ac57019080601f830112156100ac578151610d7d81610fe3565b92610d8a85519485610fc2565b81845260208085019260051b8201019283116100ac57602001905b828210610db6575050509082610d12565b8151815260209182019101610da5565b50513d5f823e3d90fd5b9195509192936020606082610e0e6001948a516040809160018060a01b03815116845260018060a01b03602082015116602085015201511515910152565b0196019101918895949392610cda565b602090610e29610ffa565b82828a01015201610c53565b600435906001600160a01b03821682036100ac57565b608435906001600160a01b03821682036100ac57565b60a435906001600160a01b03821682036100ac57565b604435906001600160a01b03821682036100ac57565b35906001600160a01b03821682036100ac57565b9181601f840112156100ac578235916001600160401b0383116100ac57602083818601950101116100ac57565b9181601f840112156100ac578235916001600160401b0383116100ac576020808501948460051b0101116100ac57565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b604090610f3b9392151581528160208201520190610efe565b90565b359081151582036100ac57565b908160609103126100ac57610f5f81610e8d565b91610f3b6040610f7160208501610e8d565b9301610f3e565b606081019081106001600160401b03821117610f9357604052565b634e487b7160e01b5f52604160045260245ffd5b60c081019081106001600160401b03821117610f9357604052565b90601f801991011681019081106001600160401b03821117610f9357604052565b6001600160401b038111610f935760051b60200190565b6040519061100782610f78565b5f6040838281528260208201520152565b8051156110255760200190565b634e487b7160e01b5f52603260045260245ffd5b8051600110156110255760400190565b80518210156110255760209160051b010190565b908160609103126100ac578051916040602083015192015190565b91908110156110255760051b81013590601e19813603018212156100ac5701908135916001600160401b0383116100ac5760200182360381136100ac579190565b909796939495979291925f5b81811061126f57505050906110dc91810190610f4b565b506001600160a01b03968716969092911686900361121b576001600160a01b039081169116036111da5761111291810190610f4b565b50926001600160a01b039091160361118a576001600160a01b0390811691160361114d57600190604051611147602082610fc2565b5f815290565b5f9060405161115d604082610fc2565b602081527f4e6174697665546f4c7031206d75737420656e64206174206c70546f6b656e31602082015290565b50505f9060405161119c606082610fc2565b602881527f4e6174697665546f4c7031206d7573742073746172742061742077726170706560208201526764206e617469766560c01b604082015290565b505050505f906040516111ee604082610fc2565b602081527f4e6174697665546f4c7030206d75737420656e64206174206c70546f6b656e30602082015290565b5050505050505f90604051611231606082610fc2565b602881527f4e6174697665546f4c7030206d7573742073746172742061742077726170706560208201526764206e617469766560c01b604082015290565b61127d61054b828486611078565b506001600160a01b038c8116911603905061129a576001016110c5565b505050505050505050505f906040516112b4606082610fc2565b602781527f52657761726420726f757465206d75737420656e642061742077726170706564602082015266206e617469766560c81b604082015290565b908160209103126100ac57516001600160a01b03811681036100ac5790565b9092916001600160a01b039091169081158015611524575b61151c57821561151c5760405163260f701f60e11b81526001600160a01b03858116600483018190529216602482018190525f60448301529190602081606481875afa90811561093a575f916114fd575b506001600160a01b03168061147c575b50906064602092604051948593849263260f701f60e11b845260048401526024830152600160448301525afa90811561093a575f9161145d575b506001600160a01b031691826113db575b5050505f90565b6040516378a051ad60e11b815260048101929092526001600160a01b0316602482015290602090829060449082905afa5f9181611429575b50611420575b80806113d4565b80156114195790565b9091506020813d602011611455575b8161144560209383610fc2565b810103126100ac5751905f611413565b3d9150611438565b611476915060203d602011610981576109738183610fc2565b5f6113c3565b6040516378a051ad60e11b8152600481018690526001600160a01b038716602482015290602090829060449082905afa5f91816114c9575b50156113895780156113895794505050505090565b9091506020813d6020116114f5575b816114e560209383610fc2565b810103126100ac5751905f6114b4565b3d91506114d8565b611516915060203d602011610981576109738183610fc2565b5f611379565b505050505f90565b506001600160a01b0384811690821614611328565b91908260609103126100ac5760405161155181610f78565b604061157b81839561156281610e8d565b855261157060208201610e8d565b602086015201610f3e565b910152565b6020818303126100ac578035906001600160401b0382116100ac57019060e0828203126100ac57604051916115b483610f78565b80356001600160401b0381116100ac57810182601f820112156100ac578035906115dd82610fe3565b916115eb6040519384610fc2565b808352602060608185019202830101918583116100ac57602001905b82821061163b57505050611633929160809185526116288360208301611539565b602086015201611539565b604082015290565b602060609161164a8885611539565b815201910190611607565b61166191810190611580565b80515115611986575f5b81518051821015611785578161168091611049565b5180516001600160a01b031615611745576020810180519091906001600160a01b031615611704575190516001600160a01b039081169116146116c55760010161166b565b50505f906040516116d7604082610fc2565b601781527f52657761726420726f7574652066726f6d203d3d20746f000000000000000000602082015290565b505050505f90604051611718604082610fc2565b602081527f496e76616c696420746f6b656e4f757420696e2072657761726420726f757465602082015290565b5050505f90604051611758604082610fc2565b601f81527f496e76616c696420746f6b656e496e20696e2072657761726420726f75746500602082015290565b5050602081018051516001600160a01b031615611947578051602001516001600160a01b031615611908575180516020909101516001600160a01b039081169116146118d1576040018051516001600160a01b031615611893578051602001516001600160a01b031615611855575180516020909101516001600160a01b0390811691161461181f57600190604051611147602082610fc2565b5f9060405161182f604082610fc2565b60168152754e6174697665546f4c70312066726f6d203d3d20746f60501b602082015290565b505f90604051611866604082610fc2565b601c81527f496e76616c6964206e6174697665546f4c703120746f6b656e4f757400000000602082015290565b505f906040516118a4604082610fc2565b601b81527f496e76616c6964206e6174697665546f4c703120746f6b656e496e0000000000602082015290565b505f906040516118e2604082610fc2565b60168152754e6174697665546f4c70302066726f6d203d3d20746f60501b602082015290565b50505f9060405161191a604082610fc2565b601c81527f496e76616c6964206e6174697665546f4c703020746f6b656e4f757400000000602082015290565b50505f90604051611959604082610fc2565b601b81527f496e76616c6964206e6174697665546f4c703020746f6b656e496e0000000000602082015290565b505f90604051611997604082610fc2565b6013815272456d7074792072657761726420726f7574657360681b602082015290565b6040516119c681610fa7565b5f815260606020820152606060408201525f60608201525f6080820152606060a08201525060018060a01b03166040516322be3de160e01b8152602081600481855afa5f9181611c6c575b50611a80575b50506040516020611a288183610fc2565b5f82525f368137604051611a3c8282610fc2565b5f81525f36813760405192611a5084610fa7565b5f84528284015260408301525f60608301525f6080830152611a756040519182610fc2565b5f815260a082015290565b604051630dfe168160e01b815291602083600481845afa5f9381611c4b575b50611aab575b50611a17565b60405163d21220a760e01b815292602084600481855afa5f9481611c2a575b50611ad55750611aa5565b604051630240bc6b60e21b8152606081600481865afa90811561093a576004935f915f93611c03575b50602090604051958680926318160ddd60e01b82525afa93841561093a575f94611bcf575b5060405195611b33606088610fc2565b60028752604093843660208a0137611b4a88611018565b6001600160a01b039091169052611b6087611039565b6001600160a01b03909116905260405192611b7c606085610fc2565b60028452366020850137611b8f83611018565b52611b9982611039565b5260405193611ba785610fa7565b6001855260208501526040840152606083015215156080820152604051611a75602082610fc2565b9093506020813d602011611bfb575b81611beb60209383610fc2565b810103126100ac5751925f611b23565b3d9150611bde565b611c219193506020925060603d606011610b9557610b848183610fc2565b50929091611afe565b611c4491955060203d602011610981576109738183610fc2565b935f611aca565b611c6591945060203d602011610981576109738183610fc2565b925f611a9f565b9091506020813d602011611ca1575b81611c8860209383610fc2565b810103126100ac575180151581036100ac57905f611a11565b3d9150611c7b565b60205f604051938285019063095ea7b360e01b825260018060a01b031695866024870152604486015260448552611ce1606486610fc2565b84519082855af15f513d82611d3c575b505015611cfd57505050565b611d35611d3a936040519063095ea7b360e01b602083015260248201525f604482015260448152611d2f606482610fc2565b82611d61565b611d61565b565b909150611d5957506001600160a01b0381163b15155b5f80611cf1565b600114611d52565b905f602091828151910182855af11561093a575f513d611db057506001600160a01b0381163b155b611d905750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b60011415611d8956fea26469706673582212204a264b211e73597135f60e2f195502df381376959bc0b90abda62ae3a7c7b91564736f6c634300081a0033

Deployed Bytecode

0x60806040526004361015610011575f80fd5b5f3560e01c80631f19e6af14610bb25780632958884314610a4a578063436b3d99146109a65780636966f521146107ae5780636ea4a2361461076157806373d896ac146106e1578063770b7bf6146106985780639f42c7e4146105ac578063aa5cc163146102f5578063c7abc3ff146100b05763ff7dcd5a14610092575f80fd5b346100ac575f3660031901126100ac5760206040515f8152f35b5f80fd5b346100ac5760203660031901126100ac576004356001600160401b0381116100ac576100e36100eb913690600401610ea1565b810190611580565b805151906100f882610fe3565b916101066040519384610fc2565b808352610115601f1991610fe3565b015f5b8181106102e45750505f5b81519081518110156101d1576001916001600160a01b0390610146908390611049565b5151166101b5838060a01b03602061015f858851611049565b51015116916101a76040610174868951611049565b510151604080516001600160a01b0394851660208201529590931692850192909252901515606084015282906080820190565b03601f198101835282610fc2565b6101bf8286611049565b526101ca8185611049565b5001610123565b505060208181015180518183015160409283015183516001600160a01b039384169581019590955291168383015215156060830152909161021f83608081015b03601f198101855284610fc2565b0151805160208083015160409384015184516001600160a01b039485169381019390935292169281019290925215156060820152916102618360808101610211565b60405191606083016060845282518091526080840190602060808260051b8701019401915f905b8282106102b95786806102b58a6102a78a8a8582036020870152610efe565b908382036040850152610efe565b0390f35b909192946020806102d6600193607f198b82030186528951610efe565b970192019201909291610288565b806060602080938701015201610118565b346100ac5760603660031901126100ac576004356001600160401b0381116100ac57610325903690600401610ece565b906024356001600160401b0381116100ac57610345903690600401610ea1565b92906044356001600160401b0381116100ac57610366903690600401610ea1565b90916040519561037587610f78565b606087526020870195610386610ffa565b87526040880195610395610ffa565b87526103a081610fe3565b6103ad6040519182610fc2565b818152601f196103bc83610fe3565b015f5b81811061059557505089525f5b81811061053657505050816103e89161041a9594930190610f4b565b90604051926103f684610f78565b6001600160a01b039081168452166020830152151560408201528552810190610f4b565b906040519261042884610f78565b60018060a01b0316835260018060a01b0316602083015215156040820152815260405191602080840152610120830193519360e060408501528451809152602061014085019501905f5b8181106104f057835180516001600160a01b039081166060890152602082015116608088015260400151151560a08701526102b5866104dc818a6101a78a5180516001600160a01b0390811660c086015260208201511660e0850152604001511515610100840152565b604051918291602083526020830190610efe565b909195602060608261052b6001948b516040809160018060a01b03815116845260018060a01b03602082015116602085015201511515910152565b019701929101610472565b8061058e8161055361054b6001958789611078565b810190610f4b565b906040519261056184610f78565b60a088901b8890039081168452166020830152151560408201528d51906105888383611049565b52611049565b50016103cc565b6020906105a0610ffa565b828286010152016103bf565b346100ac5760203660031901126100ac576105cd6105c8610e35565b6119ba565b6040516020815260e081019180511515602083015260208101519260c060408401528351809152602061010084019401905f5b81811061067957505050604081015192601f19838203016060840152602080855192838152019401905f5b8181106106635784806102b58860a0886060810151608086015260808101511515828601520151601f198483030160c0850152610efe565b825186526020958601959092019160010161062b565b82516001600160a01b0316865260209586019590920191600101610600565b346100ac5760203660031901126100ac576004356001600160401b0381116100ac576106cb6106d1913690600401610ea1565b90611655565b906102b560405192839283610f22565b346100ac5760603660031901126100ac576004356001600160401b0381116100ac57610711903690600401610ea1565b505061071b610e77565b5060405162461bcd60e51b815260206004820152601a60248201527f53696d756c6174696f6e206e6f7420696d706c656d656e7465640000000000006044820152606490fd5b346100ac5760803660031901126100ac5761077a610e35565b6024356001600160a01b03811681036100ac576020916107a69161079c610e77565b9060643592611310565b604051908152f35b346100ac5760c03660031901126100ac576107c7610e35565b6024356001600160401b0381116100ac576107e6903690600401610ea1565b91604435926107f3610e61565b6001600160a01b0383169390919084156109975785156109885761081991810190610f4b565b60405163260f701f60e11b81526001600160a01b0393841660048201819052929093166024840181905281151560448501529096909491929091906020816064818a5afa91821561093a576108809284925f91610959575b506001600160a01b0316611ca9565b61012c42019485421161094557604095610104945f938851998a98899763037b79b160e21b895260048901526024880152151560448701526064860152606435608486015260843560a486015260018060a01b031660c485015260e48401525af1801561093a575f905f90610900575b6040809350519182526020820152f35b50506040813d604011610932575b8161091b60409383610fc2565b810103126100ac57806020604092519101516108f0565b3d915061090e565b6040513d5f823e3d90fd5b634e487b7160e01b5f52601160045260245ffd5b61097b915060203d602011610981575b6109738183610fc2565b8101906112f1565b8a610871565b503d610969565b63628d981160e11b5f5260045ffd5b634c83788f60e11b5f5260045ffd5b346100ac5760c03660031901126100ac576004356001600160401b0381116100ac576109d6903690600401610ece565b906024356001600160401b0381116100ac576109f6903690600401610ea1565b6044939193356001600160401b0381116100ac57610a18903690600401610ea1565b606435929091906001600160a01b03841684036100ac576106d196610a3b610e4b565b95610a44610e61565b976110b9565b346100ac5760e03660031901126100ac57610a63610e35565b6024356001600160401b0381116100ac57610a82903690600401610ea1565b9160c4356001600160a01b0381169260643591604435908590036100ac576001600160a01b03841680156109975781158015610baa575b610b9c57610ace83610af29886950190610f4b565b986001600160a01b0391821697919092169490610aec858288611ca9565b87611ca9565b61012c420180421161094557606096610124955f946040519a8b998a98635a47ddc360e01b8a5260048a01526024890152151560448801526064870152608486015260843560a486015260a43560c486015260e48501526101048401525af1801561093a576020915f91610b6a575b50604051908152f35b610b8c915060603d606011610b95575b610b848183610fc2565b81019061105d565b91505082610b61565b503d610b7a565b62b784c960e41b5f5260045ffd5b508315610ab9565b346100ac5760a03660031901126100ac57610bcb610e35565b6024356001600160401b0381116100ac57610bea903690600401610ea1565b909160443592610bf8610e4b565b6001600160a01b03831692831561099757851561098857610c2083610c389688950190610f4b565b9690946001600160a01b039092169290919083611ca9565b604094855193610c488786610fc2565b60018552601f1987015f5b818110610e1e575050865192610c6884610f78565b83526001600160a01b03166020830152151585820152610c8783611018565b52610c9182611018565b5061012c420190814211610945579491908451958693631e82ecdb60e31b855260a48501906004860152606435602486015260a060448601528351809152602060c486019401905f5b818110610dd0575050506001600160a01b0316606484015260848301525f929082900390829084905af1918215610dc6575f92610d35575b5081515f1981019290831161094557602092610d2d91611049565b519051908152f35b9091503d805f833e610d478183610fc2565b8101906020818303126100ac578051906001600160401b0382116100ac57019080601f830112156100ac578151610d7d81610fe3565b92610d8a85519485610fc2565b81845260208085019260051b8201019283116100ac57602001905b828210610db6575050509082610d12565b8151815260209182019101610da5565b50513d5f823e3d90fd5b9195509192936020606082610e0e6001948a516040809160018060a01b03815116845260018060a01b03602082015116602085015201511515910152565b0196019101918895949392610cda565b602090610e29610ffa565b82828a01015201610c53565b600435906001600160a01b03821682036100ac57565b608435906001600160a01b03821682036100ac57565b60a435906001600160a01b03821682036100ac57565b604435906001600160a01b03821682036100ac57565b35906001600160a01b03821682036100ac57565b9181601f840112156100ac578235916001600160401b0383116100ac57602083818601950101116100ac57565b9181601f840112156100ac578235916001600160401b0383116100ac576020808501948460051b0101116100ac57565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b604090610f3b9392151581528160208201520190610efe565b90565b359081151582036100ac57565b908160609103126100ac57610f5f81610e8d565b91610f3b6040610f7160208501610e8d565b9301610f3e565b606081019081106001600160401b03821117610f9357604052565b634e487b7160e01b5f52604160045260245ffd5b60c081019081106001600160401b03821117610f9357604052565b90601f801991011681019081106001600160401b03821117610f9357604052565b6001600160401b038111610f935760051b60200190565b6040519061100782610f78565b5f6040838281528260208201520152565b8051156110255760200190565b634e487b7160e01b5f52603260045260245ffd5b8051600110156110255760400190565b80518210156110255760209160051b010190565b908160609103126100ac578051916040602083015192015190565b91908110156110255760051b81013590601e19813603018212156100ac5701908135916001600160401b0383116100ac5760200182360381136100ac579190565b909796939495979291925f5b81811061126f57505050906110dc91810190610f4b565b506001600160a01b03968716969092911686900361121b576001600160a01b039081169116036111da5761111291810190610f4b565b50926001600160a01b039091160361118a576001600160a01b0390811691160361114d57600190604051611147602082610fc2565b5f815290565b5f9060405161115d604082610fc2565b602081527f4e6174697665546f4c7031206d75737420656e64206174206c70546f6b656e31602082015290565b50505f9060405161119c606082610fc2565b602881527f4e6174697665546f4c7031206d7573742073746172742061742077726170706560208201526764206e617469766560c01b604082015290565b505050505f906040516111ee604082610fc2565b602081527f4e6174697665546f4c7030206d75737420656e64206174206c70546f6b656e30602082015290565b5050505050505f90604051611231606082610fc2565b602881527f4e6174697665546f4c7030206d7573742073746172742061742077726170706560208201526764206e617469766560c01b604082015290565b61127d61054b828486611078565b506001600160a01b038c8116911603905061129a576001016110c5565b505050505050505050505f906040516112b4606082610fc2565b602781527f52657761726420726f757465206d75737420656e642061742077726170706564602082015266206e617469766560c81b604082015290565b908160209103126100ac57516001600160a01b03811681036100ac5790565b9092916001600160a01b039091169081158015611524575b61151c57821561151c5760405163260f701f60e11b81526001600160a01b03858116600483018190529216602482018190525f60448301529190602081606481875afa90811561093a575f916114fd575b506001600160a01b03168061147c575b50906064602092604051948593849263260f701f60e11b845260048401526024830152600160448301525afa90811561093a575f9161145d575b506001600160a01b031691826113db575b5050505f90565b6040516378a051ad60e11b815260048101929092526001600160a01b0316602482015290602090829060449082905afa5f9181611429575b50611420575b80806113d4565b80156114195790565b9091506020813d602011611455575b8161144560209383610fc2565b810103126100ac5751905f611413565b3d9150611438565b611476915060203d602011610981576109738183610fc2565b5f6113c3565b6040516378a051ad60e11b8152600481018690526001600160a01b038716602482015290602090829060449082905afa5f91816114c9575b50156113895780156113895794505050505090565b9091506020813d6020116114f5575b816114e560209383610fc2565b810103126100ac5751905f6114b4565b3d91506114d8565b611516915060203d602011610981576109738183610fc2565b5f611379565b505050505f90565b506001600160a01b0384811690821614611328565b91908260609103126100ac5760405161155181610f78565b604061157b81839561156281610e8d565b855261157060208201610e8d565b602086015201610f3e565b910152565b6020818303126100ac578035906001600160401b0382116100ac57019060e0828203126100ac57604051916115b483610f78565b80356001600160401b0381116100ac57810182601f820112156100ac578035906115dd82610fe3565b916115eb6040519384610fc2565b808352602060608185019202830101918583116100ac57602001905b82821061163b57505050611633929160809185526116288360208301611539565b602086015201611539565b604082015290565b602060609161164a8885611539565b815201910190611607565b61166191810190611580565b80515115611986575f5b81518051821015611785578161168091611049565b5180516001600160a01b031615611745576020810180519091906001600160a01b031615611704575190516001600160a01b039081169116146116c55760010161166b565b50505f906040516116d7604082610fc2565b601781527f52657761726420726f7574652066726f6d203d3d20746f000000000000000000602082015290565b505050505f90604051611718604082610fc2565b602081527f496e76616c696420746f6b656e4f757420696e2072657761726420726f757465602082015290565b5050505f90604051611758604082610fc2565b601f81527f496e76616c696420746f6b656e496e20696e2072657761726420726f75746500602082015290565b5050602081018051516001600160a01b031615611947578051602001516001600160a01b031615611908575180516020909101516001600160a01b039081169116146118d1576040018051516001600160a01b031615611893578051602001516001600160a01b031615611855575180516020909101516001600160a01b0390811691161461181f57600190604051611147602082610fc2565b5f9060405161182f604082610fc2565b60168152754e6174697665546f4c70312066726f6d203d3d20746f60501b602082015290565b505f90604051611866604082610fc2565b601c81527f496e76616c6964206e6174697665546f4c703120746f6b656e4f757400000000602082015290565b505f906040516118a4604082610fc2565b601b81527f496e76616c6964206e6174697665546f4c703120746f6b656e496e0000000000602082015290565b505f906040516118e2604082610fc2565b60168152754e6174697665546f4c70302066726f6d203d3d20746f60501b602082015290565b50505f9060405161191a604082610fc2565b601c81527f496e76616c6964206e6174697665546f4c703020746f6b656e4f757400000000602082015290565b50505f90604051611959604082610fc2565b601b81527f496e76616c6964206e6174697665546f4c703020746f6b656e496e0000000000602082015290565b505f90604051611997604082610fc2565b6013815272456d7074792072657761726420726f7574657360681b602082015290565b6040516119c681610fa7565b5f815260606020820152606060408201525f60608201525f6080820152606060a08201525060018060a01b03166040516322be3de160e01b8152602081600481855afa5f9181611c6c575b50611a80575b50506040516020611a288183610fc2565b5f82525f368137604051611a3c8282610fc2565b5f81525f36813760405192611a5084610fa7565b5f84528284015260408301525f60608301525f6080830152611a756040519182610fc2565b5f815260a082015290565b604051630dfe168160e01b815291602083600481845afa5f9381611c4b575b50611aab575b50611a17565b60405163d21220a760e01b815292602084600481855afa5f9481611c2a575b50611ad55750611aa5565b604051630240bc6b60e21b8152606081600481865afa90811561093a576004935f915f93611c03575b50602090604051958680926318160ddd60e01b82525afa93841561093a575f94611bcf575b5060405195611b33606088610fc2565b60028752604093843660208a0137611b4a88611018565b6001600160a01b039091169052611b6087611039565b6001600160a01b03909116905260405192611b7c606085610fc2565b60028452366020850137611b8f83611018565b52611b9982611039565b5260405193611ba785610fa7565b6001855260208501526040840152606083015215156080820152604051611a75602082610fc2565b9093506020813d602011611bfb575b81611beb60209383610fc2565b810103126100ac5751925f611b23565b3d9150611bde565b611c219193506020925060603d606011610b9557610b848183610fc2565b50929091611afe565b611c4491955060203d602011610981576109738183610fc2565b935f611aca565b611c6591945060203d602011610981576109738183610fc2565b925f611a9f565b9091506020813d602011611ca1575b81611c8860209383610fc2565b810103126100ac575180151581036100ac57905f611a11565b3d9150611c7b565b60205f604051938285019063095ea7b360e01b825260018060a01b031695866024870152604486015260448552611ce1606486610fc2565b84519082855af15f513d82611d3c575b505015611cfd57505050565b611d35611d3a936040519063095ea7b360e01b602083015260248201525f604482015260448152611d2f606482610fc2565b82611d61565b611d61565b565b909150611d5957506001600160a01b0381163b15155b5f80611cf1565b600114611d52565b905f602091828151910182855af11561093a575f513d611db057506001600160a01b0381163b155b611d905750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b60011415611d8956fea26469706673582212204a264b211e73597135f60e2f195502df381376959bc0b90abda62ae3a7c7b91564736f6c634300081a0033

Deployed Bytecode Sourcemap

1097:16836:9:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7069:36;1097:16836;7069:36;;;1097:16836;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1097:16836:9;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1097:16836:9;;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;4373:41;1097:16836;;;;;;:::i;:::-;4373:41;;;;:::i;:::-;4492:17;;1097:16836;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;4532:13;;1097:16836;4577:3;4551:17;;1097:16836;;;4547:28;;;;;1097:16836;;-1:-1:-1;;;;;1097:16836:9;4642:20;;1097:16836;;4642:20;:::i;:::-;;1097:16836;;4614:153;1097:16836;;;;;;4685:20;:17;;;:20;:::i;:::-;;:23;1097:16836;;4726:17;4614:153;1097:16836;4726:20;:17;;;:20;:::i;:::-;;:27;1097:16836;;;;-1:-1:-1;;;;;1097:16836:9;;;;4614:153;;1097:16836;;;;;;;;;;;;;;;;;;;;;;;;;;4614:153;;1097:16836;;4614:153;;;;;;:::i;:::-;4596:171;;;;:::i;:::-;;;;;;:::i;:::-;;1097:16836;4532:13;;4547:28;-1:-1:-1;;1097:16836:9;4862:16;;;;1097:16836;;4897:19;;;1097:16836;;4930:23;;;1097:16836;;;-1:-1:-1;;;;;1097:16836:9;;;4838:125;;;1097:16836;;;;;;;;;;;;;;;;;;4838:125;1097:16836;;;;4838:125;;1097:16836;;4838:125;;;;;;:::i;:::-;5020:16;;1097:16836;;;5055:19;;;1097:16836;;5088:23;;;1097:16836;;;-1:-1:-1;;;;;1097:16836:9;;;4996:125;;;1097:16836;;;;;;;;;;;;;;;;;;;;4996:125;1097:16836;;;;4996:125;1097:16836;4996:125;1097:16836;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1097:16836:9;;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;:::i;:::-;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;-1:-1:-1;;1097:16836:9;;;:::i;:::-;;;;;;;;;5698:66;;;;1097:16836;5794:30;;;;;;6184:90;;;;;;6450;6184;;;;;;:::i;:::-;1097:16836;;;;;;;:::i;:::-;-1:-1:-1;;;;;1097:16836:9;;;;;;;6303:53;;1097:16836;;;;6303:53;;1097:16836;6284:72;;6450:90;;;;:::i;:::-;1097:16836;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;6569:53;;1097:16836;;;;6569:53;;1097:16836;6550:72;;1097:16836;;6700:16;1097:16836;6700:16;;;1097:16836;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;;;;;;;;;;;;;;;;;6700:16;1097:16836;;;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;;;;;;;;;;;;;;;;6700:16;1097:16836;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5826:3;5915:22;6007:73;5915:22;5887:106;5915:22;1097:16836;5915:22;;;;:::i;:::-;5887:106;;;;:::i;:::-;1097:16836;;;;;;;:::i;:::-;;;;;;;;;;;;;;;6030:50;;1097:16836;;;;6030:50;;1097:16836;6007:17;;;:73;;:17;:73;:::i;:::-;;;:::i;:::-;;1097:16836;5779:13;;1097:16836;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;;1097:16836:9;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1097:16836:9;;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;1097:16836:9;;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;-1:-1:-1;1097:16836:9;;-1:-1:-1;;;7069:36:9;;1097:16836;;7069:36;;1097:16836;;;;;;;;;;;7069:36;;;1097:16836;;;;;;-1:-1:-1;;1097:16836:9;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;;:::i;:::-;;;;;;:::i;:::-;;;;;;;;;;;;;-1:-1:-1;;1097:16836:9;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;-1:-1:-1;;;;;1097:16836:9;;;;;;11510:20;;11506:55;;11575:13;;11571:45;;11722:51;;;;;;:::i;:::-;1097:16836;;-1:-1:-1;;;11842:54:9;;-1:-1:-1;;;;;1097:16836:9;;;;11842:54;;1097:16836;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11842:54;;;;;;;;11991:8;11842:54;;;1097:16836;11842:54;;;1097:16836;-1:-1:-1;;;;;;1097:16836:9;11991:8;:::i;:::-;12291:3;12273:15;1097:16836;12273:15;;;1097:16836;;;;;12075:229;1097:16836;;;;;;;;;;;;;12075:229;;1097:16836;12075:229;;1097:16836;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12075:229;;;;;;1097:16836;;;12075:229;;;1097:16836;;;;;;;;;;;;;;12075:229;;;1097:16836;12075:229;;1097:16836;12075:229;;;;;;1097:16836;12075:229;;;:::i;:::-;;;1097:16836;;;;;;;;;;;;12075:229;;;;;-1:-1:-1;12075:229:9;;;1097:16836;;;;;;;;;;;;;;;;;;;;;11842:54;;;;1097:16836;11842:54;1097:16836;11842:54;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;11571:45;8072:19;;;1097:16836;11597:19;1097:16836;;11597:19;11506:55;8014:22;;;1097:16836;11539:22;1097:16836;;11539:22;1097:16836;;;;;;-1:-1:-1;;1097:16836:9;;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;:::i;:::-;;;;:::i;:::-;;;:::i;:::-;;;;;;-1:-1:-1;;1097:16836:9;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;;;;-1:-1:-1;;;;;1097:16836:9;;9829:20;;9825:55;;9894:12;;:28;;;;1097:16836;9890:61;;10057:51;;10253:7;10057:51;;;;;;:::i;:::-;1097:16836;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;10199:7;;;1097:16836;10199:7;:::i;:::-;10253;;:::i;:::-;10570:3;10552:15;1097:16836;10552:15;;1097:16836;;;;;10337:246;1097:16836;;;;;;;;;;;;;10337:246;;1097:16836;10337:246;;1097:16836;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10337:246;;;;;;1097:16836;;;10337:246;;;1097:16836;;;;;;;;10337:246;;;;1097:16836;10337:246;1097:16836;10337:246;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;;;9890:61;9931:20;;;1097:16836;9931:20;1097:16836;;9931:20;9894:28;9910:12;;;9894:28;;1097:16836;;;;;;-1:-1:-1;;1097:16836:9;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;-1:-1:-1;;;;;1097:16836:9;;;7985:20;;7981:55;;8050:13;;8046:45;;8185:43;;8325:8;8185:43;;;;;;:::i;:::-;1097:16836;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;8325:8;:::i;:::-;1097:16836;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;1097:16836:9;;;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1097:16836:9;;8493:113;;1097:16836;;;8493:113;;;1097:16836;8481:125;;;:::i;:::-;;;;;:::i;:::-;;8839:3;8821:15;1097:16836;8821:15;;;1097:16836;;;;;;;;;;;;;;8676:176;;1097:16836;;;8676:176;1097:16836;8676:176;;1097:16836;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;1097:16836:9;;;;;;;;;;;8676:176;;;;;1097:16836;;;;8676:176;;;;;;;1097:16836;8676:176;;;1097:16836;-1:-1:-1;1097:16836:9;;-1:-1:-1;;1097:16836:9;;;;;;;;;8878:27;;;;:::i;:::-;1097:16836;;;;;;;8676:176;;;;;;1097:16836;8676:176;;;;;;:::i;:::-;;;1097:16836;;;;;;;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;8676:176;;;;;;;1097:16836;;;;;;;;;;;;;8676:176;1097:16836;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;:::o;:::-;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;:::o;:::-;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;:::o;:::-;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;:::o;:::-;;;-1:-1:-1;;;;;1097:16836:9;;;;;;:::o;:::-;;;;;;;;;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;1097:16836:9;;;;;;;;-1:-1:-1;;1097:16836:9;;;;:::o;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;:::o;:::-;;;;-1:-1:-1;1097:16836:9;;;;;-1:-1:-1;1097:16836:9;;;;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;:::o;:::-;;;;;;;;;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;:::o;:::-;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;:::o;:::-;;;;;;;:::i;:::-;-1:-1:-1;1097:16836:9;;;;;;;;;;;;:::o;:::-;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;14877:1;1097:16836;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;;;;;:::o;16544:1387::-;;;;;;;;;;;1097:16836;16912:24;;;;;;17253:50;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;;1097:16836:9;;;;;;;;17317:20;;;17313:109;;-1:-1:-1;;;;;1097:16836:9;;;;;17435:15;17431:96;;17615:50;;;;;;:::i;:::-;-1:-1:-1;1097:16836:9;-1:-1:-1;;;;;1097:16836:9;;;17679:20;17675:109;;-1:-1:-1;;;;;1097:16836:9;;;;;17797:15;17793:96;;1097:16836;;;;;;;;:::i;:::-;-1:-1:-1;1097:16836:9;;16544:1387;:::o;17793:96::-;1097:16836;;;;;;;;:::i;:::-;;;;;;;;;17828:50;:::o;17675:109::-;17715:58;;1097:16836;;;;;;;;:::i;:::-;;;;;;;;;-1:-1:-1;;;1097:16836:9;;;;17715:58;:::o;17431:96::-;17466:50;;;;1097:16836;;;;;;;;:::i;:::-;;;;;;;;;17466:50;:::o;17313:109::-;17353:58;;;;;;1097:16836;;;;;;;;:::i;:::-;;;;;;;;;-1:-1:-1;;;1097:16836:9;;;;17353:58;:::o;16938:3::-;16974:54;16985:16;;;;;:::i;16974:54::-;-1:-1:-1;;;;;;1097:16836:9;;;;;17046:17;;-1:-1:-1;17042:113:9;;1097:16836;;16897:13;;17042:113;17083:57;;;;;;;;;;1097:16836;;;;;;;;:::i;:::-;;;;;;;;;-1:-1:-1;;;1097:16836:9;;;;17083:57;:::o;1097:16836::-;;;;;;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;:::o;12783:1013::-;;;;-1:-1:-1;;;;;1097:16836:9;;;;12973:20;;:43;;;;12783:1013;12969:57;;13040:13;;13036:27;;1097:16836;;-1:-1:-1;;;13140:56:9;;-1:-1:-1;;;;;1097:16836:9;;;13140:56;;;1097:16836;;;;;;;;;;;-1:-1:-1;1097:16836:9;;;;;;;;13140:56;1097:16836;13140:56;;;;;;;;1097:16836;13140:56;;;12783:1013;-1:-1:-1;;;;;;1097:16836:9;;13206:215;;12783:1013;1097:16836;;13140:56;1097:16836;;;;;;;;;;;;13487:55;;13140:56;13487:55;;1097:16836;;;;;;;;;;13487:55;;;;;;;1097:16836;13487:55;;;12783:1013;-1:-1:-1;;;;;;1097:16836:9;;;13552:211;;12783:1013;13781:8;;;1097:16836;12783:1013;:::o;13552:211::-;1097:16836;;-1:-1:-1;;;13600:56:9;;13140;13600;;1097:16836;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;;;;13600:56;;1097:16836;;13600:56;;;13552:211;13596:157;;;13552:211;;;;;13596:157;13704:10;13700:29;13596:157;13700:29;13716:13;:::o;13600:56::-;;;;1097:16836;13600:56;;1097:16836;13600:56;;;;;;1097:16836;13600:56;;;:::i;:::-;;;1097:16836;;;;;13600:56;;;;;;;-1:-1:-1;13600:56:9;;13487:55;;;;1097:16836;13487:55;1097:16836;13487:55;;;;;;;:::i;:::-;;;;13206:215;1097:16836;;-1:-1:-1;;;13256:58:9;;13140:56;13256:58;;1097:16836;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;;;;;13256:58;;1097:16836;;13256:58;;;13206:215;13252:159;;13206:215;13252:159;13362:10;13358:29;13206:215;13358:29;13374:13;;;;;;;:::o;13256:58::-;;;;1097:16836;13256:58;;1097:16836;13256:58;;;;;;1097:16836;13256:58;;;:::i;:::-;;;1097:16836;;;;;13256:58;;;;;;;-1:-1:-1;13256:58:9;;13140:56;;;;1097:16836;13140:56;1097:16836;13140:56;;;;;;;:::i;:::-;;;;13036:27;13055:8;;;;1097:16836;13055:8;:::o;12973:43::-;-1:-1:-1;;;;;;1097:16836:9;;;;;;12997:19;12973:43;;1097:16836;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;:::o;:::-;;;;;;;;:::i;:::-;;;;;;;;;2106:1846;2332:41;2106:1846;2332:41;;;;:::i;:::-;2436:17;;1097:16836;2436:29;2432:97;;1097:16836;2635:3;2609:17;;1097:16836;;2605:28;;;;;2682:20;;;;:::i;:::-;;1097:16836;;-1:-1:-1;;;;;1097:16836:9;2733:24;2729:112;;2858:8;;;1097:16836;;2858:8;;;-1:-1:-1;;;;;1097:16836:9;2858:22;2854:111;;1097:16836;;;-1:-1:-1;;;;;1097:16836:9;;;;;2982:22;2978:102;;1097:16836;;2590:13;;2978:102;3024:41;;1097:16836;;;;;;;;:::i;:::-;;;;;2858:8;1097:16836;;;3024:41;:::o;2854:111::-;2900:50;;;;1097:16836;;;;;;;;:::i;:::-;;;;;2858:8;1097:16836;;;2900:50;:::o;2729:112::-;2777:49;;;1097:16836;;;;;;;;:::i;:::-;;;;;2858:8;1097:16836;;;2777:49;:::o;2605:28::-;-1:-1:-1;;2858:8:9;3150:16;;;;1097:16836;-1:-1:-1;;;;;1097:16836:9;3150:35;3146:111;;3270:16;;2858:8;3270:19;1097:16836;-1:-1:-1;;;;;1097:16836:9;3270:33;3266:110;;3389:16;1097:16836;;2858:8;3414:19;;;1097:16836;-1:-1:-1;;;;;1097:16836:9;;;;;3389:44;3385:115;;3560:16;;;;1097:16836;-1:-1:-1;;;;;1097:16836:9;3560:35;3556:111;;3680:16;;2858:8;3680:19;1097:16836;-1:-1:-1;;;;;1097:16836:9;3680:33;3676:110;;3799:16;1097:16836;;2858:8;3824:19;;;1097:16836;-1:-1:-1;;;;;1097:16836:9;;;;;3799:44;3795:115;;1097:16836;;;;;;;;:::i;3795:115::-;1097:16836;;;;;;;;:::i;:::-;;;;-1:-1:-1;;;2858:8:9;1097:16836;;;3859:40;:::o;3676:110::-;3729:46;1097:16836;;;;;;;;:::i;:::-;;;;;2858:8;1097:16836;;;3729:46;:::o;3556:111::-;3611:45;1097:16836;;;;;;;;:::i;:::-;;;;;2858:8;1097:16836;;;3611:45;:::o;3385:115::-;3449:40;1097:16836;;;;;;;;:::i;:::-;;;;-1:-1:-1;;;2858:8:9;1097:16836;;;3449:40;:::o;3266:110::-;3319:46;;1097:16836;;;;;;;;:::i;:::-;;;;;2858:8;1097:16836;;;3319:46;:::o;3146:111::-;3201:45;;1097:16836;;;;;;;;:::i;:::-;;;;;2858:8;1097:16836;;;3201:45;:::o;2432:97::-;2481:37;1097:16836;;;;;;;;:::i;:::-;;;;-1:-1:-1;;;1097:16836:9;;;;2481:37;:::o;14073:1814::-;1097:16836;;;;;:::i;:::-;-1:-1:-1;1097:16836:9;;;;;;;;;;;;-1:-1:-1;1097:16836:9;;;;-1:-1:-1;1097:16836:9;;;;;;;;;;;;;;;;;;;;;14229:28;;1097:16836;14229:28;;;;;;-1:-1:-1;;14229:28:9;;;14073:1814;14225:1371;;;14073:1814;-1:-1:-1;;1097:16836:9;;;;;;;:::i;:::-;-1:-1:-1;1097:16836:9;;-1:-1:-1;1097:16836:9;;;;;;;;;:::i;:::-;-1:-1:-1;1097:16836:9;;-1:-1:-1;1097:16836:9;;;;;;;;;:::i;:::-;-1:-1:-1;1097:16836:9;;15671:209;;;1097:16836;;15671:209;;1097:16836;-1:-1:-1;1097:16836:9;15671:209;;1097:16836;-1:-1:-1;1097:16836:9;15671:209;;1097:16836;;;;;;;:::i;:::-;-1:-1:-1;1097:16836:9;;;15671:209;;1097:16836;14073:1814;:::o;14225:1371::-;1097:16836;;-1:-1:-1;;;14298:28:9;;1097:16836;;;14229:28;1097:16836;;14298:28;;-1:-1:-1;;14298:28:9;;;14225:1371;14294:1283;;;14225:1371;;;;14294:1283;1097:16836;;-1:-1:-1;;;14374:28:9;;1097:16836;;;14229:28;1097:16836;14374:28;;;-1:-1:-1;;14374:28:9;;;14294:1283;14370:1184;;;14294:1283;;;14370:1184;1097:16836;;-1:-1:-1;;;14549:33:9;;1097:16836;;14229:28;1097:16836;14549:33;;;;;;;;14229:28;14549:33;-1:-1:-1;;;14549:33:9;;;14370:1184;1097:16836;;;;;;;;;;;;14626:33;;;;;;;;;-1:-1:-1;14626:33:9;;;14370:1184;1097:16836;;;;;;;;:::i;:::-;14806:1;1097:16836;;;;;;;;;;14830:18;;;:::i;:::-;-1:-1:-1;;;;;1097:16836:9;;;;;14870:18;;;:::i;:::-;-1:-1:-1;;;;;1097:16836:9;;;;;;;;;;;;:::i;:::-;14806:1;1097:16836;;;;;;;15040:22;;;:::i;:::-;1097:16836;15084:22;;;:::i;:::-;1097:16836;;;;;;;:::i;:::-;14877:1;1097:16836;;;15200:326;;1097:16836;;15200:326;;1097:16836;;15200:326;;1097:16836;;;;15200:326;;1097:16836;;;;;;;:::i;14626:33::-;;;;1097:16836;14626:33;;1097:16836;14626:33;;;;;;1097:16836;14626:33;;;:::i;:::-;;;1097:16836;;;;;14626:33;;;;;;;-1:-1:-1;14626:33:9;;14549;;;;;1097:16836;14549:33;;1097:16836;14549:33;1097:16836;14549:33;;;;;;;:::i;:::-;-1:-1:-1;14549:33:9;;;;;14374:28;;;;;1097:16836;14374:28;1097:16836;14374:28;;;;;;;:::i;:::-;;;;;14298;;;;;1097:16836;14298:28;1097:16836;14298:28;;;;;;;:::i;:::-;;;;;14229;;;;1097:16836;14229:28;;1097:16836;14229:28;;;;;;1097:16836;14229:28;;;:::i;:::-;;;1097:16836;;;;;;;;;;;;14229:28;;;;;;;-1:-1:-1;14229:28:9;;5084:380:4;5199:47;-1:-1:-1;1097:16836:9;;5199:47:4;;;;1097:16836:9;;;;5199:47:4;;1097:16836:9;;;;;;5199:47:4;;;;;1097:16836:9;;;;;;5199:47:4;;;;;;:::i;:::-;9770:199;;;;;;;-1:-1:-1;9770:199:4;;9985:80;;;5084:380;5261:45;;;5257:201;;5084:380;;;:::o;5257:201::-;5349:43;5434:12;1097:16836:9;;;;;;;5199:47:4;5349:43;;;5199:47;5349:43;;1097:16836:9;-1:-1:-1;1097:16836:9;;;;;5349:43:4;;;5199:47;5349:43;;:::i;:::-;;;:::i;:::-;5434:12;:::i;:::-;5084:380::o;9985:80::-;9997:67;;-1:-1:-1;9997:15:4;;-1:-1:-1;;;;;;1097:16836:9;;10015:26:4;:30;;9997:67;9985:80;;;;9997:67;10063:1;10048:16;9997:67;;8370:720;;-1:-1:-1;8507:421:4;8370:720;8507:421;;;;;;;;;;;;-1:-1:-1;8507:421:4;;8942:15;;-1:-1:-1;;;;;;1097:16836:9;;8960:26:4;:31;8942:68;8938:146;;8370:720;:::o;8938:146::-;-1:-1:-1;;;;9033:40:4;;;-1:-1:-1;;;;;1097:16836:9;;;;9033:40:4;1097:16836:9;;;9033:40:4;8942:68;9009:1;8994:16;;8942:68;

Swarm Source

ipfs://4a264b211e73597135f60e2f195502df381376959bc0b90abda62ae3a7c7b915

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

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

Validator Index Block Amount
View All Withdrawals

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

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