// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.24;
import {IERC20} from "./interfaces/IERC20.sol";
import {IUniswapV3Adapter, ILaunchGraduationCallback} from "./interfaces/IUniswapV3Adapter.sol";
import {ReentrancyGuard} from "./lib/ReentrancyGuard.sol";
import {SafeTransferLib} from "./lib/SafeTransferLib.sol";
import {
IUniswapV3FactoryMinimal,
IUniswapV3PoolStateMinimal,
INonfungiblePositionManagerMinimal,
ISwapRouterMinimal
} from "./uniswap/IUniswapV3Minimal.sol";
import {TickMath} from "./uniswap/TickMath.sol";
import {LiquidityAmounts} from "./uniswap/LiquidityAmounts.sol";
/// @notice Production-candidate adapter for direct, one-sided Uniswap V3 launches.
/// @dev The NFPM position is minted to this contract. This contract deliberately exposes no
/// NFT transfer, approval, liquidity decrease, burn, arbitrary call, or token rescue method.
/// Position principal and rounding dust are therefore permanently locked by bytecode.
///
/// `sqrtPriceX96` follows native Uniswap ordering: sqrt(token1 / token0) as Q64.96 after
/// sorting the pair by address. It MUST be exactly on a usable tick boundary.
contract UniswapV3LaunchAdapter is IUniswapV3Adapter, ReentrancyGuard {
using SafeTransferLib for IERC20;
uint256 public constant MAX_DUST_DENOMINATOR = 1_000_000_000; // at most one part per billion
bool public constant SUPPORTS_ONCHAIN_GRADUATION = true;
uint32 public constant GRADUATION_TWAP_WINDOW = 15 minutes;
int24 public constant MAX_GRADUATION_TICK_DEVIATION = 10;
uint16 public constant OBSERVATION_CARDINALITY_NEXT = 16;
error InvalidAddress(address value);
error InvalidInfrastructure(address component, address expected, address actual);
error OnlyConfigurator(address caller);
error FactoryAlreadyBound(address launchFactory);
error OnlyLaunchFactory(address caller, address launchFactory);
error InvalidLaunchParameters();
error UnsupportedQuoteToken(address provided, address required);
error UnsupportedPoolFee(uint24 fee);
error PoolAlreadyExists(address pool);
error PoolCreationMismatch(address expected, address actual);
error InvalidSqrtPrice(uint160 sqrtPriceX96);
error PoolPriceMismatch(uint160 expected, uint160 actual);
error PriceNotOnTickBoundary(uint160 sqrtPriceX96, int24 reportedTick);
error TickNotAligned(int24 tick, int24 tickSpacing);
error InvalidTickRange(int24 tickLower, int24 tickUpper);
error UnexpectedTokenBalance(uint256 balance);
error TokenTransferMismatch(uint256 expected, uint256 received);
error InvalidMintAmounts(uint256 amount0, uint256 amount1);
error NoLiquidityMinted();
error ExcessiveLockedDust(uint256 maximum, uint256 actual);
error PositionVerificationFailed(uint256 positionId);
error PositionAlreadyRegistered(uint256 positionId);
error TokenAlreadyLaunched(address token, uint256 positionId);
error UnknownPosition(uint256 positionId);
error OnlyFeeRecipient(address caller, address feeRecipient);
error InvalidFeeRecipient(address recipient, address required);
error OnlyPositionManager(address caller);
error PoolLocked(address pool);
error OracleObservationUnavailable(address pool);
error OracleTickOutOfRange(int256 arithmeticMeanTick);
error NoGraduationCheckpoint(uint256 positionId, address observer);
error GraduationCheckpointPending(uint256 positionId, uint64 readyAt, uint64 currentTimestamp);
error GraduationPriceUnstable(int24 currentTick, int24 twapTick, int24 maximumDeviation);
error BelowGraduationThreshold(uint256 threshold, uint256 quotePrincipal);
error AlreadyGraduated(uint256 positionId);
error DirectNativePaymentNotAllowed();
struct LockedPosition {
address launchToken;
address token0;
address token1;
address pool;
address feeRecipient;
uint24 poolFee;
int24 tickLower;
int24 tickUpper;
uint128 liquidity;
uint256 lockedDust;
uint256 graduationThreshold;
bool graduated;
bool exists;
}
struct PoolContext {
address token0;
address token1;
address pool;
int24 tickLower;
int24 tickUpper;
}
struct GraduationCheckpoint {
int56 tickCumulative;
uint64 startedAt;
bool active;
}
struct MintResult {
uint256 positionId;
uint128 liquidity;
uint256 tokenUsed;
uint256 lockedDust;
}
address public immutable configurator;
IUniswapV3FactoryMinimal public immutable uniswapFactory;
INonfungiblePositionManagerMinimal public immutable positionManager;
ISwapRouterMinimal public immutable swapRouter;
address public immutable wrappedNativeToken;
address public launchFactory;
mapping(uint256 positionId => LockedPosition position) private _positions;
mapping(uint256 positionId => mapping(address observer => GraduationCheckpoint checkpoint)) private
_graduationCheckpoints;
mapping(address token => uint256 positionId) public positionForToken;
event LaunchFactoryBound(address indexed launchFactory);
event LiquidityPermanentlyLocked(
address indexed token,
address indexed pool,
uint256 indexed positionId,
address token0,
address token1,
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
uint256 tokenUsed,
uint256 lockedDust,
address feeRecipient
);
event GraduationBoundaryRecorded(
address indexed token, uint256 indexed positionId, uint256 graduationThreshold, bool enforcedOnchain
);
event GraduationCheckpointStarted(
address indexed token,
uint256 indexed positionId,
address indexed observer,
address pool,
uint256 quotePrincipal,
uint64 startedAt,
uint64 readyAt,
int24 currentTick,
int56 tickCumulative
);
event GraduationCheckpointRestarted(
address indexed token,
uint256 indexed positionId,
address indexed observer,
address pool,
uint64 previousStartedAt,
uint64 startedAt,
uint64 readyAt,
int24 currentTick,
int56 tickCumulative
);
event AdapterFeesCollected(uint256 indexed positionId, address indexed recipient, uint256 amount0, uint256 amount1);
event GraduationSynced(
address indexed token,
address indexed pool,
uint256 indexed positionId,
uint256 quotePrincipal,
uint256 graduationThreshold,
uint160 sqrtPriceX96,
int24 currentTick,
int24 twapTick
);
constructor(
address configurator_,
address uniswapFactory_,
address positionManager_,
address swapRouter_,
address wrappedNativeToken_
) {
if (configurator_ == address(0)) revert InvalidAddress(address(0));
_requireContract(uniswapFactory_);
_requireContract(positionManager_);
_requireContract(swapRouter_);
_requireContract(wrappedNativeToken_);
address managerFactory = INonfungiblePositionManagerMinimal(positionManager_).factory();
if (managerFactory != uniswapFactory_) {
revert InvalidInfrastructure(positionManager_, uniswapFactory_, managerFactory);
}
address managerWeth = INonfungiblePositionManagerMinimal(positionManager_).WETH9();
if (managerWeth != wrappedNativeToken_) {
revert InvalidInfrastructure(positionManager_, wrappedNativeToken_, managerWeth);
}
address routerFactory = ISwapRouterMinimal(swapRouter_).factory();
if (routerFactory != uniswapFactory_) {
revert InvalidInfrastructure(swapRouter_, uniswapFactory_, routerFactory);
}
address routerWeth = ISwapRouterMinimal(swapRouter_).WETH9();
if (routerWeth != wrappedNativeToken_) {
revert InvalidInfrastructure(swapRouter_, wrappedNativeToken_, routerWeth);
}
configurator = configurator_;
uniswapFactory = IUniswapV3FactoryMinimal(uniswapFactory_);
positionManager = INonfungiblePositionManagerMinimal(positionManager_);
swapRouter = ISwapRouterMinimal(swapRouter_);
wrappedNativeToken = wrappedNativeToken_;
}
/// @notice One-time binding solves the deployment cycle: adapter -> factory -> adapter.
function bindLaunchFactory(address launchFactory_) external {
if (msg.sender != configurator) revert OnlyConfigurator(msg.sender);
if (launchFactory != address(0)) revert FactoryAlreadyBound(launchFactory);
_requireContract(launchFactory_);
launchFactory = launchFactory_;
emit LaunchFactoryBound(launchFactory_);
}
function createPoolAndLockLiquidity(LaunchParams calldata params)
external
override
nonReentrant
returns (address pool, uint256 positionId)
{
if (msg.sender != launchFactory) revert OnlyLaunchFactory(msg.sender, launchFactory);
_validateLaunch(params);
if (positionForToken[params.token] != 0) {
revert TokenAlreadyLaunched(params.token, positionForToken[params.token]);
}
int24 tickSpacing = uniswapFactory.feeAmountTickSpacing(params.poolFee);
if (tickSpacing <= 0) revert UnsupportedPoolFee(params.poolFee);
address existingPool = uniswapFactory.getPool(params.token, params.quoteToken, params.poolFee);
if (existingPool != address(0)) {
_requireContract(existingPool);
(uint160 existingSqrtPriceX96,,,,,,) = IUniswapV3PoolStateMinimal(existingPool).slot0();
// A squatter may permissionlessly create the deterministic pool before token deploy.
// Accept it only while uninitialized, or if initialized at the exact committed price.
if (existingSqrtPriceX96 != 0 && existingSqrtPriceX96 != params.sqrtPriceX96) {
revert PoolPriceMismatch(params.sqrtPriceX96, existingSqrtPriceX96);
}
}
uint256 balanceBefore = IERC20(params.token).balanceOf(address(this));
if (balanceBefore != 0) revert UnexpectedTokenBalance(balanceBefore);
IERC20(params.token).safeTransferFrom(msg.sender, address(this), params.tokenAmount);
uint256 received = IERC20(params.token).balanceOf(address(this));
if (received != params.tokenAmount) revert TokenTransferMismatch(params.tokenAmount, received);
PoolContext memory context = _initializePool(params, tickSpacing);
MintResult memory minted = _mintLockedPosition(params, context);
pool = context.pool;
positionId = minted.positionId;
if (_positions[positionId].exists) revert PositionAlreadyRegistered(positionId);
_positions[positionId] = LockedPosition({
launchToken: params.token,
token0: context.token0,
token1: context.token1,
pool: pool,
feeRecipient: params.feeRecipient,
poolFee: params.poolFee,
tickLower: context.tickLower,
tickUpper: context.tickUpper,
liquidity: minted.liquidity,
lockedDust: minted.lockedDust,
graduationThreshold: params.graduationThreshold,
graduated: false,
exists: true
});
positionForToken[params.token] = positionId;
_emitLockEvents(positionId, minted.tokenUsed);
}
function positionTokens(uint256 positionId) external view override returns (address token0, address token1) {
LockedPosition storage position = _requirePosition(positionId);
return (position.token0, position.token1);
}
function positionInfo(uint256 positionId) external view returns (LockedPosition memory) {
return _requirePosition(positionId);
}
function collectFees(uint256 positionId, address recipient)
external
override
nonReentrant
returns (address token0, address token1, uint256 amount0, uint256 amount1)
{
LockedPosition memory position = _requirePosition(positionId);
if (msg.sender != position.feeRecipient) revert OnlyFeeRecipient(msg.sender, position.feeRecipient);
if (recipient != position.feeRecipient) revert InvalidFeeRecipient(recipient, position.feeRecipient);
token0 = position.token0;
token1 = position.token1;
(amount0, amount1) = positionManager.collect(
INonfungiblePositionManagerMinimal.CollectParams({
tokenId: positionId, recipient: recipient, amount0Max: type(uint128).max, amount1Max: type(uint128).max
})
);
emit AdapterFeesCollected(positionId, recipient, amount0, amount1);
}
/// @notice Permissionlessly checkpoints, then synchronizes, the direct-V3 graduation state.
/// @dev The threshold is measured only from this NFT's WETH principal. Pool donations and
/// uncollected fees are excluded. The first successful call stores observe(0)'s current
/// cumulative tick for msg.sender. The same observer may complete at least 15 minutes later;
/// both reads use observe(0), so ring-buffer churn cannot block completion. Checkpoints are
/// isolated per observer: a malicious or badly timed checkpoint cannot delay another keeper.
/// Failed and early calls cannot reset any checkpoint. A checkpoint/re-checkpoint call never
/// invokes the graduation callback.
function syncGraduation(uint256 positionId)
external
nonReentrant
returns (uint256 quotePrincipal, int24 currentTick, int24 twapTick)
{
LockedPosition storage position = _requirePosition(positionId);
if (position.graduated) revert AlreadyGraduated(positionId);
uint160 sqrtPriceX96;
bool unlocked;
(quotePrincipal, sqrtPriceX96, currentTick, unlocked) = _positionQuotePrincipal(position);
if (!unlocked) revert PoolLocked(position.pool);
if (quotePrincipal < position.graduationThreshold) {
revert BelowGraduationThreshold(position.graduationThreshold, quotePrincipal);
}
GraduationCheckpoint storage checkpoint = _graduationCheckpoints[positionId][msg.sender];
if (!checkpoint.active) {
_startGraduationCheckpoint(position, positionId, msg.sender, quotePrincipal, currentTick);
twapTick = currentTick;
return (quotePrincipal, currentTick, twapTick);
}
twapTick = _completeGraduation(
position, checkpoint, positionId, msg.sender, quotePrincipal, sqrtPriceX96, currentTick
);
}
function positionQuotePrincipal(uint256 positionId)
external
view
returns (uint256 quotePrincipal, uint160 sqrtPriceX96, int24 currentTick, bool poolUnlocked)
{
return _positionQuotePrincipal(_requirePosition(positionId));
}
/// @notice Returns the immutable observation used for the two-stage graduation guard.
function graduationCheckpoint(uint256 positionId, address observer)
external
view
returns (bool active, uint64 startedAt, uint64 readyAt, int56 tickCumulative)
{
LockedPosition storage position = _requirePosition(positionId);
GraduationCheckpoint storage checkpoint = _graduationCheckpoints[positionId][observer];
active = checkpoint.active && !position.graduated;
if (!active) return (false, 0, 0, 0);
startedAt = checkpoint.startedAt;
readyAt = startedAt + uint64(GRADUATION_TWAP_WINDOW);
tickCumulative = checkpoint.tickCumulative;
}
/// @notice Replaces only msg.sender's matured checkpoint with a fresh observe(0) anchor.
/// @dev Useful after that observer's measured window was volatile. Other observers are untouched.
function restartGraduationCheckpoint(uint256 positionId)
external
nonReentrant
returns (uint256 quotePrincipal, int24 currentTick)
{
LockedPosition storage position = _requirePosition(positionId);
if (position.graduated) revert AlreadyGraduated(positionId);
GraduationCheckpoint storage checkpoint = _graduationCheckpoints[positionId][msg.sender];
if (!checkpoint.active) revert NoGraduationCheckpoint(positionId, msg.sender);
uint64 currentTimestamp = uint64(block.timestamp);
uint64 readyAt = checkpoint.startedAt + uint64(GRADUATION_TWAP_WINDOW);
if (currentTimestamp < readyAt) {
revert GraduationCheckpointPending(positionId, readyAt, currentTimestamp);
}
bool unlocked;
(quotePrincipal,, currentTick, unlocked) = _positionQuotePrincipal(position);
if (!unlocked) revert PoolLocked(position.pool);
if (quotePrincipal < position.graduationThreshold) {
revert BelowGraduationThreshold(position.graduationThreshold, quotePrincipal);
}
int56 tickCumulative = _observeCurrentTickCumulative(position.pool);
uint64 previousStartedAt = checkpoint.startedAt;
checkpoint.tickCumulative = tickCumulative;
checkpoint.startedAt = currentTimestamp;
emit GraduationCheckpointRestarted(
position.launchToken,
positionId,
msg.sender,
position.pool,
previousStartedAt,
currentTimestamp,
currentTimestamp + uint64(GRADUATION_TWAP_WINDOW),
currentTick,
tickCumulative
);
}
/// @dev Canonical NPM currently uses `_mint`, but accepting only its safe-mint callback keeps
/// this adapter compatible with equivalent deployments without accepting arbitrary NFTs.
function onERC721Received(address, address, uint256, bytes calldata) external view returns (bytes4) {
if (msg.sender != address(positionManager)) revert OnlyPositionManager(msg.sender);
return this.onERC721Received.selector;
}
function sqrtPriceAtTick(int24 tick) external pure returns (uint160) {
return TickMath.getSqrtRatioAtTick(tick);
}
receive() external payable {
revert DirectNativePaymentNotAllowed();
}
function _validateLaunch(LaunchParams calldata params) private view {
if (
params.token == address(0) || params.token == params.quoteToken || params.tokenAmount == 0
|| params.feeRecipient == address(0) || params.graduationThreshold == 0
) {
revert InvalidLaunchParameters();
}
_requireContract(params.token);
_requireContract(params.feeRecipient);
if (params.quoteToken != wrappedNativeToken) {
revert UnsupportedQuoteToken(params.quoteToken, wrappedNativeToken);
}
if (params.sqrtPriceX96 < TickMath.MIN_SQRT_RATIO || params.sqrtPriceX96 >= TickMath.MAX_SQRT_RATIO) {
revert InvalidSqrtPrice(params.sqrtPriceX96);
}
}
function _initializePool(LaunchParams calldata params, int24 tickSpacing)
private
returns (PoolContext memory context)
{
(context.token0, context.token1) = params.token < params.quoteToken
? (params.token, params.quoteToken)
: (params.quoteToken, params.token);
context.pool = positionManager.createAndInitializePoolIfNecessary(
context.token0, context.token1, params.poolFee, params.sqrtPriceX96
);
address canonicalPool = uniswapFactory.getPool(context.token0, context.token1, params.poolFee);
if (canonicalPool != context.pool) revert PoolCreationMismatch(canonicalPool, context.pool);
_requireContract(context.pool);
(uint160 actualSqrtPriceX96, int24 currentTick,,,,,) = IUniswapV3PoolStateMinimal(context.pool).slot0();
if (actualSqrtPriceX96 != params.sqrtPriceX96) {
revert PoolPriceMismatch(params.sqrtPriceX96, actualSqrtPriceX96);
}
if (TickMath.getSqrtRatioAtTick(currentTick) != params.sqrtPriceX96) {
revert PriceNotOnTickBoundary(params.sqrtPriceX96, currentTick);
}
if (currentTick % tickSpacing != 0) revert TickNotAligned(currentTick, tickSpacing);
IUniswapV3PoolStateMinimal(context.pool).increaseObservationCardinalityNext(OBSERVATION_CARDINALITY_NEXT);
int24 minUsableTick = (TickMath.MIN_TICK / tickSpacing) * tickSpacing;
int24 maxUsableTick = (TickMath.MAX_TICK / tickSpacing) * tickSpacing;
if (params.token == context.token0) {
context.tickLower = currentTick;
context.tickUpper = maxUsableTick;
} else {
context.tickLower = minUsableTick;
context.tickUpper = currentTick;
}
if (context.tickLower >= context.tickUpper) {
revert InvalidTickRange(context.tickLower, context.tickUpper);
}
}
function _mintLockedPosition(LaunchParams calldata params, PoolContext memory context)
private
returns (MintResult memory result)
{
uint256 maxDust = params.tokenAmount / MAX_DUST_DENOMINATOR;
if (maxDust == 0) maxDust = 1;
uint256 minimumTokenUsed = params.tokenAmount - maxDust;
bool launchTokenIsToken0 = params.token == context.token0;
IERC20(params.token).safeApprove(address(positionManager), params.tokenAmount);
uint256 amount0;
uint256 amount1;
(result.positionId, result.liquidity, amount0, amount1) = positionManager.mint(
INonfungiblePositionManagerMinimal.MintParams({
token0: context.token0,
token1: context.token1,
fee: params.poolFee,
tickLower: context.tickLower,
tickUpper: context.tickUpper,
amount0Desired: launchTokenIsToken0 ? params.tokenAmount : 0,
amount1Desired: launchTokenIsToken0 ? 0 : params.tokenAmount,
amount0Min: launchTokenIsToken0 ? minimumTokenUsed : 0,
amount1Min: launchTokenIsToken0 ? 0 : minimumTokenUsed,
recipient: address(this),
deadline: block.timestamp
})
);
IERC20(params.token).safeApprove(address(positionManager), 0);
if (result.liquidity == 0) revert NoLiquidityMinted();
if (launchTokenIsToken0) {
if (amount0 == 0 || amount0 > params.tokenAmount || amount1 != 0) {
revert InvalidMintAmounts(amount0, amount1);
}
result.tokenUsed = amount0;
} else {
if (amount1 == 0 || amount1 > params.tokenAmount || amount0 != 0) {
revert InvalidMintAmounts(amount0, amount1);
}
result.tokenUsed = amount1;
}
result.lockedDust = params.tokenAmount - result.tokenUsed;
if (result.lockedDust > maxDust) revert ExcessiveLockedDust(maxDust, result.lockedDust);
uint256 residualBalance = IERC20(params.token).balanceOf(address(this));
if (residualBalance != result.lockedDust) {
revert TokenTransferMismatch(result.lockedDust, residualBalance);
}
_verifyPosition(result.positionId, context, params.poolFee, result.liquidity);
}
function _verifyPosition(uint256 positionId, PoolContext memory context, uint24 poolFee, uint128 liquidity)
private
view
{
(
,,
address storedToken0,
address storedToken1,
uint24 storedFee,
int24 storedTickLower,
int24 storedTickUpper,
uint128 storedLiquidity,,,,
) = positionManager.positions(positionId);
if (
positionManager.ownerOf(positionId) != address(this) || storedToken0 != context.token0
|| storedToken1 != context.token1 || storedFee != poolFee || storedTickLower != context.tickLower
|| storedTickUpper != context.tickUpper || storedLiquidity != liquidity
) {
revert PositionVerificationFailed(positionId);
}
}
function _positionQuotePrincipal(LockedPosition storage position)
private
view
returns (uint256 quotePrincipal, uint160 sqrtPriceX96, int24 currentTick, bool poolUnlocked)
{
(sqrtPriceX96, currentTick,,,,, poolUnlocked) = IUniswapV3PoolStateMinimal(position.pool).slot0();
uint160 sqrtLowerX96 = TickMath.getSqrtRatioAtTick(position.tickLower);
uint160 sqrtUpperX96 = TickMath.getSqrtRatioAtTick(position.tickUpper);
(uint256 principal0, uint256 principal1) =
LiquidityAmounts.getAmountsForLiquidity(sqrtPriceX96, sqrtLowerX96, sqrtUpperX96, position.liquidity);
quotePrincipal = position.token0 == wrappedNativeToken ? principal0 : principal1;
}
function _startGraduationCheckpoint(
LockedPosition storage position,
uint256 positionId,
address observer,
uint256 quotePrincipal,
int24 currentTick
) private {
int56 tickCumulative = _observeCurrentTickCumulative(position.pool);
uint64 startedAt = uint64(block.timestamp);
uint64 readyAt = startedAt + uint64(GRADUATION_TWAP_WINDOW);
_graduationCheckpoints[positionId][observer] =
GraduationCheckpoint({tickCumulative: tickCumulative, startedAt: startedAt, active: true});
emit GraduationCheckpointStarted(
position.launchToken,
positionId,
observer,
position.pool,
quotePrincipal,
startedAt,
readyAt,
currentTick,
tickCumulative
);
}
function _completeGraduation(
LockedPosition storage position,
GraduationCheckpoint storage checkpoint,
uint256 positionId,
address observer,
uint256 quotePrincipal,
uint160 sqrtPriceX96,
int24 currentTick
) private returns (int24 twapTick) {
uint64 currentTimestamp = uint64(block.timestamp);
uint64 readyAt = checkpoint.startedAt + uint64(GRADUATION_TWAP_WINDOW);
if (currentTimestamp < readyAt) {
revert GraduationCheckpointPending(positionId, readyAt, currentTimestamp);
}
int56 currentTickCumulative = _observeCurrentTickCumulative(position.pool);
uint64 elapsed = currentTimestamp - checkpoint.startedAt;
twapTick = _arithmeticMeanTick(checkpoint.tickCumulative, currentTickCumulative, elapsed);
_requireStablePrice(currentTick, twapTick);
position.graduated = true;
delete _graduationCheckpoints[positionId][observer];
ILaunchGraduationCallback(launchFactory).markGraduated(position.launchToken, quotePrincipal);
_emitGraduationSynced(position, positionId, quotePrincipal, sqrtPriceX96, currentTick, twapTick);
}
function _emitGraduationSynced(
LockedPosition storage position,
uint256 positionId,
uint256 quotePrincipal,
uint160 sqrtPriceX96,
int24 currentTick,
int24 twapTick
) private {
emit GraduationSynced(
position.launchToken,
position.pool,
positionId,
quotePrincipal,
position.graduationThreshold,
sqrtPriceX96,
currentTick,
twapTick
);
}
function _observeCurrentTickCumulative(address pool) private view returns (int56 tickCumulative) {
uint32[] memory secondsAgos = new uint32[](1);
secondsAgos[0] = 0;
try IUniswapV3PoolStateMinimal(pool).observe(secondsAgos) returns (
int56[] memory observedTicks, uint160[] memory
) {
if (observedTicks.length != 1) revert OracleObservationUnavailable(pool);
return observedTicks[0];
} catch {
revert OracleObservationUnavailable(pool);
}
}
function _requireStablePrice(int24 currentTick, int24 twapTick) private pure {
if (!_priceIsStable(currentTick, twapTick)) {
revert GraduationPriceUnstable(currentTick, twapTick, MAX_GRADUATION_TICK_DEVIATION);
}
}
function _priceIsStable(int24 currentTick, int24 twapTick) private pure returns (bool) {
int256 tickDelta = int256(currentTick) - int256(twapTick);
if (tickDelta < 0) tickDelta = -tickDelta;
return tickDelta <= int256(MAX_GRADUATION_TICK_DEVIATION);
}
function _arithmeticMeanTick(int56 startCumulative, int56 endCumulative, uint64 elapsed)
private
pure
returns (int24 arithmeticMeanTick)
{
int56 tickDelta;
// Uniswap V3's int56 cumulative is deliberately allowed to wrap. The elapsed time here is
// at least 15 minutes and a real wrap remains unambiguous for more than a millennium.
unchecked {
tickDelta = endCumulative - startCumulative;
}
int256 divisor = int256(uint256(elapsed));
int256 meanTick = int256(tickDelta) / divisor;
// Solidity rounds negative division toward zero; Uniswap oracle ticks round toward -infinity.
if (tickDelta < 0 && (int256(tickDelta) % divisor != 0)) meanTick--;
if (meanTick < TickMath.MIN_TICK || meanTick > TickMath.MAX_TICK) {
revert OracleTickOutOfRange(meanTick);
}
arithmeticMeanTick = int24(meanTick);
}
function _emitLockEvents(uint256 positionId, uint256 tokenUsed) private {
LockedPosition storage position = _positions[positionId];
emit LiquidityPermanentlyLocked(
position.launchToken,
position.pool,
positionId,
position.token0,
position.token1,
position.tickLower,
position.tickUpper,
position.liquidity,
tokenUsed,
position.lockedDust,
position.feeRecipient
);
emit GraduationBoundaryRecorded(
position.launchToken, positionId, position.graduationThreshold, SUPPORTS_ONCHAIN_GRADUATION
);
}
function _requirePosition(uint256 positionId) private view returns (LockedPosition storage position) {
position = _positions[positionId];
if (!position.exists) revert UnknownPosition(positionId);
}
function _requireContract(address value) private view {
if (value == address(0) || value.code.length == 0) revert InvalidAddress(value);
}
}[
{
"type": "constructor",
"inputs": [
{
"name": "configurator_",
"type": "address",
"internalType": "address"
},
{
"name": "uniswapFactory_",
"type": "address",
"internalType": "address"
},
{
"name": "positionManager_",
"type": "address",
"internalType": "address"
},
{
"name": "swapRouter_",
"type": "address",
"internalType": "address"
},
{
"name": "wrappedNativeToken_",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "nonpayable"
},
{
"name": "AlreadyGraduated",
"type": "error",
"inputs": [
{
"name": "positionId",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "BelowGraduationThreshold",
"type": "error",
"inputs": [
{
"name": "threshold",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "quotePrincipal",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "DirectNativePaymentNotAllowed",
"type": "error",
"inputs": []
},
{
"name": "DivisionByZero",
"type": "error",
"inputs": []
},
{
"name": "ERC20CallFailed",
"type": "error",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "ExcessiveLockedDust",
"type": "error",
"inputs": [
{
"name": "maximum",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "actual",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "FactoryAlreadyBound",
"type": "error",
"inputs": [
{
"name": "launchFactory",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "GraduationCheckpointPending",
"type": "error",
"inputs": [
{
"name": "positionId",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "readyAt",
"type": "uint64",
"internalType": "uint64"
},
{
"name": "currentTimestamp",
"type": "uint64",
"internalType": "uint64"
}
]
},
{
"name": "GraduationPriceUnstable",
"type": "error",
"inputs": [
{
"name": "currentTick",
"type": "int24",
"internalType": "int24"
},
{
"name": "twapTick",
"type": "int24",
"internalType": "int24"
},
{
"name": "maximumDeviation",
"type": "int24",
"internalType": "int24"
}
]
},
{
"name": "InvalidAddress",
"type": "error",
"inputs": [
{
"name": "value",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "InvalidFeeRecipient",
"type": "error",
"inputs": [
{
"name": "recipient",
"type": "address",
"internalType": "address"
},
{
"name": "required",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "InvalidInfrastructure",
"type": "error",
"inputs": [
{
"name": "component",
"type": "address",
"internalType": "address"
},
{
"name": "expected",
"type": "address",
"internalType": "address"
},
{
"name": "actual",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "InvalidLaunchParameters",
"type": "error",
"inputs": []
},
{
"name": "InvalidMintAmounts",
"type": "error",
"inputs": [
{
"name": "amount0",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amount1",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "InvalidSqrtPrice",
"type": "error",
"inputs": [
{
"name": "sqrtPriceX96",
"type": "uint160",
"internalType": "uint160"
}
]
},
{
"name": "InvalidTickRange",
"type": "error",
"inputs": [
{
"name": "tickLower",
"type": "int24",
"internalType": "int24"
},
{
"name": "tickUpper",
"type": "int24",
"internalType": "int24"
}
]
},
{
"name": "NoGraduationCheckpoint",
"type": "error",
"inputs": [
{
"name": "positionId",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "observer",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "NoLiquidityMinted",
"type": "error",
"inputs": []
},
{
"name": "OnlyConfigurator",
"type": "error",
"inputs": [
{
"name": "caller",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "OnlyFeeRecipient",
"type": "error",
"inputs": [
{
"name": "caller",
"type": "address",
"internalType": "address"
},
{
"name": "feeRecipient",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "OnlyLaunchFactory",
"type": "error",
"inputs": [
{
"name": "caller",
"type": "address",
"internalType": "address"
},
{
"name": "launchFactory",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "OnlyPositionManager",
"type": "error",
"inputs": [
{
"name": "caller",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "OracleObservationUnavailable",
"type": "error",
"inputs": [
{
"name": "pool",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "OracleTickOutOfRange",
"type": "error",
"inputs": [
{
"name": "arithmeticMeanTick",
"type": "int256",
"internalType": "int256"
}
]
},
{
"name": "PoolAlreadyExists",
"type": "error",
"inputs": [
{
"name": "pool",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "PoolCreationMismatch",
"type": "error",
"inputs": [
{
"name": "expected",
"type": "address",
"internalType": "address"
},
{
"name": "actual",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "PoolLocked",
"type": "error",
"inputs": [
{
"name": "pool",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "PoolPriceMismatch",
"type": "error",
"inputs": [
{
"name": "expected",
"type": "uint160",
"internalType": "uint160"
},
{
"name": "actual",
"type": "uint160",
"internalType": "uint160"
}
]
},
{
"name": "PositionAlreadyRegistered",
"type": "error",
"inputs": [
{
"name": "positionId",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "PositionVerificationFailed",
"type": "error",
"inputs": [
{
"name": "positionId",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "PriceNotOnTickBoundary",
"type": "error",
"inputs": [
{
"name": "sqrtPriceX96",
"type": "uint160",
"internalType": "uint160"
},
{
"name": "reportedTick",
"type": "int24",
"internalType": "int24"
}
]
},
{
"name": "Reentrancy",
"type": "error",
"inputs": []
},
{
"name": "ResultOverflow",
"type": "error",
"inputs": []
},
{
"name": "TickNotAligned",
"type": "error",
"inputs": [
{
"name": "tick",
"type": "int24",
"internalType": "int24"
},
{
"name": "tickSpacing",
"type": "int24",
"internalType": "int24"
}
]
},
{
"name": "TickOutOfBounds",
"type": "error",
"inputs": [
{
"name": "tick",
"type": "int24",
"internalType": "int24"
}
]
},
{
"name": "TokenAlreadyLaunched",
"type": "error",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
},
{
"name": "positionId",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "TokenTransferMismatch",
"type": "error",
"inputs": [
{
"name": "expected",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "received",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "UnexpectedTokenBalance",
"type": "error",
"inputs": [
{
"name": "balance",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "UnknownPosition",
"type": "error",
"inputs": [
{
"name": "positionId",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "UnsupportedPoolFee",
"type": "error",
"inputs": [
{
"name": "fee",
"type": "uint24",
"internalType": "uint24"
}
]
},
{
"name": "UnsupportedQuoteToken",
"type": "error",
"inputs": [
{
"name": "provided",
"type": "address",
"internalType": "address"
},
{
"name": "required",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "AdapterFeesCollected",
"type": "event",
"inputs": [
{
"name": "positionId",
"type": "uint256",
"indexed": true,
"internalType": "uint256"
},
{
"name": "recipient",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "amount0",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "amount1",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "GraduationBoundaryRecorded",
"type": "event",
"inputs": [
{
"name": "token",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "positionId",
"type": "uint256",
"indexed": true,
"internalType": "uint256"
},
{
"name": "graduationThreshold",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "enforcedOnchain",
"type": "bool",
"indexed": false,
"internalType": "bool"
}
],
"anonymous": false
},
{
"name": "GraduationCheckpointRestarted",
"type": "event",
"inputs": [
{
"name": "token",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "positionId",
"type": "uint256",
"indexed": true,
"internalType": "uint256"
},
{
"name": "observer",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "pool",
"type": "address",
"indexed": false,
"internalType": "address"
},
{
"name": "previousStartedAt",
"type": "uint64",
"indexed": false,
"internalType": "uint64"
},
{
"name": "startedAt",
"type": "uint64",
"indexed": false,
"internalType": "uint64"
},
{
"name": "readyAt",
"type": "uint64",
"indexed": false,
"internalType": "uint64"
},
{
"name": "currentTick",
"type": "int24",
"indexed": false,
"internalType": "int24"
},
{
"name": "tickCumulative",
"type": "int56",
"indexed": false,
"internalType": "int56"
}
],
"anonymous": false
},
{
"name": "GraduationCheckpointStarted",
"type": "event",
"inputs": [
{
"name": "token",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "positionId",
"type": "uint256",
"indexed": true,
"internalType": "uint256"
},
{
"name": "observer",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "pool",
"type": "address",
"indexed": false,
"internalType": "address"
},
{
"name": "quotePrincipal",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "startedAt",
"type": "uint64",
"indexed": false,
"internalType": "uint64"
},
{
"name": "readyAt",
"type": "uint64",
"indexed": false,
"internalType": "uint64"
},
{
"name": "currentTick",
"type": "int24",
"indexed": false,
"internalType": "int24"
},
{
"name": "tickCumulative",
"type": "int56",
"indexed": false,
"internalType": "int56"
}
],
"anonymous": false
},
{
"name": "GraduationSynced",
"type": "event",
"inputs": [
{
"name": "token",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "pool",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "positionId",
"type": "uint256",
"indexed": true,
"internalType": "uint256"
},
{
"name": "quotePrincipal",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "graduationThreshold",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "sqrtPriceX96",
"type": "uint160",
"indexed": false,
"internalType": "uint160"
},
{
"name": "currentTick",
"type": "int24",
"indexed": false,
"internalType": "int24"
},
{
"name": "twapTick",
"type": "int24",
"indexed": false,
"internalType": "int24"
}
],
"anonymous": false
},
{
"name": "LaunchFactoryBound",
"type": "event",
"inputs": [
{
"name": "launchFactory",
"type": "address",
"indexed": true,
"internalType": "address"
}
],
"anonymous": false
},
{
"name": "LiquidityPermanentlyLocked",
"type": "event",
"inputs": [
{
"name": "token",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "pool",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "positionId",
"type": "uint256",
"indexed": true,
"internalType": "uint256"
},
{
"name": "token0",
"type": "address",
"indexed": false,
"internalType": "address"
},
{
"name": "token1",
"type": "address",
"indexed": false,
"internalType": "address"
},
{
"name": "tickLower",
"type": "int24",
"indexed": false,
"internalType": "int24"
},
{
"name": "tickUpper",
"type": "int24",
"indexed": false,
"internalType": "int24"
},
{
"name": "liquidity",
"type": "uint128",
"indexed": false,
"internalType": "uint128"
},
{
"name": "tokenUsed",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "lockedDust",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "feeRecipient",
"type": "address",
"indexed": false,
"internalType": "address"
}
],
"anonymous": false
},
{
"name": "GRADUATION_TWAP_WINDOW",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint32",
"internalType": "uint32"
}
],
"stateMutability": "view"
},
{
"name": "MAX_DUST_DENOMINATOR",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "MAX_GRADUATION_TICK_DEVIATION",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "int24",
"internalType": "int24"
}
],
"stateMutability": "view"
},
{
"name": "OBSERVATION_CARDINALITY_NEXT",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint16",
"internalType": "uint16"
}
],
"stateMutability": "view"
},
{
"name": "SUPPORTS_ONCHAIN_GRADUATION",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "bool",
"internalType": "bool"
}
],
"stateMutability": "view"
},
{
"name": "bindLaunchFactory",
"type": "function",
"inputs": [
{
"name": "launchFactory_",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "collectFees",
"type": "function",
"inputs": [
{
"name": "positionId",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "recipient",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "token0",
"type": "address",
"internalType": "address"
},
{
"name": "token1",
"type": "address",
"internalType": "address"
},
{
"name": "amount0",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amount1",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "nonpayable"
},
{
"name": "configurator",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "createPoolAndLockLiquidity",
"type": "function",
"inputs": [
{
"name": "params",
"type": "tuple",
"components": [
{
"name": "token",
"type": "address",
"internalType": "address"
},
{
"name": "quoteToken",
"type": "address",
"internalType": "address"
},
{
"name": "tokenAmount",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "feeRecipient",
"type": "address",
"internalType": "address"
},
{
"name": "poolFee",
"type": "uint24",
"internalType": "uint24"
},
{
"name": "sqrtPriceX96",
"type": "uint160",
"internalType": "uint160"
},
{
"name": "graduationThreshold",
"type": "uint256",
"internalType": "uint256"
}
],
"internalType": "struct IUniswapV3Adapter.LaunchParams"
}
],
"outputs": [
{
"name": "pool",
"type": "address",
"internalType": "address"
},
{
"name": "positionId",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "nonpayable"
},
{
"name": "graduationCheckpoint",
"type": "function",
"inputs": [
{
"name": "positionId",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "observer",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "active",
"type": "bool",
"internalType": "bool"
},
{
"name": "startedAt",
"type": "uint64",
"internalType": "uint64"
},
{
"name": "readyAt",
"type": "uint64",
"internalType": "uint64"
},
{
"name": "tickCumulative",
"type": "int56",
"internalType": "int56"
}
],
"stateMutability": "view"
},
{
"name": "launchFactory",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "onERC721Received",
"type": "function",
"inputs": [
{
"name": "",
"type": "address",
"internalType": "address"
},
{
"name": "",
"type": "address",
"internalType": "address"
},
{
"name": "",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "",
"type": "bytes",
"internalType": "bytes"
}
],
"outputs": [
{
"name": "",
"type": "bytes4",
"internalType": "bytes4"
}
],
"stateMutability": "view"
},
{
"name": "positionForToken",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "positionId",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "positionInfo",
"type": "function",
"inputs": [
{
"name": "positionId",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "tuple",
"components": [
{
"name": "launchToken",
"type": "address",
"internalType": "address"
},
{
"name": "token0",
"type": "address",
"internalType": "address"
},
{
"name": "token1",
"type": "address",
"internalType": "address"
},
{
"name": "pool",
"type": "address",
"internalType": "address"
},
{
"name": "feeRecipient",
"type": "address",
"internalType": "address"
},
{
"name": "poolFee",
"type": "uint24",
"internalType": "uint24"
},
{
"name": "tickLower",
"type": "int24",
"internalType": "int24"
},
{
"name": "tickUpper",
"type": "int24",
"internalType": "int24"
},
{
"name": "liquidity",
"type": "uint128",
"internalType": "uint128"
},
{
"name": "lockedDust",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "graduationThreshold",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "graduated",
"type": "bool",
"internalType": "bool"
},
{
"name": "exists",
"type": "bool",
"internalType": "bool"
}
],
"internalType": "struct UniswapV3LaunchAdapter.LockedPosition"
}
],
"stateMutability": "view"
},
{
"name": "positionManager",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "contract INonfungiblePositionManagerMinimal"
}
],
"stateMutability": "view"
},
{
"name": "positionQuotePrincipal",
"type": "function",
"inputs": [
{
"name": "positionId",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "quotePrincipal",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "sqrtPriceX96",
"type": "uint160",
"internalType": "uint160"
},
{
"name": "currentTick",
"type": "int24",
"internalType": "int24"
},
{
"name": "poolUnlocked",
"type": "bool",
"internalType": "bool"
}
],
"stateMutability": "view"
},
{
"name": "positionTokens",
"type": "function",
"inputs": [
{
"name": "positionId",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "token0",
"type": "address",
"internalType": "address"
},
{
"name": "token1",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "restartGraduationCheckpoint",
"type": "function",
"inputs": [
{
"name": "positionId",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "quotePrincipal",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "currentTick",
"type": "int24",
"internalType": "int24"
}
],
"stateMutability": "nonpayable"
},
{
"name": "sqrtPriceAtTick",
"type": "function",
"inputs": [
{
"name": "tick",
"type": "int24",
"internalType": "int24"
}
],
"outputs": [
{
"name": "",
"type": "uint160",
"internalType": "uint160"
}
],
"stateMutability": "pure"
},
{
"name": "swapRouter",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "contract ISwapRouterMinimal"
}
],
"stateMutability": "view"
},
{
"name": "syncGraduation",
"type": "function",
"inputs": [
{
"name": "positionId",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "quotePrincipal",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "currentTick",
"type": "int24",
"internalType": "int24"
},
{
"name": "twapTick",
"type": "int24",
"internalType": "int24"
}
],
"stateMutability": "nonpayable"
},
{
"name": "uniswapFactory",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "contract IUniswapV3FactoryMinimal"
}
],
"stateMutability": "view"
},
{
"name": "wrappedNativeToken",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"type": "receive",
"stateMutability": "payable"
}
]0x61012060405260015f5534801562000015575f80fd5b50604051620052c8380380620052c88339810160408190526200003891620003fe565b6001600160a01b0385166200006757604051634726455360e11b81525f60048201526024015b60405180910390fd5b620000728462000395565b6200007d8362000395565b620000888262000395565b620000938162000395565b5f836001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000d1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620000f791906200046a565b9050846001600160a01b0316816001600160a01b031614620001485760405163100da9bd60e31b81526001600160a01b0380861660048301528087166024830152821660448201526064016200005e565b5f846001600160a01b0316634aa4a4fc6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000186573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620001ac91906200046a565b9050826001600160a01b0316816001600160a01b031614620001fd5760405163100da9bd60e31b81526001600160a01b0380871660048301528085166024830152821660448201526064016200005e565b5f846001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200023b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200026191906200046a565b9050866001600160a01b0316816001600160a01b031614620002b25760405163100da9bd60e31b81526001600160a01b0380871660048301528089166024830152821660448201526064016200005e565b5f856001600160a01b0316634aa4a4fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002f0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200031691906200046a565b9050846001600160a01b0316816001600160a01b031614620003675760405163100da9bd60e31b81526001600160a01b0380881660048301528087166024830152821660448201526064016200005e565b5050506001600160a01b039586166080525092841660a05290831660c052821660e05216610100526200048d565b6001600160a01b0381161580620003b457506001600160a01b0381163b155b15620003df57604051634726455360e11b81526001600160a01b03821660048201526024016200005e565b50565b80516001600160a01b0381168114620003f9575f80fd5b919050565b5f805f805f60a0868803121562000413575f80fd5b6200041e86620003e2565b94506200042e60208701620003e2565b93506200043e60408701620003e2565b92506200044e60608701620003e2565b91506200045e60808701620003e2565b90509295509295909350565b5f602082840312156200047b575f80fd5b6200048682620003e2565b9392505050565b60805160a05160c05160e05161010051614d94620005345f395f818161021c01528181612314015281816129ae0152612a3401525f6105a701525f818161043601528181610689015281816109f001528181612d8a015281816133d401528181613419015281816135a901528181613d6a0152613e1401525f8181610495015281816112bd015281816113cd0152612e8b01525f81816102c40152611b620152614d945ff3fe60806040526004361061017b575f3560e01c80636c0f4bf8116100d1578063b548f7761161007c578063d2389ce311610057578063d2389ce3146105c9578063d4bea83114610607578063e6f5275614610628575f80fd5b8063b548f77614610505578063bc17a5c814610543578063c31c9c0714610596575f80fd5b80638bdb2afa116100ac5780638bdb2afa14610484578063a5288d6b146104b7578063ac0255e4146104ee575f80fd5b80636c0f4bf8146103fe578063791b98bc1461042557806389097a6a14610458575f80fd5b8063359100b811610131578063629fa8a41161010c578063629fa8a41461038e57806362bdb477146103b557806365ff01fc146103df575f80fd5b8063359100b8146102e657806351f3b4bd14610325578063536dac9b1461036f575f80fd5b8063273cae3211610161578063273cae321461025657806327d282281461028f5780632b507df8146102b3575f80fd5b8063150b7a02146101b657806317fcb39b1461020b575f80fd5b366101b2576040517ff656d26f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80fd5b3480156101c1575f80fd5b506101d56101d03660046141eb565b61067d565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b348015610216575f80fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610202565b348015610261575f80fd5b50610281610270366004614282565b60046020525f908152604090205481565b604051908152602001610202565b34801561029a575f80fd5b506102a3600181565b6040519015158152602001610202565b3480156102be575f80fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156102f1575f80fd5b5061030561030036600461429d565b610712565b604080516001600160a01b03938416815292909116602083015201610202565b348015610330575f80fd5b5061034461033f3660046142b4565b61073f565b604080516001600160a01b039586168152949093166020850152918301526060820152608001610202565b34801561037a575f80fd5b5060015461023e906001600160a01b031681565b348015610399575f80fd5b506103a2600a81565b60405160029190910b8152602001610202565b3480156103c0575f80fd5b506103ca61038481565b60405163ffffffff9091168152602001610202565b3480156103ea575f80fd5b5061023e6103f93660046142f0565b610ab3565b348015610409575f80fd5b50610412601081565b60405161ffff9091168152602001610202565b348015610430575f80fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b348015610463575f80fd5b5061047761047236600461429d565b610ac3565b604051610202919061430b565b34801561048f575f80fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156104c2575f80fd5b506104d66104d136600461429d565b610c4a565b6040805192835260029190910b602083015201610202565b3480156104f9575f80fd5b50610281633b9aca0081565b348015610510575f80fd5b5061052461051f36600461429d565b610f9e565b60408051938452600292830b6020850152910b90820152606001610202565b34801561054e575f80fd5b5061056261055d36600461429d565b611148565b60405161020294939291909384526001600160a01b0392909216602084015260020b60408301521515606082015260800190565b3480156105a1575f80fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156105d4575f80fd5b506105e86105e336600461441e565b61116c565b604080516001600160a01b039093168352602083019190915201610202565b348015610612575f80fd5b50610626610621366004614282565b611b57565b005b348015610633575f80fd5b506106476106423660046142b4565b611c77565b6040516102029493929190931515845267ffffffffffffffff92831660208501529116604083015260060b606082015260800190565b5f336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146106e7576040517fe6c3d6070000000000000000000000000000000000000000000000000000000081523360048201526024015b60405180910390fd5b507f150b7a020000000000000000000000000000000000000000000000000000000095945050505050565b5f805f61071e84611d27565b60018101546002909101546001600160a01b03918216969116945092505050565b5f805f805f5460011461077e576040517fab143c0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025f90815561078d87611d27565b604080516101a08101825282546001600160a01b03908116825260018401548116602083015260028085015482169383019390935260038401548116606083015260048401549081166080830181905262ffffff7401000000000000000000000000000000000000000083041660a0840152770100000000000000000000000000000000000000000000008204840b60c08401527a01000000000000000000000000000000000000000000000000000090910490920b60e082015260058301546fffffffffffffffffffffffffffffffff16610100808301919091526006840154610120830152600784015461014083015260089093015460ff8082161515610160840152939004909216151561018083015290915033146108f25760808101516040517f59de481f0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0390911660248201526044016106de565b80608001516001600160a01b0316866001600160a01b03161461095a5760808101516040517ff544e9290000000000000000000000000000000000000000000000000000000081526001600160a01b03808916600483015290911660248201526044016106de565b60208082015160408084015181516080810183528b81526001600160a01b038b81169582019586526fffffffffffffffffffffffffffffffff8285018181526060840182815295517ffc6f786500000000000000000000000000000000000000000000000000000000815293516004850152965182166024840152955186166044830152925190941660648501529197509095507f0000000000000000000000000000000000000000000000000000000000000000169063fc6f78659060840160408051808303815f875af1158015610a35573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a599190614434565b60408051838152602081018390529295509093506001600160a01b0388169189917f06303b1def7ad89114cd60aeec098ca990b68939eef4723039ee4185ee9d940f910160405180910390a35060015f5592959194509250565b5f610abd82611d7f565b92915050565b604080516101a0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101829052610180810191909152610b3482611d27565b604080516101a08101825282546001600160a01b0390811682526001840154811660208301526002808501548216938301939093526003840154811660608301526004840154908116608083015262ffffff7401000000000000000000000000000000000000000082041660a0830152770100000000000000000000000000000000000000000000008104830b60c08301527a010000000000000000000000000000000000000000000000000000900490910b60e082015260058201546fffffffffffffffffffffffffffffffff16610100808301919091526006830154610120830152600783015461014083015260089092015460ff8082161515610160840152929004909116151561018082015292915050565b5f805f54600114610c87576040517fab143c0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025f908155610c9684611d27565b600881015490915060ff1615610cdb576040517fc2eb1967000000000000000000000000000000000000000000000000000000008152600481018590526024016106de565b5f848152600360209081526040808320338452909152902080546f01000000000000000000000000000000900460ff16610d4a576040517fb6c9f8f6000000000000000000000000000000000000000000000000000000008152600481018690523360248201526044016106de565b805442905f90610d729061038490670100000000000000900467ffffffffffffffff16614483565b90508067ffffffffffffffff168267ffffffffffffffff161015610ddd576040517f3831e85a0000000000000000000000000000000000000000000000000000000081526004810188905267ffffffffffffffff8083166024830152831660448201526064016106de565b5f610de7856121ee565b9299509750909150819050610e395760038501546040517fa7dc65360000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016106de565b8460070154871015610e875760078501546040517fcc647b170000000000000000000000000000000000000000000000000000000081526004810191909152602481018890526044016106de565b60038501545f90610ea0906001600160a01b031661235a565b855467ffffffffffffffff8681166701000000000000009081027fffffffffffffffffffffffffffffffffff000000000000000000000000000000841666ffffffffffffff861617178955895460038b01549495509204169133918c916001600160a01b03918216917fecce9bd95f72aca3dcc57ab2bd7347baedd3fcc2d7ad5968104feddb290678f19116858a610f3a61038482614483565b604080516001600160a01b03909516855267ffffffffffffffff93841660208601529183169184019190915216606082015260028d900b6080820152600687900b60a082015260c00160405180910390a45050505050505060015f81905550915091565b5f805f8054600114610fdc576040517fab143c0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025f908155610feb85611d27565b600881015490915060ff1615611030576040517fc2eb1967000000000000000000000000000000000000000000000000000000008152600481018690526024016106de565b5f8061103b836121ee565b9298509650925090508061108c5760038301546040517fa7dc65360000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016106de565b82600701548610156110da5760078301546040517fcc647b170000000000000000000000000000000000000000000000000000000081526004810191909152602481018790526044016106de565b5f878152600360209081526040808320338452909152902080546f01000000000000000000000000000000900460ff166111275761111b8489338a8a6124f0565b8594505050505061113d565b61113684828a338b888c6126bf565b9450505050505b60015f559193909250565b5f805f8061115d61115886611d27565b6121ee565b93509350935093509193509193565b5f805f546001146111a9576040517fab143c0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025f556001546001600160a01b03163314611206576001546040517f6f8075290000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0390911660248201526044016106de565b61120f836128ba565b60045f61121f6020860186614282565b6001600160a01b0316815260208101919091526040015f2054156112b25761124a6020840184614282565b60045f61125a6020870187614282565b6001600160a01b039081168252602082019290925260409081015f205490517fe6bb1dbe00000000000000000000000000000000000000000000000000000000815292909116600483015260248201526044016106de565b5f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166322afcccb6112f260a08701608088016144bb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815262ffffff9091166004820152602401602060405180830381865afa158015611348573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061136c91906144e1565b90505f8160020b136113c25761138860a08501608086016144bb565b6040517f98f8f43d00000000000000000000000000000000000000000000000000000000815262ffffff90911660048201526024016106de565b5f6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016631698ee826113ff6020880188614282565b61140f6040890160208a01614282565b61141f60a08a0160808b016144bb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b03938416600482015292909116602483015262ffffff166044820152606401602060405180830381865afa15801561148c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114b09190614507565b90506001600160a01b038116156115ca576114ca81612b10565b5f816001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa158015611507573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061152b9190614542565b5050505050509050806001600160a01b03165f1415801561156d575061155760c0870160a08801614282565b6001600160a01b0316816001600160a01b031614155b156115c85761158260c0870160a08801614282565b6040517f39cf850a0000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015290821660248201526044016106de565b505b5f6115d86020870187614282565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015611635573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061165991906145cf565b90508015611696576040517f5802ee27000000000000000000000000000000000000000000000000000000008152600481018290526024016106de565b6116be333060408901356116ad60208b018b614282565b6001600160a01b0316929190612b70565b5f6116cc6020880188614282565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015611729573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061174d91906145cf565b90508660400135811461179957604080517f29adafdc000000000000000000000000000000000000000000000000000000008152908801356004820152602481018290526044016106de565b5f6117a48886612cd3565b90505f6117b1898361333e565b60408381015182515f81815260026020529290922060080154909a50909850909150610100900460ff1615611815576040517fffa74afd000000000000000000000000000000000000000000000000000000008152600481018890526024016106de565b604080516101a081019091528061182f60208c018c614282565b6001600160a01b03168152602001835f01516001600160a01b0316815260200183602001516001600160a01b03168152602001896001600160a01b031681526020018a60600160208101906118849190614282565b6001600160a01b031681526020016118a260a08c0160808d016144bb565b62ffffff168152602001836060015160020b8152602001836080015160020b815260200182602001516fffffffffffffffffffffffffffffffff168152602001826060015181526020018a60c0013581526020015f151581526020016001151581525060025f8981526020019081526020015f205f820151815f015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506020820151816001015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506040820151816002015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506060820151816003015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506080820151816004015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060a08201518160040160146101000a81548162ffffff021916908362ffffff16021790555060c08201518160040160176101000a81548162ffffff021916908360020b62ffffff16021790555060e082015181600401601a6101000a81548162ffffff021916908360020b62ffffff160217905550610100820151816005015f6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555061012082015181600601556101408201518160070155610160820151816008015f6101000a81548160ff0219169083151502179055506101808201518160080160016101000a81548160ff0219169083151502179055509050508660045f8b5f016020810190611b149190614282565b6001600160a01b03166001600160a01b031681526020019081526020015f2081905550611b45878260400151613863565b50505050505060015f81905550915091565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611bbb576040517f29bcd81c0000000000000000000000000000000000000000000000000000000081523360048201526024016106de565b6001546001600160a01b031615611c0d576001546040517fe4051a330000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016106de565b611c1681612b10565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f2cb91bfa84e90001cba9a9d48b73c95f60565e07cf37287fe10249f402e29d09905f90a250565b5f805f805f611c8587611d27565b5f8881526003602090815260408083206001600160a01b038b16845290915290208054919250906f01000000000000000000000000000000900460ff168015611cd35750600882015460ff16155b955085611ced575f805f8095509550955095505050611d1e565b8054670100000000000000900467ffffffffffffffff169450611d1261038486614483565b905490935060060b9150505b92959194509250565b5f8181526002602052604090206008810154610100900460ff16611d7a576040517fa2016c11000000000000000000000000000000000000000000000000000000008152600481018390526024016106de565b919050565b5f805f8360020b12611d94578260020b611da1565b8260020b611da1906145e6565b9050611dcc7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2761861461c565b62ffffff16811115611e10576040517f5aaafcdd000000000000000000000000000000000000000000000000000000008152600284900b60048201526024016106de565b5f816001165f03611e3257700100000000000000000000000000000000611e44565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff1690506002821615611e83576080611e7e826ffff97272373d413259a46990580e213a614658565b901c90505b6004821615611ead576080611ea8826ffff2e50f5f656932ef12357cf3c7fdcc614658565b901c90505b6008821615611ed7576080611ed2826fffe5caca7e10e4e61c3624eaa0941cd0614658565b901c90505b6010821615611f01576080611efc826fffcb9843d60f6159c9db58835c926644614658565b901c90505b6020821615611f2b576080611f26826fff973b41fa98c081472e6896dfb254c0614658565b901c90505b6040821615611f55576080611f50826fff2ea16466c96a3843ec78b326b52861614658565b901c90505b6080821615611f7f576080611f7a826ffe5dee046a99a2a811c461f1969c3053614658565b901c90505b610100821615611faa576080611fa5826ffcbe86c7900a88aedcffc83b479aa3a4614658565b901c90505b610200821615611fd5576080611fd0826ff987a7253ac413176f2b074cf7815e54614658565b901c90505b610400821615612000576080611ffb826ff3392b0822b70005940c7a398e4b70f3614658565b901c90505b61080082161561202b576080612026826fe7159475a2c29b7443b29c7fa6e889d9614658565b901c90505b611000821615612056576080612051826fd097f3bdfd2022b8845ad8f792aa5825614658565b901c90505b61200082161561208157608061207c826fa9f746462d870fdf8a65dc1f90e061e5614658565b901c90505b6140008216156120ac5760806120a7826f70d869a156d2a1b890bb3df62baf32f7614658565b901c90505b6180008216156120d75760806120d2826f31be135f97d08fd981231505542fcfa6614658565b901c90505b620100008216156121035760806120fe826f09aa508b5b7a84e1c677de54f3e99bc9614658565b901c90505b6202000082161561212e576080612129826e5d6af8dedb81196699c329225ee604614658565b901c90505b62040000821615612158576080612153826d2216e584f5fa1ea926041bedfe98614658565b901c90505b6208000082161561218057608061217b826b048a170391f7dc42444e8fa2614658565b901c90505b5f8460020b13156121b8576121b5817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61469c565b90505b6121c7640100000000826146af565b156121d35760016121d5565b5f5b6121e69060ff16602083901c6146c2565b949350505050565b5f805f80846003015f9054906101000a90046001600160a01b03166001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa158015612244573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122689190614542565b60048c01549699509497509395505f946122a5945077010000000000000000000000000000000000000000000000900460020b9250611d7f915050565b60048701549091505f906122d9907a010000000000000000000000000000000000000000000000000000900460020b611d7f565b90505f806123088785858c6005015f9054906101000a90046fffffffffffffffffffffffffffffffff166139ac565b60018b015491935091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161461234b578061234d565b815b9750505050509193509193565b6040805160018082528183019092525f91829190602080830190803683370190505090505f815f8151811061239157612391614702565b63ffffffff909216602092830291909101909101526040517f883bdbfd0000000000000000000000000000000000000000000000000000000081526001600160a01b0384169063883bdbfd906123eb90849060040161472f565b5f60405180830381865afa92505050801561244557506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612442919081019061485f565b60015b612486576040517f47d670860000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024016106de565b81516001146124cc576040517f47d670860000000000000000000000000000000000000000000000000000000081526001600160a01b03861660048201526024016106de565b815f815181106124de576124de614702565b60200260200101519350505050919050565b60038501545f90612509906001600160a01b031661235a565b9050425f61251961038483614483565b905060405180606001604052808460060b81526020018367ffffffffffffffff1681526020016001151581525060035f8981526020019081526020015f205f886001600160a01b03166001600160a01b031681526020019081526020015f205f820151815f015f6101000a81548166ffffffffffffff021916908360060b66ffffffffffffff1602179055506020820151815f0160076101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040820151815f01600f6101000a81548160ff021916908315150217905550905050856001600160a01b031687895f015f9054906101000a90046001600160a01b03166001600160a01b03167f44d7142d4db66d26fcfd669f5c3034aaff9ad0cc727767cd6912b2794ecb9dfd8b6003015f9054906101000a90046001600160a01b03168987878b8b6040516126ad969594939291906001600160a01b03969096168652602086019490945267ffffffffffffffff92831660408601529116606084015260020b608083015260060b60a082015260c00190565b60405180910390a45050505050505050565b85545f90429082906126e99061038490670100000000000000900467ffffffffffffffff16614483565b90508067ffffffffffffffff168267ffffffffffffffff161015612754576040517f3831e85a0000000000000000000000000000000000000000000000000000000081526004810189905267ffffffffffffffff8083166024830152831660448201526064016106de565b60038a01545f9061276d906001600160a01b031661235a565b8a549091505f9061279390670100000000000000900467ffffffffffffffff1685614923565b8b549091506127a69060060b8383613a47565b94506127b28686613b34565b60088c0180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091555f8b81526003602090815260408083206001600160a01b038e8116855292529182902080547fffffffffffffffffffffffffffffffff0000000000000000000000000000000016905591548e5491517fa64f2a9d0000000000000000000000000000000000000000000000000000000081529183166004830152602482018b90529091169063a64f2a9d906044015f604051808303815f87803b158015612887575f80fd5b505af1158015612899573d5f803e3d5ffd5b505050506128ab8c8b8a8a8a8a613b8d565b50505050979650505050505050565b5f6128c86020830183614282565b6001600160a01b0316148061290957506128e86040820160208301614282565b6001600160a01b03166128fe6020830183614282565b6001600160a01b0316145b8061291657506040810135155b8061293857505f61292d6080830160608401614282565b6001600160a01b0316145b80612945575060c0810135155b1561297c576040517fbd637c4700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61299161298c6020830183614282565b612b10565b6129a461298c6080830160608401614282565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166129de6040830160208401614282565b6001600160a01b031614612a63576129fc6040820160208301614282565b6040517f518ea5bf0000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201527f000000000000000000000000000000000000000000000000000000000000000090911660248201526044016106de565b6401000276a3612a7960c0830160a08401614282565b6001600160a01b03161080612aba575073fffd8963efd1fc6a506488495d951d5263988d26612aae60c0830160a08401614282565b6001600160a01b031610155b15612b0d57612acf60c0820160a08301614282565b6040517f614875240000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016106de565b50565b6001600160a01b0381161580612b2e57506001600160a01b0381163b155b15612b0d576040517f8e4c8aa60000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016106de565b6040516001600160a01b0384811660248301528381166044830152606482018390525f918291871690608401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905251612c1d9190614944565b5f604051808303815f865af19150503d805f8114612c56576040519150601f19603f3d011682016040523d82523d5f602084013e612c5b565b606091505b5091509150811580612c895750805115801590612c89575080806020019051810190612c879190614970565b155b15612ccb576040517f3ccc3cdd0000000000000000000000000000000000000000000000000000000081526001600160a01b03871660048201526024016106de565b505050505050565b6040805160a0810182525f80825260208201819052918101829052606081018290526080810191909152612d0d6040840160208501614282565b6001600160a01b0316612d236020850185614282565b6001600160a01b031610612d5357612d416040840160208501614282565b612d4e6020850185614282565b612d70565b612d606020840184614282565b612d706040850160208601614282565b6001600160a01b03908116602084018190529181168084527f0000000000000000000000000000000000000000000000000000000000000000909116916313ead5629190612dc460a08801608089016144bb565b612dd460c0890160a08a01614282565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b1681526001600160a01b039485166004820152928416602484015262ffffff90911660448301529190911660648201526084016020604051808303815f875af1158015612e4c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e709190614507565b6001600160a01b039081166040830152815160208301515f927f00000000000000000000000000000000000000000000000000000000000000001691631698ee8291612ec260a0890160808a016144bb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b03938416600482015292909116602483015262ffffff166044820152606401602060405180830381865afa158015612f2f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f539190614507565b905081604001516001600160a01b0316816001600160a01b031614612fbd5760408083015190517f9a8687ac0000000000000000000000000000000000000000000000000000000081526001600160a01b03808416600483015290911660248201526044016106de565b612fca8260400151612b10565b5f8083604001516001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa15801561300c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130309190614542565b5050505050915091508560a001602081019061304c9190614282565b6001600160a01b0316826001600160a01b0316146130ba5761307460c0870160a08801614282565b6040517f39cf850a0000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015290831660248201526044016106de565b6130ca60c0870160a08801614282565b6001600160a01b03166130dc82611d7f565b6001600160a01b031614613142576130fa60c0870160a08801614282565b6040517f445476c10000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152600282900b60248201526044016106de565b61314c8582614989565b60020b15613194576040517feacb2c92000000000000000000000000000000000000000000000000000000008152600282810b600483015286900b60248201526044016106de565b60408085015190517f32148f67000000000000000000000000000000000000000000000000000000008152601060048201526001600160a01b03909116906332148f67906024015f604051808303815f87803b1580156131f2575f80fd5b505af1158015613204573d5f803e3d5ffd5b505050505f85867ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2761861323691906149aa565b6132409190614a1d565b90505f868061326e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2761861461c565b61327891906149aa565b6132829190614a1d565b86519091506001600160a01b031661329d60208a018a614282565b6001600160a01b0316036132c257600283810b606088015281900b60808701526132d5565b600282810b606088015283900b60808701525b856080015160020b866060015160020b1261333357606086015160808701516040517f5bbbea32000000000000000000000000000000000000000000000000000000008152600292830b6004820152910b60248201526044016106de565b505050505092915050565b61337760405180608001604052805f81526020015f6fffffffffffffffffffffffffffffffff1681526020015f81526020015f81525090565b5f61338a633b9aca00604086013561469c565b9050805f03613397575060015b5f6133a6826040870135614a3c565b84519091505f906001600160a01b03166133c36020880188614282565b6001600160a01b03161490506134157f0000000000000000000000000000000000000000000000000000000000000000604088013561340560208a018a614282565b6001600160a01b03169190613c08565b5f807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663883164566040518061016001604052808a5f01516001600160a01b031681526020018a602001516001600160a01b031681526020018b608001602081019061348a91906144bb565b62ffffff1681526020018a6060015160020b81526020018a6080015160020b8152602001866134b9575f6134bf565b8b604001355b8152602001866134d3578b604001356134d5565b5f5b8152602001866134e5575f6134e7565b875b8152602001866134f757876134f9565b5f5b815230602082015242604091820152517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815261353f9190600401614a4f565b6080604051808303815f875af115801561355b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061357f9190614b32565b6fffffffffffffffffffffffffffffffff9092166020808b0191909152928952935091506135d7907f0000000000000000000000000000000000000000000000000000000000000000905f90613405908c018c614282565b85602001516fffffffffffffffffffffffffffffffff165f03613626576040517ff564880500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82156136935781158061363c5750876040013582115b8061364657508015155b15613687576040517f210ba5c000000000000000000000000000000000000000000000000000000000815260048101839052602481018290526044016106de565b604086018290526136f6565b8015806136a35750876040013581115b806136ad57508115155b156136ee576040517f210ba5c000000000000000000000000000000000000000000000000000000000815260048101839052602481018290526044016106de565b604086018190525b604080870151613708918a0135614a3c565b606087018190528510156137585760608601516040517fb76fc01f0000000000000000000000000000000000000000000000000000000081526106de918791600401918252602082015260400190565b5f61376660208a018a614282565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa1580156137c3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137e791906145cf565b9050866060015181146138365760608701516040517f29adafdc0000000000000000000000000000000000000000000000000000000081526004810191909152602481018290526044016106de565b8651613857908961384d60a08d0160808e016144bb565b8a60200151613d62565b50505050505092915050565b5f82815260026020818152604092839020600381015481546001830154838601546004850154600586015460068701548a516001600160a01b03958616815293851698840198909852770100000000000000000000000000000000000000000000008204890b838b01527a010000000000000000000000000000000000000000000000000000820490980b60608301526fffffffffffffffffffffffffffffffff909716608082015260a0810189905260c081019590955294851660e0850152945191948794918216939116917f17ca67cff1843fa0f601c169439571c98a9be78d29c3b3ce930c77eb71bbd812918190036101000190a480546007820154604080519182526001602083015285926001600160a01b0316917f0412bc1aed3f65d8b055b66f7ee23260a81ab263936a0adad9050306e4f90657910160405180910390a3505050565b5f80836001600160a01b0316856001600160a01b031611156139cc579293925b846001600160a01b0316866001600160a01b0316116139f7576139f0858585613f97565b9150613a3e565b836001600160a01b0316866001600160a01b03161015613a3057613a1c868585613f97565b9150613a29858785614012565b9050613a3e565b613a3b858585614012565b90505b94509492505050565b5f83830367ffffffffffffffff831682613a6582600685900b614b6b565b90505f8360060b128015613a855750613a8282600685900b614bd2565b15155b15613a985780613a9481614be5565b9150505b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff27618811280613af05750613aea7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2761861461c565b60020b81135b15613b2a576040517f10a1101f000000000000000000000000000000000000000000000000000000008152600481018290526024016106de565b9695505050505050565b613b3e828261406d565b613b89576040517f75296539000000000000000000000000000000000000000000000000000000008152600283810b600483015282900b6024820152600a60448201526064016106de565b5050565b6003860154865460078801546040805188815260208101929092526001600160a01b0387811691830191909152600286810b606084015285900b6080830152889381169216907f594982e2539cc82223cece99a181b73cef0b368c6696cb0a13d821dbd193205d9060a00160405180910390a4505050505050565b6040516001600160a01b038381166024830152604482018390525f918291861690606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905251613cad9190614944565b5f604051808303815f865af19150503d805f8114613ce6576040519150601f19603f3d011682016040523d82523d5f602084013e613ceb565b606091505b5091509150811580613d195750805115801590613d19575080806020019051810190613d179190614970565b155b15613d5b576040517f3ccc3cdd0000000000000000000000000000000000000000000000000000000081526001600160a01b03861660048201526024016106de565b5050505050565b5f805f805f807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166399fbab888b6040518263ffffffff1660e01b8152600401613db691815260200190565b61018060405180830381865afa158015613dd2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613df69190614c46565b505050509750975097509750975097505050306001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636352211e8c6040518263ffffffff1660e01b8152600401613e6091815260200190565b602060405180830381865afa158015613e7b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e9f9190614507565b6001600160a01b0316141580613ec2575088516001600160a01b03878116911614155b80613ee3575088602001516001600160a01b0316856001600160a01b031614155b80613ef857508762ffffff168462ffffff1614155b80613f0d5750886060015160020b8360020b14155b80613f225750886080015160020b8260020b14155b80613f515750866fffffffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff1614155b15613f8b576040517f2f4fe7a9000000000000000000000000000000000000000000000000000000008152600481018b90526024016106de565b50505050505050505050565b5f826001600160a01b0316846001600160a01b03161115613fb6579192915b6001600160a01b0384166140087bffffffffffffffffffffffffffffffff000000000000000000000000606085901b16613ff08787614d1f565b6001600160a01b0316866001600160a01b03166140a2565b6121e6919061469c565b5f826001600160a01b0316846001600160a01b03161115614031579192915b6121e66fffffffffffffffffffffffffffffffff83166140518686614d1f565b6001600160a01b03166c010000000000000000000000006140a2565b5f808260020b8460020b6140819190614d3f565b90505f81121561409757614094816145e6565b90505b600a12159392505050565b5f80807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff858709858702925082811083820303915050805f0361413157835f03614118576040517f23d359a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8382816141275761412761466f565b04925050506141d0565b80841161416a576040517fc53abd5500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f848688098519600190810187169687900496828603819004959092119093035f82900391909104909201919091029190911760038402600290811880860282030280860282030280860282030280860282030280860282030280860290910302029150505b9392505050565b6001600160a01b0381168114612b0d575f80fd5b5f805f805f608086880312156141ff575f80fd5b853561420a816141d7565b9450602086013561421a816141d7565b935060408601359250606086013567ffffffffffffffff8082111561423d575f80fd5b818801915088601f830112614250575f80fd5b81358181111561425e575f80fd5b89602082850101111561426f575f80fd5b9699959850939650602001949392505050565b5f60208284031215614292575f80fd5b81356141d0816141d7565b5f602082840312156142ad575f80fd5b5035919050565b5f80604083850312156142c5575f80fd5b8235915060208301356142d7816141d7565b809150509250929050565b8060020b8114612b0d575f80fd5b5f60208284031215614300575f80fd5b81356141d0816142e2565b81516001600160a01b031681526101a08101602083015161433760208401826001600160a01b03169052565b50604083015161435260408401826001600160a01b03169052565b50606083015161436d60608401826001600160a01b03169052565b50608083015161438860808401826001600160a01b03169052565b5060a083015161439f60a084018262ffffff169052565b5060c08301516143b460c084018260020b9052565b5060e08301516143c960e084018260020b9052565b50610100838101516fffffffffffffffffffffffffffffffff16908301526101208084015190830152610140808401519083015261016080840151151590830152610180928301511515929091019190915290565b5f60e0828403121561442e575f80fd5b50919050565b5f8060408385031215614445575f80fd5b505080516020909101519092909150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b67ffffffffffffffff8181168382160190808211156144a4576144a4614456565b5092915050565b62ffffff81168114612b0d575f80fd5b5f602082840312156144cb575f80fd5b81356141d0816144ab565b8051611d7a816142e2565b5f602082840312156144f1575f80fd5b81516141d0816142e2565b8051611d7a816141d7565b5f60208284031215614517575f80fd5b81516141d0816141d7565b805161ffff81168114611d7a575f80fd5b80518015158114611d7a575f80fd5b5f805f805f805f60e0888a031215614558575f80fd5b8751614563816141d7565b6020890151909750614574816142e2565b955061458260408901614522565b945061459060608901614522565b935061459e60808901614522565b925060a088015160ff811681146145b3575f80fd5b91506145c160c08901614533565b905092959891949750929550565b5f602082840312156145df575f80fd5b5051919050565b5f7f8000000000000000000000000000000000000000000000000000000000000000820361461657614616614456565b505f0390565b5f8160020b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff800000810361465057614650614456565b5f0392915050565b8082028115828204841417610abd57610abd614456565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f826146aa576146aa61466f565b500490565b5f826146bd576146bd61466f565b500690565b80820180821115610abd57610abd614456565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b602080825282518282018190525f9190848201906040850190845b8181101561476c57835163ffffffff168352928401929184019160010161474a565b50909695505050505050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156147bf576147bf6146d5565b604052919050565b5f67ffffffffffffffff8211156147e0576147e06146d5565b5060051b60200190565b5f82601f8301126147f9575f80fd5b8151602061480e614809836147c7565b614778565b8083825260208201915060208460051b87010193508684111561482f575f80fd5b602086015b84811015614854578051614847816141d7565b8352918301918301614834565b509695505050505050565b5f8060408385031215614870575f80fd5b825167ffffffffffffffff80821115614887575f80fd5b818501915085601f83011261489a575f80fd5b815160206148aa614809836147c7565b82815260059290921b840181019181810190898411156148c8575f80fd5b948201945b838610156148f45785518060060b81146148e5575f80fd5b825294820194908201906148cd565b9188015191965090935050508082111561490c575f80fd5b50614919858286016147ea565b9150509250929050565b67ffffffffffffffff8281168282160390808211156144a4576144a4614456565b5f82515f5b818110156149635760208186018101518583015201614949565b505f920191825250919050565b5f60208284031215614980575f80fd5b6141d082614533565b5f8260020b8061499b5761499b61466f565b808360020b0791505092915050565b5f8160020b8360020b806149c0576149c061466f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81147fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000083141615614a1457614a14614456565b90059392505050565b5f8260020b8260020b028060020b91508082146144a4576144a4614456565b81810381811115610abd57610abd614456565b81516001600160a01b0316815261016081016020830151614a7b60208401826001600160a01b03169052565b506040830151614a92604084018262ffffff169052565b506060830151614aa7606084018260020b9052565b506080830151614abc608084018260020b9052565b5060a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151614b02828501826001600160a01b03169052565b505061014092830151919092015290565b80516fffffffffffffffffffffffffffffffff81168114611d7a575f80fd5b5f805f8060808587031215614b45575f80fd5b84519350614b5560208601614b13565b6040860151606090960151949790965092505050565b5f82614b7957614b7961466f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f800000000000000000000000000000000000000000000000000000000000000083141615614bcd57614bcd614456565b500590565b5f82614be057614be061466f565b500790565b5f7f80000000000000000000000000000000000000000000000000000000000000008203614c1557614c15614456565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b8051611d7a816144ab565b5f805f805f805f805f805f806101808d8f031215614c62575f80fd5b8c516bffffffffffffffffffffffff81168114614c7d575f80fd5b9b50614c8b60208e016144fc565b9a50614c9960408e016144fc565b9950614ca760608e016144fc565b9850614cb560808e01614c3b565b9750614cc360a08e016144d6565b9650614cd160c08e016144d6565b9550614cdf60e08e01614b13565b94506101008d015193506101208d01519250614cfe6101408e01614b13565b9150614d0d6101608e01614b13565b90509295989b509295989b509295989b565b6001600160a01b038281168282160390808211156144a4576144a4614456565b8181035f8312801583831316838312821617156144a4576144a461445656fea264697066735822122072caf59a16200d711df5b4bf30a13c04df44b99fb6a585aec8286de44e00f72c64736f6c634300081800330000000000000000000000009f2a37124db1a679a6c429859105ed4220e9d7830000000000000000000000001f7d7550b1b028f7571e69a784071f0205fd2efa00000000000000000000000073991a25c818bf1f1128deaab1492d45638de0d3000000000000000000000000caf681a66d020601342297493863e78c959e5cb20000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad73
0x60806040526004361061017b575f3560e01c80636c0f4bf8116100d1578063b548f7761161007c578063d2389ce311610057578063d2389ce3146105c9578063d4bea83114610607578063e6f5275614610628575f80fd5b8063b548f77614610505578063bc17a5c814610543578063c31c9c0714610596575f80fd5b80638bdb2afa116100ac5780638bdb2afa14610484578063a5288d6b146104b7578063ac0255e4146104ee575f80fd5b80636c0f4bf8146103fe578063791b98bc1461042557806389097a6a14610458575f80fd5b8063359100b811610131578063629fa8a41161010c578063629fa8a41461038e57806362bdb477146103b557806365ff01fc146103df575f80fd5b8063359100b8146102e657806351f3b4bd14610325578063536dac9b1461036f575f80fd5b8063273cae3211610161578063273cae321461025657806327d282281461028f5780632b507df8146102b3575f80fd5b8063150b7a02146101b657806317fcb39b1461020b575f80fd5b366101b2576040517ff656d26f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80fd5b3480156101c1575f80fd5b506101d56101d03660046141eb565b61067d565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b348015610216575f80fd5b5061023e7f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad7381565b6040516001600160a01b039091168152602001610202565b348015610261575f80fd5b50610281610270366004614282565b60046020525f908152604090205481565b604051908152602001610202565b34801561029a575f80fd5b506102a3600181565b6040519015158152602001610202565b3480156102be575f80fd5b5061023e7f0000000000000000000000009f2a37124db1a679a6c429859105ed4220e9d78381565b3480156102f1575f80fd5b5061030561030036600461429d565b610712565b604080516001600160a01b03938416815292909116602083015201610202565b348015610330575f80fd5b5061034461033f3660046142b4565b61073f565b604080516001600160a01b039586168152949093166020850152918301526060820152608001610202565b34801561037a575f80fd5b5060015461023e906001600160a01b031681565b348015610399575f80fd5b506103a2600a81565b60405160029190910b8152602001610202565b3480156103c0575f80fd5b506103ca61038481565b60405163ffffffff9091168152602001610202565b3480156103ea575f80fd5b5061023e6103f93660046142f0565b610ab3565b348015610409575f80fd5b50610412601081565b60405161ffff9091168152602001610202565b348015610430575f80fd5b5061023e7f00000000000000000000000073991a25c818bf1f1128deaab1492d45638de0d381565b348015610463575f80fd5b5061047761047236600461429d565b610ac3565b604051610202919061430b565b34801561048f575f80fd5b5061023e7f0000000000000000000000001f7d7550b1b028f7571e69a784071f0205fd2efa81565b3480156104c2575f80fd5b506104d66104d136600461429d565b610c4a565b6040805192835260029190910b602083015201610202565b3480156104f9575f80fd5b50610281633b9aca0081565b348015610510575f80fd5b5061052461051f36600461429d565b610f9e565b60408051938452600292830b6020850152910b90820152606001610202565b34801561054e575f80fd5b5061056261055d36600461429d565b611148565b60405161020294939291909384526001600160a01b0392909216602084015260020b60408301521515606082015260800190565b3480156105a1575f80fd5b5061023e7f000000000000000000000000caf681a66d020601342297493863e78c959e5cb281565b3480156105d4575f80fd5b506105e86105e336600461441e565b61116c565b604080516001600160a01b039093168352602083019190915201610202565b348015610612575f80fd5b50610626610621366004614282565b611b57565b005b348015610633575f80fd5b506106476106423660046142b4565b611c77565b6040516102029493929190931515845267ffffffffffffffff92831660208501529116604083015260060b606082015260800190565b5f336001600160a01b037f00000000000000000000000073991a25c818bf1f1128deaab1492d45638de0d316146106e7576040517fe6c3d6070000000000000000000000000000000000000000000000000000000081523360048201526024015b60405180910390fd5b507f150b7a020000000000000000000000000000000000000000000000000000000095945050505050565b5f805f61071e84611d27565b60018101546002909101546001600160a01b03918216969116945092505050565b5f805f805f5460011461077e576040517fab143c0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025f90815561078d87611d27565b604080516101a08101825282546001600160a01b03908116825260018401548116602083015260028085015482169383019390935260038401548116606083015260048401549081166080830181905262ffffff7401000000000000000000000000000000000000000083041660a0840152770100000000000000000000000000000000000000000000008204840b60c08401527a01000000000000000000000000000000000000000000000000000090910490920b60e082015260058301546fffffffffffffffffffffffffffffffff16610100808301919091526006840154610120830152600784015461014083015260089093015460ff8082161515610160840152939004909216151561018083015290915033146108f25760808101516040517f59de481f0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0390911660248201526044016106de565b80608001516001600160a01b0316866001600160a01b03161461095a5760808101516040517ff544e9290000000000000000000000000000000000000000000000000000000081526001600160a01b03808916600483015290911660248201526044016106de565b60208082015160408084015181516080810183528b81526001600160a01b038b81169582019586526fffffffffffffffffffffffffffffffff8285018181526060840182815295517ffc6f786500000000000000000000000000000000000000000000000000000000815293516004850152965182166024840152955186166044830152925190941660648501529197509095507f00000000000000000000000073991a25c818bf1f1128deaab1492d45638de0d3169063fc6f78659060840160408051808303815f875af1158015610a35573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a599190614434565b60408051838152602081018390529295509093506001600160a01b0388169189917f06303b1def7ad89114cd60aeec098ca990b68939eef4723039ee4185ee9d940f910160405180910390a35060015f5592959194509250565b5f610abd82611d7f565b92915050565b604080516101a0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101829052610180810191909152610b3482611d27565b604080516101a08101825282546001600160a01b0390811682526001840154811660208301526002808501548216938301939093526003840154811660608301526004840154908116608083015262ffffff7401000000000000000000000000000000000000000082041660a0830152770100000000000000000000000000000000000000000000008104830b60c08301527a010000000000000000000000000000000000000000000000000000900490910b60e082015260058201546fffffffffffffffffffffffffffffffff16610100808301919091526006830154610120830152600783015461014083015260089092015460ff8082161515610160840152929004909116151561018082015292915050565b5f805f54600114610c87576040517fab143c0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025f908155610c9684611d27565b600881015490915060ff1615610cdb576040517fc2eb1967000000000000000000000000000000000000000000000000000000008152600481018590526024016106de565b5f848152600360209081526040808320338452909152902080546f01000000000000000000000000000000900460ff16610d4a576040517fb6c9f8f6000000000000000000000000000000000000000000000000000000008152600481018690523360248201526044016106de565b805442905f90610d729061038490670100000000000000900467ffffffffffffffff16614483565b90508067ffffffffffffffff168267ffffffffffffffff161015610ddd576040517f3831e85a0000000000000000000000000000000000000000000000000000000081526004810188905267ffffffffffffffff8083166024830152831660448201526064016106de565b5f610de7856121ee565b9299509750909150819050610e395760038501546040517fa7dc65360000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016106de565b8460070154871015610e875760078501546040517fcc647b170000000000000000000000000000000000000000000000000000000081526004810191909152602481018890526044016106de565b60038501545f90610ea0906001600160a01b031661235a565b855467ffffffffffffffff8681166701000000000000009081027fffffffffffffffffffffffffffffffffff000000000000000000000000000000841666ffffffffffffff861617178955895460038b01549495509204169133918c916001600160a01b03918216917fecce9bd95f72aca3dcc57ab2bd7347baedd3fcc2d7ad5968104feddb290678f19116858a610f3a61038482614483565b604080516001600160a01b03909516855267ffffffffffffffff93841660208601529183169184019190915216606082015260028d900b6080820152600687900b60a082015260c00160405180910390a45050505050505060015f81905550915091565b5f805f8054600114610fdc576040517fab143c0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025f908155610feb85611d27565b600881015490915060ff1615611030576040517fc2eb1967000000000000000000000000000000000000000000000000000000008152600481018690526024016106de565b5f8061103b836121ee565b9298509650925090508061108c5760038301546040517fa7dc65360000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016106de565b82600701548610156110da5760078301546040517fcc647b170000000000000000000000000000000000000000000000000000000081526004810191909152602481018790526044016106de565b5f878152600360209081526040808320338452909152902080546f01000000000000000000000000000000900460ff166111275761111b8489338a8a6124f0565b8594505050505061113d565b61113684828a338b888c6126bf565b9450505050505b60015f559193909250565b5f805f8061115d61115886611d27565b6121ee565b93509350935093509193509193565b5f805f546001146111a9576040517fab143c0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025f556001546001600160a01b03163314611206576001546040517f6f8075290000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0390911660248201526044016106de565b61120f836128ba565b60045f61121f6020860186614282565b6001600160a01b0316815260208101919091526040015f2054156112b25761124a6020840184614282565b60045f61125a6020870187614282565b6001600160a01b039081168252602082019290925260409081015f205490517fe6bb1dbe00000000000000000000000000000000000000000000000000000000815292909116600483015260248201526044016106de565b5f6001600160a01b037f0000000000000000000000001f7d7550b1b028f7571e69a784071f0205fd2efa166322afcccb6112f260a08701608088016144bb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815262ffffff9091166004820152602401602060405180830381865afa158015611348573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061136c91906144e1565b90505f8160020b136113c25761138860a08501608086016144bb565b6040517f98f8f43d00000000000000000000000000000000000000000000000000000000815262ffffff90911660048201526024016106de565b5f6001600160a01b037f0000000000000000000000001f7d7550b1b028f7571e69a784071f0205fd2efa16631698ee826113ff6020880188614282565b61140f6040890160208a01614282565b61141f60a08a0160808b016144bb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b03938416600482015292909116602483015262ffffff166044820152606401602060405180830381865afa15801561148c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114b09190614507565b90506001600160a01b038116156115ca576114ca81612b10565b5f816001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa158015611507573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061152b9190614542565b5050505050509050806001600160a01b03165f1415801561156d575061155760c0870160a08801614282565b6001600160a01b0316816001600160a01b031614155b156115c85761158260c0870160a08801614282565b6040517f39cf850a0000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015290821660248201526044016106de565b505b5f6115d86020870187614282565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015611635573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061165991906145cf565b90508015611696576040517f5802ee27000000000000000000000000000000000000000000000000000000008152600481018290526024016106de565b6116be333060408901356116ad60208b018b614282565b6001600160a01b0316929190612b70565b5f6116cc6020880188614282565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015611729573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061174d91906145cf565b90508660400135811461179957604080517f29adafdc000000000000000000000000000000000000000000000000000000008152908801356004820152602481018290526044016106de565b5f6117a48886612cd3565b90505f6117b1898361333e565b60408381015182515f81815260026020529290922060080154909a50909850909150610100900460ff1615611815576040517fffa74afd000000000000000000000000000000000000000000000000000000008152600481018890526024016106de565b604080516101a081019091528061182f60208c018c614282565b6001600160a01b03168152602001835f01516001600160a01b0316815260200183602001516001600160a01b03168152602001896001600160a01b031681526020018a60600160208101906118849190614282565b6001600160a01b031681526020016118a260a08c0160808d016144bb565b62ffffff168152602001836060015160020b8152602001836080015160020b815260200182602001516fffffffffffffffffffffffffffffffff168152602001826060015181526020018a60c0013581526020015f151581526020016001151581525060025f8981526020019081526020015f205f820151815f015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506020820151816001015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506040820151816002015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506060820151816003015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506080820151816004015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060a08201518160040160146101000a81548162ffffff021916908362ffffff16021790555060c08201518160040160176101000a81548162ffffff021916908360020b62ffffff16021790555060e082015181600401601a6101000a81548162ffffff021916908360020b62ffffff160217905550610100820151816005015f6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555061012082015181600601556101408201518160070155610160820151816008015f6101000a81548160ff0219169083151502179055506101808201518160080160016101000a81548160ff0219169083151502179055509050508660045f8b5f016020810190611b149190614282565b6001600160a01b03166001600160a01b031681526020019081526020015f2081905550611b45878260400151613863565b50505050505060015f81905550915091565b336001600160a01b037f0000000000000000000000009f2a37124db1a679a6c429859105ed4220e9d7831614611bbb576040517f29bcd81c0000000000000000000000000000000000000000000000000000000081523360048201526024016106de565b6001546001600160a01b031615611c0d576001546040517fe4051a330000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016106de565b611c1681612b10565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f2cb91bfa84e90001cba9a9d48b73c95f60565e07cf37287fe10249f402e29d09905f90a250565b5f805f805f611c8587611d27565b5f8881526003602090815260408083206001600160a01b038b16845290915290208054919250906f01000000000000000000000000000000900460ff168015611cd35750600882015460ff16155b955085611ced575f805f8095509550955095505050611d1e565b8054670100000000000000900467ffffffffffffffff169450611d1261038486614483565b905490935060060b9150505b92959194509250565b5f8181526002602052604090206008810154610100900460ff16611d7a576040517fa2016c11000000000000000000000000000000000000000000000000000000008152600481018390526024016106de565b919050565b5f805f8360020b12611d94578260020b611da1565b8260020b611da1906145e6565b9050611dcc7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2761861461c565b62ffffff16811115611e10576040517f5aaafcdd000000000000000000000000000000000000000000000000000000008152600284900b60048201526024016106de565b5f816001165f03611e3257700100000000000000000000000000000000611e44565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff1690506002821615611e83576080611e7e826ffff97272373d413259a46990580e213a614658565b901c90505b6004821615611ead576080611ea8826ffff2e50f5f656932ef12357cf3c7fdcc614658565b901c90505b6008821615611ed7576080611ed2826fffe5caca7e10e4e61c3624eaa0941cd0614658565b901c90505b6010821615611f01576080611efc826fffcb9843d60f6159c9db58835c926644614658565b901c90505b6020821615611f2b576080611f26826fff973b41fa98c081472e6896dfb254c0614658565b901c90505b6040821615611f55576080611f50826fff2ea16466c96a3843ec78b326b52861614658565b901c90505b6080821615611f7f576080611f7a826ffe5dee046a99a2a811c461f1969c3053614658565b901c90505b610100821615611faa576080611fa5826ffcbe86c7900a88aedcffc83b479aa3a4614658565b901c90505b610200821615611fd5576080611fd0826ff987a7253ac413176f2b074cf7815e54614658565b901c90505b610400821615612000576080611ffb826ff3392b0822b70005940c7a398e4b70f3614658565b901c90505b61080082161561202b576080612026826fe7159475a2c29b7443b29c7fa6e889d9614658565b901c90505b611000821615612056576080612051826fd097f3bdfd2022b8845ad8f792aa5825614658565b901c90505b61200082161561208157608061207c826fa9f746462d870fdf8a65dc1f90e061e5614658565b901c90505b6140008216156120ac5760806120a7826f70d869a156d2a1b890bb3df62baf32f7614658565b901c90505b6180008216156120d75760806120d2826f31be135f97d08fd981231505542fcfa6614658565b901c90505b620100008216156121035760806120fe826f09aa508b5b7a84e1c677de54f3e99bc9614658565b901c90505b6202000082161561212e576080612129826e5d6af8dedb81196699c329225ee604614658565b901c90505b62040000821615612158576080612153826d2216e584f5fa1ea926041bedfe98614658565b901c90505b6208000082161561218057608061217b826b048a170391f7dc42444e8fa2614658565b901c90505b5f8460020b13156121b8576121b5817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61469c565b90505b6121c7640100000000826146af565b156121d35760016121d5565b5f5b6121e69060ff16602083901c6146c2565b949350505050565b5f805f80846003015f9054906101000a90046001600160a01b03166001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa158015612244573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122689190614542565b60048c01549699509497509395505f946122a5945077010000000000000000000000000000000000000000000000900460020b9250611d7f915050565b60048701549091505f906122d9907a010000000000000000000000000000000000000000000000000000900460020b611d7f565b90505f806123088785858c6005015f9054906101000a90046fffffffffffffffffffffffffffffffff166139ac565b60018b015491935091507f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad736001600160a01b0390811691161461234b578061234d565b815b9750505050509193509193565b6040805160018082528183019092525f91829190602080830190803683370190505090505f815f8151811061239157612391614702565b63ffffffff909216602092830291909101909101526040517f883bdbfd0000000000000000000000000000000000000000000000000000000081526001600160a01b0384169063883bdbfd906123eb90849060040161472f565b5f60405180830381865afa92505050801561244557506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612442919081019061485f565b60015b612486576040517f47d670860000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024016106de565b81516001146124cc576040517f47d670860000000000000000000000000000000000000000000000000000000081526001600160a01b03861660048201526024016106de565b815f815181106124de576124de614702565b60200260200101519350505050919050565b60038501545f90612509906001600160a01b031661235a565b9050425f61251961038483614483565b905060405180606001604052808460060b81526020018367ffffffffffffffff1681526020016001151581525060035f8981526020019081526020015f205f886001600160a01b03166001600160a01b031681526020019081526020015f205f820151815f015f6101000a81548166ffffffffffffff021916908360060b66ffffffffffffff1602179055506020820151815f0160076101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040820151815f01600f6101000a81548160ff021916908315150217905550905050856001600160a01b031687895f015f9054906101000a90046001600160a01b03166001600160a01b03167f44d7142d4db66d26fcfd669f5c3034aaff9ad0cc727767cd6912b2794ecb9dfd8b6003015f9054906101000a90046001600160a01b03168987878b8b6040516126ad969594939291906001600160a01b03969096168652602086019490945267ffffffffffffffff92831660408601529116606084015260020b608083015260060b60a082015260c00190565b60405180910390a45050505050505050565b85545f90429082906126e99061038490670100000000000000900467ffffffffffffffff16614483565b90508067ffffffffffffffff168267ffffffffffffffff161015612754576040517f3831e85a0000000000000000000000000000000000000000000000000000000081526004810189905267ffffffffffffffff8083166024830152831660448201526064016106de565b60038a01545f9061276d906001600160a01b031661235a565b8a549091505f9061279390670100000000000000900467ffffffffffffffff1685614923565b8b549091506127a69060060b8383613a47565b94506127b28686613b34565b60088c0180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091555f8b81526003602090815260408083206001600160a01b038e8116855292529182902080547fffffffffffffffffffffffffffffffff0000000000000000000000000000000016905591548e5491517fa64f2a9d0000000000000000000000000000000000000000000000000000000081529183166004830152602482018b90529091169063a64f2a9d906044015f604051808303815f87803b158015612887575f80fd5b505af1158015612899573d5f803e3d5ffd5b505050506128ab8c8b8a8a8a8a613b8d565b50505050979650505050505050565b5f6128c86020830183614282565b6001600160a01b0316148061290957506128e86040820160208301614282565b6001600160a01b03166128fe6020830183614282565b6001600160a01b0316145b8061291657506040810135155b8061293857505f61292d6080830160608401614282565b6001600160a01b0316145b80612945575060c0810135155b1561297c576040517fbd637c4700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61299161298c6020830183614282565b612b10565b6129a461298c6080830160608401614282565b6001600160a01b037f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad73166129de6040830160208401614282565b6001600160a01b031614612a63576129fc6040820160208301614282565b6040517f518ea5bf0000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201527f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad7390911660248201526044016106de565b6401000276a3612a7960c0830160a08401614282565b6001600160a01b03161080612aba575073fffd8963efd1fc6a506488495d951d5263988d26612aae60c0830160a08401614282565b6001600160a01b031610155b15612b0d57612acf60c0820160a08301614282565b6040517f614875240000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016106de565b50565b6001600160a01b0381161580612b2e57506001600160a01b0381163b155b15612b0d576040517f8e4c8aa60000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016106de565b6040516001600160a01b0384811660248301528381166044830152606482018390525f918291871690608401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905251612c1d9190614944565b5f604051808303815f865af19150503d805f8114612c56576040519150601f19603f3d011682016040523d82523d5f602084013e612c5b565b606091505b5091509150811580612c895750805115801590612c89575080806020019051810190612c879190614970565b155b15612ccb576040517f3ccc3cdd0000000000000000000000000000000000000000000000000000000081526001600160a01b03871660048201526024016106de565b505050505050565b6040805160a0810182525f80825260208201819052918101829052606081018290526080810191909152612d0d6040840160208501614282565b6001600160a01b0316612d236020850185614282565b6001600160a01b031610612d5357612d416040840160208501614282565b612d4e6020850185614282565b612d70565b612d606020840184614282565b612d706040850160208601614282565b6001600160a01b03908116602084018190529181168084527f00000000000000000000000073991a25c818bf1f1128deaab1492d45638de0d3909116916313ead5629190612dc460a08801608089016144bb565b612dd460c0890160a08a01614282565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b1681526001600160a01b039485166004820152928416602484015262ffffff90911660448301529190911660648201526084016020604051808303815f875af1158015612e4c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e709190614507565b6001600160a01b039081166040830152815160208301515f927f0000000000000000000000001f7d7550b1b028f7571e69a784071f0205fd2efa1691631698ee8291612ec260a0890160808a016144bb565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b03938416600482015292909116602483015262ffffff166044820152606401602060405180830381865afa158015612f2f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f539190614507565b905081604001516001600160a01b0316816001600160a01b031614612fbd5760408083015190517f9a8687ac0000000000000000000000000000000000000000000000000000000081526001600160a01b03808416600483015290911660248201526044016106de565b612fca8260400151612b10565b5f8083604001516001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa15801561300c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130309190614542565b5050505050915091508560a001602081019061304c9190614282565b6001600160a01b0316826001600160a01b0316146130ba5761307460c0870160a08801614282565b6040517f39cf850a0000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015290831660248201526044016106de565b6130ca60c0870160a08801614282565b6001600160a01b03166130dc82611d7f565b6001600160a01b031614613142576130fa60c0870160a08801614282565b6040517f445476c10000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152600282900b60248201526044016106de565b61314c8582614989565b60020b15613194576040517feacb2c92000000000000000000000000000000000000000000000000000000008152600282810b600483015286900b60248201526044016106de565b60408085015190517f32148f67000000000000000000000000000000000000000000000000000000008152601060048201526001600160a01b03909116906332148f67906024015f604051808303815f87803b1580156131f2575f80fd5b505af1158015613204573d5f803e3d5ffd5b505050505f85867ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2761861323691906149aa565b6132409190614a1d565b90505f868061326e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2761861461c565b61327891906149aa565b6132829190614a1d565b86519091506001600160a01b031661329d60208a018a614282565b6001600160a01b0316036132c257600283810b606088015281900b60808701526132d5565b600282810b606088015283900b60808701525b856080015160020b866060015160020b1261333357606086015160808701516040517f5bbbea32000000000000000000000000000000000000000000000000000000008152600292830b6004820152910b60248201526044016106de565b505050505092915050565b61337760405180608001604052805f81526020015f6fffffffffffffffffffffffffffffffff1681526020015f81526020015f81525090565b5f61338a633b9aca00604086013561469c565b9050805f03613397575060015b5f6133a6826040870135614a3c565b84519091505f906001600160a01b03166133c36020880188614282565b6001600160a01b03161490506134157f00000000000000000000000073991a25c818bf1f1128deaab1492d45638de0d3604088013561340560208a018a614282565b6001600160a01b03169190613c08565b5f807f00000000000000000000000073991a25c818bf1f1128deaab1492d45638de0d36001600160a01b031663883164566040518061016001604052808a5f01516001600160a01b031681526020018a602001516001600160a01b031681526020018b608001602081019061348a91906144bb565b62ffffff1681526020018a6060015160020b81526020018a6080015160020b8152602001866134b9575f6134bf565b8b604001355b8152602001866134d3578b604001356134d5565b5f5b8152602001866134e5575f6134e7565b875b8152602001866134f757876134f9565b5f5b815230602082015242604091820152517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815261353f9190600401614a4f565b6080604051808303815f875af115801561355b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061357f9190614b32565b6fffffffffffffffffffffffffffffffff9092166020808b0191909152928952935091506135d7907f00000000000000000000000073991a25c818bf1f1128deaab1492d45638de0d3905f90613405908c018c614282565b85602001516fffffffffffffffffffffffffffffffff165f03613626576040517ff564880500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82156136935781158061363c5750876040013582115b8061364657508015155b15613687576040517f210ba5c000000000000000000000000000000000000000000000000000000000815260048101839052602481018290526044016106de565b604086018290526136f6565b8015806136a35750876040013581115b806136ad57508115155b156136ee576040517f210ba5c000000000000000000000000000000000000000000000000000000000815260048101839052602481018290526044016106de565b604086018190525b604080870151613708918a0135614a3c565b606087018190528510156137585760608601516040517fb76fc01f0000000000000000000000000000000000000000000000000000000081526106de918791600401918252602082015260400190565b5f61376660208a018a614282565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa1580156137c3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137e791906145cf565b9050866060015181146138365760608701516040517f29adafdc0000000000000000000000000000000000000000000000000000000081526004810191909152602481018290526044016106de565b8651613857908961384d60a08d0160808e016144bb565b8a60200151613d62565b50505050505092915050565b5f82815260026020818152604092839020600381015481546001830154838601546004850154600586015460068701548a516001600160a01b03958616815293851698840198909852770100000000000000000000000000000000000000000000008204890b838b01527a010000000000000000000000000000000000000000000000000000820490980b60608301526fffffffffffffffffffffffffffffffff909716608082015260a0810189905260c081019590955294851660e0850152945191948794918216939116917f17ca67cff1843fa0f601c169439571c98a9be78d29c3b3ce930c77eb71bbd812918190036101000190a480546007820154604080519182526001602083015285926001600160a01b0316917f0412bc1aed3f65d8b055b66f7ee23260a81ab263936a0adad9050306e4f90657910160405180910390a3505050565b5f80836001600160a01b0316856001600160a01b031611156139cc579293925b846001600160a01b0316866001600160a01b0316116139f7576139f0858585613f97565b9150613a3e565b836001600160a01b0316866001600160a01b03161015613a3057613a1c868585613f97565b9150613a29858785614012565b9050613a3e565b613a3b858585614012565b90505b94509492505050565b5f83830367ffffffffffffffff831682613a6582600685900b614b6b565b90505f8360060b128015613a855750613a8282600685900b614bd2565b15155b15613a985780613a9481614be5565b9150505b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff27618811280613af05750613aea7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2761861461c565b60020b81135b15613b2a576040517f10a1101f000000000000000000000000000000000000000000000000000000008152600481018290526024016106de565b9695505050505050565b613b3e828261406d565b613b89576040517f75296539000000000000000000000000000000000000000000000000000000008152600283810b600483015282900b6024820152600a60448201526064016106de565b5050565b6003860154865460078801546040805188815260208101929092526001600160a01b0387811691830191909152600286810b606084015285900b6080830152889381169216907f594982e2539cc82223cece99a181b73cef0b368c6696cb0a13d821dbd193205d9060a00160405180910390a4505050505050565b6040516001600160a01b038381166024830152604482018390525f918291861690606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905251613cad9190614944565b5f604051808303815f865af19150503d805f8114613ce6576040519150601f19603f3d011682016040523d82523d5f602084013e613ceb565b606091505b5091509150811580613d195750805115801590613d19575080806020019051810190613d179190614970565b155b15613d5b576040517f3ccc3cdd0000000000000000000000000000000000000000000000000000000081526001600160a01b03861660048201526024016106de565b5050505050565b5f805f805f807f00000000000000000000000073991a25c818bf1f1128deaab1492d45638de0d36001600160a01b03166399fbab888b6040518263ffffffff1660e01b8152600401613db691815260200190565b61018060405180830381865afa158015613dd2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613df69190614c46565b505050509750975097509750975097505050306001600160a01b03167f00000000000000000000000073991a25c818bf1f1128deaab1492d45638de0d36001600160a01b0316636352211e8c6040518263ffffffff1660e01b8152600401613e6091815260200190565b602060405180830381865afa158015613e7b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e9f9190614507565b6001600160a01b0316141580613ec2575088516001600160a01b03878116911614155b80613ee3575088602001516001600160a01b0316856001600160a01b031614155b80613ef857508762ffffff168462ffffff1614155b80613f0d5750886060015160020b8360020b14155b80613f225750886080015160020b8260020b14155b80613f515750866fffffffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff1614155b15613f8b576040517f2f4fe7a9000000000000000000000000000000000000000000000000000000008152600481018b90526024016106de565b50505050505050505050565b5f826001600160a01b0316846001600160a01b03161115613fb6579192915b6001600160a01b0384166140087bffffffffffffffffffffffffffffffff000000000000000000000000606085901b16613ff08787614d1f565b6001600160a01b0316866001600160a01b03166140a2565b6121e6919061469c565b5f826001600160a01b0316846001600160a01b03161115614031579192915b6121e66fffffffffffffffffffffffffffffffff83166140518686614d1f565b6001600160a01b03166c010000000000000000000000006140a2565b5f808260020b8460020b6140819190614d3f565b90505f81121561409757614094816145e6565b90505b600a12159392505050565b5f80807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff858709858702925082811083820303915050805f0361413157835f03614118576040517f23d359a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8382816141275761412761466f565b04925050506141d0565b80841161416a576040517fc53abd5500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f848688098519600190810187169687900496828603819004959092119093035f82900391909104909201919091029190911760038402600290811880860282030280860282030280860282030280860282030280860282030280860290910302029150505b9392505050565b6001600160a01b0381168114612b0d575f80fd5b5f805f805f608086880312156141ff575f80fd5b853561420a816141d7565b9450602086013561421a816141d7565b935060408601359250606086013567ffffffffffffffff8082111561423d575f80fd5b818801915088601f830112614250575f80fd5b81358181111561425e575f80fd5b89602082850101111561426f575f80fd5b9699959850939650602001949392505050565b5f60208284031215614292575f80fd5b81356141d0816141d7565b5f602082840312156142ad575f80fd5b5035919050565b5f80604083850312156142c5575f80fd5b8235915060208301356142d7816141d7565b809150509250929050565b8060020b8114612b0d575f80fd5b5f60208284031215614300575f80fd5b81356141d0816142e2565b81516001600160a01b031681526101a08101602083015161433760208401826001600160a01b03169052565b50604083015161435260408401826001600160a01b03169052565b50606083015161436d60608401826001600160a01b03169052565b50608083015161438860808401826001600160a01b03169052565b5060a083015161439f60a084018262ffffff169052565b5060c08301516143b460c084018260020b9052565b5060e08301516143c960e084018260020b9052565b50610100838101516fffffffffffffffffffffffffffffffff16908301526101208084015190830152610140808401519083015261016080840151151590830152610180928301511515929091019190915290565b5f60e0828403121561442e575f80fd5b50919050565b5f8060408385031215614445575f80fd5b505080516020909101519092909150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b67ffffffffffffffff8181168382160190808211156144a4576144a4614456565b5092915050565b62ffffff81168114612b0d575f80fd5b5f602082840312156144cb575f80fd5b81356141d0816144ab565b8051611d7a816142e2565b5f602082840312156144f1575f80fd5b81516141d0816142e2565b8051611d7a816141d7565b5f60208284031215614517575f80fd5b81516141d0816141d7565b805161ffff81168114611d7a575f80fd5b80518015158114611d7a575f80fd5b5f805f805f805f60e0888a031215614558575f80fd5b8751614563816141d7565b6020890151909750614574816142e2565b955061458260408901614522565b945061459060608901614522565b935061459e60808901614522565b925060a088015160ff811681146145b3575f80fd5b91506145c160c08901614533565b905092959891949750929550565b5f602082840312156145df575f80fd5b5051919050565b5f7f8000000000000000000000000000000000000000000000000000000000000000820361461657614616614456565b505f0390565b5f8160020b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff800000810361465057614650614456565b5f0392915050565b8082028115828204841417610abd57610abd614456565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f826146aa576146aa61466f565b500490565b5f826146bd576146bd61466f565b500690565b80820180821115610abd57610abd614456565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b602080825282518282018190525f9190848201906040850190845b8181101561476c57835163ffffffff168352928401929184019160010161474a565b50909695505050505050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156147bf576147bf6146d5565b604052919050565b5f67ffffffffffffffff8211156147e0576147e06146d5565b5060051b60200190565b5f82601f8301126147f9575f80fd5b8151602061480e614809836147c7565b614778565b8083825260208201915060208460051b87010193508684111561482f575f80fd5b602086015b84811015614854578051614847816141d7565b8352918301918301614834565b509695505050505050565b5f8060408385031215614870575f80fd5b825167ffffffffffffffff80821115614887575f80fd5b818501915085601f83011261489a575f80fd5b815160206148aa614809836147c7565b82815260059290921b840181019181810190898411156148c8575f80fd5b948201945b838610156148f45785518060060b81146148e5575f80fd5b825294820194908201906148cd565b9188015191965090935050508082111561490c575f80fd5b50614919858286016147ea565b9150509250929050565b67ffffffffffffffff8281168282160390808211156144a4576144a4614456565b5f82515f5b818110156149635760208186018101518583015201614949565b505f920191825250919050565b5f60208284031215614980575f80fd5b6141d082614533565b5f8260020b8061499b5761499b61466f565b808360020b0791505092915050565b5f8160020b8360020b806149c0576149c061466f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81147fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000083141615614a1457614a14614456565b90059392505050565b5f8260020b8260020b028060020b91508082146144a4576144a4614456565b81810381811115610abd57610abd614456565b81516001600160a01b0316815261016081016020830151614a7b60208401826001600160a01b03169052565b506040830151614a92604084018262ffffff169052565b506060830151614aa7606084018260020b9052565b506080830151614abc608084018260020b9052565b5060a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151614b02828501826001600160a01b03169052565b505061014092830151919092015290565b80516fffffffffffffffffffffffffffffffff81168114611d7a575f80fd5b5f805f8060808587031215614b45575f80fd5b84519350614b5560208601614b13565b6040860151606090960151949790965092505050565b5f82614b7957614b7961466f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f800000000000000000000000000000000000000000000000000000000000000083141615614bcd57614bcd614456565b500590565b5f82614be057614be061466f565b500790565b5f7f80000000000000000000000000000000000000000000000000000000000000008203614c1557614c15614456565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b8051611d7a816144ab565b5f805f805f805f805f805f806101808d8f031215614c62575f80fd5b8c516bffffffffffffffffffffffff81168114614c7d575f80fd5b9b50614c8b60208e016144fc565b9a50614c9960408e016144fc565b9950614ca760608e016144fc565b9850614cb560808e01614c3b565b9750614cc360a08e016144d6565b9650614cd160c08e016144d6565b9550614cdf60e08e01614b13565b94506101008d015193506101208d01519250614cfe6101408e01614b13565b9150614d0d6101608e01614b13565b90509295989b509295989b509295989b565b6001600160a01b038281168282160390808211156144a4576144a4614456565b8181035f8312801583831316838312821617156144a4576144a461445656fea264697066735822122072caf59a16200d711df5b4bf30a13c04df44b99fb6a585aec8286de44e00f72c64736f6c63430008180033
| Token | Symbol | Balance | Price | Value |
|---|---|---|---|---|
| Uniswap V3 Positions NFT-V1 (UNI-V3-POS) | UNI-V3-POS | 1 | — | — |
| HoodForge Canary (HFCANARY) | HFCANARY | 0.000000 | — | — |
| Type | Age | Block | Details |
|---|---|---|---|
| no cross-chain L1↔L2 transactions for this address | |||
| Txn Hash | Age | Event | Topics / Data |
|---|---|---|---|
| 0xf20ecc…88c6d1 | 26 days agoMon, 20 Jul 2026 15:32:09 UTC | 0x0412bc…0657 | [0] 0x000000000000…89e865c2 [1] 0x000000000000…0003ccf4 data: 0x000000000000000000…00000001 |
| 0xf20ecc…88c6d1 | 26 days agoMon, 20 Jul 2026 15:32:09 UTC | 0x17ca67…d812 | [0] 0x000000000000…89e865c2 [1] 0x000000000000…482c9463 [2] 0x000000000000…0003ccf4 data: 0x000000000000000000…218b3987 |
| 0x3471a8…6742de | 26 days agoMon, 20 Jul 2026 14:56:44 UTC | 0x2cb91b…9d09 | [0] 0x000000000000…2b34cdf2 |
| Block | Age | Parent Transaction Hash | Type | Method | From | To | Value | |
|---|---|---|---|---|---|---|---|---|
| no internal transactions found for this address yet (traced blocks + on-demand) | ||||||||
| Transaction Hash | Method | Block | Age | From | To | Amount | Token | ||
|---|---|---|---|---|---|---|---|---|---|
| 0xf20eccf5…88c6d1 | Transfer | 14,811,099 | 26 days agoMon, 20 Jul 2026 15:32:09 UTC | 0xfc44…8cfa | OUT | 0x8d5c…9463 | 1,000,000,000.000000 HFCANARY | HoodForge Canary (HFCANARY) | |
| 0xf20eccf5…88c6d1 | Transfer | 14,811,099 | 26 days agoMon, 20 Jul 2026 15:32:09 UTC | 0x57de…cdf2 | IN | 0xfc44…8cfa | 1,000,000,000.000000 HFCANARY | HoodForge Canary (HFCANARY) |
| Transaction Hash | Method ? | Block | Age | From | To | Amount | Txn Fee ? | ||
|---|---|---|---|---|---|---|---|---|---|
| 0x3471a8…6742de | bindLaunchFactory | 14,789,868 | 26 days agoMon, 20 Jul 2026 14:56:44 UTC | 0x9f2a…d783 | IN | UniswapV3LaunchAdapter | $0.000 ETH | 0.00000249 | |
| !0xd31b7e…6ab0d2 | bindLaunchFactory | 14,788,012 | 26 days agoMon, 20 Jul 2026 14:53:37 UTC | 0x9f2a…d783 | IN | UniswapV3LaunchAdapter | $0.000 ETH | 0.00000248 |
| Transaction Hash | Method | Block | Age | From | To | Type | Item | ||
|---|---|---|---|---|---|---|---|---|---|
| 0xf20eccf5…88c6d1 | Transfer | 14,811,099 | 26 days agoMon, 20 Jul 2026 15:32:09 UTC | 0x0000…0000 | IN | 0xfc44…8cfa | Mint | Uniswap V3 Positions NFT-V1 (UNI-V3-POS) #249076 |