Source Code
Overview
S Balance
S Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
ShadowStrategyImplementation
Compiler Version
v0.8.26+commit.8a97fa7a
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "../../01_abstracts/AbstractLiquidityPairStrategy.sol";
import "../../../interfaces/protocols/Shadow/IShadowGauge.sol";
import "../../../interfaces/protocols/Shadow/IShadowVoter.sol";
import "../../../interfaces/protocols/Shadow/IXShadow.sol";
import "../../../interfaces/protocols/Shadow/IShadowRouter.sol";
import "../../../interfaces/protocols/Shadow/IShadowInterfaces.sol";
import "../../../interfaces/routing/IRoutableStrategy.sol";
import "../../../interfaces/routing/IRouterLibrary.sol";
import "../../../interfaces/libraries/ISolidlyLibrary.sol";
// ShadowStrategyFactory no longer needed - using UniversalFactoryFacet
// ============ SHADOW-SPECIFIC ERRORS ============
error InvalidRoute();
error LibraryNotRegistered();
error RouterNotSet();
error OnlyController();
/**
* @title ShadowStrategyImplementation
* @author Petals Protocol
* @notice LP strategy implementation for gauge-based reward farming protocols
*
* @dev Master implementation for LP strategies deployed via minimal proxy pattern.
* Extends AbstractLiquidityPairStrategy with protocol-specific gauge interactions and reward processing.
*
* **Protocol Integration:**
* - **Gauge Staking**: Stakes LP tokens in protocol gauges to earn rewards
* - **Multi-Token Rewards**: Processes native tokens and protocol-specific reward tokens
* - **Dual Router Support**: Uses separate routers for swaps and liquidity operations
* - **Flexible Routing**: Supports various DEX routing formats via generic interface
*
* **Implementation Details:**
* - Clone pattern with factory deployment for gas efficiency (~45k vs ~2.5M gas)
* - Initializable pattern supporting custom configuration per pool
* - Just-in-time approvals for enhanced security (no infinite approvals)
* - Generic router interface adaptable to different protocols
*
* @notice Deployed as master implementation - actual strategies are minimal proxy clones
* created by factory with pool-specific configurations.
*
* Architecture: Library-Centric Design
* - NO inheritance from router-specific abstracts (no AbstractSolidlyStrategy)
* - ALL swap and liquidity logic delegated to external SolidlyLibrary
* - Smaller contract size (~16-18KB vs 21-22KB)
* - Hot-swappable library for bug fixes without redeployment
*/
contract ShadowStrategyImplementation is AbstractLiquidityPairStrategy, IRoutableStrategy, Initializable {
using SafeERC20 for IERC20;
// ============ Library-Centric State ============
/// @notice Shadow uses Solidly-fork router type
RouterType public constant ROUTER_TYPE = RouterType.SOLIDLY;
/// @notice Whether this pair uses stable or volatile pool
bool public stable;
// ============ State Variables ============
/// @notice The Shadow Finance gauge contract for LP token staking
/// @dev This is where LP tokens are deposited to earn rewards
address public gauge;
/// @notice The SHADOW token address for the Shadow Finance protocol
/// @dev Used for reward processing and route configuration
address public shadowToken;
/// @notice The xSHADOW token address (Shadow's escrowed token)
/// @dev Special handling required for xShadow token unwrapping
address public xShadowToken;
// ============ OPTIMIZED EVENTS ============
// CONSOLIDATED: Single event for all strategy configuration changes
event StrategyConfigured(
uint8 indexed configType, // 0=Init, 1=ShadowAddresses, 2=Recovery
address indexed asset,
address indexed gauge,
address[] rewardTokens,
uint256 timestamp
);
// ============ CONSTRUCTOR (Implementation Only) ============
/// @notice Constructor for implementation - prevents initialization
/// @dev This constructor is only called when deploying the implementation
constructor() {
// Disable initializers to prevent implementation from being initialized
_disableInitializers();
}
// ============ EXTERNAL FUNCTIONS ============
/**
* @notice Initialize the strategy clone with pool-specific parameters
* @dev Called once by factory when creating a new strategy clone
* @param initData Encoded initialization parameters
*/
function initialize(bytes calldata initData) external initializer {
// UniversalFactory sends: abi.encode(strategyType, innerData)
// We need to decode the nested structure
(bytes32 _strategyType, bytes memory innerData) = abi.decode(initData, (bytes32, bytes));
(
address _gauge,
string memory _strategyName,
address[] memory _routers,
bytes[] memory _rewardRoutes,
bytes memory _nativeToLp0Route,
bytes memory _nativeToLp1Route,
address _feeRecipient,
address _vaultController,
// _wrappedNativeToken unused: fetched dynamically via getWrappedNativeToken()
) = abi.decode(
innerData, (address, string, address[], bytes[], bytes, bytes, address, address, address)
);
// Auto-derive ALL addresses from gauge only!
address _asset = IShadowGauge(_gauge).stake(); // Get LP token from gauge
address _xShadowToken = IShadowGauge(_gauge).xShadow(); // Get xSHADOW from gauge
address _shadowToken = IXShadow(_xShadowToken).shadow(); // Get SHADOW from xSHADOW
// Initialize parent strategy with dual router array - Shadow uses separate swap/liquidity routers
_initializeStrategy(_asset, _routers, _stringToBytes32(_strategyName), _feeRecipient, _strategyType);
// Set core addresses (all auto-derived from gauge!)
gauge = _gauge;
shadowToken = _shadowToken;
xShadowToken = _xShadowToken;
// Get LP token components
lpToken0 = ILP(_asset).token0();
lpToken1 = ILP(_asset).token1();
// CRITICAL FIX: Set cached controller before routing configuration
_setCachedController(_vaultController);
// Initialize routing configuration with route data directly (no encoding needed)
_initializeRoutingConfiguration(_rewardRoutes, _nativeToLp0Route, _nativeToLp1Route);
// Setup all required approvals
_setupApprovals();
// Emit initialization event for monitoring (use extracted reward tokens)
emit StrategyConfigured(
0, // Initialization event
_asset,
_gauge,
rewardTokens, // Use the array populated by _initializeRoutingConfiguration
block.timestamp
);
}
/// @notice Update Shadow protocol addresses (STRATEGIST_ROLE only)
/// @dev Allows updating Shadow/xShadow addresses if protocol migrates
/// @param _shadowToken New SHADOW token address
/// @param _xShadowToken New xSHADOW token address
function setShadowAddresses(address _shadowToken, address _xShadowToken) external onlyRole(STRATEGIST_ROLE) {
if (_shadowToken == address(0) || _xShadowToken == address(0)) revert ZeroAddress();
shadowToken = _shadowToken;
xShadowToken = _xShadowToken;
emit StrategyConfigured(1, asset, gauge, rewardTokens, block.timestamp);
}
/// @notice Get reward configuration
function getRewardConfiguration() external view returns (address[] memory, bytes[] memory) { return (rewardTokens, rewardTokenRoutes); }
/**
* @notice Public route decoder for Solidly-style routes
* @dev No longer inherited - implemented directly for library-centric design
*/
function decodeRoute(bytes memory routeBytes) public pure returns (address tokenIn, address tokenOut, bool isStable) {
return abi.decode(routeBytes, (address, address, bool));
}
/**
* @notice Extract reward tokens from routes
* @dev No longer inherited - implemented directly for library-centric design
*/
function _extractRewardTokens(bytes[] memory _rewardRoutes) internal pure override returns (address[] memory tokens) {
tokens = new address[](_rewardRoutes.length);
for (uint256 i = 0; i < _rewardRoutes.length; i++) {
(address tokenIn,,) = abi.decode(_rewardRoutes[i], (address, address, bool));
tokens[i] = tokenIn;
}
return tokens;
}
/// @notice Get Shadow addresses
function getShadowAddresses() external view returns (address, address) { return (shadowToken, xShadowToken); }
// ============ PROTOCOL CONFIGURATION ============
// Moved harvest workflow functions to REQUIRED OVERRIDES section
/**
* @notice Library-centric swap - delegates to SolidlyLibrary via delegatecall
* @dev OPTIMIZED: Uses delegatecall to execute library in strategy's context (~2.6K gas savings)
* Library handles: decoding, approvals (in our context), route conversion, execution
* Routes must be correct - swap failures will revert the entire harvest
*/
function _swap(uint256 amountIn, bytes memory routeBytes) internal returns (uint256 amountOut) {
if (amountIn == 0 || routeBytes.length == 0) return amountIn;
// Get SolidlyLibrary from ProtocolLibraryManagerFacet
address routerLibraryAddr = getRouterLibrary(RouterType.SOLIDLY);
if (routerLibraryAddr == address(0)) revert LibraryNotRegistered();
address router = getRouter(0);
if (router == address(0)) revert RouterNotSet();
// Calculate minimum output with slippage protection
uint256 basis = _getControllerData(IPetalsControllerForStrategy.BASIS_POINTS.selector, 10_000);
uint256 minOut = slippageTolerance > 0
? (amountIn * (basis - slippageTolerance)) / basis
: 0;
// DELEGATECALL: Execute library code in our context (saves ~2.6K gas)
(bool success, bytes memory data) = routerLibraryAddr.delegatecall(
abi.encodeWithSelector(
IRouterLibrary.swap.selector,
router,
routeBytes,
amountIn,
minOut,
address(this)
)
);
require(success, "Library swap failed");
amountOut = abi.decode(data, (uint256));
}
// Moved _protocolEmergencyWithdraw to REQUIRED OVERRIDES section
/// @notice Setup minimal initial approvals for security and efficiency
/// @dev Protocol-specific - Shadow requires gauge and router approvals
function _setupApprovals() internal {
// Core gauge approval (minimal amount)
IERC20(asset).forceApprove(gauge, 1);
// Router approvals for LP tokens and native token (minimal amounts)
address swapRouter = getRouter(0);
if (swapRouter != address(0)) {
IERC20(lpToken0).forceApprove(swapRouter, 1);
IERC20(lpToken1).forceApprove(swapRouter, 1);
address nativeToken = getWrappedNativeToken();
if (nativeToken != address(0)) {
IERC20(nativeToken).forceApprove(swapRouter, 1);
}
}
}
// ============ REQUIRED OVERRIDES - SHADOW PROTOCOL IMPLEMENTATIONS ============
// ** PROTOCOL INTEGRATION FUNCTIONS **
/// @notice Deposit LP tokens into gauge with just-in-time approval (regular deposits)
function _protocolDeposit(uint256 amount) internal override {
if (amount == 0) return;
_ensureApproval(asset, gauge, amount);
IShadowGauge(gauge).deposit(amount);
}
/// @notice Withdraw LP tokens from gauge
function _protocolWithdraw(uint256 amount) internal override {
if (amount > 0) IShadowGauge(gauge).withdraw(amount);
}
/// @notice Get balance of LP tokens staked in gauge (inlined for gas efficiency)
function _protocolBalanceOf() internal view override returns (uint256) {
return IShadowGauge(gauge).balanceOf(address(this));
}
/// @notice Emergency withdrawal from gauge
function _protocolEmergencyWithdraw() internal override {
uint256 stakedBalance = _protocolBalanceOf();
if (stakedBalance > 0) IShadowGauge(gauge).withdraw(stakedBalance);
}
// ** ROUTE CONFIGURATION FUNCTIONS **
// Route validation is now handled by AbstractSolidlyStrategy's validateRoutes()
// which implements IRoutableStrategy interface
// ** HARVEST WORKFLOW FUNCTIONS **
/// @notice Step 1: Claim rewards only for tokens we can process (route exists and user has accrual)
function _claimRewards() internal override returns (uint256 claimedRewards) {
// Build minimal token set: include xSHADOW (if set) and route-start rewardTokens
uint256 n = rewardTokens.length;
uint256 addX = xShadowToken != address(0) ? 1 : 0;
address[] memory claimTokens = new address[](n + addX);
uint256 idx = 0;
if (addX == 1) {
claimTokens[idx++] = xShadowToken;
}
for (uint256 i = 0; i < n; i++) {
claimTokens[idx++] = rewardTokens[i];
}
// Claim directly from gauge; xSHADOW is converted to SHADOW on exit
IShadowGauge(gauge).getRewardAndExit(address(this), claimTokens);
// We don't rely on this return value downstream; return 0 to keep gas minimal
return 0;
}
/// @notice Step 2: Swap all reward tokens to native token
/// @return nativeAmount Amount of native tokens received after swapping
function _swapRewardsToNative(uint256 /* claimedRewards */) internal override returns (uint256 nativeAmount) {
address nativeToken = getWrappedNativeToken();
uint256 startingBalance = IERC20(nativeToken).balanceOf(address(this));
// Process each reward token
for (uint256 i = 0; i < rewardTokens.length; i++) {
address rewardToken = rewardTokens[i];
// Skip native token (already processed)
if (rewardToken == nativeToken) continue;
uint256 balance = IERC20(rewardToken).balanceOf(address(this));
if (balance == 0) continue;
// Convert reward to native using configured Solidly route
_swap(balance, rewardTokenRoutes[i]);
}
// Calculate total native generated
uint256 endingBalance = IERC20(nativeToken).balanceOf(address(this));
return endingBalance > startingBalance ? endingBalance - startingBalance : 0;
}
/// @notice Step 3: Swap native rewards to LP token components
/// @param nativeAmount Amount of native tokens to swap
/// @return token0Amount Amount of token0 received
/// @return token1Amount Amount of token1 received
function _swapRewards(uint256 nativeAmount) internal override returns (uint256 token0Amount, uint256 token1Amount) {
if (nativeAmount == 0) return (0, 0);
address nativeToken = getWrappedNativeToken();
// Split native 50/50 for optimal LP provision
uint256 halfNative = nativeAmount >> 1; // Gas-optimized division by 2
uint256 remainingNative = nativeAmount - halfNative;
// Convert to token0 using configured route (empty route means WNATIVE identity)
if (lpToken0 != nativeToken) {
token0Amount = _swap(halfNative, nativeToLp0);
} else {
token0Amount = halfNative;
}
// Convert to token1 using configured route
if (lpToken1 != nativeToken) {
token1Amount = _swap(remainingNative, nativeToLp1);
} else {
token1Amount = remainingNative;
}
}
/**
* @notice Step 4: Add liquidity - delegates to SolidlyLibrary
* @dev Uses library for all liquidity logic (validation, approvals, execution)
* Type-safe external call through IRouterLibrary interface
* Includes LP amount slippage protection against MEV sandwich attacks
* @param token0Amount Amount of token0 to add
* @param token1Amount Amount of token1 to add
* @return lpReceived Amount of LP tokens received
*/
function _addLiquidityToPool(uint256 token0Amount, uint256 token1Amount) internal override returns (uint256 lpReceived) {
if (token0Amount == 0 || token1Amount == 0) return 0;
// Calculate minimum token amounts with slippage tolerance (prevents unused tokens)
uint256 basis = _getControllerData(IPetalsControllerForStrategy.BASIS_POINTS.selector, 10_000);
uint256 amountAMin = token0Amount * (basis - slippageTolerance) / basis;
uint256 amountBMin = token1Amount * (basis - slippageTolerance) / basis;
// Calculate minimum LP tokens expected (protects against pool manipulation)
// Conservative: Expect LP >= sum of input values (adjusted for slippage)
// This protects against MEV bots manipulating pool reserves before our tx
uint256 minLPExpected = ((token0Amount + token1Amount) * (basis - slippageTolerance)) / basis;
// Get SolidlyLibrary from ProtocolLibraryManagerFacet
address routerLibraryAddr = getRouterLibrary(RouterType.SOLIDLY);
if (routerLibraryAddr == address(0)) revert LibraryNotRegistered();
// Get Shadow router
address liquidityRouter = getRouter(0);
if (liquidityRouter == address(0)) revert RouterNotSet();
// Encode liquidity data: (token0, token1, stable)
bytes memory liquidityData = abi.encode(lpToken0, lpToken1, false); // Shadow uses volatile pairs
// DELEGATECALL: Execute library code in our context (saves ~2.6K gas)
(bool success, bytes memory data) = routerLibraryAddr.delegatecall(
abi.encodeWithSelector(
IRouterLibrary.addLiquidity.selector,
liquidityRouter,
liquidityData,
token0Amount,
token1Amount,
amountAMin,
amountBMin,
address(this)
)
);
require(success, "Library addLiquidity failed");
lpReceived = abi.decode(data, (uint256));
// Validate LP amount received (prevents MEV sandwich attacks on LP provision)
if (lpReceived < minLPExpected) revert InvalidRoute(); // Slippage exceeded on LP tokens
}
/// @notice Step 5: Deposit LP tokens into gauge (harvest deposits)
function _deposit(uint256 lpAmount) internal override {
if (lpAmount == 0) return;
_protocolDeposit(lpAmount);
}
/// @notice Get pending rewards for all tokens
function totalRewardsAvailable()
external
view
override
returns (address[] memory tokens, uint256[] memory amounts)
{
address[] memory list = IShadowGauge(gauge).rewardsList();
tokens = list;
amounts = new uint256[](list.length);
for (uint256 i = 0; i < list.length; i++) {
amounts[i] = IShadowGauge(gauge).earned(list[i], address(this));
}
return (tokens, amounts);
}
// ============ REQUIRED INTERFACE IMPLEMENTATIONS ============
// Note: balanceOf(), balanceOfWant(), want() now inherited from AbstractLiquidityPairStrategy
// ============ IROUTABLE STRATEGY INTERFACE ============
/**
* @notice Get the router type this strategy uses
* @return Router type (SOLIDLY for Shadow/Velodrome/Aerodrome/etc.)
*/
function getRouterType() external pure override returns (RouterType) {
return ROUTER_TYPE;
}
/**
* @notice Validate routes - delegates to SolidlyLibrary
* @dev Centralized validation logic in library reduces strategy contract size
* @param _rewardRoutes Array of encoded reward token routes
* @param _nativeToLp0 Encoded route from native to LP token0
* @param _nativeToLp1 Encoded route from native to LP token1
* @return valid Whether all routes are valid
* @return reason Error message if invalid
*/
function validateRoutes(
bytes[] calldata _rewardRoutes,
bytes calldata _nativeToLp0,
bytes calldata _nativeToLp1
) external view override returns (bool valid, string memory reason) {
// Get SolidlyLibrary from controller
address routerLibraryAddr = getRouterLibrary(RouterType.SOLIDLY);
if (routerLibraryAddr == address(0)) {
return (false, "Router library not registered");
}
// Delegate validation to library
return ISolidlyLibrary(routerLibraryAddr).validateRoutes(
_rewardRoutes,
_nativeToLp0,
_nativeToLp1,
getWrappedNativeToken(),
lpToken0,
lpToken1
);
}
/**
* @notice Apply new route configuration (called by ProtocolLibraryManagerFacet)
* @dev Uses default implementation from AbstractLiquidityPairStrategy
* Override if Shadow-specific logic needed
*/
function applyRouteUpdate(
bytes[] calldata _rewardRoutes,
bytes calldata _nativeToLp0,
bytes calldata _nativeToLp1
) external override {
if (msg.sender != getController()) revert OnlyController();
_applyRouteUpdate(_rewardRoutes, _nativeToLp0, _nativeToLp1);
emit StrategyConfigUpdated(1, abi.encode(_rewardRoutes.length, block.timestamp));
}
/**
* @notice Get current encoded routes from storage
* @dev Uses default implementation from AbstractLiquidityPairStrategy
* Override if Shadow-specific logic needed
*/
function getEncodedRoutes()
external
view
override
returns (
bytes[] memory _rewardRoutes,
bytes memory _nativeToLp0,
bytes memory _nativeToLp1
)
{
return (rewardTokenRoutes, nativeToLp0, nativeToLp1);
}
}// 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);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity >=0.6.2;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC-20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reinitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
*
* NOTE: Consider following the ERC-7201 formula to derive storage locations.
*/
function _initializableStorageSlot() internal pure virtual returns (bytes32) {
return INITIALIZABLE_STORAGE;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
bytes32 slot = _initializableStorageSlot();
assembly {
$.slot := slot
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/utils/Pausable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "../../interfaces/strategies/IPetalsStrategy.sol";
import "../../interfaces/internal/IPetalsVault.sol";
import "../../interfaces/internal/IPetalsController.sol";
import "../../interfaces/common/ICommonErrors.sol";
import "../../interfaces/common/ICommonEvents.sol";
import "../../interfaces/routing/RouterTypes.sol";
import "../../interfaces/libraries/IFeesLibrary.sol";
import "../../interfaces/IStrategySwapInterface.sol";
// ============ STANDARDIZED ERRORS ============
error InvalidInput(string reason);
error OperationFailed(string reason);
error Unauthorized();
error DelayNotMet(string delayType);
error ControllerNotSet();
error InsufficientLiquidity(uint256 requested, uint256 available);
/**
* @title AbstractLiquidityPairStrategy
* @author Petals Protocol
* @notice Optimized base contract for LP token autocompounding strategies
*
* @dev Provides the complete framework for yield farming with LP tokens across any DeFi protocol.
* This version uses strategy-specific validation for routing configuration.
*
* **Required Implementations (Virtual Functions):**
* - `_protocolDeposit()`: How to stake/deposit into the protocol (regular deposits)
* - `_protocolWithdraw()`: How to unstake/withdraw from the protocol
* - `_protocolBalanceOf()`: How to query staked balance
* - `_protocolEmergencyWithdraw()`: How to emergency withdraw all funds
*
* **Harvest Functions (Virtual - Override in Strategy):**
* - `_claimRewards()`: Step 1 - How to claim rewards from protocol
* - `_swapRewardsToNative()`: Step 2 - How to swap rewards to native token
* - `_swapRewards()`: How to swap native to LP token components
* - `_addLiquidityToPool()`: How to add liquidity to create LP tokens
* - `_deposit()`: Step 5 - How to deposit LP tokens back into protocol
*/
abstract contract AbstractLiquidityPairStrategy is
Pausable,
ReentrancyGuard,
IPetalsStrategy,
ICommonErrors,
ICommonEvents,
IStrategySwapInterface
{
using SafeERC20 for IERC20;
using Math for uint256;
// ============ Core Strategy State ============
/// @notice The vault that owns this strategy
address public vault;
/// @notice Cached controller address for gas optimization
address private _cachedController;
/// @notice The LP token that this strategy manages
address public asset;
/// @notice Array of DEX routers for different operations (swap, liquidity, etc.)
address[] public routers;
/// @notice The factory that deployed this strategy (for validation)
address public factory;
/// @notice The protocol type identifier (for classification)
bytes32 public protocolType;
/// @notice Timestamp of the last harvest operation
uint256 public lastHarvest;
/// @notice Slippage tolerance for DEX operations in basis points
uint256 public slippageTolerance;
/// @notice Whether the strategy is active and can perform operations
bool public vaultActive = true;
// ============ Cached Permission System ============
/// @notice Role definitions that must match the controller's roles
uint64 public constant MASTER_ROLE = 0; // DEFAULT_ADMIN_ROLE
uint64 public constant STRATEGIST_ROLE = 1;
uint64 public constant GUARDIAN_ROLE = 2;
/// @notice The fee recipient address that receives performance fees from this strategy
address public feeRecipient;
// ============ Failed Fee Accumulation ============
/// @notice Accumulated fees that failed to distribute (by token address)
/// @dev Treasury can claim these via claimPendingTreasuryFees
mapping(address => uint256) public pendingTreasuryFees;
// ============ Fee Library Access ============
/// @notice Get fees library address from controller
function getFeesLibrary() internal view returns (address) {
address ctrl = getController();
if (ctrl == address(0)) return address(0);
bytes memory callData = abi.encodeWithSignature("getFeesLibrary()");
(bool success, bytes memory result) = ctrl.staticcall(callData);
if (success && result.length >= 32) {
return abi.decode(result, (address));
}
return address(0);
}
// ============ Multi-Reward System ============
/// @notice Array of all reward tokens this strategy handles
address[] public rewardTokens;
/// @notice Quick lookup mapping for reward token validation
mapping(address => bool) public isRewardToken;
// ============ Routing Configuration ============
/// @notice The first token in the LP pair
address public lpToken0;
/// @notice The second token in the LP pair
address public lpToken1;
/// @notice Encoded routing data for converting each reward token to native
bytes[] public rewardTokenRoutes;
/// @notice Encoded route for converting native token to LP token0
bytes public nativeToLp0;
/// @notice Encoded route for converting native token to LP token1
bytes public nativeToLp1;
// ============ Strategy Metadata ============
/// @notice The strategy name stored as bytes32 for gas efficiency
bytes32 private _name;
// ============ Controller Data Access (Consolidated) ============
/// @notice Generic controller data accessor with fallback values
/// @param selector Function selector to call on controller
/// @param defaultValue Fallback value if controller unavailable or call fails
/// @return value Controller value or fallback
function _getControllerData(bytes4 selector, uint256 defaultValue) internal view returns (uint256) {
address ctrl = getController();
if (ctrl == address(0)) return defaultValue;
(bool success, bytes memory data) = ctrl.staticcall(abi.encodeWithSelector(selector));
return success && data.length >= 32 ? abi.decode(data, (uint256)) : defaultValue;
}
// ============ PROTOCOL LIBRARY DELEGATION (Library-Centric Architecture) ============
/**
* @notice Get router library address for a specific router type
* @dev Delegates to ProtocolLibraryManagerFacet for library registry lookup
* @param routerType Type of router (SOLIDLY, UNIV2, UNIV3, CURVE, etc.)
* @return libraryAddress Address of the router library contract
*/
function getRouterLibrary(RouterType routerType) internal view returns (address libraryAddress) {
address ctrl = getController();
if (ctrl == address(0)) return address(0);
// Call ProtocolLibraryManagerFacet.getRouterLibrary(routerType)
bytes memory callData = abi.encodeWithSignature("getRouterLibrary(uint8)", uint8(routerType));
(bool success, bytes memory result) = ctrl.staticcall(callData);
if (success && result.length >= 32) {
libraryAddress = abi.decode(result, (address));
}
}
// ============ SIMPLIFIED EVENTS ============
// Event imported from types.sol - no local declaration needed
// event StrategyConfigUpdated(uint8 indexed updateType, bytes data);
/**
* @notice Harvest completion event with comprehensive analytics data
* @param harvester Address that triggered the harvest
* @param yield Amount of yield generated
* @param totalAssets Total strategy assets after harvest (TVL)
* @param sharePrice Current share price (totalAssets / totalSupply)
* @param totalShares Total shares outstanding (for validation and metrics)
* @param timestamp Block timestamp for analytics convenience
*/
event HarvestCompleted(
address indexed harvester,
uint256 yield,
uint256 totalAssets,
uint256 sharePrice,
uint256 totalShares,
uint256 timestamp
);
// ============ SIMPLIFIED PERMISSION MANAGEMENT ============
/**
* @notice Simplified role check modifier - directly delegates to controller
* @dev No caching complexity, just direct delegation for simplicity
*/
modifier onlyRole(uint64 role) {
address controllerAddress = getController();
if (controllerAddress == address(0)) revert ControllerNotSet();
if (!IPetalsControllerForStrategy(controllerAddress).hasContractRole(address(this), role, msg.sender)) {
revert Unauthorized();
}
_;
}
/**
* @notice Internal role check function for conditional logic
* @param role Role to check
* @param account Account to check
* @return hasRole Whether account has role
*/
function _hasRole(uint64 role, address account) internal view returns (bool) {
address controllerAddress = getController();
if (controllerAddress == address(0)) return false;
try IPetalsControllerForStrategy(controllerAddress).hasContractRole(address(this), role, account) returns (bool roleExists) {
return roleExists;
} catch {
return false;
}
}
// ============ SIMPLIFIED ROUTER ACCESS ============
/**
* @notice Get router by index with fallback logic
* @param index Router index (0=primary, 1=secondary, etc.)
* @return router Router address or zero address if index out of bounds
*/
function getRouter(uint256 index) internal view returns (address router) {
return index < routers.length ? routers[index] : address(0);
}
// ============ REQUIRED OVERRIDES - MUST BE IMPLEMENTED BY STRATEGY ============
// ** PROTOCOL INTEGRATION FUNCTIONS **
/// @notice Deposit LP tokens into the protocol for yield farming
/// @param amount Amount of LP tokens to deposit
function _protocolDeposit(uint256 amount) internal virtual;
/// @notice Withdraw LP tokens from the protocol
/// @param amount Amount of LP tokens to withdraw
function _protocolWithdraw(uint256 amount) internal virtual;
/// @notice Get current balance of LP tokens staked in protocol
/// @return balance Current staked balance
function _protocolBalanceOf() internal view virtual returns (uint256 balance);
/// @notice Emergency withdraw all LP tokens from protocol
function _protocolEmergencyWithdraw() internal virtual;
// ** ROUTE CONFIGURATION FUNCTIONS **
/// @notice Extract reward tokens from route configuration
/// @dev Simple token extraction - no validation, just parsing
/// @param _rewardRoutes Array of encoded reward routes
/// @return rewardTokens Array of reward token addresses extracted from routes
function _extractRewardTokens(bytes[] memory _rewardRoutes) internal view virtual returns (address[] memory rewardTokens);
// ** HARVEST WORKFLOW FUNCTIONS **
/// @notice Step 1: Claim all rewards from protocol
/// @return claimedRewards Amount of rewards claimed for tracking
function _claimRewards() internal virtual returns (uint256 claimedRewards);
/// @notice Step 2: Swap all reward tokens to native token
/// @param claimedRewards Total rewards claimed (for validation)
/// @return nativeAmount Amount of native tokens received after swapping
function _swapRewardsToNative(uint256 claimedRewards) internal virtual returns (uint256 nativeAmount);
/// @notice Step 3: Swap native tokens to LP token components
/// @param nativeAmount Amount of native tokens to swap
/// @return token0Amount Amount of token0 received
/// @return token1Amount Amount of token1 received
function _swapRewards(uint256 nativeAmount) internal virtual returns (uint256 token0Amount, uint256 token1Amount);
/// @notice Step 4: Add liquidity to create LP tokens
/// @param token0Amount Amount of token0 to add
/// @param token1Amount Amount of token1 to add
/// @return lpReceived Amount of LP tokens received
function _addLiquidityToPool(uint256 token0Amount, uint256 token1Amount) internal virtual returns (uint256 lpReceived);
/// @notice Step 5: Deposit LP tokens back into protocol
/// @param lpAmount Amount of LP tokens to deposit
function _deposit(uint256 lpAmount) internal virtual;
// ** SWAP EXECUTION FUNCTIONS **
/// @notice Execute a swap with strategy-specific route data
/// @dev Must be implemented by each strategy to handle their specific DEX routing
/// Users provide only route data (paths, route structs), strategy builds complete calls
function executeSwap(bytes calldata /* params */) external virtual override returns (uint256 /* amountOut */) {
revert OperationFailed("Strategy must implement executeSwap");
}
// ** REWARDS QUERY FUNCTIONS **
/// @notice Get all pending rewards available for harvest
/// @return tokens Array of reward token addresses
/// @return amounts Array of pending reward amounts
function totalRewardsAvailable() external view virtual returns (address[] memory tokens, uint256[] memory amounts);
// ============ Constructor ============
constructor() {
// Constructor for clone pattern compatibility
}
// ============ Clone-Compatible Initialization ============
function _initializeStrategy(
address _asset,
address[] memory _routers,
bytes32 _strategyName,
address _feeRecipient,
bytes32 _protocolType
) internal {
if (asset != address(0)) revert AlreadyInitialized();
if (_asset == address(0)) revert InvalidAsset();
if (_routers.length == 0) revert InvalidRouter();
if (_feeRecipient == address(0)) revert InvalidInput("Fee recipient cannot be zero address");
// Validate all routers are non-zero
for (uint256 i = 0; i < _routers.length; i++) {
if (_routers[i] == address(0)) revert InvalidRouter();
}
asset = _asset;
routers = _routers;
_name = _strategyName;
slippageTolerance = 300;
feeRecipient = _feeRecipient;
vaultActive = true;
factory = msg.sender; // Factory is always the deployer
protocolType = _protocolType;
}
// ============ CONTROLLER INTEGRATION ============
function getController() public view returns (address) {
return _cachedController;
}
/**
* @notice Internal function to set cached controller during initialization
* @dev Used by strategy implementations to set controller before routing configuration
* @param controller Controller address to cache
*/
function _setCachedController(address controller) internal {
_cachedController = controller;
}
/**
* @notice Get wrapped native token from controller
* @dev Always reads from controller - no caching for simplicity
* @return Wrapped native token address or zero address if controller not set
*/
function getWrappedNativeToken() public view returns (address) {
address controller = getController();
return controller == address(0) ? address(0) : IPetalsControllerForStrategy(controller).wrappedNativeToken();
}
// ============ STANDARD ERC4626 IMPLEMENTATION ============
function name() public view returns (string memory) {
return string(abi.encodePacked(_name));
}
function decimals() public view returns (uint8) {
return IERC20Metadata(asset).decimals();
}
function totalAssets() public view returns (uint256) {
return balanceOfAsset() + balanceOfPool();
}
function balanceOfAsset() public view returns (uint256) {
return IERC20(asset).balanceOf(address(this));
}
function balanceOfPool() public view returns (uint256) {
return _protocolBalanceOf();
}
// ============ ERC4626 Interface Compliance (Simplified) ============
/// @notice 1:1 conversion functions (LP strategies use direct asset mapping)
function convertToShares(uint256 assets) external pure returns (uint256) { return assets; }
function convertToAssets(uint256 shares) external pure returns (uint256) { return shares; }
function previewDeposit(uint256 assets) external pure returns (uint256) { return assets; }
function previewMint(uint256 shares) external pure returns (uint256) { return shares; }
function previewWithdraw(uint256 assets) external pure returns (uint256) { return assets; }
function previewRedeem(uint256 shares) external pure returns (uint256) { return shares; }
/// @notice Maximum operation limits based on strategy status and balances
function maxDeposit(address) external view returns (uint256) { return vaultActive ? type(uint256).max : 0; }
function maxMint(address) external view returns (uint256) { return vaultActive ? type(uint256).max : 0; }
function maxWithdraw(address) external view returns (uint256) { return totalAssets(); }
function maxRedeem(address account) external view returns (uint256) { return IERC20(vault).balanceOf(account); }
// ============ CORE STRATEGY FUNCTIONS ============
function deposit() external whenNotPaused {
uint256 assetBal = balanceOfAsset();
if (assetBal > 0) _protocolDeposit(assetBal);
}
/// @notice Estimate harvester reward for calling harvest
function callReward() external view returns (uint256) {
(address[] memory tokens, uint256[] memory amounts) = this.totalRewardsAvailable();
if (tokens.length == 0) return 0;
// Sum native token rewards (non-native need oracles)
address nativeToken = getWrappedNativeToken();
uint256 nativeRewards;
for (uint256 i = 0; i < tokens.length;) {
if (tokens[i] == nativeToken) nativeRewards += amounts[i];
unchecked { ++i; }
}
if (nativeRewards == 0) return 0;
address ctrl = getController();
if (ctrl == address(0)) return 0;
try IPetalsControllerForStrategy(ctrl).getVaultFeeRatios(vault) returns (VaultFeeConfig memory config) {
uint256 totalFees = (nativeRewards * _getControllerData(IPetalsControllerForStrategy.DEFAULT_PERFORMANCE_FEE.selector, 300)) /
_getControllerData(IPetalsControllerForStrategy.BASIS_POINTS.selector, 10_000);
bytes32 label = keccak256("harvester");
for (uint256 i = 0; i < config.recipients.length;) {
if (config.labels[i] == label) return (totalFees * config.ratios[i]) / 1000;
unchecked { ++i; }
}
} catch {}
return 0;
}
function withdraw(uint256 _amount) external nonReentrant {
if (msg.sender != vault) revert OnlyVault();
uint256 assetBal = balanceOfAsset();
if (assetBal < _amount) {
_protocolWithdraw(_amount - assetBal);
assetBal = balanceOfAsset();
// STRICT MODE: Revert if insufficient liquidity during normal operations
// For LP staking strategies, gauge should always return full amount or revert
// Partial withdrawal indicates a serious issue (protocol exploit, bug, etc.)
if (assetBal < _amount && !paused()) {
revert InsufficientLiquidity(_amount, assetBal);
}
// EMERGENCY MODE: Allow partial withdrawal when paused (best effort recovery)
// During panic/retirement, get whatever is available
if (assetBal < _amount) {
_amount = assetBal;
}
}
IERC20(asset).safeTransfer(vault, _amount);
}
/**
* @notice Execute harvest operation - clean 6-step process
* @dev Consolidated harvest flow with clear, single-purpose functions
*/
function harvest(address harvester) external nonReentrant whenNotPaused {
// Pre-harvest validation and state caching
uint256 minDelay = _getControllerData(IPetalsControllerForStrategy.MIN_HARVEST_DELAY.selector, 0);
if (minDelay > 0 && block.timestamp < lastHarvest + minDelay) {
revert DelayNotMet("harvest");
}
uint256 totalAssetsBefore = balanceOfAsset() + _protocolBalanceOf();
address[] memory rewardTokensCached = rewardTokens;
// === 6-STEP HARVEST PROCESS ===
// 1. Claim all rewards from protocol
uint256 claimedRewards = _claimRewards();
// 2. Swap all reward tokens to native token
uint256 nativeAmount = _swapRewardsToNative(claimedRewards);
if (nativeAmount == 0) revert OperationFailed("No rewards available");
// 3. Charge performance fees on native rewards
uint256 remainingNative = _chargeFees(harvester, nativeAmount, rewardTokensCached);
// 4. Convert native to LP tokens (swap + add liquidity)
uint256 lpReceived = _addLiquidity(remainingNative);
// 5. Deposit LP tokens back into protocol
_deposit(lpReceived);
// 6. Update controller with harvest results
_updateController(totalAssetsBefore, harvester, rewardTokensCached);
// Update harvest timestamp
lastHarvest = block.timestamp;
}
// ============ HARVEST STEP 3 & 4 & 6 - IMPLEMENTED IN BASE ============
/**
* @notice Step 3: Charge performance fees on native rewards
* @param harvester Address that triggered the harvest
* @param nativeAmount Amount of native tokens before fees
* @return remainingNative Amount of native tokens after fees
*/
function _chargeFees(address harvester, uint256 nativeAmount, address[] memory /* rewardTokensCached */) internal returns (uint256 remainingNative) {
if (nativeAmount == 0) return 0;
address controllerAddress = getController();
if (controllerAddress == address(0)) return nativeAmount;
IPetalsControllerForStrategy controller = IPetalsControllerForStrategy(controllerAddress);
VaultFeeConfig memory feeConfig = controller.getVaultFeeRatios(vault);
address nativeToken = getWrappedNativeToken();
uint256 performanceFee = _getControllerData(IPetalsControllerForStrategy.DEFAULT_PERFORMANCE_FEE.selector, 300);
uint256 basisPoints = _getControllerData(IPetalsControllerForStrategy.BASIS_POINTS.selector, 10_000);
(uint256 totalDistributed, uint256 recipientCount) = _distributeFees(
feeConfig,
nativeToken,
nativeAmount,
performanceFee,
basisPoints,
harvester,
feeRecipient
);
if (totalDistributed > 0) {
emit StrategyConfigUpdated(2, abi.encode(harvester, totalDistributed, recipientCount)); // 2 = Fee update
}
// Return remaining native balance after fees
return nativeToken != address(0) ? IERC20(nativeToken).balanceOf(address(this)) : 0;
}
// ============ Fee Distribution via Library ============
event FeesAccumulatedForTreasury(address indexed token, uint256 amount, uint256 totalPending);
/**
* @notice Distribute fees using centralized FeesLibrary
* @dev Delegates to library for distribution logic, handles failed fees locally
*/
function _distributeFees(
VaultFeeConfig memory feeConfig,
address feeToken,
uint256 feeTokenAmount,
uint256 performanceFee,
uint256 basisPoints,
address harvester,
address configuredFeeRecipient
) internal returns (uint256 totalDistributed, uint256 recipientCount) {
address feesLib = getFeesLibrary();
if (feesLib == address(0)) {
// Fallback: no fees distributed if library not set
return (0, 0);
}
// Call library to distribute fees
uint256 totalFailed;
(totalDistributed, totalFailed, recipientCount) = IFeesLibrary(feesLib).distributeFees(
feeConfig,
feeToken,
feeTokenAmount,
performanceFee,
basisPoints,
harvester,
configuredFeeRecipient
);
// Accumulate any failed fees for treasury to claim
if (totalFailed > 0) {
pendingTreasuryFees[feeToken] += totalFailed;
emit FeesAccumulatedForTreasury(feeToken, totalFailed, pendingTreasuryFees[feeToken]);
}
}
/**
* @notice Step 4: Convert native tokens to LP tokens (swap + add liquidity)
* @param nativeAmount Amount of native tokens to convert
* @return lpReceived Amount of LP tokens received
*/
function _addLiquidity(uint256 nativeAmount) internal returns (uint256 lpReceived) {
if (nativeAmount == 0) return 0;
uint256 lpBalanceBefore = balanceOfAsset();
// Use new split autocompound logic
(uint256 token0Amount, uint256 token1Amount) = _swapRewards(nativeAmount);
if (token0Amount > 0 && token1Amount > 0) {
_addLiquidityToPool(token0Amount, token1Amount);
}
uint256 lpBalanceAfter = balanceOfAsset();
return lpBalanceAfter > lpBalanceBefore ? lpBalanceAfter - lpBalanceBefore : 0;
}
/**
* @notice Step 6: Update controller with harvest results (simplified)
* @param totalAssetsBefore Total assets before harvest
* @param harvester Address that triggered harvest
*/
function _updateController(uint256 totalAssetsBefore, address harvester, address[] memory /* rewardTokensCached */) internal {
// Calculate harvest yield
uint256 totalAssetsAfter = balanceOfAsset() + _protocolBalanceOf();
uint256 harvestYield = totalAssetsAfter > totalAssetsBefore ? totalAssetsAfter - totalAssetsBefore : 0;
// Update controller with essential harvest data
_updateControllerOnHarvest(harvestYield, totalAssetsAfter);
// Emit simplified harvest completion event
// Calculate share price and total shares for analytics
uint256 vaultTotalShares = IERC20(address(vault)).totalSupply();
uint256 vaultSharePrice = vaultTotalShares > 0
? (totalAssetsAfter * 1e18) / vaultTotalShares
: 1e18; // Default to 1.0 if no shares exist
emit HarvestCompleted(
harvester,
harvestYield,
totalAssetsAfter,
vaultSharePrice, // Share price in 18 decimals for analytics
vaultTotalShares, // Total shares for analytics
block.timestamp
);
}
// ============ EMERGENCY FUNCTIONS ============
/**
* @notice Emergency panic - withdraw all funds from protocol
* @dev Only callable by vault (removes duplicate access control)
* Vault.pause() already checks GUARDIAN_ROLE before calling this
*/
function panic() external {
if (msg.sender != vault) revert Unauthorized();
_pause();
_protocolEmergencyWithdraw();
}
function retireStrat() external {
// Allow either vault or MASTER_ROLE to retire strategy
if (msg.sender != vault && !_hasRole(MASTER_ROLE, msg.sender)) {
revert Unauthorized();
}
// Best-effort emergency withdraw - continue retirement even if this fails
try this._internalEmergencyWithdraw() {} catch {}
uint256 assetBal = balanceOfAsset();
if (assetBal > 0) IERC20(asset).safeTransfer(vault, assetBal);
vaultActive = false;
}
function _internalEmergencyWithdraw() external {
if (msg.sender != address(this)) revert Unauthorized();
_protocolEmergencyWithdraw();
}
function setVault(address _vault) external {
if (vault != address(0) && msg.sender != vault) revert UnauthorizedUpdate();
vault = _vault;
// Cache controller for gas optimization
if (_vault != address(0)) {
try IPetalsVault(_vault).controller() returns (address ctrl) {
_cachedController = ctrl;
} catch {
_cachedController = address(0);
}
} else {
_cachedController = address(0);
}
}
/**
* @notice Set slippage tolerance for DEX operations
* @dev Called by controller during vault approval - MASTER_ROLE only via controller
* @param _slippageTolerance Slippage tolerance in basis points (0-1000 = 0-10%)
*/
function setSlippageTolerance(uint256 _slippageTolerance) external {
// Only controller can set slippage (called during approval)
address controllerAddress = getController();
if (msg.sender != controllerAddress) revert Unauthorized();
if (_slippageTolerance > 1000) revert InvalidInput("Slippage too high (max 10%)");
slippageTolerance = _slippageTolerance;
emit StrategyConfigUpdated(0, abi.encode("slippageTolerance", _slippageTolerance));
}
// ============ REWARD TOKEN MANAGEMENT (Strategy-Specific Validation) ============
/**
* @notice Initialize routing configuration during strategy setup (no timer required)
* @dev Called only during initialization - bypasses timer for initial setup
* @param _rewardRoutes Array of encoded reward routes
* @param _nativeToLp0Route Route from native to LP token0
* @param _nativeToLp1Route Route from native to LP token1
*/
function _initializeRoutingConfiguration(
bytes[] memory _rewardRoutes,
bytes memory _nativeToLp0Route,
bytes memory _nativeToLp1Route
) internal {
if (_rewardRoutes.length == 0) revert EmptyArray();
address nativeToken = getWrappedNativeToken();
if (nativeToken == address(0)) revert NativeTokenNotConfigured();
// Extract reward tokens from routes
address[] memory newRewardTokens = _extractRewardTokens(_rewardRoutes);
// Set configuration
for (uint256 i = 0; i < newRewardTokens.length;) {
isRewardToken[newRewardTokens[i]] = true;
unchecked { ++i; }
}
rewardTokenRoutes = _rewardRoutes;
rewardTokens = newRewardTokens;
nativeToLp0 = _nativeToLp0Route;
nativeToLp1 = _nativeToLp1Route;
// Emit initialization event
emit StrategyConfigUpdated(1, abi.encode(newRewardTokens, _rewardRoutes, _nativeToLp0Route, _nativeToLp1Route, false));
}
/**
* @notice Internal function to apply route updates
* @dev INTERNAL USE ONLY - Must be wrapped by child strategies with controller-only check
* Child strategies should implement IRoutableStrategy.applyRouteUpdate() which calls this
* @param _rewardRoutes Array of encoded reward routes
* @param _nativeToLp0Route Route from native to LP token0
* @param _nativeToLp1Route Route from native to LP token1
*/
function _applyRouteUpdate(
bytes[] memory _rewardRoutes,
bytes memory _nativeToLp0Route,
bytes memory _nativeToLp1Route
) internal {
if (_rewardRoutes.length == 0) revert EmptyArray();
// Extract reward tokens from routes
address[] memory newRewardTokens = _extractRewardTokens(_rewardRoutes);
// Clear existing mappings
for (uint256 i = 0; i < rewardTokens.length;) {
delete isRewardToken[rewardTokens[i]];
unchecked { ++i; }
}
// Set new configuration
for (uint256 i = 0; i < newRewardTokens.length;) {
isRewardToken[newRewardTokens[i]] = true;
unchecked { ++i; }
}
rewardTokenRoutes = _rewardRoutes;
rewardTokens = newRewardTokens;
nativeToLp0 = _nativeToLp0Route;
nativeToLp1 = _nativeToLp1Route;
// Update controller with new reward tokens
if (vault != address(0)) {
_updateControllerRewardData();
}
// Emit route update event
emit StrategyConfigUpdated(1, abi.encode(newRewardTokens, _rewardRoutes, _nativeToLp0Route, _nativeToLp1Route, true));
}
/**
* @notice Update controller with harvest results and current reward tokens
* @dev Consolidates both harvest metrics and reward token tracking in single call
* @param harvestYield Amount of yield generated from this harvest
* @param totalAssetsAfter Total assets after harvest for APY calculation
*/
function _updateControllerOnHarvest(uint256 harvestYield, uint256 totalAssetsAfter) internal {
address controllerAddress = getController();
if (controllerAddress == address(0)) return;
// Update harvest metrics (critical)
IPetalsControllerForStrategy(controllerAddress).onStrategyHarvest(vault, harvestYield, totalAssetsAfter);
// Update reward token tracking (optional event)
try IPetalsControllerForStrategy(controllerAddress).updateStrategyRewardTokens(vault, rewardTokens) {} catch {}
}
/**
* @notice Update controller with current reward tokens (for route configuration changes)
* @dev Separate function for non-harvest reward token updates
*/
function _updateControllerRewardData() internal {
address controllerAddress = getController();
if (controllerAddress != address(0)) {
try IPetalsControllerForStrategy(controllerAddress).updateStrategyRewardTokens(vault, rewardTokens) {} catch {}
}
}
function setFeeRecipient(address newFeeRecipient) external {
if (msg.sender != vault) revert OnlyVault();
if (newFeeRecipient == address(0)) revert ZeroAddress();
feeRecipient = newFeeRecipient;
emit StrategyConfigUpdated(0, abi.encode("feeRecipient", feeRecipient, newFeeRecipient)); // 0 = Config update
}
// ============ IPETALS STRATEGY IMPLEMENTATION ============
/// @notice Required interface implementations (legacy compatibility)
function beforeDeposit() external { /* No preparation needed */ }
/// @notice Pausable interface overrides
function paused() public view override(Pausable, IPetalsStrategy) returns (bool) { return super.paused(); }
function pause() external override onlyRole(GUARDIAN_ROLE) { _pause(); }
function unpause() external override onlyRole(GUARDIAN_ROLE) { _unpause(); }
// ============ GENERIC HELPER FUNCTIONS (Virtual - Override if Needed) ============
/**
* @notice Required by IPetalsStrategy interface - returns vault balance for account
* @dev Virtual - override if custom logic needed
*/
function balanceOf(address account) external view virtual returns (uint256) {
return IERC20(vault).balanceOf(account);
}
/**
* @notice Required by IPetalsStrategy interface - returns strategy's asset balance
* @dev Virtual - override if custom logic needed
*/
function balanceOfWant() external view virtual returns (uint256) {
return balanceOfAsset();
}
/**
* @notice Required by IPetalsStrategy interface - returns the strategy's managed asset
* @dev Virtual - override if custom logic needed
*/
function want() external view virtual returns (address) {
return asset;
}
/// @notice Get the factory address that deployed this strategy
function getFactory() external view returns (address) {
return factory;
}
/// @notice Get the protocol type identifier for this strategy
function getProtocolType() external view returns (bytes32) {
return protocolType;
}
/**
* @notice Unified approval helper with gas-efficient just-in-time approval pattern
* @dev Virtual - override if protocol needs custom approval logic
* @param token Token to approve
* @param spender Spender to approve
* @param amount Amount needed for operation
*/
function _ensureApproval(address token, address spender, uint256 amount) internal virtual {
uint256 currentAllowance = IERC20(token).allowance(address(this), spender);
if (currentAllowance < amount) {
if (currentAllowance > 0) IERC20(token).forceApprove(spender, 0);
IERC20(token).forceApprove(spender, amount);
}
}
/**
* @notice Claim accumulated failed fees (MASTER_ROLE only)
* @dev Treasury can claim fees that failed to distribute to recipients
* @param token Fee token to claim
*/
function claimPendingTreasuryFees(address token) external onlyRole(MASTER_ROLE) {
uint256 amount = pendingTreasuryFees[token];
if (amount == 0) revert OperationFailed("No pending fees");
pendingTreasuryFees[token] = 0;
IERC20(token).safeTransfer(msg.sender, amount);
emit StrategyConfigUpdated(2, abi.encode("treasuryFeeClaimed", token, amount)); // 2 = Fee update
}
/**
* @notice Emergency token recovery (GUARDIAN_ROLE only)
* @dev Virtual - override if protocol needs custom recovery logic
* @dev Note: Can also recover pendingTreasuryFees if needed
* @param token Token to recover
* @param amount Amount to recover (0 = all)
* @param recipient Recovery recipient
*/
function emergencyRecoverToken(address token, uint256 amount, address recipient)
external
virtual
onlyRole(GUARDIAN_ROLE)
{
if (token == asset) revert InvalidInput("Cannot recover main asset");
if (recipient == address(0)) revert InvalidInput("Invalid recipient address");
uint256 balance = IERC20(token).balanceOf(address(this));
if (balance == 0) revert OperationFailed("No tokens to recover");
uint256 actualAmount = amount == 0 ? balance : amount;
if (actualAmount > balance) revert InvalidInput("Amount exceeds balance");
// Clear pendingTreasuryFees if recovering that token (prevents double-claim)
if (pendingTreasuryFees[token] > 0) {
delete pendingTreasuryFees[token];
}
IERC20(token).safeTransfer(recipient, actualAmount);
emit StrategyConfigUpdated(3, abi.encode(token, actualAmount, recipient)); // 3 = Emergency
}
/**
* @notice Convert string to bytes32 (gas-efficient storage)
* @dev Virtual - utility function that can be overridden if needed
*/
function _stringToBytes32(string memory _string) internal pure virtual returns (bytes32 result) {
bytes memory bytesString = bytes(_string);
if (bytesString.length == 0) return 0x0;
assembly { result := mload(add(bytesString, 32)) }
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IShadowGauge {
struct Reward {
uint256 rewardRate;
uint256 periodFinish;
uint256 lastUpdateTime;
uint256 rewardPerTokenStored;
}
// State variables
function stake() external view returns (address);
function voter() external view returns (address);
function xShadow() external view returns (address);
// Reward token functions (moved to proper location below)
function totalSupply() external view returns (uint256);
function balanceOf(address user) external view returns (uint256);
// Mapping views
function userRewardPerTokenStored(address user, address token) external view returns (uint256);
function storedRewardsPerUser(address user, address token) external view returns (uint256);
function isReward(address token) external view returns (bool);
// Events
event Deposit(address indexed from, uint256 amount);
event Withdraw(address indexed from, uint256 amount);
event NotifyReward(address indexed from, address indexed reward, uint256 amount);
event ClaimRewards(address indexed from, address indexed reward, uint256 amount);
// Reward functions
function rewardsList() external view returns (address[] memory _rewards);
function rewardsListLength() external view returns (uint256 _length);
function lastTimeRewardApplicable(address token) external view returns (uint256);
function rewardData(address token) external view returns (Reward memory data);
function earned(address token, address account) external view returns (uint256 _reward);
function rewardPerToken(address token) external view returns (uint256);
function left(address token) external view returns (uint256);
// Staking functions
function depositAll() external;
function depositFor(address recipient, uint256 amount) external;
function deposit(uint256 amount) external;
function withdrawAll() external;
function withdraw(uint256 amount) external;
// Reward claiming functions
function getReward(address account, address[] calldata tokens) external;
function getRewardAndExit(address account, address[] calldata tokens) external;
function unstakeAndClaimAll(address[] calldata tokens) external;
// Reward notification
function notifyRewardAmount(address token, uint256 amount) external;
// Whitelisting
function isWhitelisted(address token) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IShadowVoter
* @notice Interface for Shadow Protocol Voter contract that handles reward distribution
* @dev Voter pattern is commonly used in Solidly-based protocols for reward management
*/
interface IShadowVoter {
/**
* @notice Claim legacy rewards from multiple gauges and immediately exit (unstake)
* @dev This is the correct way to claim rewards in Shadow protocol - not directly from gauge
* @param _gauges Array of gauge addresses to claim rewards from
* @param _tokens Array of arrays containing reward token addresses for each gauge
*/
function claimLegacyRewardsAndExit(
address[] calldata _gauges,
address[][] calldata _tokens
) external;
/**
* @notice Claim rewards from multiple gauges without exiting/unstaking
* @param _gauges Array of gauge addresses to claim rewards from
* @param _tokens Array of arrays containing reward token addresses for each gauge
*/
function claimRewards(
address[] calldata _gauges,
address[][] calldata _tokens
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IXShadow {
// Standard ERC20 functions
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
// xShadow specific functions
function shadow() external view returns (address);
function totalShadow() external view returns (uint256);
// xShadow specific exit function (50% penalty conversion)
function exit(uint256 amount) external;
// Wrapping functions - SHADOW to xSHADOW (for completeness)
function deposit(uint256 amount) external;
function depositAll() external;
// Exchange rate functions (common patterns)
function shadowPerXShadow() external view returns (uint256);
function xShadowPerShadow() external view returns (uint256);
// Alternative function names that might exist
function exchangeRate() external view returns (uint256);
function rate() external view returns (uint256);
function pricePerShare() external view returns (uint256);
// Events
event Deposit(address indexed user, uint256 shadowAmount, uint256 xShadowAmount);
event Withdraw(address indexed user, uint256 xShadowAmount, uint256 shadowAmount);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IShadowRouter {
struct route {
address from;
address to;
bool stable;
}
function factory() external view returns (address);
function WETH() external view returns (address);
function sortTokens(address tokenA, address tokenB) external pure returns (address token0, address token1);
function pairFor(address tokenA, address tokenB, bool stable) external view returns (address pair);
function getReserves(
address tokenA,
address tokenB,
bool stable
)
external
view
returns (uint256 reserveA, uint256 reserveB);
function getAmountsOut(uint256 amountIn, route[] memory routes) external view returns (uint256[] memory amounts);
function getAmountsIn(uint256 amountOut, route[] memory routes) external view returns (uint256[] memory amounts);
function getAmountOut(
uint256 amountIn,
address tokenIn,
address tokenOut
)
external
view
returns (uint256 amount, bool stable);
function quoteAddLiquidity(
address tokenA,
address tokenB,
bool stable,
uint256 amountADesired,
uint256 amountBDesired
)
external
view
returns (uint256 amountA, uint256 amountB, uint256 liquidity);
function quoteRemoveLiquidity(
address tokenA,
address tokenB,
bool stable,
uint256 liquidity
)
external
view
returns (uint256 amountA, uint256 amountB);
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 addLiquidityETH(
address token,
bool stable,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
)
external
payable
returns (uint256 amountToken, uint256 amountETH, 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 removeLiquidityETH(
address token,
bool stable,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
)
external
returns (uint256 amountToken, uint256 amountETH);
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
route[] calldata routes,
address to,
uint256 deadline
)
external
returns (uint256[] memory amounts);
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
route[] memory routes,
address to,
uint256 deadline
)
external
returns (uint256[] memory amounts);
function swapExactETHForTokens(
uint256 amountOutMin,
route[] calldata routes,
address to,
uint256 deadline
)
external
payable
returns (uint256[] memory amounts);
function swapTokensForExactETH(
uint256 amountOut,
uint256 amountInMax,
route[] calldata routes,
address to,
uint256 deadline
)
external
returns (uint256[] memory amounts);
function swapExactTokensForETH(
uint256 amountIn,
uint256 amountOutMin,
route[] calldata routes,
address to,
uint256 deadline
)
external
returns (uint256[] memory amounts);
function swapETHForExactTokens(
uint256 amountOut,
route[] calldata routes,
address to,
uint256 deadline
)
external
payable
returns (uint256[] memory amounts);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
route[] calldata routes,
address to,
uint256 deadline
)
external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint256 amountOutMin,
route[] calldata routes,
address to,
uint256 deadline
)
external
payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
route[] calldata routes,
address to,
uint256 deadline
)
external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title IGauge
/// @notice Interface for Shadow protocol gauge contracts
interface IGauge {
function deposit(uint256 amount) external;
function withdraw(uint256 amount) external;
function balanceOf(address account) external view returns (uint256);
function getReward() external;
function earned(address account) external view returns (uint256);
function voter() external view returns (address);
}
/// @title IRewardToken
/// @notice Interface for Shadow protocol reward tokens (like xShadow)
interface IRewardToken {
function redeem(uint256 amount, uint256 duration) external;
function balanceOf(address account) external view returns (uint256);
function getRedeemAmount(uint256 amount, uint256 duration) external view returns (uint256);
}
/// @title IRouter
/// @notice Interface for Shadow protocol router (DEX functionality)
interface IRouter {
function getAmountsOut(
uint256 amountIn,
address[] calldata path
)
external
view
returns (uint256[] memory amounts);
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
)
external
returns (uint256[] memory amounts);
function addLiquidity(
address tokenA,
address tokenB,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
)
external
returns (uint256 amountA, uint256 amountB, uint256 liquidity);
}
/// @title ILP
/// @notice Interface for Shadow protocol LP tokens
interface ILP {
function token0() external view returns (address);
function token1() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./RouterTypes.sol";
/**
* @title IRoutableStrategy
* @notice Interface for strategies that support dynamic route configuration
* @dev All router-specific strategy abstracts must implement this interface
*
* Architecture:
* - Strategy stores routes as bytes[] internally for gas efficiency during harvests
* - Strategy validates routes with router-specific logic
* - Strategy applies route updates only when called by controller (RoutingFacet)
* - Routes are read during harvests and decoded internally by the strategy
*/
interface IRoutableStrategy {
/**
* @notice Get the router type this strategy uses
* @dev Used by RoutingFacet to select appropriate router library
* @return The RouterType enum value (SOLIDLY, UNIV2, UNIV3, etc.)
*/
function getRouterType() external view returns (RouterType);
/**
* @notice Validate routes with strategy-specific logic
* @dev Called by RoutingFacet before applying routes
* Additional validation beyond library validation (e.g., token whitelisting)
* @param rewardRoutes Encoded reward token routes
* @param nativeToLp0 Encoded native->LP0 route
* @param nativeToLp1 Encoded native->LP1 route
* @return valid Whether routes are valid for this strategy
* @return reason Error message if invalid
*/
function validateRoutes(
bytes[] calldata rewardRoutes,
bytes calldata nativeToLp0,
bytes calldata nativeToLp1
) external view returns (bool valid, string memory reason);
/**
* @notice Apply new route configuration
* @dev Only callable by controller (RoutingFacet)
* Updates internal route storage and reward token arrays
* @param rewardRoutes Encoded reward token routes
* @param nativeToLp0 Encoded native->LP0 route
* @param nativeToLp1 Encoded native->LP1 route
*/
function applyRouteUpdate(
bytes[] calldata rewardRoutes,
bytes calldata nativeToLp0,
bytes calldata nativeToLp1
) external;
/**
* @notice Get current encoded routes from strategy storage
* @dev Used by RoutingFacet view functions to return routes to frontend
* @return rewardRoutes Array of encoded reward routes
* @return nativeToLp0 Encoded native->LP0 route
* @return nativeToLp1 Encoded native->LP1 route
*/
function getEncodedRoutes()
external
view
returns (
bytes[] memory rewardRoutes,
bytes memory nativeToLp0,
bytes memory nativeToLp1
);
}// 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);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title ISolidlyLibrary
* @notice Interface for SolidlyLibrary route validation
*/
interface ISolidlyLibrary {
/**
* @notice Validate Solidly route configuration
* @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);
}// 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
// OpenZeppelin Contracts (last updated v5.3.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
bool private _paused;
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
import {Panic} from "../Panic.sol";
import {SafeCast} from "./SafeCast.sol";
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Return the 512-bit addition of two uint256.
*
* The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.
*/
function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
assembly ("memory-safe") {
low := add(a, b)
high := lt(low, a)
}
}
/**
* @dev Return the 512-bit multiplication of two uint256.
*
* The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.
*/
function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
// 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
// the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = high * 2²⁵⁶ + low.
assembly ("memory-safe") {
let mm := mulmod(a, b, not(0))
low := mul(a, b)
high := sub(sub(mm, low), lt(mm, low))
}
}
/**
* @dev Returns the addition of two unsigned integers, with a success flag (no overflow).
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a + b;
success = c >= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a - b;
success = c <= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a * b;
assembly ("memory-safe") {
// Only true when the multiplication doesn't overflow
// (c / a == b) || (a == 0)
success := or(eq(div(c, a), b), iszero(a))
}
// equivalent to: success ? c : 0
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
success = b > 0;
assembly ("memory-safe") {
// The `DIV` opcode returns zero when the denominator is 0.
result := div(a, b)
}
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
success = b > 0;
assembly ("memory-safe") {
// The `MOD` opcode returns zero when the denominator is 0.
result := mod(a, b)
}
}
}
/**
* @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryAdd(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.
*/
function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {
(, uint256 result) = trySub(a, b);
return result;
}
/**
* @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryMul(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
*
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
* one branch when needed, making this function more expensive.
*/
function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
// branchless ternary works because:
// b ^ (a ^ b) == a
// b ^ 0 == b
return b ^ ((a ^ b) * SafeCast.toUint(condition));
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a > b, a, b);
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a < b, a, b);
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
Panic.panic(Panic.DIVISION_BY_ZERO);
}
// The following calculation ensures accurate ceiling division without overflow.
// Since a is non-zero, (a - 1) / b will not overflow.
// The largest possible result occurs when (a - 1) / b is type(uint256).max,
// but the largest value we can obtain is type(uint256).max - 1, which happens
// when a = type(uint256).max and b = 1.
unchecked {
return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
}
}
/**
* @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
*
* Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
(uint256 high, uint256 low) = mul512(x, y);
// Handle non-overflow cases, 256 by 256 division.
if (high == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return low / denominator;
}
// Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
if (denominator <= high) {
Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [high low].
uint256 remainder;
assembly ("memory-safe") {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
high := sub(high, gt(remainder, low))
low := sub(low, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly ("memory-safe") {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [high low] by twos.
low := div(low, twos)
// Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from high into low.
low |= high * twos;
// Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
// that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv ≡ 1 mod 2⁴.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2⁸
inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
inverse *= 2 - denominator * inverse; // inverse mod 2³²
inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is
// less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high
// is no longer required.
result = low * inverse;
return result;
}
}
/**
* @dev Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
}
/**
* @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.
*/
function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {
unchecked {
(uint256 high, uint256 low) = mul512(x, y);
if (high >= 1 << n) {
Panic.panic(Panic.UNDER_OVERFLOW);
}
return (high << (256 - n)) | (low >> n);
}
}
/**
* @dev Calculates x * y >> n with full precision, following the selected rounding direction.
*/
function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {
return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);
}
/**
* @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
*
* If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
* If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
*
* If the input value is not inversible, 0 is returned.
*
* NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
* inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
*/
function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
unchecked {
if (n == 0) return 0;
// The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
// Used to compute integers x and y such that: ax + ny = gcd(a, n).
// When the gcd is 1, then the inverse of a modulo n exists and it's x.
// ax + ny = 1
// ax = 1 + (-y)n
// ax ≡ 1 (mod n) # x is the inverse of a modulo n
// If the remainder is 0 the gcd is n right away.
uint256 remainder = a % n;
uint256 gcd = n;
// Therefore the initial coefficients are:
// ax + ny = gcd(a, n) = n
// 0a + 1n = n
int256 x = 0;
int256 y = 1;
while (remainder != 0) {
uint256 quotient = gcd / remainder;
(gcd, remainder) = (
// The old remainder is the next gcd to try.
remainder,
// Compute the next remainder.
// Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
// where gcd is at most n (capped to type(uint256).max)
gcd - remainder * quotient
);
(x, y) = (
// Increment the coefficient of a.
y,
// Decrement the coefficient of n.
// Can overflow, but the result is casted to uint256 so that the
// next value of y is "wrapped around" to a value between 0 and n - 1.
x - y * int256(quotient)
);
}
if (gcd != 1) return 0; // No inverse exists.
return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
}
}
/**
* @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
*
* From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
* prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
* `a**(p-2)` is the modular multiplicative inverse of a in Fp.
*
* NOTE: this function does NOT check that `p` is a prime greater than `2`.
*/
function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
unchecked {
return Math.modExp(a, p - 2, p);
}
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
*
* Requirements:
* - modulus can't be zero
* - underlying staticcall to precompile must succeed
*
* IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
* sure the chain you're using it on supports the precompiled contract for modular exponentiation
* at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
* the underlying function will succeed given the lack of a revert, but the result may be incorrectly
* interpreted as 0.
*/
function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
(bool success, uint256 result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
* It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
* to operate modulo 0 or if the underlying precompile reverted.
*
* IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
* you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
* https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
* of a revert, but the result may be incorrectly interpreted as 0.
*/
function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
if (m == 0) return (false, 0);
assembly ("memory-safe") {
let ptr := mload(0x40)
// | Offset | Content | Content (Hex) |
// |-----------|------------|--------------------------------------------------------------------|
// | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x60:0x7f | value of b | 0x<.............................................................b> |
// | 0x80:0x9f | value of e | 0x<.............................................................e> |
// | 0xa0:0xbf | value of m | 0x<.............................................................m> |
mstore(ptr, 0x20)
mstore(add(ptr, 0x20), 0x20)
mstore(add(ptr, 0x40), 0x20)
mstore(add(ptr, 0x60), b)
mstore(add(ptr, 0x80), e)
mstore(add(ptr, 0xa0), m)
// Given the result < m, it's guaranteed to fit in 32 bytes,
// so we can use the memory scratch space located at offset 0.
success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
result := mload(0x00)
}
}
/**
* @dev Variant of {modExp} that supports inputs of arbitrary length.
*/
function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
(bool success, bytes memory result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Variant of {tryModExp} that supports inputs of arbitrary length.
*/
function tryModExp(
bytes memory b,
bytes memory e,
bytes memory m
) internal view returns (bool success, bytes memory result) {
if (_zeroBytes(m)) return (false, new bytes(0));
uint256 mLen = m.length;
// Encode call args in result and move the free memory pointer
result = abi.encodePacked(b.length, e.length, mLen, b, e, m);
assembly ("memory-safe") {
let dataPtr := add(result, 0x20)
// Write result on top of args to avoid allocating extra memory.
success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
// Overwrite the length.
// result.length > returndatasize() is guaranteed because returndatasize() == m.length
mstore(result, mLen)
// Set the memory pointer after the returned data.
mstore(0x40, add(dataPtr, mLen))
}
}
/**
* @dev Returns whether the provided byte array is zero.
*/
function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
for (uint256 i = 0; i < byteArray.length; ++i) {
if (byteArray[i] != 0) {
return false;
}
}
return true;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* This method is based on Newton's method for computing square roots; the algorithm is restricted to only
* using integer operations.
*/
function sqrt(uint256 a) internal pure returns (uint256) {
unchecked {
// Take care of easy edge cases when a == 0 or a == 1
if (a <= 1) {
return a;
}
// In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
// sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
// the current value as `ε_n = | x_n - sqrt(a) |`.
//
// For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
// of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
// bigger than any uint256.
//
// By noticing that
// `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
// we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
// to the msb function.
uint256 aa = a;
uint256 xn = 1;
if (aa >= (1 << 128)) {
aa >>= 128;
xn <<= 64;
}
if (aa >= (1 << 64)) {
aa >>= 64;
xn <<= 32;
}
if (aa >= (1 << 32)) {
aa >>= 32;
xn <<= 16;
}
if (aa >= (1 << 16)) {
aa >>= 16;
xn <<= 8;
}
if (aa >= (1 << 8)) {
aa >>= 8;
xn <<= 4;
}
if (aa >= (1 << 4)) {
aa >>= 4;
xn <<= 2;
}
if (aa >= (1 << 2)) {
xn <<= 1;
}
// We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
//
// We can refine our estimation by noticing that the middle of that interval minimizes the error.
// If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
// This is going to be our x_0 (and ε_0)
xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)
// From here, Newton's method give us:
// x_{n+1} = (x_n + a / x_n) / 2
//
// One should note that:
// x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
// = ((x_n² + a) / (2 * x_n))² - a
// = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
// = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
// = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
// = (x_n² - a)² / (2 * x_n)²
// = ((x_n² - a) / (2 * x_n))²
// ≥ 0
// Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
//
// This gives us the proof of quadratic convergence of the sequence:
// ε_{n+1} = | x_{n+1} - sqrt(a) |
// = | (x_n + a / x_n) / 2 - sqrt(a) |
// = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
// = | (x_n - sqrt(a))² / (2 * x_n) |
// = | ε_n² / (2 * x_n) |
// = ε_n² / | (2 * x_n) |
//
// For the first iteration, we have a special case where x_0 is known:
// ε_1 = ε_0² / | (2 * x_0) |
// ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
// ≤ 2**(2*e-4) / (3 * 2**(e-1))
// ≤ 2**(e-3) / 3
// ≤ 2**(e-3-log2(3))
// ≤ 2**(e-4.5)
//
// For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
// ε_{n+1} = ε_n² / | (2 * x_n) |
// ≤ (2**(e-k))² / (2 * 2**(e-1))
// ≤ 2**(2*e-2*k) / 2**e
// ≤ 2**(e-2*k)
xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above
xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5
xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9
xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18
xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36
xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72
// Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
// ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
// sqrt(a) or sqrt(a) + 1.
return xn - SafeCast.toUint(xn > a / xn);
}
}
/**
* @dev Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 x) internal pure returns (uint256 r) {
// If value has upper 128 bits set, log2 result is at least 128
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
// If upper 64 bits of 128-bit half set, add 64 to result
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
// If upper 32 bits of 64-bit half set, add 32 to result
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
// If upper 16 bits of 32-bit half set, add 16 to result
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
// If upper 8 bits of 16-bit half set, add 8 to result
r |= SafeCast.toUint((x >> r) > 0xff) << 3;
// If upper 4 bits of 8-bit half set, add 4 to result
r |= SafeCast.toUint((x >> r) > 0xf) << 2;
// Shifts value right by the current result and use it as an index into this lookup table:
//
// | x (4 bits) | index | table[index] = MSB position |
// |------------|---------|-----------------------------|
// | 0000 | 0 | table[0] = 0 |
// | 0001 | 1 | table[1] = 0 |
// | 0010 | 2 | table[2] = 1 |
// | 0011 | 3 | table[3] = 1 |
// | 0100 | 4 | table[4] = 2 |
// | 0101 | 5 | table[5] = 2 |
// | 0110 | 6 | table[6] = 2 |
// | 0111 | 7 | table[7] = 2 |
// | 1000 | 8 | table[8] = 3 |
// | 1001 | 9 | table[9] = 3 |
// | 1010 | 10 | table[10] = 3 |
// | 1011 | 11 | table[11] = 3 |
// | 1100 | 12 | table[12] = 3 |
// | 1101 | 13 | table[13] = 3 |
// | 1110 | 14 | table[14] = 3 |
// | 1111 | 15 | table[15] = 3 |
//
// The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.
assembly ("memory-safe") {
r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))
}
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 x) internal pure returns (uint256 r) {
// If value has upper 128 bits set, log2 result is at least 128
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
// If upper 64 bits of 128-bit half set, add 64 to result
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
// If upper 32 bits of 64-bit half set, add 32 to result
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
// If upper 16 bits of 32-bit half set, add 16 to result
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
// Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8
return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.9.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IPetalsStrategy {
// ERC4626 events
event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares
);
// ERC4626 metadata functions
function name() external view returns (string memory);
function decimals() external view returns (uint8);
// ERC4626-aligned view functions
function asset() external view returns (address);
function totalAssets() external view returns (uint256);
function convertToShares(uint256 assets) external view returns (uint256);
function convertToAssets(uint256 shares) external view returns (uint256);
function maxDeposit(address receiver) external view returns (uint256);
function maxMint(address receiver) external view returns (uint256);
function maxWithdraw(address owner) external view returns (uint256);
function maxRedeem(address owner) external view returns (uint256);
function previewDeposit(uint256 assets) external view returns (uint256 shares);
function previewMint(uint256 shares) external view returns (uint256 assets);
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
function previewRedeem(uint256 shares) external view returns (uint256 assets);
// Strategy-specific view functions
function balanceOfPool() external view returns (uint256);
function totalRewardsAvailable() external view returns (address[] memory tokens, uint256[] memory amounts);
function callReward() external view returns (uint256);
function lastHarvest() external view returns (uint256);
// Strategy metadata (for deployment validation)
function getFactory() external view returns (address);
function getProtocolType() external view returns (bytes32);
// Strategy-specific state-changing functions
function deposit() external;
function withdraw(uint256 assets) external;
function retireStrat() external;
function harvest(address harvester) external;
function panic() external;
function setVault(address vault) external;
function setFeeRecipient(address newFeeRecipient) external;
function setSlippageTolerance(uint256 tolerance) external;
function balanceOf(address account) external view returns (uint256);
function balanceOfWant() external view returns (uint256);
function beforeDeposit() external;
function pause() external;
function unpause() external;
function paused() external view returns (bool);
function vault() external view returns (address);
function want() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title IPetalsVault
/// @notice Interface for PetalsVault contract used by strategies
interface IPetalsVault {
function controller() external view returns (address);
}
/// @title IPetalsController
/// @notice Interface for PetalsController contract used by vaults
interface IPetalsController {
function onVaultOperation(
address user,
uint256 newTotalAssets,
uint256 newTotalSupply,
uint256 depositAmount,
uint256 withdrawAmount,
bool isDeposit
)
external;
function onStrategyHarvest(address vault, uint256 rewardAmount, uint256 previousTotalAssets) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../../vaults/00_libraries/types.sol";
/// @title IPetalsControllerForStrategy
/// @notice Interface for PetalsController contract used by strategies
interface IPetalsControllerForStrategy {
function wrappedNativeToken() external view returns (address);
function updateStrategyRewardTokens(address vault, address[] calldata rewardTokens) external;
function onStrategyHarvest(address vault, uint256 harvestYield, uint256 totalAssets) external;
// Constants access for strategies
function BASIS_POINTS() external view returns (uint256);
function MAX_SLIPPAGE() external view returns (uint256);
function MIN_HARVEST_DELAY() external view returns (uint256);
function MAX_WITHDRAWAL_FEE() external view returns (uint256);
function DEFAULT_PERFORMANCE_FEE() external view returns (uint256);
function DEFAULT_SLIPPAGE_TOLERANCE() external view returns (uint256);
function DEFAULT_CALL_REWARD() external view returns (uint256);
// Fee management
function getVaultFeeRatios(address vault) external view returns (VaultFeeConfig memory config);
// Permission management for role-based access control
function hasContractRole(address contractAddr, uint64 role, address account) external view returns (bool);
// Route manager for universal DEX routing
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title ICommonErrors
/// @notice Common error definitions used across multiple contracts
/// @dev Inherit this interface to access common errors and reduce code duplication
interface ICommonErrors {
// ============ COMMON ERRORS ============
error ZeroAddress();
error UnauthorizedUpdate();
error AlreadyInitialized();
error InvalidStrategy(address strategy);
error VaultNotFound();
error EmptyArray();
error InvalidAsset();
error InvalidRouter();
error NoRewardTokens();
error NativeTokenNotConfigured();
error InsufficientBalance();
// ============ COMMON ACCESS ERRORS ============
error OnlyVault();
error InvalidRecipient();
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title ICommonEvents
/// @notice Common event definitions used across multiple contracts
/// @dev Inherit this interface to access common events and reduce code duplication
interface ICommonEvents {
// ============ ROLE MANAGEMENT EVENTS ============
event RoleCacheUpdated(bytes32 indexed role, address indexed account, bool granted);
event FeeRecipientUpdated(address indexed previousFeeRecipient, address indexed newFeeRecipient);
// ============ STRATEGY LIFECYCLE EVENTS ============
event StrategyUpdated(address indexed newStrategy);
event StrategySet(address indexed strategy, bool wasRegistered);
// ============ REWARD ROUTING EVENTS ============
event RewardConfigurationUpdated(address[] tokens, bytes[] routes);
event NativeToLp0RouteSet(bytes route);
event NativeToLp1RouteSet(bytes route);
// ============ FAILURE EVENTS (as events, not errors) ============
event EmergencyWithdrawFailed(bytes reason);
event SwapFailed(address indexed tokenIn, address indexed tokenOut, uint256 amountIn, string reason);
}// 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
pragma solidity ^0.8.0;
import "../../vaults/00_libraries/types.sol";
/**
* @title IFeesLibrary
* @notice Interface for centralized fee distribution library
*/
interface IFeesLibrary {
/**
* @notice Distribute performance fees to configured recipients
* @param feeConfig Fee configuration from controller
* @param feeToken Token to distribute fees in
* @param feeTokenAmount Total amount available for fees
* @param performanceFee Performance fee percentage in basis points
* @param basisPoints Basis points denominator
* @param harvester Address that triggered the harvest
* @param configuredFeeRecipient Configured fee recipient for this strategy
* @return totalDistributed Total amount successfully distributed
* @return totalFailed Total amount that failed to distribute
* @return recipientCount Number of fee recipients
*/
function distributeFees(
VaultFeeConfig memory feeConfig,
address feeToken,
uint256 feeTokenAmount,
uint256 performanceFee,
uint256 basisPoints,
address harvester,
address configuredFeeRecipient
) external returns (uint256 totalDistributed, uint256 totalFailed, uint256 recipientCount);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IStrategySwapInterface
* @author Petals Protocol
* @notice Ultra-minimal interface for strategy swap execution
* @dev Maximum flexibility - strategies define their own parameter encoding
*/
interface IStrategySwapInterface {
/**
* @notice Execute a swap with strategy-specific parameter encoding
* @dev Strategy decodes params however it needs - zero assumptions about format
* @param params Encoded swap parameters (strategy-specific format)
* @return amountOut Actual output amount received
*/
function executeSwap(bytes calldata params) external returns (uint256 amountOut);
}// 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.0.0) (interfaces/IERC20.sol)
pragma solidity >=0.4.16;
import {IERC20} from "../token/ERC20/IERC20.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.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)
pragma solidity ^0.8.20;
/**
* @dev Helper library for emitting standardized panic codes.
*
* ```solidity
* contract Example {
* using Panic for uint256;
*
* // Use any of the declared internal constants
* function foo() { Panic.GENERIC.panic(); }
*
* // Alternatively
* function foo() { Panic.panic(Panic.GENERIC); }
* }
* ```
*
* Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
*
* _Available since v5.1._
*/
// slither-disable-next-line unused-state
library Panic {
/// @dev generic / unspecified error
uint256 internal constant GENERIC = 0x00;
/// @dev used by the assert() builtin
uint256 internal constant ASSERT = 0x01;
/// @dev arithmetic underflow or overflow
uint256 internal constant UNDER_OVERFLOW = 0x11;
/// @dev division or modulo by zero
uint256 internal constant DIVISION_BY_ZERO = 0x12;
/// @dev enum conversion error
uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
/// @dev invalid encoding in storage
uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
/// @dev empty array pop
uint256 internal constant EMPTY_ARRAY_POP = 0x31;
/// @dev array out of bounds access
uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
/// @dev resource error (too large allocation or too large array)
uint256 internal constant RESOURCE_ERROR = 0x41;
/// @dev calling invalid internal function
uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;
/// @dev Reverts with a panic code. Recommended to use with
/// the internal constants with predefined codes.
function panic(uint256 code) internal pure {
assembly ("memory-safe") {
mstore(0x00, 0x4e487b71)
mstore(0x20, code)
revert(0x1c, 0x24)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
/**
* @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
*/
function toUint(bool b) internal pure returns (uint256 u) {
assembly ("memory-safe") {
u := iszero(iszero(b))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @notice Strategy factory interface for clone deployment
/// @dev Extended to support multi-type factories and Universal Factory pattern
interface IStrategyFactory {
// ============ DEPLOYMENT ============
/**
* @notice Deploy a strategy clone with custom configuration
* @param config ABI-encoded configuration (format depends on factory implementation)
* @param owner Strategy owner address
* @return strategy Deployed strategy address
*/
function createStrategy(bytes calldata config, address owner) external returns (address strategy);
// ============ LEGACY FUNCTIONS (for backward compatibility) ============
/**
* @notice Get master implementation address
* @dev For single-type factories, returns the implementation
* @dev For multi-type factories, may return address(0) or primary implementation
* @return Implementation address
*/
function implementation() external view returns (address);
/**
* @notice Get estimated gas cost for strategy deployment
* @return Estimated gas cost
*/
function getStrategyCreationGas() external view returns (uint256);
// ============ MULTI-TYPE FACTORY SUPPORT (NEW) ============
/**
* @notice Get base protocol this factory serves
* @dev Used by Universal Factory pattern to identify factory type
* @return baseProtocol Base protocol identifier (e.g., bytes32("Shadow"))
*/
function getBaseProtocol() external view returns (bytes32 baseProtocol);
/**
* @notice Get all strategy types this factory can deploy
* @dev Used for enumeration and UI display
* @return strategyTypes Array of strategy type identifiers
*/
function getSupportedStrategyTypes() external view returns (bytes32[] memory strategyTypes);
}// SPDX-License-Identifier: MIT
// 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);
}{
"remappings": [
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"ControllerNotSet","type":"error"},{"inputs":[{"internalType":"string","name":"delayType","type":"string"}],"name":"DelayNotMet","type":"error"},{"inputs":[],"name":"EmptyArray","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"}],"name":"InsufficientLiquidity","type":"error"},{"inputs":[],"name":"InvalidAsset","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[{"internalType":"string","name":"reason","type":"string"}],"name":"InvalidInput","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidRoute","type":"error"},{"inputs":[],"name":"InvalidRouter","type":"error"},{"inputs":[{"internalType":"address","name":"strategy","type":"address"}],"name":"InvalidStrategy","type":"error"},{"inputs":[],"name":"LibraryNotRegistered","type":"error"},{"inputs":[],"name":"NativeTokenNotConfigured","type":"error"},{"inputs":[],"name":"NoRewardTokens","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"OnlyController","type":"error"},{"inputs":[],"name":"OnlyVault","type":"error"},{"inputs":[{"internalType":"string","name":"reason","type":"string"}],"name":"OperationFailed","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"RouterNotSet","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnauthorizedUpdate","type":"error"},{"inputs":[],"name":"VaultNotFound","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"reason","type":"bytes"}],"name":"EmergencyWithdrawFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousFeeRecipient","type":"address"},{"indexed":true,"internalType":"address","name":"newFeeRecipient","type":"address"}],"name":"FeeRecipientUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalPending","type":"uint256"}],"name":"FeesAccumulatedForTreasury","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"harvester","type":"address"},{"indexed":false,"internalType":"uint256","name":"yield","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalAssets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharePrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"HarvestCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"route","type":"bytes"}],"name":"NativeToLp0RouteSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"route","type":"bytes"}],"name":"NativeToLp1RouteSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"tokens","type":"address[]"},{"indexed":false,"internalType":"bytes[]","name":"routes","type":"bytes[]"}],"name":"RewardConfigurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"granted","type":"bool"}],"name":"RoleCacheUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"updateType","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"StrategyConfigUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"configType","type":"uint8"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":true,"internalType":"address","name":"gauge","type":"address"},{"indexed":false,"internalType":"address[]","name":"rewardTokens","type":"address[]"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"StrategyConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"},{"indexed":false,"internalType":"bool","name":"wasRegistered","type":"bool"}],"name":"StrategySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newStrategy","type":"address"}],"name":"StrategyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":true,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"string","name":"reason","type":"string"}],"name":"SwapFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"GUARDIAN_ROLE","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MASTER_ROLE","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROUTER_TYPE","outputs":[{"internalType":"enum RouterType","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STRATEGIST_ROLE","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_internalEmergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"_rewardRoutes","type":"bytes[]"},{"internalType":"bytes","name":"_nativeToLp0","type":"bytes"},{"internalType":"bytes","name":"_nativeToLp1","type":"bytes"}],"name":"applyRouteUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balanceOfAsset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balanceOfPool","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balanceOfWant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"beforeDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"callReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"claimPendingTreasuryFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"routeBytes","type":"bytes"}],"name":"decodeRoute","outputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"bool","name":"isStable","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"emergencyRecoverToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"executeSwap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gauge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEncodedRoutes","outputs":[{"internalType":"bytes[]","name":"_rewardRoutes","type":"bytes[]"},{"internalType":"bytes","name":"_nativeToLp0","type":"bytes"},{"internalType":"bytes","name":"_nativeToLp1","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProtocolType","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardConfiguration","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRouterType","outputs":[{"internalType":"enum RouterType","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getShadowAddresses","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWrappedNativeToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"harvester","type":"address"}],"name":"harvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"initData","type":"bytes"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isRewardToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastHarvest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpToken0","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpToken1","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nativeToLp0","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nativeToLp1","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"panic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"pendingTreasuryFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"protocolType","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"retireStrat","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardTokenRoutes","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"routers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newFeeRecipient","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_shadowToken","type":"address"},{"internalType":"address","name":"_xShadowToken","type":"address"}],"name":"setShadowAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_slippageTolerance","type":"uint256"}],"name":"setSlippageTolerance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"}],"name":"setVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shadowToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"slippageTolerance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRewardsAvailable","outputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"_rewardRoutes","type":"bytes[]"},{"internalType":"bytes","name":"_nativeToLp0","type":"bytes"},{"internalType":"bytes","name":"_nativeToLp1","type":"bytes"}],"name":"validateRoutes","outputs":[{"internalType":"bool","name":"valid","type":"bool"},{"internalType":"string","name":"reason","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"want","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"xShadowToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
6080806040523460e15760018055600160ff19600a541617600a557ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c1660d2576002600160401b03196001600160401b03821601606d575b60405161510990816100e68239f35b6001600160401b0319166001600160401b039081177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005581527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80605e565b63f92ee8a960e01b5f5260045ffd5b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c806301e1d1141461047857806306fdde031461047357806307a2d13a146103745780630a28a477146103745780630e5c011e1461046e5780631158808614610469578063117da1ee14610464578063193b47281461045f5780631d9478b61461045a5780631f1fcd511461043257806322be3de11461045557806324735bdf1461045057806324ea54f41461044b5780632e1a7d4d146104465780633018205f14610441578063313ce5671461043c57806337bdd2041461043757806338d52e0f146104325780633f4ba83a1461042d578063402d267d146103a1578063439fab911461042857806346904840146104235780634700d3051461041e5780634cdad506146103745780634e9c111814610419578063573fef0a14610414578063577fe7b41461040f5780635c975abb1461040a5780635ee167c01461040557806365daa5cd146103b55780636817031b146104005780636de813f1146103fb57806370a0823114610388578063785dbc3a146103f6578063797bf343146103ab5780637bb7bed1146103f15780638456cb59146103ec578063877562b6146103e757806388cc58e4146103a65780638ee2f35b1461034c57806393288637146103e257806397fd323d146103dd578063985f61a1146103d85780639e591bc6146103d3578063a22d45b4146103ce578063a378a324146103c9578063a6f19c84146103c4578063b3d7f6b914610374578063b5fd73f8146103bf578063b6274cba146103ba578063bd8d4bd8146103b5578063c1176461146103b0578063c1a3d44c146103ab578063c45a0155146103a6578063c63d75b6146103a1578063c6e6f59214610374578063ce96cb771461039c578063cfd9eb0d14610397578063d03153aa14610392578063d0e30db01461038d578063d905777e14610388578063dc22486314610383578063e74b981b1461037e578063ea82eb9e14610379578063ef8b30f714610374578063f0ac28421461036f578063f0b63beb1461036a578063f1a392da14610365578063f382331f14610360578063fa9858af1461035b578063fb61778714610356578063fbfa77cf14610351578063ff7dcd5a1461034c5763ffc5d97a14610347575f80fd5b611faf565b611845565b611f87565b611ec9565b611dd5565b611dad565b611d90565b611d55565b611d22565b610517565b611d07565b611c1b565b611c01565b6115d6565b611bd1565b611bb4565b611b0d565b611ae7565b610ee8565b61181d565b6116f7565b611aaa565b6112d2565b611a48565b611a08565b6119dc565b6119c1565b61191d565b6118fb565b611899565b61187f565b611860565b6117f5565b61176b565b611711565b6116af565b61149b565b6112ef565b6112aa565b611289565b6111f2565b6111e0565b611186565b6110d6565b6110aa565b610f4d565b610e3f565b6108c2565b610e24565b610b5e565b610b36565b610a47565b610a2c565b6109c6565b6108ea565b610896565b61085a565b610697565b61067d565b610546565b6104d1565b61048b565b5f91031261048757565b5f80fd5b34610487575f3660031901126104875760206104a5611ffd565b604051908152f35b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b34610487575f36600319011261048757610513601354604051906020820152602081526104ff604082610920565b6040519182916020835260208301906104ad565b0390f35b34610487576020366003190112610487576020600435604051908152f35b6001600160a01b0381160361048757565b346104875760203660031901126104875760043561056381610535565b61056b613204565b610573613224565b61057b61326d565b8015159081610668575b50610638576105a3610595612ad8565b61059d6133c2565b90611feb565b906105ac612019565b506105b5613432565b506105be613554565b9182156105fb576105e26105dd6105d86105e795856136d9565b61381a565b613878565b61388a565b6105f042600855565b6105f960018055565b005b604051630c0092c960e21b81526020600482015260146024820152734e6f207265776172647320617661696c61626c6560601b6044820152606490fd5b60405163315c91ed60e21b81526020600482015260076024820152661a185c9d995cdd60ca1b6044820152606490fd5b6106759150600854611feb565b42105f610585565b34610487575f3660031901126104875760206104a56133c2565b3461048757602036600319011261048757600354600435906001600160a01b0316330361078a576103e88111610744575f8051602061507483398151915261073f610725610733846106e95f96600955565b604051928391602083019190604083526011604084015270736c697070616765546f6c6572616e636560781b6060840152602060808401930152565b03601f198101835282610920565b60405191829182610e13565b0390a2005b60405163d647364f60e01b815260206004820152601b60248201527f536c69707061676520746f6f206869676820286d6178203130252900000000006044820152606490fd5b6282b42960e81b5f5260045ffd5b9181601f84011215610487578235916001600160401b038311610487576020838186019501011161048757565b606060031982011261048757600435916001600160401b0383116104875781602384011215610487578260040135926001600160401b038411610487578260248560051b830101116104875760240192916024356001600160401b038111610487578161083491600401610798565b92909291604435906001600160401b0382116104875761085691600401610798565b9091565b346104875761087761086b366107c5565b94939093929192612211565b90610513604051928392151583526040602084015260408301906104ad565b34610487575f3660031901126104875760206108b061230c565b6040516001600160a01b039091168152f35b34610487575f366003190112610487576004546040516001600160a01b039091168152602090f35b34610487575f36600319011261048757602060ff601454166040519015158152f35b634e487b7160e01b5f52604160045260245ffd5b90601f801991011681019081106001600160401b0382111761094157604052565b61090c565b6040519061095560c083610920565b565b6001600160401b03811161094157601f01601f191660200190565b92919261097e82610957565b9161098c6040519384610920565b829481845281830111610487578281602093845f960137010152565b9080601f83011215610487578160206109c393359101610972565b90565b34610487576020366003190112610487576004356001600160401b03811161048757610a0a6109fb60609236906004016109a8565b6020808251830101910161236f565b604080516001600160a01b039485168152939092166020840152151590820152f35b34610487575f36600319011261048757602060405160028152f35b3461048757602036600319011261048757600435610a63613204565b60025481906001600160a01b03163303610b2757610a7f612ad8565b828110610abc575b6004546105f0908390610aaa906001600160a01b03165b6001600160a01b031690565b6002546001600160a01b031690613a84565b610ac9610ace91846123a0565b613a2f565b610ad6612ad8565b8281108080610b0f575b610af6576105f0935015610a875790505f610a87565b63a17e11d560e01b5f526004849052602482905260445ffd5b50610b22610b1e60ff5f541690565b1590565b610ae0565b638d1af8bd60e01b5f5260045ffd5b34610487575f366003190112610487576003546040516001600160a01b039091168152602090f35b34610487575f366003190112610487576004805460405163313ce56760e01b81529160209183919082906001600160a01b03165afa8015610bee575f90610bb0575b60405160ff919091168152602090f35b506020813d602011610be6575b81610bca60209383610920565b81010312610487575160ff811681036104875761051390610ba0565b3d9150610bbd565b612206565b90600182811c92168015610c21575b6020831014610c0d57565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610c02565b604051905f8260125491610c3e83610bf3565b8083529260018116908115610cc15750600114610c62575b61095592500383610920565b5060125f90815290917fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec34445b818310610ca557505090602061095592820101610c56565b6020919350806001915483858901015201910190918492610c8d565b6020925061095594915060ff191682840152151560051b820101610c56565b604051905f8260115491610cf383610bf3565b8083529260018116908115610cc15750600114610d165761095592500383610920565b5060115f90815290917f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c685b818310610d5957505090602061095592820101610c56565b6020919350806001915483858901015201910190918492610d41565b9060405191825f825492610d8884610bf3565b8084529360018116908115610df15750600114610dad575b5061095592500383610920565b90505f9291925260205f20905f915b818310610dd5575050906020610955928201015f610da0565b6020919350806001915483858901015201910190918492610dbc565b90506020925061095594915060ff191682840152151560051b8201015f610da0565b9060206109c39281815201906104ad565b34610487575f366003190112610487576105136104ff610c2b565b34610487575f366003190112610487576003546001600160a01b03168015610ed9576040516379b60be960e01b81523060048201526002602482015233604482015290602090829060649082905afa908115610bee575f91610eaa575b501561078a576105f9613ac5565b610ecc915060203d602011610ed2575b610ec48183610920565b8101906123ad565b5f610e9c565b503d610eba565b632110f99160e01b5f5260045ffd5b3461048757602036600319011261048757610f04600435610535565b600a5460ff1615610f1b5760205f19604051908152f35b60205f6104a5565b602060031982011261048757600435906001600160401b0382116104875761085691600401610798565b3461048757610f5b36610f23565b5f805160206150b48339815191525491906001600160401b03610f8d60ff604086901c1615946001600160401b031690565b16801590816110a2575b6001149081611098575b15908161108f575b5061108057610fec9183610fe360016001600160401b03195f805160206150b48339815191525416175f805160206150b483398151915255565b61104b57612620565b610ff257005b61101c60ff60401b195f805160206150b483398151915254165f805160206150b483398151915255565b604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1005b61107b600160401b60ff60401b195f805160206150b48339815191525416175f805160206150b483398151915255565b612620565b63f92ee8a960e01b5f5260045ffd5b9050155f610fa9565b303b159150610fa1565b849150610f97565b34610487575f36600319011261048757600a5460405160089190911c6001600160a01b03168152602090f35b34610487575f366003190112610487576002546001600160a01b0316330361078a57611100613224565b600160ff195f5416175f557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a16105f9614376565b634e487b7160e01b5f52603260045260245ffd5b600c5481101561116957600c5f5260205f2001905f90565b61113d565b6010548110156111695760105f5260205f2001905f90565b34610487576020366003190112610487576004356005548110156104875760055f527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db001546040516001600160a01b039091168152602090f35b34610487575f36600319011261048757005b346104875760203660031901126104875760043561120f81610535565b6003546001600160a01b03168015610ed9576040516379b60be960e01b81523060048201525f602482015233604482015290602090829060649082905afa908115610bee575f9161126a575b501561078a576105f990612902565b611283915060203d602011610ed257610ec48183610920565b5f61125b565b34610487575f36600319011261048757602060ff5f54166040519015158152f35b34610487575f36600319011261048757600e546040516001600160a01b039091168152602090f35b34610487575f366003190112610487576020600754604051908152f35b346104875760203660031901126104875760043561130c81610535565b6002546001600160a01b031680151590816113fd575b506113ee57600280546001600160a01b0319166001600160a01b0383161790556001600160a01b031680156113db5760206004916040519283809263f77c479160e01b82525afa5f91816113aa575b506113895750600380546001600160a01b0319169055005b600380546001600160a01b0319166001600160a01b03909216919091179055005b6113cd91925060203d6020116113d4575b6113c58183610920565b8101906122f7565b905f611371565b503d6113bb565b50600380546001600160a01b0319169055005b634f1f214760e01b5f5260045ffd5b6001600160a01b031690503314155f611322565b90602080835192838152019201905f5b81811061142e5750505090565b82516001600160a01b0316845260209384019390920191600101611421565b9061146090604083526040830190611411565b906020818303910152602080835192838152019201905f5b8181106114855750505090565b8251845260209384019390920191600101611478565b34610487575f366003190112610487576014546114c590610a9e9060081c6001600160a01b031681565b604051632000ed8560e21b81525f81600481855afa908115610bee575f916115b4575b506114f38151612a15565b915f5b82518110156115a35780602061151f61151261154e9487612a54565b516001600160a01b031690565b60405163211dc32d60e01b81526001600160a01b03909116600482015230602482015292839081906044820190565b0381865afa8015610bee576001925f91611575575b5061156e8287612a54565b52016114f6565b611596915060203d811161159c575b61158e8183610920565b810190612a68565b5f611563565b503d611584565b50506105136040519283928361144d565b6115d091503d805f833e6115c88183610920565b8101906129f0565b5f6114e8565b34610487576020366003190112610487576004356115f381610535565b6002546040516370a0823160e01b81526001600160a01b0392831660048201529160209183916024918391165afa8015610bee576020915f9161163a575b50604051908152f35b6116519150823d841161159c5761158e8183610920565b5f611631565b9080602083519182815201916020808360051b8301019401925f915b83831061168257505050505090565b90919293946020806116a0600193601f1986820301875289516104ad565b97019301930191939290611673565b34610487575f366003190112610487576116e96116ca612019565b6105136116d5612a77565b604051938493604085526040850190611411565b908382036020850152611657565b34610487575f3660031901126104875760206104a5612ad8565b3461048757602036600319011261048757600435600c5481101561048757600c5f527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c701546040516001600160a01b039091168152602090f35b34610487575f366003190112610487576003546001600160a01b03168015610ed9576040516379b60be960e01b81523060048201526002602482015233604482015290602090829060649082905afa908115610bee575f916117d6575b501561078a576105f9614337565b6117ef915060203d602011610ed257610ec48183610920565b5f6117c8565b34610487575f36600319011261048757600f546040516001600160a01b039091168152602090f35b34610487575f366003190112610487576006546040516001600160a01b039091168152602090f35b34610487575f366003190112610487576040515f8152602090f35b34610487575f3660031901126104875730330361078a576105f9614376565b34610487575f3660031901126104875760206104a5612d53565b34610487576118a736610f23565b5050604051630c0092c960e21b815260206004820152602360248201527f5374726174656779206d75737420696d706c656d656e7420657865637574655360448201526207761760ec1b6064820152608490fd5b34610487575f36600319011261048757602060ff600a54166040519015158152f35b346104875760403660031901126104875760043561193a81610535565b60243561194681610535565b6003546001600160a01b03168015610ed9576040516379b60be960e01b81523060048201526001602482015233604482015290602090829060649082905afa908115610bee575f916119a2575b501561078a576105f991612f25565b6119bb915060203d602011610ed257610ec48183610920565b5f611993565b34610487575f36600319011261048757602060405160018152f35b34610487575f3660031901126104875760145460405160089190911c6001600160a01b03168152602090f35b3461048757602036600319011261048757600435611a2581610535565b60018060a01b03165f52600d602052602060ff60405f2054166040519015158152f35b34610487575f36600319011261048757611a8e611a63612a77565b610513611a6e610ce0565b611a9c611a79610c2b565b91604051958695606087526060870190611657565b9085820360208701526104ad565b9083820360408501526104ad565b3461048757602036600319011261048757600435601054811015610487576104ff6105139160105f525f8051602061509483398151915201610d75565b3461048757602036600319011261048757611b03600435610535565b60206104a5611ffd565b3461048757606036600319011261048757600435611b2a81610535565b604435602435611b3982610535565b6003546001600160a01b03168015610ed9576040516379b60be960e01b81523060048201526002602482015233604482015290602090829060649082905afa908115610bee575f91611b95575b501561078a576105f992612fce565b611bae915060203d602011610ed257610ec48183610920565b5f611b86565b34610487575f366003190112610487576020600954604051908152f35b34610487575f36600319011261048757611be9613224565b611bf1612ad8565b80611bf857005b6105f99061437e565b34610487575f3660031901126104875760206040515f8152f35b3461048757602036600319011261048757600435611c3881610535565b600254611c4d906001600160a01b0316610a9e565b3303610b27576001600160a01b03811615611cf857600a8054610100600160a81b031916600883901b610100600160a81b03161790555f905f805160206150748339815191529061073f90600a546107339060081c6001600160a01b031660408051606060208201819052600c60808301526b199959549958da5c1a595b9d60a21b60a08301526001600160a01b039384169282019290925293909116908301528160c08101610725565b63d92e233d60e01b5f5260045ffd5b34610487575f366003190112610487576105136104ff610ce0565b34610487575f36600319011261048757601554601654604080516001600160a01b03938416815292909116602083015290f35b3461048757602036600319011261048757600435611d7281610535565b60018060a01b03165f52600b602052602060405f2054604051908152f35b34610487575f366003190112610487576020600854604051908152f35b34610487575f366003190112610487576016546040516001600160a01b039091168152602090f35b3461048757611de3366107c5565b60035494959490939192906001600160a01b03163303611eba57611e06866123ee565b94611e146040519687610920565b86865260208601908760051b8101903682116104875780925b828410611e8e57505060015f8051602061507483398151915261073f6107256107338c611e738d8d611e6d8e611e658f8f3691610972565b923691610972565b9161453f565b60408051602081019290925242908201529182906060820190565b83356001600160401b03811161048757602091611eaf8392369086016109a8565b815201930192611e2d565b635990781360e01b5f5260045ffd5b34610487575f36600319011261048757600254611eee906001600160a01b0316610a9e565b33141580611f75575b61078a57303b1561048757604051639328863760e01b81525f8160048183305af1611f5b575b50611f26612ad8565b80611f3b575b6105f960ff19600a5416600a55565b600454611f559190610aaa906001600160a01b0316610a9e565b5f611f2c565b80611f695f611f6f93610920565b8061047d565b5f611f1d565b50611f82610b1e33614626565b611ef7565b34610487575f366003190112610487576002546040516001600160a01b039091168152602090f35b34610487575f366003190112610487576015546040516001600160a01b039091168152602090f35b634e487b7160e01b5f52601160045260245ffd5b91908201809211611ff857565b611fd7565b612005612ad8565b61200d6133c2565b8101809111611ff85790565b60405190600c548083528260208101600c5f5260205f20925f5b81811061204857505061095592500383610920565b84546001600160a01b0316835260019485019487945060209093019201612033565b5190811515820361048757565b81601f820112156104875760208151910161209182610957565b9261209f6040519485610920565b8284528282011161048757815f926020928386015e8301015290565b919091604081840312610487576120d18161206a565b9260208201516001600160401b038111610487576109c39201612077565b908060209392818452848401375f828201840152601f01601f1916010190565b9699989795939192908360c0890160c08a525260e0880160e08560051b8a010194825f90601e19813603015b8383106121ae57505050505050869461219e9461216e8561218e9561217c956109559d9c60a09c990360208c01526120ef565b9187830360408901526120ef565b6001600160a01b039099166060850152565b6001600160a01b03166080830152565b6001600160a01b03909216910152565b90919293949760df198d820301865288358281121561048757830190602082359201916001600160401b038111610487578036038313610487576121f860209283926001956120ef565b9a019601949301919061213b565b6040513d5f823e3d90fd5b9395929492939192916001600160a01b0361222a6139a8565b169283156122b2575f95969761227b9161224261230c565b600e546001600160a01b0316600f549092906001600160a01b0316936040519c8d9a8b998a9963436b3d9960e01b8b5260048b0161210f565b03915afa918215610bee575f905f9361229357509190565b90506108569192503d805f833e6122aa8183610920565b8101906120bb565b50505050509150505f906040516122ca604082610920565b601d81527f526f75746572206c696272617279206e6f742072656769737465726564000000602082015290565b9081602091031261048757516109c381610535565b6003546001600160a01b03168061232257505f90565b6020600491604051928380926317fcb39b60e01b82525afa908115610bee575f9161234b575090565b6109c3915060203d6020116113d4576113c58183610920565b519061095582610535565b9081606091031261048757805161238581610535565b916109c36040602084015161239981610535565b930161206a565b91908203918211611ff857565b90816020910312610487576109c39061206a565b9190916040818403126104875780359260208201356001600160401b038111610487576109c392016109a8565b6001600160401b0381116109415760051b60200190565b9080601f8301121561048757815161241c816123ee565b9261242a6040519485610920565b81845260208085019260051b82010192831161048757602001905b8282106124525750505090565b60208091835161246181610535565b815201910190612445565b9080601f83011215610487578151612483816123ee565b926124916040519485610920565b81845260208085019260051b820101918383116104875760208201905b8382106124bd57505050505090565b81516001600160401b038111610487576020916124df87848094880101612077565b8152019101906124ae565b61012081830312610487576124fe81612364565b9260208201516001600160401b038111610487578361251e918401612077565b9260408301516001600160401b038111610487578161253e918501612405565b9260608101516001600160401b038111610487578261255e91830161246c565b9260808201516001600160401b038111610487578361257e918401612077565b9260a0830151906001600160401b0382116104875761259e918401612077565b916125ab60c08201612364565b916109c36101006125be60e08501612364565b9301612364565b90602082549182815201915f5260205f20905f5b8181106125e65750505090565b82546001600160a01b03168452602090930192600192830192016125d9565b919060408352602061261b60408501600c6125c5565b930152565b61263090612642928101906123c1565b602080829493945183010191016124ea565b509592939660018060a0979394971b03169760405192633a4b66f160e01b84526020846004818d5afa938415610bee575f946128de575b50604051634256f5e760e01b815293949293926020846004818e5afa938415610bee575f946128bd575b50604051632b18028f60e21b8152926020846004816001600160a01b0389165afa918215610bee5761275396612736955f94612896575b506126f16126f8949560018060a01b031692613b11565b9089613c35565b60148054610100600160a81b03191660088c901b610100600160a81b031617905560018060a01b03166001600160601b0360a01b6015541617601555565b60018060a01b03166001600160601b0360a01b6016541617601655565b604051630dfe168160e01b81526001600160a01b03919091169490602081600481895afa8015610bee576127a6915f91612877575b5060018060a01b03166001600160601b0360a01b600e541617600e55565b60405163d21220a760e01b815293602085600481895afa908115610bee576127f46128169261281b975f91612858575b5060018060a01b03166001600160601b0360a01b600f541617600f55565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6141c3565b6128236142ab565b5f7fa8aee87aedb58bbffb10d4e26201cdff2b8b590739a576965328e0aad7838c2e604051806128534282612605565b0390a4565b612871915060203d6020116113d4576113c58183610920565b5f6127d6565b612890915060203d6020116113d4576113c58183610920565b5f612788565b6126f894506128b66126f19160203d6020116113d4576113c58183610920565b94506126da565b6128d791945060203d6020116113d4576113c58183610920565b925f6126a3565b60049394506128fb9060203d6020116113d4576113c58183610920565b9392612679565b6001600160a01b0381165f818152600b60205260409020549182156129b85782610733826129616002965f80516020615074833981519152965f6129596129b39860018060a01b03165f52600b60205260405f2090565b553390613a84565b6040805160606020820181905260126080830152711d1c99585cdd5c9e51995950db185a5b595960721b60a08301526001600160a01b0390931691810191909152908101929092528160c08101610725565b0390a2565b604051630c0092c960e21b815260206004820152600f60248201526e4e6f2070656e64696e67206665657360881b6044820152606490fd5b906020828203126104875781516001600160401b038111610487576109c39201612405565b90612a1f826123ee565b612a2c6040519182610920565b8281528092612a3d601f19916123ee565b0190602036910137565b8051156111695760200190565b80518210156111695760209160051b010190565b90816020910312610487575190565b60105490612a84826123ee565b91612a926040519384610920565b80835260105f9081525f80516020615094833981519152602085015b838310612abb5750505050565b600160208192612aca85610d75565b815201920192019190612aae565b6024602060018060a01b0360045416604051928380926370a0823160e01b82523060048301525afa908115610bee575f91612b11575090565b6109c3915060203d60201161159c5761158e8183610920565b9080601f83011215610487578151612b41816123ee565b92612b4f6040519485610920565b81845260208085019260051b82010192831161048757602001905b828210612b775750505090565b8151815260209182019101612b6a565b9190916040818403126104875780516001600160401b0381116104875783612bb0918301612405565b9260208201516001600160401b038111610487576109c39201612b2a565b519061ffff8216820361048757565b9080601f83011215610487578151612bf4816123ee565b92612c026040519485610920565b81845260208085019260051b82010192831161048757602001905b828210612c2a5750505090565b8151815260209182019101612c1d565b602081830312610487578051906001600160401b038211610487570160c08183031261048757612c68610946565b91612c7282612bce565b835260208201516001600160401b0381116104875781612c93918401612405565b602084015260408201516001600160401b0381116104875781612cb7918401612b2a565b60408401526060820151916001600160401b03831161048757612ce160a092612cf6948301612bdd565b6060850152608081015160808501520161206a565b60a082015290565b90670de0b6b3a7640000820291808304670de0b6b3a76400001490151715611ff857565b81810292918115918404141715611ff857565b8115612d3f570490565b634e487b7160e01b5f52601260045260245ffd5b604051636de813f160e01b81525f81600481305afa8015610bee575f915f91612f01575b50815115612e3657612d8761230c565b5f926001600160a01b0390911690835b8151811015612ddf5782612db1610a9e6115128486612a54565b14612dbf575b600101612d97565b93612dd7600191612dd08787612a54565b5190611feb565b949050612db7565b505050508015612efc576003546001600160a01b0316908115612e3657600254604051632138c36160e11b81526001600160a01b039091166004820152915f90839060249082905afa5f9281612ed8575b50612e3c575b50505f90565b612e51612e5f91612e4b6132da565b90612d22565b612e5961334e565b90612d35565b5f5b602083015151811015612ece577eabf5fabef4a428c85b26a0d8174a974f9b7ba3a28d69a208a013e37f688c2f612e9c826060860151612a54565b5114612eaa57600101612e61565b90612ebf612ec69260406109c3950151612a54565b5190612d22565b6103e8900490565b5050505f80612e36565b612ef59193503d805f833e612eed8183610920565b810190612c3a565b915f612e30565b505f90565b9050612f1f91503d805f833e612f178183610920565b810190612b87565b5f612d77565b6001600160a01b03169081158015612fbd575b611cf857612f70916001600160601b0360a01b601554161760155560018060a01b03166001600160601b0360a01b6016541617601655565b60045460145460405160089190911c6001600160a01b039081169216906001907fa8aee87aedb58bbffb10d4e26201cdff2b8b590739a576965328e0aad7838c2e90806128534282612605565b506001600160a01b03811615612f38565b600454909190612fe6906001600160a01b0316610a9e565b6001600160a01b038316919082146131be576001600160a01b03841615613178576040516370a0823160e01b815230600482015290602082602481865afa918215610bee575f92613157575b50811561311a57806131145750805b81116130d557610733836107258661308c856003996129b3986130825f805160206150748339815191529b60018060a01b03165f52600b60205260405f2090565b546130b857613a84565b604080516001600160a01b03948516602082015290810195909552909116606084015282906080820190565b6001600160a01b0387165f908152600b6020526040812055613a84565b60405163d647364f60e01b8152602060048201526016602482015275416d6f756e7420657863656564732062616c616e636560501b6044820152606490fd5b90613041565b604051630c0092c960e21b81526020600482015260146024820152732737903a37b5b2b739903a37903932b1b7bb32b960611b6044820152606490fd5b61317191925060203d60201161159c5761158e8183610920565b905f613032565b60405163d647364f60e01b815260206004820152601960248201527f496e76616c696420726563697069656e742061646472657373000000000000006044820152606490fd5b60405163d647364f60e01b815260206004820152601960248201527f43616e6e6f74207265636f766572206d61696e206173736574000000000000006044820152606490fd5b600260015414613215576002600155565b633ee5aeb560e01b5f5260045ffd5b60ff5f541661322f57565b63d93c066560e01b5f5260045ffd5b3d15613268573d9061324f82610957565b9161325d6040519384610920565b82523d5f602084013e565b606090565b6003546001600160a01b03168015612efc575f80916040516020810190630783fad960e41b8252600481526132a3602482610920565b51915afa6132af61323e565b90806132ce575b15612efc57806020806109c393518301019101612a68565b506020815110156132b6565b6003546001600160a01b0316801561333b575f80916040516020810190637772f9c760e01b825260048152613310602482610920565b51915afa61331c61323e565b9080613342575b1561333b57806020806109c393518301019101612a68565b5061012c90565b50602081511015613323565b6003546001600160a01b031680156133af575f8091604051602081019063e1f1c4a760e01b825260048152613384602482610920565b51915afa61339061323e565b90806133b6575b156133af57806020806109c393518301019101612a68565b5061271090565b50602081511015613397565b6014546040516370a0823160e01b8152306004820152906020908290602490829060081c6001600160a01b03165afa908115610bee575f91612b11575090565b5f198114611ff85760010190565b6001600160a01b0390911681526040602082018190526109c392910190611411565b600c546016546001600160a01b031690811561354c5760ff60015b1661346061345b8284611feb565b612a15565b9260015f9214613535575b505f5b8281106134e65750506014546134929150610a9e9060081c6001600160a01b031681565b803b156104875760405163169f6dd360e01b8152915f9183918290849082906134bf903060048401613410565b03925af18015610bee576134d257505f90565b80611f695f6134e093610920565b5f612efc565b8061352f61350d6134f8600194611151565b905460039190911b1c6001600160a01b031690565b61352061351986613402565b9588612a54565b6001600160a01b039091169052565b0161346e565b905061354660019161352085612a47565b5f61346b565b60ff5f61344d565b6001600160a01b0361356461230c565b6040516370a0823160e01b8152306004820152911691602082602481865afa918215610bee575f926136b8575b505f5b600c54811015613652576135c16135aa82611151565b90546001600160a01b039260039290921b1c821690565b1690848214613649576040516370a0823160e01b815230600482015291602090839060249082905afa8015610bee576001925f9161362b575b5080156136255761361d906136176136118461116e565b50610d75565b90614725565b505b01613594565b5061361f565b613643915060203d811161159c5761158e8183610920565b5f6135fa565b6001915061361f565b506040516370a0823160e01b81523060048201529092909190602090839060249082905afa918215610bee575f92613697575b5080821115612e36576109c3916123a0565b6136b191925060203d60201161159c5761158e8183610920565b905f613685565b6136d291925060203d60201161159c5761158e8183610920565b905f613591565b8115612e36576003546001600160a01b0316801561381557600254604051632138c36160e11b81526001600160a01b039091166004820152905f90829060249082905afa8015610bee57613763915f916137fb575b508261373861230c565b946137416132da565b61374961334e565b600a54909290889060081c6001600160a01b031695614962565b9091826137ae575b5050506001600160a01b03168015612efc576040516370a0823160e01b815230600482015290602090829060249082905afa908115610bee575f91612b11575090565b604080516001600160a01b03909216602083015281019290925260608201526002905f80516020615074833981519152906137f0906107338160808101610725565b0390a25f808061376b565b61380f91503d805f833e612eed8183610920565b5f61372e565b505090565b8015612efc5761383161382b612ad8565b91614a87565b8115158061386f575b61385e575b5050613849612ad8565b9080821115612e36578103908111611ff85790565b61386791614b8d565b505f8061383f565b5080151561383a565b8015613887576109559061437e565b50565b90600490613899610595612ad8565b92808411156139a0576138ac90846123a0565b905b6138b88483614cf0565b6002546020906138d290610a9e906001600160a01b031681565b6040516318160ddd60e01b815294859182905afa918215610bee577f5d8077a9c609196570b2ccce581be21d954ce035f63805a111bd59a8853f9e25935f9361397b575b506129b390831561396c576139338461392e88612cfe565b612d35565b935b6040805192835260208301979097529581019390935260608301949094524260808301526001600160a01b031692819060a0820190565b670de0b6b3a764000093613935565b6129b39193506139999060203d60201161159c5761158e8183610920565b9290613916565b505f906138ae565b6003545f91906001600160a01b03168015613a29576040516317da19fd60e31b602082019081525f602483018190529283929091906139ea8160448101610725565b51915afa6139f661323e565b9080613a1d575b613a045750565b6109c391925080602080610a9e935183010191016122f7565b506020815110156139fd565b505f9150565b80613a375750565b60145460081c6001600160a01b031690813b15610487575f91602483926040519485938492632e1a7d4d60e01b845260048401525af18015610bee57613a7a5750565b5f61095591610920565b60405163a9059cbb60e01b60208201526001600160a01b0392909216602483015260448083019390935291815261095591613ac0606483610920565b614db5565b5f5460ff811615613b025760ff19165f557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1565b638dfc202b60e01b5f5260045ffd5b805115612efc576020015190565b818110613b2a575050565b5f8155600101613b1f565b8051906001600160401b03821161094157600160401b82116109415760209060055483600555808410613b99575b500160055f5260205f205f5b838110613b7c5750505050565b82516001600160a01b031682820155602090920191600101613b6f565b613baf9060055f5284845f209182019101613b1f565b5f613b63565b8051906001600160401b03821161094157600160401b821161094157602090600c5483600c55808410613c19575b5001600c5f5260205f205f5b838110613bfc5750505050565b82516001600160a01b031682820155602090920191600101613bef565b613c2f90600c5f5284845f209182019101613b1f565b5f613be3565b6004549095919491939192906001600160a01b0316613da2576001600160a01b03861615613d9357845115613c9b576001600160a01b03821615613d41575f5b8551811015613caa57613c8e610a9e6115128389612a54565b15613c9b57600101613c75565b63466d7fef60e01b5f5260045ffd5b50613ce690613ce161095596613cdc613d1896979960018060a01b03166001600160601b0360a01b6004541617600455565b613b35565b601355565b613cf161012c600955565b600a8054610100600160a81b03191660089290921b610100600160a81b0316919091179055565b613d2a600160ff19600a541617600a55565b600680546001600160a01b03191633179055600755565b60405163d647364f60e01b8152602060048201526024808201527f46656520726563697069656e742063616e6e6f74206265207a65726f206164646044820152637265737360e01b6064820152608490fd5b636448d6e960e11b5f5260045ffd5b62dc149f60e41b5f5260045ffd5b9190601f8111613dbf57505050565b610955925f5260205f20906020601f840160051c83019310613de9575b601f0160051c0190613b1f565b9091508190613ddc565b9081516001600160401b03811161094157613e1a81613e13601154610bf3565b6011613db0565b602092601f8211600114613e5a57613e4a929382915f92613e4f575b50508160011b915f199060031b1c19161790565b601155565b015190505f80613e36565b60115f52601f198216937f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c68915f5b868110613ebe5750836001959610613ea6575b505050811b01601155565b01515f1960f88460031b161c191690555f8080613e9b565b91926020600181928685015181550194019201613e88565b9081516001600160401b03811161094157613efd81613ef6601254610bf3565b6012613db0565b602092601f8211600114613f3157613f2c929382915f92613e4f5750508160011b915f199060031b1c19161790565b601255565b60125f52601f198216937fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec3444915f5b868110613f955750836001959610613f7d575b505050811b01601255565b01515f1960f88460031b161c191690555f8080613f72565b91926020600181928685015181550194019201613f5f565b91909182516001600160401b03811161094157613fd481613fce8454610bf3565b84613db0565b6020601f82116001146140075781906140039394955f92613e4f5750508160011b915f199060031b1c19161790565b9055565b601f1982169061401a845f5260205f2090565b915f5b8181106140545750958360019596971061403c575b505050811b019055565b01515f1960f88460031b161c191690555f8080614032565b9192602060018192868b01518155019401920161401d565b805190600160401b821161094157601054826010558083106140cc575b5060105f526020015f805160206150948339815191525f915b8383106140af5750505050565b60016020826140c083945186613fad565b019201920191906140a2565b60105f525f805160206150948339815191529081019083015b8181106140f25750614089565b806140ff60019254610bf3565b8061410c575b50016140e5565b601f8111831461412157505f81555b5f614105565b6141439083601f614135855f5260205f2090565b920160051c82019101613b1f565b5f818152602081208183555561411b565b94936141925f9461418460809561417661261b9660a08c5260a08c0190611411565b908a820360208c0152611657565b9088820360408a01526104ad565b9086820360608801526104ad565b949361419260019461418460809561417661261b9660a08c5260a08c0190611411565b9290919280511561429c576001600160a01b036141de61230c565b161561428d576141ed81614e0d565b935f5b855181101561423b578061423561422861420f6115126001958b612a54565b6001600160a01b03165f908152600d6020526040902090565b805460ff19166001179055565b016141f0565b50906107335f8051602061507483398151915293956107256129b3946001976142638661406c565b61426c84613bb5565b61427581613df3565b61427e82613ed6565b60405195869460208601614154565b63158dcda960e01b5f5260045ffd5b63521299a960e01b5f5260045ffd5b6004546014546142cc916001600160a01b0360089290921c82169116614e62565b6142d4614f6b565b6001600160a01b0381166142e55750565b600e546142fc9082906001600160a01b0316614e62565b600f546143139082906001600160a01b0316614e62565b6001600160a01b0361432361230c565b16908161432e575050565b61095591614e62565b61433f613224565b600160ff195f5416175f557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1565b613a2f6133c2565b80156138875760048054601454604051636eb1769f60e11b8152309381019390935260081c6001600160a01b039081166024840181905291169190602082604481865afa928315610bee5784925f9461451e575b5082841061443d575b50506014546143f99250610a9e915060081c6001600160a01b031681565b803b156104875760405163b6b55f2560e01b815260048101929092525f908290602490829084905af18015610bee5761442f5750565b80611f695f61095593610920565b61444a9361445357614f2e565b5f8181806143db565b60405163095ea7b360e01b60208083019182526001600160a01b03851660248401525f60448085018290528452909161448d606485610920565b83519082865af15f51903d816144fb575b501590505b6144ae575b50614f2e565b60405163095ea7b360e01b60208201526001600160a01b03841660248201525f60448201526144f591906144ef906144e98160648101610725565b84614db5565b82614db5565b5f6144a8565b1515905061451257506144a3823b15155b5f61449e565b60016144a3911461450c565b61453891945060203d60201161159c5761158e8183610920565b925f6143d2565b9283511561429c5761455084614e0d565b935f5b600c54811015614582578061457c61457261420f6134f8600195611151565b805460ff19169055565b01614553565b509091925f5b85518110156145ad57806145a761422861420f6115126001958b612a54565b01614588565b50906107335f8051602061507483398151915293956107256129b3946001976145d58661406c565b6145de84613bb5565b6145e781613df3565b6145f082613ed6565b60025460a08a901b8a9003166001600160a01b0316614619575b604051958694602086016141a0565b614621614faa565b61460a565b6003546001600160a01b03168015612e36576040516379b60be960e01b81523060048201525f60248201526001600160a01b03929092166044830152602090829060649082905afa5f9181614680575b506109c357505f90565b61469a91925060203d602011610ed257610ec48183610920565b905f614676565b93906080939695926146c89160018060a01b0316865260a0602087015260a08601906104ad565b604085019690965260608401526001600160a01b0316910152565b156146ea57565b60405162461bcd60e51b8152602060048201526013602482015272131a589c985c9e481cddd85c0819985a5b1959606a1b6044820152606490fd5b80158015614810575b61480b5761473a6139a8565b906001600160a01b038216156147fc57614752614f6b565b916001600160a01b038316156147ed576109c3935f936147bd859461477561334e565b60095480151588146147e1578161392e61479561479b93610725956123a0565b85612d22565b935b6040519485936020850197631f19e6af60e01b89523093602487016146a1565b51915af46147d26147cc61323e565b916146e3565b60208082518301019101612a68565b5050610725869361479d565b63179ce99f60e01b5f5260045ffd5b6321c7ca3d60e01b5f5260045ffd5b905090565b5081511561472e565b90816060910312610487578051916040602083015192015190565b90602080835192838152019201905f5b8181106148515750505090565b8251845260209384019390920191600101614844565b94929097969593919760e086526101a0860161ffff82511660e088015260208201519060c0610100890152815180915260206101c089019201905f5b818110614943575050509260c095926149248361491260a06148fa6148e361219e9a6109559f9e9c99604001518d61012060df1982850301910152614834565b60608501518c820360df19016101408e0152614834565b60808401516101608c015292015115156101808a0152565b6001600160a01b03909c166020880152565b6040860152606085015260808401526001600160a01b031660a0830152565b82516001600160a01b03168452602093840193909201916001016148a3565b9193929590969460018060a01b03614978615002565b16938415614a7957926149aa89935f9360609897966040519b8c998a988997636e06907960e11b895260048901614867565b03925af1918215610bee575f925f915f91614a43575b509293816149cc575050565b6001600160a01b0381165f908152600b602052604090207f6c04d07f86188951f3cb794b579d368362f0465c03036426a0d21b44258a30319190614a11848254611feb565b90556001600160a01b03165f818152600b602090815260409182902054825195865290850152909290819081016129b3565b915050614a6991925060603d606011614a72575b614a618183610920565b810190614819565b9192915f6149c0565b503d614a57565b505f97508796505050505050565b908115614aec57614a9661230c565b918060011c808203918211611ff857600e546001600160a01b0394851694168414614ae657614ac790613617610ce0565b925b600f546001600160a01b0316146109c3576109c390613617610c2b565b92614ac9565b5f91508190565b95929796939060c09592614b1c9160018060a01b0316885260e0602089015260e08801906104ad565b60408701989098526060860152608085015260a08401526001600160a01b0316910152565b15614b4857565b60405162461bcd60e51b815260206004820152601b60248201527f4c696272617279206164644c6971756964697479206661696c656400000000006044820152606490fd5b919082158015614cc6575b613a2957614ba461334e565b92600954614bf2614bc28661392e614bbc85836123a0565b86612d22565b9561392e614bdd8261392e614bd787836123a0565b89612d22565b93612e4b614beb8888611feb565b91846123a0565b94614bfb6139a8565b906001600160a01b038216156147fc57614c13614f6b565b946001600160a01b038616156147ed57614c995f95610725614cae988897614c42600e5460018060a01b031690565b600f54604080516001600160a01b03938416602082015292909116908201525f606080830191909152815296614c79608089610920565b6040519687956020870199632958884360e01b8b52309560248901614af3565b51915af46147d2614ca861323e565b91614b41565b918210614cb757565b63427282e960e11b5f5260045ffd5b508015614b98565b6001600160a01b0390911681526040602082018190526109c39101600c6125c5565b6003546001600160a01b031691908215614db0576002546001600160a01b031690833b15610487576040516374a3658160e01b81526001600160a01b03929092166004830152602482015260448101919091525f8160648183865af18015610bee57614d9c575b506002546001600160a01b031690803b15610487576040516301f12f3960e11b8152915f918391829084908290614d919060048301614cce565b03925af161442f5750565b80611f695f614daa93610920565b5f614d57565b505050565b905f602091828151910182855af115612206575f513d614e0457506001600160a01b0381163b155b614de45750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b60011415614ddd565b90614e188251612a15565b5f5b8351811015614e5d5780614e43614e3360019387612a54565b516020808251830101910161236f565b5050828060a01b0316614e568285612a54565b5201614e1a565b509150565b60405163095ea7b360e01b60208083019182526001600160a01b038516602484015260016044840152919291905f90614ea885606481015b03601f198101875286610920565b84519082855af15f51903d81614f02575b501590505b614ec757505050565b60405163095ea7b360e01b60208201526001600160a01b0390931660248401525f604484015261095592613ac0906144ef8160648101610725565b15159050614f225750614ebe6001600160a01b0382163b15155b5f614eb9565b6001614ebe9114614f1c565b60405163095ea7b360e01b60208281019182526001600160a01b03851660248401526044830195909552929390925f90614ea88560648101614e9a565b6005541580612efc576111695760055f527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0546001600160a01b031690565b6003546001600160a01b031680614fbe5750565b6002546001600160a01b031690803b15610487576040516301f12f3960e11b8152915f918391829084908290614ff79060048301614cce565b03925af1613a7a5750565b6003546001600160a01b03168015612efc575f8091604051602081019063876dcc4160e01b825260048152615038602482610920565b51915afa61504461323e565b9080615067575b61505457505f90565b80602080610a9e935183010191016122f7565b5060208151101561504b56fe67e3df1218a20e3bb0b11c3a0295e5cc1a84004b1873f6eaedaeb935de8676d31b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae672f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a2646970667358221220be92bed85733e6db52b862295dddecf6d3d58bca9e5419d5bce0e0406cddeaf164736f6c634300081a0033
Deployed Bytecode
0x60806040526004361015610011575f80fd5b5f3560e01c806301e1d1141461047857806306fdde031461047357806307a2d13a146103745780630a28a477146103745780630e5c011e1461046e5780631158808614610469578063117da1ee14610464578063193b47281461045f5780631d9478b61461045a5780631f1fcd511461043257806322be3de11461045557806324735bdf1461045057806324ea54f41461044b5780632e1a7d4d146104465780633018205f14610441578063313ce5671461043c57806337bdd2041461043757806338d52e0f146104325780633f4ba83a1461042d578063402d267d146103a1578063439fab911461042857806346904840146104235780634700d3051461041e5780634cdad506146103745780634e9c111814610419578063573fef0a14610414578063577fe7b41461040f5780635c975abb1461040a5780635ee167c01461040557806365daa5cd146103b55780636817031b146104005780636de813f1146103fb57806370a0823114610388578063785dbc3a146103f6578063797bf343146103ab5780637bb7bed1146103f15780638456cb59146103ec578063877562b6146103e757806388cc58e4146103a65780638ee2f35b1461034c57806393288637146103e257806397fd323d146103dd578063985f61a1146103d85780639e591bc6146103d3578063a22d45b4146103ce578063a378a324146103c9578063a6f19c84146103c4578063b3d7f6b914610374578063b5fd73f8146103bf578063b6274cba146103ba578063bd8d4bd8146103b5578063c1176461146103b0578063c1a3d44c146103ab578063c45a0155146103a6578063c63d75b6146103a1578063c6e6f59214610374578063ce96cb771461039c578063cfd9eb0d14610397578063d03153aa14610392578063d0e30db01461038d578063d905777e14610388578063dc22486314610383578063e74b981b1461037e578063ea82eb9e14610379578063ef8b30f714610374578063f0ac28421461036f578063f0b63beb1461036a578063f1a392da14610365578063f382331f14610360578063fa9858af1461035b578063fb61778714610356578063fbfa77cf14610351578063ff7dcd5a1461034c5763ffc5d97a14610347575f80fd5b611faf565b611845565b611f87565b611ec9565b611dd5565b611dad565b611d90565b611d55565b611d22565b610517565b611d07565b611c1b565b611c01565b6115d6565b611bd1565b611bb4565b611b0d565b611ae7565b610ee8565b61181d565b6116f7565b611aaa565b6112d2565b611a48565b611a08565b6119dc565b6119c1565b61191d565b6118fb565b611899565b61187f565b611860565b6117f5565b61176b565b611711565b6116af565b61149b565b6112ef565b6112aa565b611289565b6111f2565b6111e0565b611186565b6110d6565b6110aa565b610f4d565b610e3f565b6108c2565b610e24565b610b5e565b610b36565b610a47565b610a2c565b6109c6565b6108ea565b610896565b61085a565b610697565b61067d565b610546565b6104d1565b61048b565b5f91031261048757565b5f80fd5b34610487575f3660031901126104875760206104a5611ffd565b604051908152f35b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b34610487575f36600319011261048757610513601354604051906020820152602081526104ff604082610920565b6040519182916020835260208301906104ad565b0390f35b34610487576020366003190112610487576020600435604051908152f35b6001600160a01b0381160361048757565b346104875760203660031901126104875760043561056381610535565b61056b613204565b610573613224565b61057b61326d565b8015159081610668575b50610638576105a3610595612ad8565b61059d6133c2565b90611feb565b906105ac612019565b506105b5613432565b506105be613554565b9182156105fb576105e26105dd6105d86105e795856136d9565b61381a565b613878565b61388a565b6105f042600855565b6105f960018055565b005b604051630c0092c960e21b81526020600482015260146024820152734e6f207265776172647320617661696c61626c6560601b6044820152606490fd5b60405163315c91ed60e21b81526020600482015260076024820152661a185c9d995cdd60ca1b6044820152606490fd5b6106759150600854611feb565b42105f610585565b34610487575f3660031901126104875760206104a56133c2565b3461048757602036600319011261048757600354600435906001600160a01b0316330361078a576103e88111610744575f8051602061507483398151915261073f610725610733846106e95f96600955565b604051928391602083019190604083526011604084015270736c697070616765546f6c6572616e636560781b6060840152602060808401930152565b03601f198101835282610920565b60405191829182610e13565b0390a2005b60405163d647364f60e01b815260206004820152601b60248201527f536c69707061676520746f6f206869676820286d6178203130252900000000006044820152606490fd5b6282b42960e81b5f5260045ffd5b9181601f84011215610487578235916001600160401b038311610487576020838186019501011161048757565b606060031982011261048757600435916001600160401b0383116104875781602384011215610487578260040135926001600160401b038411610487578260248560051b830101116104875760240192916024356001600160401b038111610487578161083491600401610798565b92909291604435906001600160401b0382116104875761085691600401610798565b9091565b346104875761087761086b366107c5565b94939093929192612211565b90610513604051928392151583526040602084015260408301906104ad565b34610487575f3660031901126104875760206108b061230c565b6040516001600160a01b039091168152f35b34610487575f366003190112610487576004546040516001600160a01b039091168152602090f35b34610487575f36600319011261048757602060ff601454166040519015158152f35b634e487b7160e01b5f52604160045260245ffd5b90601f801991011681019081106001600160401b0382111761094157604052565b61090c565b6040519061095560c083610920565b565b6001600160401b03811161094157601f01601f191660200190565b92919261097e82610957565b9161098c6040519384610920565b829481845281830111610487578281602093845f960137010152565b9080601f83011215610487578160206109c393359101610972565b90565b34610487576020366003190112610487576004356001600160401b03811161048757610a0a6109fb60609236906004016109a8565b6020808251830101910161236f565b604080516001600160a01b039485168152939092166020840152151590820152f35b34610487575f36600319011261048757602060405160028152f35b3461048757602036600319011261048757600435610a63613204565b60025481906001600160a01b03163303610b2757610a7f612ad8565b828110610abc575b6004546105f0908390610aaa906001600160a01b03165b6001600160a01b031690565b6002546001600160a01b031690613a84565b610ac9610ace91846123a0565b613a2f565b610ad6612ad8565b8281108080610b0f575b610af6576105f0935015610a875790505f610a87565b63a17e11d560e01b5f526004849052602482905260445ffd5b50610b22610b1e60ff5f541690565b1590565b610ae0565b638d1af8bd60e01b5f5260045ffd5b34610487575f366003190112610487576003546040516001600160a01b039091168152602090f35b34610487575f366003190112610487576004805460405163313ce56760e01b81529160209183919082906001600160a01b03165afa8015610bee575f90610bb0575b60405160ff919091168152602090f35b506020813d602011610be6575b81610bca60209383610920565b81010312610487575160ff811681036104875761051390610ba0565b3d9150610bbd565b612206565b90600182811c92168015610c21575b6020831014610c0d57565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610c02565b604051905f8260125491610c3e83610bf3565b8083529260018116908115610cc15750600114610c62575b61095592500383610920565b5060125f90815290917fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec34445b818310610ca557505090602061095592820101610c56565b6020919350806001915483858901015201910190918492610c8d565b6020925061095594915060ff191682840152151560051b820101610c56565b604051905f8260115491610cf383610bf3565b8083529260018116908115610cc15750600114610d165761095592500383610920565b5060115f90815290917f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c685b818310610d5957505090602061095592820101610c56565b6020919350806001915483858901015201910190918492610d41565b9060405191825f825492610d8884610bf3565b8084529360018116908115610df15750600114610dad575b5061095592500383610920565b90505f9291925260205f20905f915b818310610dd5575050906020610955928201015f610da0565b6020919350806001915483858901015201910190918492610dbc565b90506020925061095594915060ff191682840152151560051b8201015f610da0565b9060206109c39281815201906104ad565b34610487575f366003190112610487576105136104ff610c2b565b34610487575f366003190112610487576003546001600160a01b03168015610ed9576040516379b60be960e01b81523060048201526002602482015233604482015290602090829060649082905afa908115610bee575f91610eaa575b501561078a576105f9613ac5565b610ecc915060203d602011610ed2575b610ec48183610920565b8101906123ad565b5f610e9c565b503d610eba565b632110f99160e01b5f5260045ffd5b3461048757602036600319011261048757610f04600435610535565b600a5460ff1615610f1b5760205f19604051908152f35b60205f6104a5565b602060031982011261048757600435906001600160401b0382116104875761085691600401610798565b3461048757610f5b36610f23565b5f805160206150b48339815191525491906001600160401b03610f8d60ff604086901c1615946001600160401b031690565b16801590816110a2575b6001149081611098575b15908161108f575b5061108057610fec9183610fe360016001600160401b03195f805160206150b48339815191525416175f805160206150b483398151915255565b61104b57612620565b610ff257005b61101c60ff60401b195f805160206150b483398151915254165f805160206150b483398151915255565b604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1005b61107b600160401b60ff60401b195f805160206150b48339815191525416175f805160206150b483398151915255565b612620565b63f92ee8a960e01b5f5260045ffd5b9050155f610fa9565b303b159150610fa1565b849150610f97565b34610487575f36600319011261048757600a5460405160089190911c6001600160a01b03168152602090f35b34610487575f366003190112610487576002546001600160a01b0316330361078a57611100613224565b600160ff195f5416175f557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a16105f9614376565b634e487b7160e01b5f52603260045260245ffd5b600c5481101561116957600c5f5260205f2001905f90565b61113d565b6010548110156111695760105f5260205f2001905f90565b34610487576020366003190112610487576004356005548110156104875760055f527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db001546040516001600160a01b039091168152602090f35b34610487575f36600319011261048757005b346104875760203660031901126104875760043561120f81610535565b6003546001600160a01b03168015610ed9576040516379b60be960e01b81523060048201525f602482015233604482015290602090829060649082905afa908115610bee575f9161126a575b501561078a576105f990612902565b611283915060203d602011610ed257610ec48183610920565b5f61125b565b34610487575f36600319011261048757602060ff5f54166040519015158152f35b34610487575f36600319011261048757600e546040516001600160a01b039091168152602090f35b34610487575f366003190112610487576020600754604051908152f35b346104875760203660031901126104875760043561130c81610535565b6002546001600160a01b031680151590816113fd575b506113ee57600280546001600160a01b0319166001600160a01b0383161790556001600160a01b031680156113db5760206004916040519283809263f77c479160e01b82525afa5f91816113aa575b506113895750600380546001600160a01b0319169055005b600380546001600160a01b0319166001600160a01b03909216919091179055005b6113cd91925060203d6020116113d4575b6113c58183610920565b8101906122f7565b905f611371565b503d6113bb565b50600380546001600160a01b0319169055005b634f1f214760e01b5f5260045ffd5b6001600160a01b031690503314155f611322565b90602080835192838152019201905f5b81811061142e5750505090565b82516001600160a01b0316845260209384019390920191600101611421565b9061146090604083526040830190611411565b906020818303910152602080835192838152019201905f5b8181106114855750505090565b8251845260209384019390920191600101611478565b34610487575f366003190112610487576014546114c590610a9e9060081c6001600160a01b031681565b604051632000ed8560e21b81525f81600481855afa908115610bee575f916115b4575b506114f38151612a15565b915f5b82518110156115a35780602061151f61151261154e9487612a54565b516001600160a01b031690565b60405163211dc32d60e01b81526001600160a01b03909116600482015230602482015292839081906044820190565b0381865afa8015610bee576001925f91611575575b5061156e8287612a54565b52016114f6565b611596915060203d811161159c575b61158e8183610920565b810190612a68565b5f611563565b503d611584565b50506105136040519283928361144d565b6115d091503d805f833e6115c88183610920565b8101906129f0565b5f6114e8565b34610487576020366003190112610487576004356115f381610535565b6002546040516370a0823160e01b81526001600160a01b0392831660048201529160209183916024918391165afa8015610bee576020915f9161163a575b50604051908152f35b6116519150823d841161159c5761158e8183610920565b5f611631565b9080602083519182815201916020808360051b8301019401925f915b83831061168257505050505090565b90919293946020806116a0600193601f1986820301875289516104ad565b97019301930191939290611673565b34610487575f366003190112610487576116e96116ca612019565b6105136116d5612a77565b604051938493604085526040850190611411565b908382036020850152611657565b34610487575f3660031901126104875760206104a5612ad8565b3461048757602036600319011261048757600435600c5481101561048757600c5f527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c701546040516001600160a01b039091168152602090f35b34610487575f366003190112610487576003546001600160a01b03168015610ed9576040516379b60be960e01b81523060048201526002602482015233604482015290602090829060649082905afa908115610bee575f916117d6575b501561078a576105f9614337565b6117ef915060203d602011610ed257610ec48183610920565b5f6117c8565b34610487575f36600319011261048757600f546040516001600160a01b039091168152602090f35b34610487575f366003190112610487576006546040516001600160a01b039091168152602090f35b34610487575f366003190112610487576040515f8152602090f35b34610487575f3660031901126104875730330361078a576105f9614376565b34610487575f3660031901126104875760206104a5612d53565b34610487576118a736610f23565b5050604051630c0092c960e21b815260206004820152602360248201527f5374726174656779206d75737420696d706c656d656e7420657865637574655360448201526207761760ec1b6064820152608490fd5b34610487575f36600319011261048757602060ff600a54166040519015158152f35b346104875760403660031901126104875760043561193a81610535565b60243561194681610535565b6003546001600160a01b03168015610ed9576040516379b60be960e01b81523060048201526001602482015233604482015290602090829060649082905afa908115610bee575f916119a2575b501561078a576105f991612f25565b6119bb915060203d602011610ed257610ec48183610920565b5f611993565b34610487575f36600319011261048757602060405160018152f35b34610487575f3660031901126104875760145460405160089190911c6001600160a01b03168152602090f35b3461048757602036600319011261048757600435611a2581610535565b60018060a01b03165f52600d602052602060ff60405f2054166040519015158152f35b34610487575f36600319011261048757611a8e611a63612a77565b610513611a6e610ce0565b611a9c611a79610c2b565b91604051958695606087526060870190611657565b9085820360208701526104ad565b9083820360408501526104ad565b3461048757602036600319011261048757600435601054811015610487576104ff6105139160105f525f8051602061509483398151915201610d75565b3461048757602036600319011261048757611b03600435610535565b60206104a5611ffd565b3461048757606036600319011261048757600435611b2a81610535565b604435602435611b3982610535565b6003546001600160a01b03168015610ed9576040516379b60be960e01b81523060048201526002602482015233604482015290602090829060649082905afa908115610bee575f91611b95575b501561078a576105f992612fce565b611bae915060203d602011610ed257610ec48183610920565b5f611b86565b34610487575f366003190112610487576020600954604051908152f35b34610487575f36600319011261048757611be9613224565b611bf1612ad8565b80611bf857005b6105f99061437e565b34610487575f3660031901126104875760206040515f8152f35b3461048757602036600319011261048757600435611c3881610535565b600254611c4d906001600160a01b0316610a9e565b3303610b27576001600160a01b03811615611cf857600a8054610100600160a81b031916600883901b610100600160a81b03161790555f905f805160206150748339815191529061073f90600a546107339060081c6001600160a01b031660408051606060208201819052600c60808301526b199959549958da5c1a595b9d60a21b60a08301526001600160a01b039384169282019290925293909116908301528160c08101610725565b63d92e233d60e01b5f5260045ffd5b34610487575f366003190112610487576105136104ff610ce0565b34610487575f36600319011261048757601554601654604080516001600160a01b03938416815292909116602083015290f35b3461048757602036600319011261048757600435611d7281610535565b60018060a01b03165f52600b602052602060405f2054604051908152f35b34610487575f366003190112610487576020600854604051908152f35b34610487575f366003190112610487576016546040516001600160a01b039091168152602090f35b3461048757611de3366107c5565b60035494959490939192906001600160a01b03163303611eba57611e06866123ee565b94611e146040519687610920565b86865260208601908760051b8101903682116104875780925b828410611e8e57505060015f8051602061507483398151915261073f6107256107338c611e738d8d611e6d8e611e658f8f3691610972565b923691610972565b9161453f565b60408051602081019290925242908201529182906060820190565b83356001600160401b03811161048757602091611eaf8392369086016109a8565b815201930192611e2d565b635990781360e01b5f5260045ffd5b34610487575f36600319011261048757600254611eee906001600160a01b0316610a9e565b33141580611f75575b61078a57303b1561048757604051639328863760e01b81525f8160048183305af1611f5b575b50611f26612ad8565b80611f3b575b6105f960ff19600a5416600a55565b600454611f559190610aaa906001600160a01b0316610a9e565b5f611f2c565b80611f695f611f6f93610920565b8061047d565b5f611f1d565b50611f82610b1e33614626565b611ef7565b34610487575f366003190112610487576002546040516001600160a01b039091168152602090f35b34610487575f366003190112610487576015546040516001600160a01b039091168152602090f35b634e487b7160e01b5f52601160045260245ffd5b91908201809211611ff857565b611fd7565b612005612ad8565b61200d6133c2565b8101809111611ff85790565b60405190600c548083528260208101600c5f5260205f20925f5b81811061204857505061095592500383610920565b84546001600160a01b0316835260019485019487945060209093019201612033565b5190811515820361048757565b81601f820112156104875760208151910161209182610957565b9261209f6040519485610920565b8284528282011161048757815f926020928386015e8301015290565b919091604081840312610487576120d18161206a565b9260208201516001600160401b038111610487576109c39201612077565b908060209392818452848401375f828201840152601f01601f1916010190565b9699989795939192908360c0890160c08a525260e0880160e08560051b8a010194825f90601e19813603015b8383106121ae57505050505050869461219e9461216e8561218e9561217c956109559d9c60a09c990360208c01526120ef565b9187830360408901526120ef565b6001600160a01b039099166060850152565b6001600160a01b03166080830152565b6001600160a01b03909216910152565b90919293949760df198d820301865288358281121561048757830190602082359201916001600160401b038111610487578036038313610487576121f860209283926001956120ef565b9a019601949301919061213b565b6040513d5f823e3d90fd5b9395929492939192916001600160a01b0361222a6139a8565b169283156122b2575f95969761227b9161224261230c565b600e546001600160a01b0316600f549092906001600160a01b0316936040519c8d9a8b998a9963436b3d9960e01b8b5260048b0161210f565b03915afa918215610bee575f905f9361229357509190565b90506108569192503d805f833e6122aa8183610920565b8101906120bb565b50505050509150505f906040516122ca604082610920565b601d81527f526f75746572206c696272617279206e6f742072656769737465726564000000602082015290565b9081602091031261048757516109c381610535565b6003546001600160a01b03168061232257505f90565b6020600491604051928380926317fcb39b60e01b82525afa908115610bee575f9161234b575090565b6109c3915060203d6020116113d4576113c58183610920565b519061095582610535565b9081606091031261048757805161238581610535565b916109c36040602084015161239981610535565b930161206a565b91908203918211611ff857565b90816020910312610487576109c39061206a565b9190916040818403126104875780359260208201356001600160401b038111610487576109c392016109a8565b6001600160401b0381116109415760051b60200190565b9080601f8301121561048757815161241c816123ee565b9261242a6040519485610920565b81845260208085019260051b82010192831161048757602001905b8282106124525750505090565b60208091835161246181610535565b815201910190612445565b9080601f83011215610487578151612483816123ee565b926124916040519485610920565b81845260208085019260051b820101918383116104875760208201905b8382106124bd57505050505090565b81516001600160401b038111610487576020916124df87848094880101612077565b8152019101906124ae565b61012081830312610487576124fe81612364565b9260208201516001600160401b038111610487578361251e918401612077565b9260408301516001600160401b038111610487578161253e918501612405565b9260608101516001600160401b038111610487578261255e91830161246c565b9260808201516001600160401b038111610487578361257e918401612077565b9260a0830151906001600160401b0382116104875761259e918401612077565b916125ab60c08201612364565b916109c36101006125be60e08501612364565b9301612364565b90602082549182815201915f5260205f20905f5b8181106125e65750505090565b82546001600160a01b03168452602090930192600192830192016125d9565b919060408352602061261b60408501600c6125c5565b930152565b61263090612642928101906123c1565b602080829493945183010191016124ea565b509592939660018060a0979394971b03169760405192633a4b66f160e01b84526020846004818d5afa938415610bee575f946128de575b50604051634256f5e760e01b815293949293926020846004818e5afa938415610bee575f946128bd575b50604051632b18028f60e21b8152926020846004816001600160a01b0389165afa918215610bee5761275396612736955f94612896575b506126f16126f8949560018060a01b031692613b11565b9089613c35565b60148054610100600160a81b03191660088c901b610100600160a81b031617905560018060a01b03166001600160601b0360a01b6015541617601555565b60018060a01b03166001600160601b0360a01b6016541617601655565b604051630dfe168160e01b81526001600160a01b03919091169490602081600481895afa8015610bee576127a6915f91612877575b5060018060a01b03166001600160601b0360a01b600e541617600e55565b60405163d21220a760e01b815293602085600481895afa908115610bee576127f46128169261281b975f91612858575b5060018060a01b03166001600160601b0360a01b600f541617600f55565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6141c3565b6128236142ab565b5f7fa8aee87aedb58bbffb10d4e26201cdff2b8b590739a576965328e0aad7838c2e604051806128534282612605565b0390a4565b612871915060203d6020116113d4576113c58183610920565b5f6127d6565b612890915060203d6020116113d4576113c58183610920565b5f612788565b6126f894506128b66126f19160203d6020116113d4576113c58183610920565b94506126da565b6128d791945060203d6020116113d4576113c58183610920565b925f6126a3565b60049394506128fb9060203d6020116113d4576113c58183610920565b9392612679565b6001600160a01b0381165f818152600b60205260409020549182156129b85782610733826129616002965f80516020615074833981519152965f6129596129b39860018060a01b03165f52600b60205260405f2090565b553390613a84565b6040805160606020820181905260126080830152711d1c99585cdd5c9e51995950db185a5b595960721b60a08301526001600160a01b0390931691810191909152908101929092528160c08101610725565b0390a2565b604051630c0092c960e21b815260206004820152600f60248201526e4e6f2070656e64696e67206665657360881b6044820152606490fd5b906020828203126104875781516001600160401b038111610487576109c39201612405565b90612a1f826123ee565b612a2c6040519182610920565b8281528092612a3d601f19916123ee565b0190602036910137565b8051156111695760200190565b80518210156111695760209160051b010190565b90816020910312610487575190565b60105490612a84826123ee565b91612a926040519384610920565b80835260105f9081525f80516020615094833981519152602085015b838310612abb5750505050565b600160208192612aca85610d75565b815201920192019190612aae565b6024602060018060a01b0360045416604051928380926370a0823160e01b82523060048301525afa908115610bee575f91612b11575090565b6109c3915060203d60201161159c5761158e8183610920565b9080601f83011215610487578151612b41816123ee565b92612b4f6040519485610920565b81845260208085019260051b82010192831161048757602001905b828210612b775750505090565b8151815260209182019101612b6a565b9190916040818403126104875780516001600160401b0381116104875783612bb0918301612405565b9260208201516001600160401b038111610487576109c39201612b2a565b519061ffff8216820361048757565b9080601f83011215610487578151612bf4816123ee565b92612c026040519485610920565b81845260208085019260051b82010192831161048757602001905b828210612c2a5750505090565b8151815260209182019101612c1d565b602081830312610487578051906001600160401b038211610487570160c08183031261048757612c68610946565b91612c7282612bce565b835260208201516001600160401b0381116104875781612c93918401612405565b602084015260408201516001600160401b0381116104875781612cb7918401612b2a565b60408401526060820151916001600160401b03831161048757612ce160a092612cf6948301612bdd565b6060850152608081015160808501520161206a565b60a082015290565b90670de0b6b3a7640000820291808304670de0b6b3a76400001490151715611ff857565b81810292918115918404141715611ff857565b8115612d3f570490565b634e487b7160e01b5f52601260045260245ffd5b604051636de813f160e01b81525f81600481305afa8015610bee575f915f91612f01575b50815115612e3657612d8761230c565b5f926001600160a01b0390911690835b8151811015612ddf5782612db1610a9e6115128486612a54565b14612dbf575b600101612d97565b93612dd7600191612dd08787612a54565b5190611feb565b949050612db7565b505050508015612efc576003546001600160a01b0316908115612e3657600254604051632138c36160e11b81526001600160a01b039091166004820152915f90839060249082905afa5f9281612ed8575b50612e3c575b50505f90565b612e51612e5f91612e4b6132da565b90612d22565b612e5961334e565b90612d35565b5f5b602083015151811015612ece577eabf5fabef4a428c85b26a0d8174a974f9b7ba3a28d69a208a013e37f688c2f612e9c826060860151612a54565b5114612eaa57600101612e61565b90612ebf612ec69260406109c3950151612a54565b5190612d22565b6103e8900490565b5050505f80612e36565b612ef59193503d805f833e612eed8183610920565b810190612c3a565b915f612e30565b505f90565b9050612f1f91503d805f833e612f178183610920565b810190612b87565b5f612d77565b6001600160a01b03169081158015612fbd575b611cf857612f70916001600160601b0360a01b601554161760155560018060a01b03166001600160601b0360a01b6016541617601655565b60045460145460405160089190911c6001600160a01b039081169216906001907fa8aee87aedb58bbffb10d4e26201cdff2b8b590739a576965328e0aad7838c2e90806128534282612605565b506001600160a01b03811615612f38565b600454909190612fe6906001600160a01b0316610a9e565b6001600160a01b038316919082146131be576001600160a01b03841615613178576040516370a0823160e01b815230600482015290602082602481865afa918215610bee575f92613157575b50811561311a57806131145750805b81116130d557610733836107258661308c856003996129b3986130825f805160206150748339815191529b60018060a01b03165f52600b60205260405f2090565b546130b857613a84565b604080516001600160a01b03948516602082015290810195909552909116606084015282906080820190565b6001600160a01b0387165f908152600b6020526040812055613a84565b60405163d647364f60e01b8152602060048201526016602482015275416d6f756e7420657863656564732062616c616e636560501b6044820152606490fd5b90613041565b604051630c0092c960e21b81526020600482015260146024820152732737903a37b5b2b739903a37903932b1b7bb32b960611b6044820152606490fd5b61317191925060203d60201161159c5761158e8183610920565b905f613032565b60405163d647364f60e01b815260206004820152601960248201527f496e76616c696420726563697069656e742061646472657373000000000000006044820152606490fd5b60405163d647364f60e01b815260206004820152601960248201527f43616e6e6f74207265636f766572206d61696e206173736574000000000000006044820152606490fd5b600260015414613215576002600155565b633ee5aeb560e01b5f5260045ffd5b60ff5f541661322f57565b63d93c066560e01b5f5260045ffd5b3d15613268573d9061324f82610957565b9161325d6040519384610920565b82523d5f602084013e565b606090565b6003546001600160a01b03168015612efc575f80916040516020810190630783fad960e41b8252600481526132a3602482610920565b51915afa6132af61323e565b90806132ce575b15612efc57806020806109c393518301019101612a68565b506020815110156132b6565b6003546001600160a01b0316801561333b575f80916040516020810190637772f9c760e01b825260048152613310602482610920565b51915afa61331c61323e565b9080613342575b1561333b57806020806109c393518301019101612a68565b5061012c90565b50602081511015613323565b6003546001600160a01b031680156133af575f8091604051602081019063e1f1c4a760e01b825260048152613384602482610920565b51915afa61339061323e565b90806133b6575b156133af57806020806109c393518301019101612a68565b5061271090565b50602081511015613397565b6014546040516370a0823160e01b8152306004820152906020908290602490829060081c6001600160a01b03165afa908115610bee575f91612b11575090565b5f198114611ff85760010190565b6001600160a01b0390911681526040602082018190526109c392910190611411565b600c546016546001600160a01b031690811561354c5760ff60015b1661346061345b8284611feb565b612a15565b9260015f9214613535575b505f5b8281106134e65750506014546134929150610a9e9060081c6001600160a01b031681565b803b156104875760405163169f6dd360e01b8152915f9183918290849082906134bf903060048401613410565b03925af18015610bee576134d257505f90565b80611f695f6134e093610920565b5f612efc565b8061352f61350d6134f8600194611151565b905460039190911b1c6001600160a01b031690565b61352061351986613402565b9588612a54565b6001600160a01b039091169052565b0161346e565b905061354660019161352085612a47565b5f61346b565b60ff5f61344d565b6001600160a01b0361356461230c565b6040516370a0823160e01b8152306004820152911691602082602481865afa918215610bee575f926136b8575b505f5b600c54811015613652576135c16135aa82611151565b90546001600160a01b039260039290921b1c821690565b1690848214613649576040516370a0823160e01b815230600482015291602090839060249082905afa8015610bee576001925f9161362b575b5080156136255761361d906136176136118461116e565b50610d75565b90614725565b505b01613594565b5061361f565b613643915060203d811161159c5761158e8183610920565b5f6135fa565b6001915061361f565b506040516370a0823160e01b81523060048201529092909190602090839060249082905afa918215610bee575f92613697575b5080821115612e36576109c3916123a0565b6136b191925060203d60201161159c5761158e8183610920565b905f613685565b6136d291925060203d60201161159c5761158e8183610920565b905f613591565b8115612e36576003546001600160a01b0316801561381557600254604051632138c36160e11b81526001600160a01b039091166004820152905f90829060249082905afa8015610bee57613763915f916137fb575b508261373861230c565b946137416132da565b61374961334e565b600a54909290889060081c6001600160a01b031695614962565b9091826137ae575b5050506001600160a01b03168015612efc576040516370a0823160e01b815230600482015290602090829060249082905afa908115610bee575f91612b11575090565b604080516001600160a01b03909216602083015281019290925260608201526002905f80516020615074833981519152906137f0906107338160808101610725565b0390a25f808061376b565b61380f91503d805f833e612eed8183610920565b5f61372e565b505090565b8015612efc5761383161382b612ad8565b91614a87565b8115158061386f575b61385e575b5050613849612ad8565b9080821115612e36578103908111611ff85790565b61386791614b8d565b505f8061383f565b5080151561383a565b8015613887576109559061437e565b50565b90600490613899610595612ad8565b92808411156139a0576138ac90846123a0565b905b6138b88483614cf0565b6002546020906138d290610a9e906001600160a01b031681565b6040516318160ddd60e01b815294859182905afa918215610bee577f5d8077a9c609196570b2ccce581be21d954ce035f63805a111bd59a8853f9e25935f9361397b575b506129b390831561396c576139338461392e88612cfe565b612d35565b935b6040805192835260208301979097529581019390935260608301949094524260808301526001600160a01b031692819060a0820190565b670de0b6b3a764000093613935565b6129b39193506139999060203d60201161159c5761158e8183610920565b9290613916565b505f906138ae565b6003545f91906001600160a01b03168015613a29576040516317da19fd60e31b602082019081525f602483018190529283929091906139ea8160448101610725565b51915afa6139f661323e565b9080613a1d575b613a045750565b6109c391925080602080610a9e935183010191016122f7565b506020815110156139fd565b505f9150565b80613a375750565b60145460081c6001600160a01b031690813b15610487575f91602483926040519485938492632e1a7d4d60e01b845260048401525af18015610bee57613a7a5750565b5f61095591610920565b60405163a9059cbb60e01b60208201526001600160a01b0392909216602483015260448083019390935291815261095591613ac0606483610920565b614db5565b5f5460ff811615613b025760ff19165f557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1565b638dfc202b60e01b5f5260045ffd5b805115612efc576020015190565b818110613b2a575050565b5f8155600101613b1f565b8051906001600160401b03821161094157600160401b82116109415760209060055483600555808410613b99575b500160055f5260205f205f5b838110613b7c5750505050565b82516001600160a01b031682820155602090920191600101613b6f565b613baf9060055f5284845f209182019101613b1f565b5f613b63565b8051906001600160401b03821161094157600160401b821161094157602090600c5483600c55808410613c19575b5001600c5f5260205f205f5b838110613bfc5750505050565b82516001600160a01b031682820155602090920191600101613bef565b613c2f90600c5f5284845f209182019101613b1f565b5f613be3565b6004549095919491939192906001600160a01b0316613da2576001600160a01b03861615613d9357845115613c9b576001600160a01b03821615613d41575f5b8551811015613caa57613c8e610a9e6115128389612a54565b15613c9b57600101613c75565b63466d7fef60e01b5f5260045ffd5b50613ce690613ce161095596613cdc613d1896979960018060a01b03166001600160601b0360a01b6004541617600455565b613b35565b601355565b613cf161012c600955565b600a8054610100600160a81b03191660089290921b610100600160a81b0316919091179055565b613d2a600160ff19600a541617600a55565b600680546001600160a01b03191633179055600755565b60405163d647364f60e01b8152602060048201526024808201527f46656520726563697069656e742063616e6e6f74206265207a65726f206164646044820152637265737360e01b6064820152608490fd5b636448d6e960e11b5f5260045ffd5b62dc149f60e41b5f5260045ffd5b9190601f8111613dbf57505050565b610955925f5260205f20906020601f840160051c83019310613de9575b601f0160051c0190613b1f565b9091508190613ddc565b9081516001600160401b03811161094157613e1a81613e13601154610bf3565b6011613db0565b602092601f8211600114613e5a57613e4a929382915f92613e4f575b50508160011b915f199060031b1c19161790565b601155565b015190505f80613e36565b60115f52601f198216937f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c68915f5b868110613ebe5750836001959610613ea6575b505050811b01601155565b01515f1960f88460031b161c191690555f8080613e9b565b91926020600181928685015181550194019201613e88565b9081516001600160401b03811161094157613efd81613ef6601254610bf3565b6012613db0565b602092601f8211600114613f3157613f2c929382915f92613e4f5750508160011b915f199060031b1c19161790565b601255565b60125f52601f198216937fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec3444915f5b868110613f955750836001959610613f7d575b505050811b01601255565b01515f1960f88460031b161c191690555f8080613f72565b91926020600181928685015181550194019201613f5f565b91909182516001600160401b03811161094157613fd481613fce8454610bf3565b84613db0565b6020601f82116001146140075781906140039394955f92613e4f5750508160011b915f199060031b1c19161790565b9055565b601f1982169061401a845f5260205f2090565b915f5b8181106140545750958360019596971061403c575b505050811b019055565b01515f1960f88460031b161c191690555f8080614032565b9192602060018192868b01518155019401920161401d565b805190600160401b821161094157601054826010558083106140cc575b5060105f526020015f805160206150948339815191525f915b8383106140af5750505050565b60016020826140c083945186613fad565b019201920191906140a2565b60105f525f805160206150948339815191529081019083015b8181106140f25750614089565b806140ff60019254610bf3565b8061410c575b50016140e5565b601f8111831461412157505f81555b5f614105565b6141439083601f614135855f5260205f2090565b920160051c82019101613b1f565b5f818152602081208183555561411b565b94936141925f9461418460809561417661261b9660a08c5260a08c0190611411565b908a820360208c0152611657565b9088820360408a01526104ad565b9086820360608801526104ad565b949361419260019461418460809561417661261b9660a08c5260a08c0190611411565b9290919280511561429c576001600160a01b036141de61230c565b161561428d576141ed81614e0d565b935f5b855181101561423b578061423561422861420f6115126001958b612a54565b6001600160a01b03165f908152600d6020526040902090565b805460ff19166001179055565b016141f0565b50906107335f8051602061507483398151915293956107256129b3946001976142638661406c565b61426c84613bb5565b61427581613df3565b61427e82613ed6565b60405195869460208601614154565b63158dcda960e01b5f5260045ffd5b63521299a960e01b5f5260045ffd5b6004546014546142cc916001600160a01b0360089290921c82169116614e62565b6142d4614f6b565b6001600160a01b0381166142e55750565b600e546142fc9082906001600160a01b0316614e62565b600f546143139082906001600160a01b0316614e62565b6001600160a01b0361432361230c565b16908161432e575050565b61095591614e62565b61433f613224565b600160ff195f5416175f557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1565b613a2f6133c2565b80156138875760048054601454604051636eb1769f60e11b8152309381019390935260081c6001600160a01b039081166024840181905291169190602082604481865afa928315610bee5784925f9461451e575b5082841061443d575b50506014546143f99250610a9e915060081c6001600160a01b031681565b803b156104875760405163b6b55f2560e01b815260048101929092525f908290602490829084905af18015610bee5761442f5750565b80611f695f61095593610920565b61444a9361445357614f2e565b5f8181806143db565b60405163095ea7b360e01b60208083019182526001600160a01b03851660248401525f60448085018290528452909161448d606485610920565b83519082865af15f51903d816144fb575b501590505b6144ae575b50614f2e565b60405163095ea7b360e01b60208201526001600160a01b03841660248201525f60448201526144f591906144ef906144e98160648101610725565b84614db5565b82614db5565b5f6144a8565b1515905061451257506144a3823b15155b5f61449e565b60016144a3911461450c565b61453891945060203d60201161159c5761158e8183610920565b925f6143d2565b9283511561429c5761455084614e0d565b935f5b600c54811015614582578061457c61457261420f6134f8600195611151565b805460ff19169055565b01614553565b509091925f5b85518110156145ad57806145a761422861420f6115126001958b612a54565b01614588565b50906107335f8051602061507483398151915293956107256129b3946001976145d58661406c565b6145de84613bb5565b6145e781613df3565b6145f082613ed6565b60025460a08a901b8a9003166001600160a01b0316614619575b604051958694602086016141a0565b614621614faa565b61460a565b6003546001600160a01b03168015612e36576040516379b60be960e01b81523060048201525f60248201526001600160a01b03929092166044830152602090829060649082905afa5f9181614680575b506109c357505f90565b61469a91925060203d602011610ed257610ec48183610920565b905f614676565b93906080939695926146c89160018060a01b0316865260a0602087015260a08601906104ad565b604085019690965260608401526001600160a01b0316910152565b156146ea57565b60405162461bcd60e51b8152602060048201526013602482015272131a589c985c9e481cddd85c0819985a5b1959606a1b6044820152606490fd5b80158015614810575b61480b5761473a6139a8565b906001600160a01b038216156147fc57614752614f6b565b916001600160a01b038316156147ed576109c3935f936147bd859461477561334e565b60095480151588146147e1578161392e61479561479b93610725956123a0565b85612d22565b935b6040519485936020850197631f19e6af60e01b89523093602487016146a1565b51915af46147d26147cc61323e565b916146e3565b60208082518301019101612a68565b5050610725869361479d565b63179ce99f60e01b5f5260045ffd5b6321c7ca3d60e01b5f5260045ffd5b905090565b5081511561472e565b90816060910312610487578051916040602083015192015190565b90602080835192838152019201905f5b8181106148515750505090565b8251845260209384019390920191600101614844565b94929097969593919760e086526101a0860161ffff82511660e088015260208201519060c0610100890152815180915260206101c089019201905f5b818110614943575050509260c095926149248361491260a06148fa6148e361219e9a6109559f9e9c99604001518d61012060df1982850301910152614834565b60608501518c820360df19016101408e0152614834565b60808401516101608c015292015115156101808a0152565b6001600160a01b03909c166020880152565b6040860152606085015260808401526001600160a01b031660a0830152565b82516001600160a01b03168452602093840193909201916001016148a3565b9193929590969460018060a01b03614978615002565b16938415614a7957926149aa89935f9360609897966040519b8c998a988997636e06907960e11b895260048901614867565b03925af1918215610bee575f925f915f91614a43575b509293816149cc575050565b6001600160a01b0381165f908152600b602052604090207f6c04d07f86188951f3cb794b579d368362f0465c03036426a0d21b44258a30319190614a11848254611feb565b90556001600160a01b03165f818152600b602090815260409182902054825195865290850152909290819081016129b3565b915050614a6991925060603d606011614a72575b614a618183610920565b810190614819565b9192915f6149c0565b503d614a57565b505f97508796505050505050565b908115614aec57614a9661230c565b918060011c808203918211611ff857600e546001600160a01b0394851694168414614ae657614ac790613617610ce0565b925b600f546001600160a01b0316146109c3576109c390613617610c2b565b92614ac9565b5f91508190565b95929796939060c09592614b1c9160018060a01b0316885260e0602089015260e08801906104ad565b60408701989098526060860152608085015260a08401526001600160a01b0316910152565b15614b4857565b60405162461bcd60e51b815260206004820152601b60248201527f4c696272617279206164644c6971756964697479206661696c656400000000006044820152606490fd5b919082158015614cc6575b613a2957614ba461334e565b92600954614bf2614bc28661392e614bbc85836123a0565b86612d22565b9561392e614bdd8261392e614bd787836123a0565b89612d22565b93612e4b614beb8888611feb565b91846123a0565b94614bfb6139a8565b906001600160a01b038216156147fc57614c13614f6b565b946001600160a01b038616156147ed57614c995f95610725614cae988897614c42600e5460018060a01b031690565b600f54604080516001600160a01b03938416602082015292909116908201525f606080830191909152815296614c79608089610920565b6040519687956020870199632958884360e01b8b52309560248901614af3565b51915af46147d2614ca861323e565b91614b41565b918210614cb757565b63427282e960e11b5f5260045ffd5b508015614b98565b6001600160a01b0390911681526040602082018190526109c39101600c6125c5565b6003546001600160a01b031691908215614db0576002546001600160a01b031690833b15610487576040516374a3658160e01b81526001600160a01b03929092166004830152602482015260448101919091525f8160648183865af18015610bee57614d9c575b506002546001600160a01b031690803b15610487576040516301f12f3960e11b8152915f918391829084908290614d919060048301614cce565b03925af161442f5750565b80611f695f614daa93610920565b5f614d57565b505050565b905f602091828151910182855af115612206575f513d614e0457506001600160a01b0381163b155b614de45750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b60011415614ddd565b90614e188251612a15565b5f5b8351811015614e5d5780614e43614e3360019387612a54565b516020808251830101910161236f565b5050828060a01b0316614e568285612a54565b5201614e1a565b509150565b60405163095ea7b360e01b60208083019182526001600160a01b038516602484015260016044840152919291905f90614ea885606481015b03601f198101875286610920565b84519082855af15f51903d81614f02575b501590505b614ec757505050565b60405163095ea7b360e01b60208201526001600160a01b0390931660248401525f604484015261095592613ac0906144ef8160648101610725565b15159050614f225750614ebe6001600160a01b0382163b15155b5f614eb9565b6001614ebe9114614f1c565b60405163095ea7b360e01b60208281019182526001600160a01b03851660248401526044830195909552929390925f90614ea88560648101614e9a565b6005541580612efc576111695760055f527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0546001600160a01b031690565b6003546001600160a01b031680614fbe5750565b6002546001600160a01b031690803b15610487576040516301f12f3960e11b8152915f918391829084908290614ff79060048301614cce565b03925af1613a7a5750565b6003546001600160a01b03168015612efc575f8091604051602081019063876dcc4160e01b825260048152615038602482610920565b51915afa61504461323e565b9080615067575b61505457505f90565b80602080610a9e935183010191016122f7565b5060208151101561504b56fe67e3df1218a20e3bb0b11c3a0295e5cc1a84004b1873f6eaedaeb935de8676d31b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae672f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a2646970667358221220be92bed85733e6db52b862295dddecf6d3d58bca9e5419d5bce0e0406cddeaf164736f6c634300081a0033
Deployed Bytecode Sourcemap
2558:19699:32:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;;;;;;:::o;:::-;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2558:19699:32;;;;;;;;-1:-1:-1;;2558:19699:32;;;;:::o;:::-;;;;;;-1:-1:-1;;2558:19699:32;;;;;15698:5:31;2558:19699:32;;;15681:23:31;;;;2558:19699:32;15681:23:31;;;;2558:19699:32;15681:23:31;;:::i;:::-;2558:19699:32;;;;;15681:23:31;2558:19699:32;;15681:23:31;2558:19699:32;;;;:::i;:::-;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;:::o;:::-;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;;;:::i;:::-;2466:103:10;;:::i;:::-;1315:72:9;;:::i;:::-;20385:78:31;;:::i;:::-;20477:12;;;:56;;;;2558:19699:32;20473:116:31;;;20626:39;:16;;:::i;:::-;20645:20;;:::i;:::-;20626:39;;:::i;:::-;2558:19699:32;;;:::i;:::-;;20858:15:31;;:::i;:::-;;13767:1018:32;;:::i;:::-;21018:17:31;;;21014:69;;21454:10;21345:30;;21184:56;21345:30;;;:::i;:::-;;:::i;:::-;21454:10;:::i;:::-;21184:56;:::i;:::-;21659:29;21673:15;21659:29;2558:19699:32;;21659:29:31;2531:1:10;1857;2558:19699:32;;2888:208:10;2531:1;2558:19699:32;21014:69:31;2558:19699:32;;-1:-1:-1;;;21044:39:31;;2558:19699:32;;21044:39:31;;2558:19699:32;;;;;;-1:-1:-1;;;2558:19699:32;;;;;;21044:39:31;20473:116;2558:19699:32;;-1:-1:-1;;;20556:22:31;;2558:19699:32;;20556:22:31;;2558:19699:32;;;;;;-1:-1:-1;;;2558:19699:32;;;;;;21044:39:31;20477:56;20511:22;2558:19699:32;;20511:11:31;2558:19699:32;20511:22:31;:::i;:::-;20493:15;:40;20477:56;;;2558:19699:32;;;;;;-1:-1:-1;;2558:19699:32;;;;;16141:20:31;;:::i;2558:19699:32:-;;;;;;-1:-1:-1;;2558:19699:32;;;;14689:17:31;2558:19699:32;;;;-1:-1:-1;;;;;2558:19699:32;29182:10:31;:31;29178:58;;29271:4;29250:25;;29246:81;;-1:-1:-1;;;;;;;;;;;29399:77:31;29424:51;;29346:38;;-1:-1:-1;29346:38:31;;2558:19699:32;;29346:38:31;2558:19699:32;;29424:51:31;;;2558:19699:32;29424:51:31;;2558:19699:32;;;;;;;;;;-1:-1:-1;;;2558:19699:32;;;;;;;;;;;;29424:51:31;;2558:19699:32;;29424:51:31;;;;;;:::i;:::-;2558:19699:32;;29399:77:31;;;;;:::i;:::-;;;;2558:19699:32;29246:81:31;2558:19699:32;;-1:-1:-1;;;29284:43:31;;2558:19699:32;;29284:43:31;;2558:19699:32;;;;;;;;;;;;;21044:39:31;29178:58;29222:14;;;-1:-1:-1;29222:14:31;2558:19699:32;-1:-1:-1;29222:14:31;2558:19699:32;;;;;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;;:::o;:::-;;-1:-1:-1;;2558:19699:32;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;;;2952:18;2558:19699;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;:::o;:::-;;:::i;:::-;;;;;;;;:::i;:::-;:::o;:::-;-1:-1:-1;;;;;2558:19699:32;;;;;;-1:-1:-1;;2558:19699:32;;;;:::o;:::-;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;2558:19699:32;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;:::o;:::-;;;;;;-1:-1:-1;;2558:19699:32;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;8008:48;2558:19699;;;;;;;;:::i;:::-;;;;;8008:48;;;;;;:::i;:::-;2558:19699;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;3636:1:31;2558:19699:32;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;;;2466:103:10;;:::i;:::-;19120:5:31;2558:19699:32;2531:1:10;;-1:-1:-1;;;;;2558:19699:32;19106:10:31;:19;19102:43;;19174:16;;:::i;:::-;19213:18;;;19209:795;;2558:19699:32;;;20056:7:31;;2558:19699:32;;20022:13:31;;-1:-1:-1;;;;;2558:19699:32;;-1:-1:-1;;;;;2558:19699:32;;;20022:13:31;19120:5;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;20056:7:31;;:::i;19209:795::-;19265:18;;;;;:::i;:::-;;:::i;:::-;19309:16;;:::i;:::-;19623:18;;;;;:31;;19209:795;19619:117;;20056:7;19919:75;;;19209:795;19919:75;19961:18;;19919:75;19209:795;;19619:117;-1:-1:-1;;;;19681:40:31;2558:19699:32;;;;;;;;;-1:-1:-1;19681:40:31;19623:31;34701:14;19645:9;34701:14;2558:19699:32;1796:7:9;2558:19699:32;;1726:84:9;;34701:14:31;19645:9;;2558:19699:32;19645:9:31;19623:31;;19102:43;19134:11;;;-1:-1:-1;19134:11:31;2558:19699:32;-1:-1:-1;19134:11:31;2558:19699:32;;;;;;-1:-1:-1;;2558:19699:32;;;;14689:17:31;2558:19699:32;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;;;-1:-1:-1;;;15783:32:31;;2558:19699:32;15783:32:31;;2558:19699:32;;;;;-1:-1:-1;;;;;2558:19699:32;15783:32:31;;;;;;2558:19699:32;15783:32:31;;;2558:19699:32;;;;;;;;;;;;;15783:32:31;;;;;;;;;;;;;;;;:::i;:::-;;;2558:19699:32;;;;;;;;;;;;;15783:32:31;;;;;;-1:-1:-1;15783:32:31;;;;:::i;2558:19699:32:-;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2558:19699:32;5394:24:31;2558:19699:32;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;5394:24:31;-1:-1:-1;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2558:19699:32;22221:11;2558:19699;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;22221:11:32;-1:-1:-1;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2558:19699:32;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;2558:19699:32;;;;;-1:-1:-1;2558:19699:32;;-1:-1:-1;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;2558:19699:32;;;;14689:17:31;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;8537:31:31;;8533:62;;2558:19699:32;;-1:-1:-1;;;8610:96:31;;8682:4;2558:19699:32;8610:96:31;;2558:19699:32;;;;;;8695:10:31;2558:19699:32;;;;;8610:96:31;;2558:19699:32;;;;;;8610:96:31;;;;;;;2558:19699:32;8610:96:31;;;2558:19699:32;8609:97:31;;8605:149;;2586:117:9;;:::i;8610:96:31:-;;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;8533:62;8577:18;;;2558:19699:32;8577:18:31;2558:19699:32;;8577:18:31;2558:19699:32;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;;:::i;:::-;17059:11:31;2558:19699:32;;;17059:35:31;;;2558:19699:32;-1:-1:-1;;2558:19699:32;;;;;;17059:35:31;2558:19699:32;-1:-1:-1;17059:35:31;;2558:19699:32;;-1:-1:-1;;2558:19699:32;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;-1:-1:-1;;;;;;;;;;;2558:19699:32;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;19645:9:31;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;;;;;4724:16:0;;:34;;;;2558:19699:32;4803:1:0;4788:16;:50;;;;2558:19699:32;4853:13:0;:30;;;;2558:19699:32;4849:91:0;;;5053:1;4949:18;;;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;-1:-1:-1;;;;;;;;;;;2558:19699:32;;;-1:-1:-1;;;;;;;;;;;2558:19699:32;;4949:18:0;4977:67;;5053:1;:::i;:::-;5064:101;;2558:19699:32;5064:101:0;5098:23;-1:-1:-1;;;2558:19699:32;-1:-1:-1;;;;;;;;;;;2558:19699:32;;-1:-1:-1;;;;;;;;;;;2558:19699:32;;5098:23:0;2558:19699:32;;4803:1:0;2558:19699:32;;5140:14:0;;2558:19699:32;;5140:14:0;2558:19699:32;4977:67:0;5011:22;-1:-1:-1;;;;;;2558:19699:32;-1:-1:-1;;;;;;;;;;;2558:19699:32;;;-1:-1:-1;;;;;;;;;;;2558:19699:32;;5011:22:0;5053:1;:::i;4849:91::-;4906:23;;;-1:-1:-1;4906:23:0;2558:19699:32;-1:-1:-1;4906:23:0;4853:30;4870:13;;;4853:30;;;4788:50;4816:4;4808:25;:30;;-1:-1:-1;4788:50:0;;4724:34;;;-1:-1:-1;4724:34:0;;2558:19699:32;;;;;;-1:-1:-1;;2558:19699:32;;;;3736:27:31;2558:19699:32;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;27429:5:31;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;27415:10:31;:19;27411:46;;1315:72:9;;:::i;:::-;2408:4;2558:19699:32;;;;;;;;2427:20:9;2558:19699:32;;;27415:10:31;2558:19699:32;;2427:20:9;27411:46:31;;:::i;2558:19699:32:-;;;;;;;;;;;;;13005:12;2558:19699;;;;;;13005:12;-1:-1:-1;2558:19699:32;;-1:-1:-1;2558:19699:32;;;-1:-1:-1;2558:19699:32;:::o;:::-;;:::i;:::-;14530:17;2558:19699;;;;;;14530:17;-1:-1:-1;2558:19699:32;;-1:-1:-1;2558:19699:32;;;-1:-1:-1;2558:19699:32;:::o;:::-;;;;;;-1:-1:-1;;2558:19699:32;;;;;;2802:24:31;2558:19699:32;2802:24:31;;;;;;-1:-1:-1;2558:19699:32;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;;;:::i;:::-;14689:17:31;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;8537:31:31;;8533:62;;2558:19699:32;;-1:-1:-1;;;8610:96:31;;8682:4;2558:19699:32;8610:96:31;;2558:19699:32;-1:-1:-1;2558:19699:32;;;;8695:10:31;2558:19699:32;;;;;;;;;;;;;8610:96:31;;;;;;;-1:-1:-1;8610:96:31;;;2558:19699:32;8609:97:31;;8605:149;;8763:1;;;:::i;8610:96::-;;;;2558:19699:32;8610:96:31;2558:19699:32;8610:96:31;;;;;;;:::i;:::-;;;;2558:19699:32;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;4994:23:31;2558:19699:32;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;;36123:12:31;2558:19699:32;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;;;:::i;:::-;28258:5:31;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;28258:19:31;;;;;:42;;2558:19699:32;28254:75:31;;;28258:5;2558:19699:32;;-1:-1:-1;;;;;;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;;;;;-1:-1:-1;;;;;2558:19699:32;28425:20:31;;2558:19699:32;;;;;;;;;;;;;;28465:33:31;;;;-1:-1:-1;;28465:33:31;;;28421:299;-1:-1:-1;28461:188:31;;-1:-1:-1;28679:30:31;2558:19699:32;;-1:-1:-1;;;;;;2558:19699:32;;;;28461:188:31;28540:24;2558:19699:32;;-1:-1:-1;;;;;;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;28465:33:31;;;;;2558:19699:32;28465:33:31;2558:19699:32;28465:33:31;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;28421:299;-1:-1:-1;28679:30:31;2558:19699:32;;-1:-1:-1;;;;;;2558:19699:32;;;;28254:75:31;28309:20;;;-1:-1:-1;28309:20:31;2558:19699:32;-1:-1:-1;28309:20:31;28258:42;-1:-1:-1;;;;;2558:19699:32;;-1:-1:-1;28281:10:31;:19;;28258:42;;;2558:19699:32;;;;;;;;;;;;;;-1:-1:-1;2558:19699:32;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;19149:5;2558:19699;19136:31;;:19;;2558:19699;;-1:-1:-1;;;;;2558:19699:32;19136:19;2558:19699;19136:31;2558:19699;;-1:-1:-1;;;19136:33:32;;2558:19699;;;;19136:33;;;;;;;;2558:19699;19136:33;;;2558:19699;;19212:26;2558:19699;;19212:26;:::i;:::-;19253:13;2558:19699;19285:3;2558:19699;;19268:15;;;;;19344:7;19317:50;19344:7;;19317:50;19344:7;;;:::i;:::-;2558:19699;-1:-1:-1;;;;;2558:19699:32;;;19344:7;2558:19699;;-1:-1:-1;;;19317:50:32;;-1:-1:-1;;;;;2558:19699:32;;;;19317:50;;2558:19699;19361:4;2558:19699;;;;;;;;;;;;;;19317:50;;;;;;;;;;2558:19699;19317:50;2558:19699;19317:50;;;19285:3;19304:63;;;;;:::i;:::-;2558:19699;;19253:13;;19317:50;;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;19268:15;;;2558:19699;;;;;;;;:::i;19136:33::-;;;;;;2558:19699;19136:33;;;;;;:::i;:::-;;;;;:::i;:::-;;;;2558:19699;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;;;:::i;:::-;35240:5:31;2558:19699:32;;;-1:-1:-1;;;35233:32:31;;-1:-1:-1;;;;;2558:19699:32;;;;35233:32:31;;2558:19699:32;;;;;;35233:32:31;;2558:19699:32;;;35233:32:31;;;;;;2558:19699:32;35233:32:31;-1:-1:-1;35233:32:31;;;2558:19699:32;35226:39:31;2558:19699:32;;;;;;35233:32:31;;;;;;;;;;;;;;:::i;:::-;;;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2558:19699:32;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;:::i;:::-;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;2558:19699:32;;;;;;4738:29:31;2558:19699:32;4738:29:31;;;;;;-1:-1:-1;2558:19699:32;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;14689:17:31;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;8537:31:31;;8533:62;;2558:19699:32;;-1:-1:-1;;;8610:96:31;;8682:4;2558:19699:32;8610:96:31;;2558:19699:32;;;;;;8695:10:31;2558:19699:32;;;;;8610:96:31;;2558:19699:32;;;;;;8610:96:31;;;;;;;2558:19699:32;8610:96:31;;;2558:19699:32;8609:97:31;;8605:149;;2339:115:9;;:::i;8610:96:31:-;;;;;;;;;;;;;;:::i;:::-;;;;2558:19699:32;;;;;;-1:-1:-1;;2558:19699:32;;;;5072:23:31;2558:19699:32;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;35956:7:31;2558:19699:32;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;28122:4:31;28100:10;:27;28096:54;;;;:::i;2558:19699:32:-;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;:::i;:::-;;;;;;;:::i;:::-;-1:-1:-1;;2558:19699:32;;-1:-1:-1;;;12996:54:31;;2558:19699:32;;12996:54:31;;2558:19699:32;;;;;;;;;;;-1:-1:-1;;;2558:19699:32;;;;12996:54:31;;;2558:19699:32;;;;;;-1:-1:-1;;2558:19699:32;;;;;;3315:30:31;2558:19699:32;;;;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;;;:::i;:::-;;;;;;:::i;:::-;14689:17:31;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;8537:31:31;;8533:62;;2558:19699:32;;-1:-1:-1;;;8610:96:31;;8682:4;2558:19699:32;8610:96:31;;2558:19699:32;;;;;;8695:10:31;2558:19699:32;;;;;;;;;;;;;8610:96:31;;;;;;;-1:-1:-1;8610:96:31;;;2558:19699:32;8609:97:31;;8605:149;;8763:1;;;:::i;8610:96::-;;;;2558:19699:32;8610:96:31;2558:19699:32;8610:96:31;;;;;;;:::i;:::-;;;;2558:19699:32;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;3590:1:31;2558:19699:32;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;3165:20;2558:19699;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;2558:19699:32;4839:45:31;2558:19699:32;;;;;-1:-1:-1;2558:19699:32;;;;;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;2558:19699:32;;;;;;5182:32:31;2558:19699:32;5182:32:31;;;;;2558:19699:32;;;5182:32:31;-1:-1:-1;2558:19699:32;-1:-1:-1;;;;;;;;;;;2558:19699:32;;:::i;:::-;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;;:::i;:::-;;17283:13:31;;:::i;2558:19699:32:-;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;14689:17:31;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;8537:31:31;;8533:62;;2558:19699:32;;-1:-1:-1;;;8610:96:31;;8682:4;2558:19699:32;8610:96:31;;2558:19699:32;;;;;;8695:10:31;2558:19699:32;;;;;;;;;;;;;8610:96:31;;;;;;;-1:-1:-1;8610:96:31;;;2558:19699:32;8609:97:31;;8605:149;;8763:1;;;:::i;8610:96::-;;;;2558:19699:32;8610:96:31;2558:19699:32;8610:96:31;;;;;;;:::i;:::-;;;;2558:19699:32;;;;;;-1:-1:-1;;2558:19699:32;;;;;3202:32:31;2558:19699:32;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;1315:72:9;;:::i;:::-;17551:16:31;;:::i;:::-;17581:12;17577:44;;2558:19699:32;17577:44:31;17612:8;;;:::i;2558:19699:32:-;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;;;:::i;:::-;34089:5:31;2558:19699:32;34075:19:31;;-1:-1:-1;;;;;2558:19699:32;;;34075:19:31;:10;:19;34071:43;;-1:-1:-1;;;;;2558:19699:32;;34128:29:31;34124:55;;34189:30;2558:19699:32;;-1:-1:-1;;;;;;2558:19699:32;;;;;-1:-1:-1;;;;;2558:19699:32;;;;-1:-1:-1;;;;;;;;;;;;;34234:83:31;;;34189:30;2558:19699:32;34259:57:31;;2558:19699:32;;-1:-1:-1;;;;;2558:19699:32;;;;;;34259:57:31;;2558:19699:32;;;;;;;;-1:-1:-1;;;2558:19699:32;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;34259:57:31;2558:19699:32;34124:55:31;34166:13;;;-1:-1:-1;34166:13:31;2558:19699:32;-1:-1:-1;34166:13:31;2558:19699:32;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;2558:19699:32;;;;8735:11;2558:19699;8748:12;2558:19699;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;2558:19699:32;3977:54:31;2558:19699:32;;;;-1:-1:-1;2558:19699:32;;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;;3099:26:31;2558:19699:32;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;3498:27;2558:19699;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;;:::i;:::-;14689:17:31;2558:19699:32;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;21533:10;:29;21529:58;;2558:19699;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21694:1;-1:-1:-1;;;;;;;;;;;21672:75:32;21697:49;;2558:19699;21597:60;2558:19699;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;21597:60;;:::i;:::-;2558:19699;;;;21697:49;;2558:19699;;;;21730:15;2558:19699;;;;;;;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;21529:58;21571:16;;;-1:-1:-1;21571:16:32;2558:19699;-1:-1:-1;21571:16:32;2558:19699;;;;;;-1:-1:-1;;2558:19699:32;;;;27650:5:31;2558:19699:32;27636:19:31;;-1:-1:-1;;;;;2558:19699:32;;;27636:19:31;:10;:19;;:57;;;2558:19699:32;27632:109:31;;27837:4;:33;;;;2558:19699:32;;-1:-1:-1;;;27837:33:31;;2558:19699:32;;;;;27837:4:31;:33;;;;2558:19699:32;27910:16:31;;;:::i;:::-;27940:12;27936:61;;2558:19699:32;28007:19:31;2558:19699:32;;28007:19:31;2558:19699:32;;28007:19:31;2558:19699:32;;27936:61:31;2558:19699:32;;27988:8:31;;2558:19699:32;27954:13:31;;-1:-1:-1;;;;;2558:19699:32;;;27988:8:31;27936:61;;;27837:33;;;2558:19699:32;27837:33:31;;;:::i;:::-;;;:::i;:::-;;;;27636:57;:10;27659:34;27660:33;27636:10;27660:33;:::i;27659:34::-;27636:57;;2558:19699:32;;;;;;-1:-1:-1;;2558:19699:32;;;;2503:20:31;2558:19699:32;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;-1:-1:-1;;2558:19699:32;;;;3329:26;2558:19699;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;:::i;15828:111:31:-;15898:16;;:::i;:::-;16141:20;;:::i;:::-;2558:19699:32;;;;;;;15828:111:31;:::o;2558:19699:32:-;;;;20713:12:31;2558:19699:32;;;;;;;;20713:12:31;-1:-1:-1;2558:19699:32;;-1:-1:-1;2558:19699:32;;-1:-1:-1;2558:19699:32;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;-1:-1:-1;2558:19699:32;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;2558:19699:32;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;:::i;:::-;;;;;;;;;;;;;-1:-1:-1;2558:19699:32;;;;;;;;-1:-1:-1;;2558:19699:32;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;20379:742;;;;;;;;;;-1:-1:-1;;;;;20673:36:32;;:::i;:::-;2558:19699;20723:31;;;20719:109;;2558:19699;21037:23;;;20895:219;21037:23;;;:::i;:::-;21074:8;2558:19699;-1:-1:-1;;;;;2558:19699:32;21096:8;2558:19699;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;20895:219;;;;;;:::i;:::-;;;;;;;;;;2558:19699;;;20895:219;;;20888:226;;20379:742;:::o;20895:219::-;;;;;;;;;2558:19699;20895:219;;;;;;:::i;:::-;;;;;:::i;20719:109::-;20770:47;;;;;;;;2558:19699;;;;;;;;:::i;:::-;;;;;;;;;20770:47;:::o;2558:19699::-;;;;;;;;;;;;;:::i;15299:234:31:-;14689:17;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;15425:24:31;2558:19699:32;;15425:101:31;-1:-1:-1;15299:234:31;:::o;15425:101::-;15465:61;;2558:19699:32;;;;;;;;;;15465:61:31;;;;;;;;;-1:-1:-1;15465:61:31;;;15425:101;15299:234;:::o;15465:61::-;;;;;;;;;;;;;;:::i;2558:19699:32:-;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;:::i;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;:::i;:::-;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;2558:19699:32;;-1:-1:-1;2558:19699:32;;-1:-1:-1;2558:19699:32;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;;;;;;6782:12;2558:19699;:::i;:::-;;;;:::o;4520:2382::-;4767:38;4520:2382;5242:123;4520:2382;4767:38;;;;:::i;:::-;5242:123;2558:19699;;;;;;5242:123;;;;;;:::i;:::-;2558:19699;;;;;;;;;;;;;;;;;;;;;;5447:28;;5242:123;5447:28;;;;;;;;;;;-1:-1:-1;5447:28:32;;;4520:2382;-1:-1:-1;2558:19699:32;;-1:-1:-1;;;5543:30:32;;2558:19699;;;;;5242:123;2558:19699;5447:28;2558:19699;;5543:30;;;;;;;-1:-1:-1;5543:30:32;;;4520:2382;-1:-1:-1;2558:19699:32;;-1:-1:-1;;;5632:32:32;;2558:19699;5242:123;2558:19699;5447:28;2558:19699;-1:-1:-1;;;;;2558:19699:32;;5632:32;;;;;;;6049:28;5632:32;6013:26;5632:32;-1:-1:-1;5632:32:32;;;4520:2382;2558:19699;5855:31;5903:13;2558:19699;;;;;;;;5855:31;;:::i;:::-;5903:13;;;:::i;:::-;5989:14;2558:19699;;-1:-1:-1;;;;;;2558:19699:32;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;6013:26;2558:19699;;;6013:26;2558:19699;;6013:26;2558:19699;;;;;;-1:-1:-1;;;;;2558:19699:32;;6049:28;2558:19699;;;6049:28;2558:19699;;6049:28;2558:19699;;-1:-1:-1;;;6134:20:32;;-1:-1:-1;;;;;2558:19699:32;;;;;;5242:123;2558:19699;5447:28;2558:19699;;6134:20;;;;;;6123:31;6134:20;-1:-1:-1;6134:20:32;;;4520:2382;6123:31;2558:19699;;;;;;-1:-1:-1;;;;;2558:19699:32;;6123:31;2558:19699;;;6123:31;2558:19699;;6123:31;2558:19699;;-1:-1:-1;;;6175:20:32;;2558:19699;5242:123;2558:19699;5447:28;2558:19699;6175:20;;;;;;;;6164:31;6303:16;6175:20;6487:17;6175:20;-1:-1:-1;6175:20:32;;;4520:2382;6164:31;2558:19699;;;;;;-1:-1:-1;;;;;2558:19699:32;;6164:31;2558:19699;;;6164:31;2558:19699;;6164:31;28540:24:31;2558:19699:32;;-1:-1:-1;;;;;;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;6303:16;6487:17;:::i;:::-;;;:::i;:::-;-1:-1:-1;6671:224:32;2558:19699;;6870:15;6671:224;6870:15;6671:224;;:::i;:::-;;;;4520:2382::o;6175:20::-;;;;5242:123;6175:20;5242:123;6175:20;;;;;;;:::i;:::-;;;;6134;;;;5242:123;6134:20;5242:123;6134:20;;;;;;;:::i;:::-;;;;5632:32;5903:13;5632:32;;;5855:31;5632:32;5242:123;5632:32;5242:123;5632:32;;;;;;;:::i;:::-;;;;;5543:30;;;;;5242:123;5543:30;5242:123;5543:30;;;;;;;:::i;:::-;;;;;5447:28;;;;;;;5242:123;5447:28;5242:123;5447:28;;;;;;;:::i;:::-;;;;;37026:419:31;-1:-1:-1;;;;;2558:19699:32;;-1:-1:-1;2558:19699:32;;;37133:19:31;2558:19699:32;;;;;;;37173:11:31;;37169:58;;37246:26;37372:47;37246:26;37325:6;37369:1;37246:26;-1:-1:-1;;;;;;;;;;;37246:26:31;-1:-1:-1;37246:26:31;37347:73;37246:26;2558:19699:32;;;;;;;;37133:19:31;2558:19699:32;;;;;;;37246:26:31;2558:19699:32;37313:10:31;37325:6;;:::i;:::-;2558:19699:32;;;;;37372:47:31;;2558:19699:32;;;;;;;;-1:-1:-1;;;2558:19699:32;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;37372:47:31;2558:19699:32;37347:73:31;;;;37026:419::o;37169:58::-;2558:19699:32;;-1:-1:-1;;;37193:34:31;;2558:19699:32;37193:34:31;;;2558:19699:32;;;;;;-1:-1:-1;;;2558:19699:32;;;;;;37193:34:31;2558:19699:32;;;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;:::o;:::-;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::o;:::-;7688:17;2558:19699;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;7688:17;-1:-1:-1;2558:19699:32;;;-1:-1:-1;;;;;;;;;;;2558:19699:32;;;;;;;;;;;;;:::o;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;15945:118:31;16018:38;2558:19699:32;;;;;;16025:5:31;2558:19699:32;;;;;;;;;;;16018:38:31;;16050:4;16025:5;16018:38;;2558:19699:32;16018:38:31;;;;;;;-1:-1:-1;16018:38:31;;;16011:45;15945:118;:::o;16018:38::-;;;;2558:19699:32;16018:38:31;2558:19699:32;16018:38:31;;;;;;;:::i;2558:19699:32:-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;:::i;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;:::i;:::-;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;:::i;:::-;;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;:::o;:::-;;26719:4:31;2558:19699:32;;;;;;26719:4:31;2558:19699:32;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;:::o;:::-;;;;;;;;;;;;17700:1329:31;2558:19699:32;;-1:-1:-1;;;17818:28:31;;2558:19699:32;;17818:28:31;2558:19699:32;17818:4:31;:28;;;;;;2558:19699:32;;;17818:28:31;;;17700:1329;2558:19699:32;;;17860:18:31;17856:32;;17991:23;;:::i;:::-;2558:19699:32;;-1:-1:-1;;;;;2558:19699:32;;;;;18060:13:31;2558:19699:32;;18075:17:31;;;;;18113:9;:24;:9;;;;;:::i;:24::-;;18109:57;;18060:13;2558:19699:32;;18060:13:31;;18109:57;18156:10;18139:27;2558:19699:32;18156:10:31;;;;;:::i;:::-;2558:19699:32;18139:27:31;;:::i;:::-;18109:57;;;;;18075:17;;;;;18221:18;;18217:32;;14689:17;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;;18312:18:31;;18308:32;;18416:5;2558:19699:32;;;-1:-1:-1;;;18363:59:31;;-1:-1:-1;;;;;2558:19699:32;;;17818:28:31;18363:59;;2558:19699:32;;-1:-1:-1;;2558:19699:32;;;;;;18363:59:31;;2558:19699:32;;18363:59:31;;;18055:153;18359:646;;;18055:153;19014:8;;2558:19699:32;17700:1329:31;:::o;18359:646::-;18497:102;18496:217;18513:86;;;:::i;:::-;18497:102;;:::i;:::-;18635:78;;:::i;:::-;18496:217;;:::i;:::-;2558:19699:32;18797:13:31;18816:17;;;;2558:19699:32;18812:28:31;;;;;18756:22;18865:16;:13;;;;;:16;:::i;:::-;2558:19699:32;18865:25:31;18861:75;;2558:19699:32;;18797:13:31;;18861:75;18912:13;:16;18900:28;18912:13;2558:19699:32;18899:37:31;18912:13;;;:16;:::i;:::-;2558:19699:32;18900:28:31;;:::i;:::-;18932:4;2558:19699:32;;;;18812:28:31;;;;18359:646;;;;18363:59;;;;;;;2558:19699:32;18363:59:31;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;18217:32;18241:8;2558:19699:32;18241:8:31;:::o;17818:28::-;;;;;;;;2558:19699:32;17818:28:31;;;;;;:::i;:::-;;;;;:::i;:::-;;;;7163:363:32;-1:-1:-1;;;;;2558:19699:32;;7285:26;;:57;;;;7163:363;7281:83;;7410:28;2558:19699;-1:-1:-1;;;;;2558:19699:32;;7374:26;2558:19699;;;7374:26;2558:19699;;;;;;;-1:-1:-1;;;;;2558:19699:32;;6049:28;2558:19699;;;6049:28;2558:19699;;7410:28;7475:5;2558:19699;7482:5;2558:19699;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;7453:66;;2558:19699;7453:66;7503:15;2558:19699;7453:66;:::i;7285:57::-;-1:-1:-1;;;;;;2558:19699:32;;7315:27;7285:57;;37797:980:31;37974:5;2558:19699:32;37797:980:31;;;37965:14;;-1:-1:-1;;;;;2558:19699:32;;;37965:14:31;-1:-1:-1;;;;;2558:19699:32;;;;37965:14:31;;37961:68;;-1:-1:-1;;;;;2558:19699:32;;38043:23:31;38039:77;;2558:19699:32;;-1:-1:-1;;;38144:38:31;;38176:4;37974:5;38144:38;;2558:19699:32;;38144:38:31;2558:19699:32;;;38144:38:31;;;;;;;;38064:1;38144:38;;;37797:980;38196:12;;;38192:64;;38289:11;;;:30;;;38333:22;;38329:73;;38710:42;38511:26;38710:42;38511:26;38657:12;38511:26;38707:1;38511:26;38685:68;38511:26;;-1:-1:-1;;;;;;;;;;;38511:26:31;2558:19699:32;;;;;;;;37133:19:31;2558:19699:32;;;;;;;38511:26:31;2558:19699:32;38507:94:31;;38657:12;:::i;:::-;2558:19699:32;;;-1:-1:-1;;;;;2558:19699:32;;;38144:38:31;38710:42;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;38507:94:31;-1:-1:-1;;;;;2558:19699:32;;38064:1:31;2558:19699:32;;;37133:19:31;2558:19699:32;;;;;;38657:12:31;:::i;38329:73::-;2558:19699:32;;-1:-1:-1;;;38364:38:31;;2558:19699:32;37974:5:31;38364:38;;2558:19699:32;;;;;;-1:-1:-1;;;2558:19699:32;;;;;;21044:39:31;38289:30;;;;38192:64;2558:19699:32;;-1:-1:-1;;;38217:39:31;;2558:19699:32;37974:5:31;38217:39;;2558:19699:32;;;;;;-1:-1:-1;;;2558:19699:32;;;;;;21044:39:31;38144:38;;;;;;;;;;;;;;;:::i;:::-;;;;;38039:77;2558:19699:32;;-1:-1:-1;;;38075:41:31;;2558:19699:32;37974:5:31;38075:41;;2558:19699:32;;;;;;;;;;;;;21044:39:31;37961:68;2558:19699:32;;-1:-1:-1;;;37988:41:31;;2558:19699:32;37974:5:31;37988:41;;2558:19699:32;;;;;;;;;;;;;21044:39:31;2575:307:10;1899:1;2702:7;2558:19699:32;2702:18:10;2698:86;;1899:1;2702:7;2558:19699:32;2575:307:10:o;2698:86::-;2743:30;;;-1:-1:-1;2743:30:10;;-1:-1:-1;2743:30:10;1878:128:9;2558:19699:32;1796:7:9;2558:19699:32;;1939:61:9;;1878:128::o;1939:61::-;1974:15;;;1796:7;1974:15;;1796:7;1974:15;2558:19699:32;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;-1:-1:-1;2558:19699:32;;;;:::o;:::-;;;:::o;5920:393:31:-;14689:17;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;6073:18:31;;6069:43;;20461:1;2558:19699:32;;;;6183:32:31;;;20404:55;;;;6183:32;;;;;;;;;:::i;:::-;6167:49;;;;;;:::i;:::-;6233:28;;;;5920:393;6233:73;;;2558:19699:32;6183:32:31;2558:19699:32;6264:27:31;2558:19699:32;;6264:27:31;;;;;;:::i;6233:28::-;2558:19699:32;6183:32:31;2558:19699:32;;6244:17:31;;6233:28;;5920:393;14689:17;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;6073:18:31;;6069:43;;2558:19699:32;;;;;6183:32:31;;;18532:61;;;;6183:32;;;;;;;;;:::i;:::-;6167:49;;;;;;:::i;:::-;6233:28;;;;5920:393;6233:73;;;2558:19699:32;6183:32:31;2558:19699:32;6264:27:31;2558:19699:32;;6264:27:31;;;;;;:::i;6233:73::-;;18595:3;5920:393;:::o;6233:28::-;2558:19699:32;6183:32:31;2558:19699:32;;6244:17:31;;6233:28;;5920:393;14689:17;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;6073:18:31;;6069:43;;2558:19699:32;;;;;6183:32:31;;;18654:50;;;;6183:32;;;;;;;;;:::i;:::-;6167:49;;;;;;:::i;:::-;6233:28;;;;5920:393;6233:73;;;2558:19699:32;6183:32:31;2558:19699:32;6264:27:31;2558:19699:32;;6264:27:31;;;;;;:::i;6233:73::-;;18706:6;5920:393;:::o;6233:28::-;2558:19699:32;6183:32:31;2558:19699:32;;6244:17:31;;6233:28;;12093:141:32;12195:5;2558:19699;;;-1:-1:-1;;;12182:44:32;;12220:4;12182:44;;;2558:19699;;12182:44;;2558:19699;;;;;;;;-1:-1:-1;;;;;2558:19699:32;12182:44;;;;;;;-1:-1:-1;12182:44:32;;;12175:51;12093:141;:::o;2558:19699::-;-1:-1:-1;;2558:19699:32;;;;;;;:::o;:::-;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;;;;;:::i;12817:804::-;13005:12;2558:19699;13049:12;2558:19699;-1:-1:-1;;;;;2558:19699:32;;13049:26;;2558:19699;;;13078:1;13049:34;2558:19699;13124:23;13138:8;;;;:::i;:::-;13124:23;:::i;:::-;13157:15;13194:1;13073;13186:9;;13182:73;;13049:34;13269:13;13073:1;13284:5;;;;;;-1:-1:-1;;13457:5:32;2558:19699;13444:36;;-1:-1:-1;13444:19:32;;2558:19699;;-1:-1:-1;;;;;2558:19699:32;13444:19;2558:19699;13444:36;:64;;;;;2558:19699;;-1:-1:-1;;;13444:64:32;;2558:19699;13073:1;;2558:19699;;;;13073:1;;2558:19699;;13444:64;;13489:4;13444:64;;;;:::i;:::-;;;;;;;;;;;13606:8;13073:1;12817:804;:::o;13444:64::-;;;13073:1;13444:64;;;:::i;:::-;;;;13291:3;13331:15;13310:36;2558:19699;13331:15;13194:1;13331:15;;:::i;:::-;2558:19699;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;13310:36;13322:5;;;:::i;:::-;13310:36;;;:::i;:::-;-1:-1:-1;;;;;2558:19699:32;;;;;;13310:36;2558:19699;13269:13;;13182:73;13223:5;;13211:33;2558:19699;13211:33;;;;:::i;:::-;13182:73;;;13049:34;2558:19699;13073:1;13049:34;;13767:1018;-1:-1:-1;;;;;13908:23:32;;:::i;:::-;2558:19699;;-1:-1:-1;;;13967:44:32;;14005:4;13967:44;;;2558:19699;;;;13967:44;2558:19699;;;;13967:44;;;;;;;-1:-1:-1;13967:44:32;;;13767:1018;14072:13;-1:-1:-1;14112:3:32;14091:12;2558:19699;14087:23;;;;;2558:19699;14153:15;;;:::i;:::-;2558:19699;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;14252:26;;;;14248:40;;2558:19699;;-1:-1:-1;;;14333:44:32;;14005:4;13967:44;14333;;2558:19699;;13967:44;;2558:19699;;;;;;14333:44;;;;;;2558:19699;14333:44;-1:-1:-1;14333:44:32;;;14112:3;14395:12;;;14391:26;;14515:36;14530:20;2558:19699;14530:20;;;:::i;:::-;2558:19699;;:::i;:::-;14515:36;;:::i;:::-;;14072:13;2558:19699;14072:13;;14391:26;14409:8;;;14333:44;;;;13967;14333;;;;;;;;;:::i;:::-;;;;14248:40;2558:19699;14280:8;;;;14087:23;-1:-1:-1;2558:19699:32;;-1:-1:-1;;;14648:44:32;;14005:4;13967:44;14648;;2558:19699;14087:23;;2558:19699;;;13967:44;;2558:19699;;;;;;14648:44;;;;;;;-1:-1:-1;14648:44:32;;;14067:495;-1:-1:-1;14709:31:32;;;;;;14743;;;:::i;14648:44::-;;;;;13967;14648;13967;14648;;;;;;;:::i;:::-;;;;;13967;;;;;;;;;;;;;;;:::i;:::-;;;;;22049:1376:31;22211:17;;22207:31;;14689:17;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;22306:31:31;;22302:56;;22531:5;2558:19699:32;;;-1:-1:-1;;;22502:35:31;;-1:-1:-1;;;;;2558:19699:32;;;22502:35:31;;;2558:19699:32;;-1:-1:-1;;2558:19699:32;;;;;;22502:35:31;;;;;;22896:201;22502:35;2558:19699:32;22502:35:31;;;22049:1376;22570:23;;;;:::i;:::-;22628:86;;;:::i;:::-;22746:78;;:::i;:::-;23075:12;2558:19699:32;;;;;;;;-1:-1:-1;;;;;2558:19699:32;22896:201:31;;:::i;:::-;23112:20;;;23108:155;;22049:1376;-1:-1:-1;;;;;;;;2558:19699:32;23342:25:31;;2558:19699:32;;;;-1:-1:-1;;;23370:44:31;;23408:4;22502:35;23370:44;;2558:19699:32;;23370:44:31;;2558:19699:32;;;;;;23370:44:31;;;;;;;2558:19699:32;23370:44:31;;;23342:76;22049:1376;:::o;23108:155::-;2558:19699:32;;;-1:-1:-1;;;;;2558:19699:32;;;23178:55:31;;;2558:19699:32;;;;;;;;;;;22531:5:31;;-1:-1:-1;;;;;;;;;;;23153:81:31;;;23178:55;2558:19699:32;;;;23178:55:31;2558:19699:32;23153:81:31;;;;23108:155;;;;;22502:35;;;;;;2558:19699:32;22502:35:31;;;;;;:::i;:::-;;;;22302:56;22339:19;;;:::o;25134:599::-;25231:17;;25227:31;;25429:26;25303:16;;:::i;:::-;25429:26;;:::i;:::-;25469:16;;;:36;;;25134:599;25465:114;;25134:599;25622:16;;;;:::i;:::-;25655:71;:32;;;;;;2558:19699:32;;;;;;;25134:599:31;:::o;25465:114::-;25521:47;;;:::i;:::-;;25465:114;;;;25469:36;25489:16;;;;25469:36;;18761:132:32;18829:13;;18825:26;;18877:8;;;:::i;18825:26::-;18844:7;:::o;25947:1146:31:-;;26591:36;25947:1146;26144:39;:16;;:::i;:39::-;26216:79;:36;;;;;;26255;;;;:::i;:::-;26216:79;;26412:16;;;;:::i;:::-;26606:5;2558:19699:32;26591:36:31;;:34;;:22;;-1:-1:-1;;;;;2558:19699:32;26591:22:31;2558:19699:32;26591:34:31;2558:19699:32;;-1:-1:-1;;;26591:36:31;;2558:19699:32;;;;;26591:36:31;;;;;;;26816:270;26591:36;-1:-1:-1;26591:36:31;;;26216:79;-1:-1:-1;26816:270:31;;26663:20;;;;26699:44;26700:23;;;;:::i;:::-;26699:44;:::i;:::-;26663:100;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;;;;;;27061:15:31;2558:19699:32;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;26663:100:31;26759:4;26663:100;;;26591:36;26816:270;26591:36;;;;;;;;;;;;;;;:::i;:::-;;;;;26216:79;;-1:-1:-1;26216:79:31;;;6732:577;14689:17;2558:19699:32;;;;-1:-1:-1;;;;;2558:19699:32;6882:18:31;;6878:41;;2558:19699:32;;-1:-1:-1;;;7035:69:31;;;;;;2558:19699:32;7035:69:31;;;2558:19699:32;;;;;;;;7035:69:31;;2558:19699:32;;;;7035:69:31;2558:19699:32;7035:69:31;7152:25;;;;;;:::i;:::-;7200:30;;;;6732:577;7196:107;;6732:577;:::o;7196:107::-;7246:46;2558:19699:32;;;;7035:69:31;2558:19699:32;7263:29:31;2558:19699:32;;7263:29:31;;;;;;:::i;7200:30::-;2558:19699:32;7035:69:31;2558:19699:32;;7211:19:31;;7200:30;;6878:41;-1:-1:-1;2558:19699:32;;-1:-1:-1;6902:17:31:o;11871:130:32:-;11946:10;11942:52;;11871:130;:::o;11942:52::-;11971:5;2558:19699;;;-1:-1:-1;;;;;2558:19699:32;;11958:36;;;;;11955:1;2558:19699;11958:36;2558:19699;;;;;;;;;;;;11958:36;;;;;2558:19699;11958:36;;;;;;;;11871:130;:::o;11958:36::-;11955:1;11958:36;;;:::i;1219:160:6:-;2558:19699:32;;-1:-1:-1;;;1328:43:6;;;;-1:-1:-1;;;;;2558:19699:32;;;;1328:43:6;;;2558:19699:32;;;;;;;;;1328:43:6;;;;;;2558:19699:32;;1328:43:6;:::i;:::-;;:::i;1565:66:9:-;1796:7;2558:19699:32;;;;2140:9:9;2136:62;;2558:19699:32;;;1796:7:9;2558:19699:32;2674:22:9;2558:19699:32;;;735:10:7;2558:19699:32;;2674:22:9;1565:66::o;2136:62::-;2172:15;;;1796:7;2172:15;;1796:7;2172:15;38940:262:31;2558:19699:32;;39101:23:31;39097:39;;39146:50;;;38940:262;:::o;2558:19699:32:-;;;;;;;;:::o;:::-;;;;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;-1:-1:-1;;;2558:19699:32;;;;;;14297:18:31;2558:19699:32;;14297:18:31;2558:19699:32;;;;;;;;;14297:18:31;-1:-1:-1;2558:19699:32;;-1:-1:-1;2558:19699:32;-1:-1:-1;2558:19699:32;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;;;;14297:18:31;-1:-1:-1;2558:19699:32;;;-1:-1:-1;2558:19699:32;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;-1:-1:-1;;;2558:19699:32;;;;;;30685:30:31;2558:19699:32;;30685:30:31;2558:19699:32;;;;;;;;;30685:30:31;-1:-1:-1;2558:19699:32;;-1:-1:-1;2558:19699:32;-1:-1:-1;2558:19699:32;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;;;;30685:30:31;-1:-1:-1;2558:19699:32;;;-1:-1:-1;2558:19699:32;;;;;;;:::i;:::-;;;;13589:965:31;13802:5;2558:19699:32;13589:965:31;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;13798:52:31;;-1:-1:-1;;;;;2558:19699:32;;13864:20:31;13860:47;;2558:19699:32;;13921:20:31;13917:48;;-1:-1:-1;;;;;2558:19699:32;;13979:27:31;13975:92;;13819:1;14172:3;2558:19699:32;;14151:19:31;;;;;14195:25;:11;;;;;:::i;:25::-;;14191:53;;2558:19699:32;;14136:13:31;;14191:53;13950:15;;;13819:1;14229:15;13802:5;13819:1;14229:15;14151:19;;14325:21;14151:19;2558:19699:32;14519:28:31;14151:19;14273:14;14389:28;14151:19;;;2558:19699:32;;;;;;-1:-1:-1;;;;;2558:19699:32;;13802:5:31;2558:19699:32;;;13802:5:31;2558:19699:32;;14273:14:31;2558:19699:32;:::i;:::-;14325:21:31;2558:19699:32;;14325:21:31;14356:23;14376:3;14356:23;2558:19699:32;;14356:23:31;34189:30;2558:19699:32;;-1:-1:-1;;;;;;2558:19699:32;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;14389:28:31;14427:18;2558:19699:32;;;14389:28:31;2558:19699:32;;;14389:28:31;2558:19699:32;;14427:18:31;14455:20;2558:19699:32;;-1:-1:-1;;;;;;2558:19699:32;14465:10:31;2558:19699:32;;;14519:28:31;2558:19699:32;;13975:92:31;2558:19699:32;;-1:-1:-1;;;14015:52:31;;2558:19699:32;13802:5:31;14015:52;;2558:19699:32;;;;;;;;;;;-1:-1:-1;;;2558:19699:32;;;;;;21044:39:31;13860:47;13893:14;;;13819:1;13893:14;13802:5;13819:1;13893:14;13798:52;13830:20;;;13819:1;13830:20;13802:5;13819:1;13830:20;2558:19699:32;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;2558:19699:32;;-1:-1:-1;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;2558:19699:32;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;30725:31:31;2558:19699:32;;:::i;:::-;30725:31:31;2558:19699:32;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;17073:17:31;;;2558:19699:32;;;;;;;;;;30725:31:31;2558:19699:32;:::o;:::-;;;;-1:-1:-1;2558:19699:32;;;;;30725:31:31;2558:19699:32;;-1:-1:-1;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;;;;;;30725:31:31;2558:19699:32;:::o;:::-;;;17073:17:31;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;30766:31:31;2558:19699:32;;:::i;:::-;30766:31:31;2558:19699:32;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;17073:17:31;;;2558:19699:32;;;;;;;;;;30766:31:31;2558:19699:32;:::o;:::-;30766:31:31;2558:19699:32;;-1:-1:-1;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;;;;;;30766:31:31;2558:19699:32;:::o;:::-;;;17073:17:31;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;17073:17:31;;;2558:19699:32;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;17073:17:31;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;2558:19699:32;;;;30642:33:31;2558:19699:32;;30642:33:31;2558:19699:32;;;;;;;-1:-1:-1;30642:33:31;2558:19699:32;;;;-1:-1:-1;;;;;;;;;;;2558:19699:32;;;;;;;;;;;;:::o;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;;30642:33:31;-1:-1:-1;2558:19699:32;-1:-1:-1;;;;;;;;;;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;30162:1:31;2558:19699:32;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;:::i;29950:1020:31:-;;;;;2558:19699:32;;30138:25:31;30134:50;;-1:-1:-1;;;;;30216:23:31;;:::i;:::-;2558:19699:32;30253:25:31;30249:64;;30404:35;;;:::i;:::-;30484:13;30162:1;30484:13;2558:19699:32;;30499:26:31;;;;;30556:18;30542:40;:33;30556:18;;30578:4;30556:18;;;:::i;:::-;-1:-1:-1;;;;;2558:19699:32;;;;;30542:13:31;2558:19699:32;;;;;;;30542:33:31;2558:19699:32;;-1:-1:-1;;2558:19699:32;30578:4:31;2558:19699:32;;;;30542:40:31;2558:19699:32;30484:13:31;;30499:26;;;30875:87;-1:-1:-1;;;;;;;;;;;30499:26:31;;30875:87;30850:113;30499:26;30578:4;30499:26;2558:19699:32;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;30875:87:31;;;;;;;:::i;30249:64::-;30287:26;;;30162:1;30287:26;;30162:1;30287:26;30134:50;30172:12;;;30162:1;30172:12;;30162:1;30172:12;10779:615:32;10880:5;2558:19699;10900:5;2558:19699;10873:36;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;10873:36;:::i;:::-;11026:12;;:::i;:::-;-1:-1:-1;;;;;2558:19699:32;;11048:340;;10779:615;:::o;11048:340::-;11099:8;2558:19699;11092:44;;2558:19699;;-1:-1:-1;;;;;2558:19699:32;11092:44;:::i;:::-;11157:8;2558:19699;11150:44;;2558:19699;;-1:-1:-1;;;;;2558:19699:32;11150:44;:::i;:::-;-1:-1:-1;;;;;11230:23:32;;:::i;:::-;2558:19699;11271:25;;11267:111;;11048:340;10779:615;:::o;11267:111::-;11316:47;;;:::i;1315:72:9:-;;;:::i;:::-;2408:4;2558:19699:32;;2398:14:9;2558:19699:32;;;2398:14:9;2558:19699:32;2427:20:9;2558:19699:32;;;735:10:7;2558:19699:32;;2427:20:9;1315:72::o;12288:193:32:-;12378:20;;:::i;11627:192::-;11701:11;;11697:24;;11746:5;2558:19699;;11753:5;2558:19699;;;-1:-1:-1;;;36581:47:31;;36613:4;36581:47;;;2558:19699:32;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;36581:47:31;2558:19699:32;;;;36581:47:31;;;;;;;;;-1:-1:-1;36581:47:31;;;11627:192:32;36642:25:31;;;;36638:177;;11627:192:32;-1:-1:-1;;11753:5:32;2558:19699;11777:27;;-1:-1:-1;11777:19:32;;-1:-1:-1;2558:19699:32;;-1:-1:-1;;;;;2558:19699:32;11777:19;2558:19699;11777:27;:35;;;;;2558:19699;;-1:-1:-1;;;11777:35:32;;11746:5;11777:35;;2558:19699;;;;-1:-1:-1;;2558:19699:32;;;;;;-1:-1:-1;;11777:35:32;;;;;;;;11627:192;:::o;11777:35::-;;;11711:1;11777:35;;;:::i;36638:177:31:-;36797:6;36687:20;36683:64;;36797:6;:::i;:::-;36638:177;;;;;;36683:64;2558:19699:32;;-1:-1:-1;;;36581:47:31;5199::6;;;;;;-1:-1:-1;;;;;2558:19699:32;;5199:47:6;;;2558:19699:32;-1:-1:-1;2558:19699:32;;;;;;;5199:47:6;;36581::31;;5199::6;2558:19699:32;;5199:47:6;:::i;:::-;9770:199;;;;;;;-1:-1:-1;9770:199:6;;;;9985:80;;36683:64:31;-1:-1:-1;5261:45:6;;-1:-1:-1;5261:45:6;5257:201;;36683:64:31;;36797:6;:::i;5257:201:6:-;2558:19699:32;;-1:-1:-1;;;36581:47:31;5349:43:6;;;-1:-1:-1;;;;;2558:19699:32;;5199:47:6;5349:43;;2558:19699:32;5389:1:6;2558:19699:32;;;;5434:12:6;;2558:19699:32;5349:43:6;;;2558:19699:32;;;;5349:43:6;2558:19699:32;5349:43:6;;;:::i;:::-;5434:12;;:::i;:::-;5257:201;;;9985:80;9997:15;;;-1:-1:-1;9997:15:6;;10015:26;5261:45;10015:26;;:30;;9997:67;9985:80;;;9997:67;10063:1;5261:45;10048:16;;9997:67;;36581:47:31;;;;;;;;;;;;;;;:::i;:::-;;;;;31423:1203;;2558:19699:32;;31597:25:31;31593:50;;31734:35;;;:::i;:::-;31820:13;31621:1;31820:13;31839:12;2558:19699:32;31835:23:31;;;;;31896:15;2558:19699:32;31882:30:31;2558:19699:32;31896:15:31;2558:19699:32;31896:15:31;;:::i;31882:30::-;2558:19699:32;;-1:-1:-1;;2558:19699:32;;;;;;31820:13:31;;31835:23;;;;;31621:1;32002:13;2558:19699:32;;32017:26:31;;;;;32074:18;32060:40;:33;32074:18;;2558:19699:32;32074:18:31;;;:::i;32060:40::-;2558:19699:32;32002:13:31;;32017:26;;;32532:86;-1:-1:-1;;;;;;;;;;;32017:26:31;;32532:86;32507:112;32017:26;2558:19699:32;32017:26:31;2558:19699:32;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;32382:5:31;2558:19699:32;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;32378:79:31;;31997:145;2558:19699:32;;32532:86:31;;;;;;;:::i;32378:79::-;;;:::i;:::-;;;8979:424;14689:17;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;9123:31:31;;9119:49;;2558:19699:32;;-1:-1:-1;;;9191:93:31;;9263:4;9191:93;;;2558:19699:32;-1:-1:-1;2558:19699:32;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;9191:93:31;;2558:19699:32;;;;;;9191:93:31;;2558:19699:32;;9191:93:31;;;8979:424;-1:-1:-1;9187:210:31;;9374:12;2558:19699:32;9374:12:31;:::o;9191:93::-;;;;;;;;;;;;;;;:::i;:::-;;;;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;:::o;:::-;;;;:::o;:::-;;;-1:-1:-1;;;2558:19699:32;;;;;;;;;;;;-1:-1:-1;;;2558:19699:32;;;;;;;9270:1280;9379:13;;:39;;;;9270:1280;9375:60;;9537:36;;:::i;:::-;2558:19699;-1:-1:-1;;;;;2558:19699:32;;9587:31;9583:66;;9677:12;;:::i;:::-;2558:19699;-1:-1:-1;;;;;2558:19699:32;;9703:20;9699:47;;10516:27;9834:78;2558:19699;9834:78;10211:215;9834:78;;;;:::i;:::-;9939:17;2558:19699;9939:21;;;;;;;9989:25;9977:38;9989:25;9976:48;9989:25;10211:215;9989:25;;:::i;:::-;9977:38;;:::i;9976:48::-;9939:102;;2558:19699;;10211:215;;;;;;10251:28;;;;10211:215;;10407:4;10211:215;;;;;:::i;:::-;10167:269;;;;10455:39;10167:269;;:::i;:::-;10455:39;;:::i;:::-;10211:215;2558:19699;;;10516:27;;;;;;:::i;9939:102::-;;;10211:215;9939:102;;;;9699:47;9732:14;;;2558:19699;9732:14;;2558:19699;9732:14;9583:66;9627:22;;;2558:19699;9627:22;;2558:19699;9627:22;9375:60;9420:15;;;:::o;9379:39::-;2558:19699;;;9396:22;9379:39;;2558:19699;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;-1:-1:-1;2558:19699:32;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;;2558:19699:32;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;;;23760:1154:31;;;;;;;;2558:19699:32;;;;;24114:16:31;;:::i;:::-;2558:19699:32;24144:21:31;;;24140:129;;2558:19699:32;24409:231:31;2558:19699:32;;24163:1:31;2558:19699:32;24409:231:31;2558:19699:32;;;;;;;;;;;;;;;24409:231:31;;;;;;:::i;:::-;;;;;;;;;;24163:1;;;;;24409:231;;;23760:1154;24359:281;;24723:15;;24719:189;;23760:1154;;:::o;24719:189::-;-1:-1:-1;;;;;2558:19699:32;;;;;;37133:19:31;2558:19699:32;;;;;24817:80:31;;24754:29;:44;2558:19699:32;;;24754:44:31;:::i;:::-;2558:19699:32;;-1:-1:-1;;;;;2558:19699:32;;;;;37133:19:31;2558:19699:32;;;;;;;;;;;;;;;;;;;;;;;;;;24817:80:31;2558:19699:32;24409:231:31;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;;;24140:129;-1:-1:-1;24163:1:31;;-1:-1:-1;24163:1:31;;-1:-1:-1;;;;;;24245:13:31:o;15028:925:32:-;;15157:17;;15153:36;;15230:23;;:::i;:::-;2558:19699;;15364:1;2558:19699;;;;;;;;;15561:8;2558:19699;-1:-1:-1;;;;;2558:19699:32;;;;;15561:23;;;;15615:30;2558:19699;;;:::i;15615:30::-;15557:155;;15786:8;2558:19699;-1:-1:-1;;;;;2558:19699:32;15786:23;;;15840:35;2558:19699;;;:::i;15557:155::-;;;;15153:36;15173:1;;-1:-1:-1;15173:1:32;;15176:13::o;2558:19699::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2558:19699:32;;;;:::o;:::-;;;;:::o;:::-;;;-1:-1:-1;;;2558:19699:32;;;;;;;;;;;;;;;;;;;;16426:2257;;;16560:17;;:38;;;;16426:2257;16556:52;;16735:78;;:::i;:::-;2558:19699;16868:17;2558:19699;17268:69;16844:50;16860:25;16844:42;16860:25;;;;:::i;:::-;16844:42;;:::i;:50::-;16941:25;17269:59;16925:50;16941:25;16925:42;16941:25;;;;:::i;:::-;16925:42;;:::i;:50::-;17270:27;17302:25;17270:27;;;;:::i;:::-;17302:25;;;:::i;17268:69::-;17447:36;;;:::i;:::-;2558:19699;-1:-1:-1;;;;;2558:19699:32;;17497:31;17493:66;;17625:12;;:::i;:::-;2558:19699;-1:-1:-1;;;;;2558:19699:32;;17651:29;17647:56;;18055:301;2558:19699;;18055:301;18455:27;2558:19699;;;;17821:8;2558:19699;;;;;;;;;;17831:8;2558:19699;;;;-1:-1:-1;;;;;2558:19699:32;;;17810:37;;;2558:19699;;;;;;;;;-1:-1:-1;2558:19699:32;;;;;;;;17810:37;;2558:19699;17810:37;2558:19699;;17810:37;:::i;:::-;2558:19699;;18055:301;;;17810:37;18055:301;;18095:36;;;;18055:301;;18337:4;18055:301;;;;;:::i;:::-;18011:355;;;;18385:47;18011:355;;:::i;:::-;18385:47;;:::i;18455:27::-;18592:26;;;18588:53;;16426:2257::o;18588:53::-;18627:14;;;2558:19699;18627:14;18055:301;2558:19699;18627:14;16560:38;16581:17;;;16560:38;;2558:19699;-1:-1:-1;;;;;2558:19699:32;;;;;;;;;;;;;;;33493:12:31;2558:19699:32;:::i;32964:560:31:-;14689:17;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;;32964:560:31;33124:31;;33120:44;;33293:5;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;33227:104:31;;;;;;2558:19699:32;;-1:-1:-1;;;33227:104:31;;-1:-1:-1;;;;;2558:19699:32;;;;33227:104:31;;;2558:19699:32;;;;;;;;;;;;-1:-1:-1;2558:19699:32;;;-1:-1:-1;33227:104:31;;;;;;;;;32964:560;-1:-1:-1;33293:5:31;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;33411:95:31;;;;;;2558:19699:32;;-1:-1:-1;;;33411:95:31;;2558:19699:32;33153:1:31;;2558:19699:32;;;;33153:1:31;;2558:19699:32;;33411:95:31;;33227:104;33411:95;;;:::i;:::-;;;;;;;32964:560;:::o;33227:104::-;;;33153:1;33227:104;;;:::i;:::-;;;;33120:44;33157:7;;;:::o;8370:720:6:-;;-1:-1:-1;8507:421:6;8370:720;8507:421;;;;;;;;;;;;-1:-1:-1;8507:421:6;;8942:15;;-1:-1:-1;;;;;;2558:19699:32;;8960:26:6;:31;8942:68;8938:146;;8370:720;:::o;8938:146::-;-1:-1:-1;;;;9033:40:6;;;-1:-1:-1;;;;;2558:19699:32;;;;9033:40:6;2558:19699:32;;;9033:40:6;8942:68;9009:1;8994:16;;8942:68;;8216:395:32;;8352:35;2558:19699;;8352:35;:::i;:::-;8414:1;8443:3;2558:19699;;8417:24;;;;;8495:16;8484:54;8495:16;2558:19699;8495:16;;;:::i;:::-;;8484:54;2558:19699;;;8484:54;;;;;;:::i;:::-;2558:19699;;;;;;;;8552:19;;;;:::i;:::-;2558:19699;;8402:13;;8417:24;-1:-1:-1;8417:24:32;-1:-1:-1;8216:395:32:o;5084:380:6:-;2558:19699:32;;-1:-1:-1;;;5199:47:6;;;;;;;-1:-1:-1;;;;;2558:19699:32;;5199:47:6;;;2558:19699:32;10907:1;2558:19699;;;;;;5199:47:6;;-1:-1:-1;;5199:47:6;2558:19699:32;;;;5199:47:6;;2558:19699:32;;5199:47:6;;;;;;:::i;:::-;9770:199;;;;;;;-1:-1:-1;9770:199:6;;;;9985:80;;5084:380;-1:-1:-1;5261:45:6;;-1:-1:-1;5261:45:6;5257:201;;5084:380;;;:::o;5257:201::-;2558:19699:32;;-1:-1:-1;;;5199:47:6;5349:43;;;-1:-1:-1;;;;;2558:19699:32;;;5199:47:6;5349:43;;2558:19699:32;5389:1:6;2558:19699:32;;;;5434:12:6;;5349:43;;;2558:19699:32;;;;5349:43:6;2558:19699:32;9985:80:6;9997:15;;;-1:-1:-1;9997:15:6;;-1:-1:-1;5261:45:6;-1:-1:-1;;;;;2558:19699:32;;10015:26:6;:30;;9997:67;9985:80;;;9997:67;10907:1:32;5261:45:6;10048:16;;9997:67;;5084:380;2558:19699:32;;-1:-1:-1;;;5199:47:6;;;;;;;-1:-1:-1;;;;;2558:19699:32;;5199:47:6;;;2558:19699:32;;;;;;;;5084:380:6;;2558:19699:32;;-1:-1:-1;;5199:47:6;2558:19699:32;;;;5199:47:6;2558:19699:32;9679:149:31;9777:7;2558:19699:32;9769:22:31;;;;2558:19699:32;;9777:7:31;11036:1:32;2558:19699;;;-1:-1:-1;;;;;2558:19699:32;;9679:149:31:o;33707:289::-;14689:17;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;;33818:172:31;;33707:289;:::o;33818:172::-;33948:5;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;;33873:95:31;;;;;2558:19699:32;;-1:-1:-1;;;33873:95:31;;2558:19699:32;33851:1:31;;2558:19699:32;;;;33851:1:31;;2558:19699:32;;33873:95:31;;;;;;:::i;:::-;;;;;;;33707:289;:::o;4156:457::-;14689:17;2558:19699:32;-1:-1:-1;;;;;2558:19699:32;4268:18:31;;4264:41;;2558:19699:32;;;;;4348:43:31;;;;;;;;;;;;;;;;:::i;:::-;4439:25;;;;;;:::i;:::-;4487:30;;;;4156:457;4483:97;;4589:17;2558:19699:32;4156:457:31;:::o;4483:97::-;2558:19699:32;4348:43:31;2558:19699:32;4540:29:31;2558:19699:32;;4540:29:31;;;;;;:::i;4487:30::-;2558:19699:32;4348:43:31;2558:19699:32;;4498:19:31;;4487:30;
Swarm Source
ipfs://be92bed85733e6db52b862295dddecf6d3d58bca9e5419d5bce0e0406cddeaf1
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in S
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.