// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import {
IUniswapV3Factory,
IUniswapV3Pool,
IUniswapV3MintCallback,
IUniswapV3SwapCallback,
IWETH9
} from "./interfaces/IUniswapV3.sol";
/// @title LeaveHood (v3 — Uniswap v3 edition)
/// @notice Launchpad on Uniswap v3. There is no in-contract bonding curve and
/// no migration step anymore: at creation the WHOLE token supply (1B)
/// is deposited as a single one-sided concentrated position in a
/// fresh v3 pool (WETH/token, 1% fee tier):
///
/// - the pool is initialized exactly at the top of the range
/// (tick 204200 ≈ 7.4e8 tokens per ETH), so the position holds
/// only tokens and buys walk the price down the range — same
/// bonding-curve UX as before, but the curve IS the pool;
/// - the range extends down to the minimum usable tick, so trading
/// never stops and there is nothing to migrate on-chain. The
/// "migration" is now purely an off-chain status: the backend
/// marks a token migrated once ~4.2 ETH (net) have been swapped
/// into the pool (~756M tokens sold; 800M sold ≈ 5.4 ETH);
/// - the position is owned by this contract forever. The 1% LP fee
/// replaces the old hook fee: claimCreatorFees() collects it,
/// burns the token side, and splits the ETH side 50/50 between
/// the protocol treasury and the token's creator fee recipient.
///
/// Buys/sells keep the exact same external ABI as v2
/// (buyWithSlippage / sellWithSlippage, Trade event) so the frontend
/// and the Goldsky pipeline change as little as possible. The Trade
/// event is emitted from inside the swap callback ON PURPOSE: it gets
/// a lower log index than the pool's own Swap event in the same tx,
/// so the indexer always sees the enriched launchpad trade before the
/// raw pool swap.
contract LeaveHood is
OwnableUpgradeable,
ReentrancyGuardUpgradeable,
UUPSUpgradeable,
IUniswapV3MintCallback,
IUniswapV3SwapCallback
{
receive() external payable {}
// ------------------------------------------------------------------
// Pool constants (see scripts/curveMathV3.py derivation in the README)
// ------------------------------------------------------------------
/// @dev 1% fee tier; its tick spacing on the canonical factory is 200.
uint24 public constant POOL_FEE = 10000;
int24 public constant TICK_SPACING = 200;
/// @dev Launch tick / price: 1.0001^204200 ≈ 7.376e8 tokens per WETH.
/// 204200 and -887200 are both multiples of the tick spacing; the
/// position is minted over [TICK_LOWER, TICK_UPPER] with the price
/// starting exactly at TICK_UPPER, i.e. 100% tokens / 0 WETH.
int24 public constant TICK_UPPER = 204200;
int24 public constant TICK_LOWER = -887200;
/// @dev TickMath.getSqrtRatioAtTick(TICK_UPPER) — the exact v3 value.
uint160 public constant START_SQRT_PRICE_X96 = 2151813121295408910812139624586144;
/// @dev TickMath.getSqrtRatioAtTick(TICK_LOWER).
uint160 public constant SQRT_PRICE_LOWER_X96 = 4310618292;
/// @dev v3 TickMath.MIN_SQRT_RATIO / MAX_SQRT_RATIO bounds for swaps.
uint160 internal constant MIN_SQRT_RATIO = 4295128739;
uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;
uint256 internal constant Q96 = 0x1000000000000000000000000;
/// @dev Token-side LP fees are burned here on every claim.
address public constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;
/// @dev Build tag. A `constant` uses no storage slot but adds a getter, so
/// this implementation's runtime bytecode differs from the previous
/// (now-orphaned) one and the explorer does not cross-link them.
string public constant BUILD_TAG = "leavehood-v3-en-r2";
// ------------------------------------------------------------------
// Storage
// ------------------------------------------------------------------
address private feeRecipient;
uint256 private createFee;
IUniswapV3Factory private uniswapV3Factory;
IWETH9 private weth;
struct TokenPool {
address pool;
bool exists;
// Liquidity of the launchpad-owned position (fixed at creation).
uint128 positionLiquidity;
}
mapping(address => TokenPool) private pools;
/// @dev Reverse lookup for the indexer: v3 pool address -> launched token.
mapping(address => address) private poolToToken;
/// @dev Share (bps) of the CLAIMED ETH LP fees sent to the token's
/// creator fee recipient; the remainder goes to the protocol
/// treasury (feeRecipient). Default 5000 = 50/50.
uint256 private creatorFeeBasisPoint;
/// @dev Per-token creator payout address, set once at creation
/// (address(0) = 100% of claimed fees to the protocol).
mapping(address => address) private tokenCreatorFeeRecipient;
/// @dev Cumulative creator fees actually paid, per token (wei of ETH).
mapping(address => uint256) private tokenCreatorFeesPaid;
/// @dev Reference threshold used by getBondingCurve().complete and by the
/// backend as the migration trigger (net ETH swapped into the pool).
uint256 private graduationEth;
/// @dev Swap/mint callback guard: the pool we are currently interacting
/// with. Only that pool may call the callbacks, only mid-flight.
address private expectedCallbackPool;
/// @dev Per-token snapshot of creatorFeeBasisPoint, taken at creation so a
/// token keeps the split it launched with even if the global default
/// later changes. 0 = no snapshot (token created before this upgrade)
/// → falls back to the current global creatorFeeBasisPoint. We never
/// snapshot 0 (a live token always has a creator share), so 0 is a safe
/// "unset" sentinel. Takes one slot out of __gap (40 → 39).
mapping(address => uint256) private tokenCreatorFeeBps;
// set a gap for future upgrades
uint256[39] private __gap;
/// @dev ABI-compatible with v1/v2 so the backend keeps decoding it.
/// Values are derived live from the v3 pool state.
struct CurveInfo {
address tokenMint;
uint256 virtualTokenReserves;
uint256 virtualEthReserves;
uint256 realTokenReserves;
uint256 realEthReserves;
uint256 tokenTotalSupply;
uint256 virtualTotalSupply;
uint256 mcapLimit;
bool complete;
address uniswapV2Pair;
}
struct SwapCallbackData {
address token;
address payer; // seller paying tokens, or address(this) paying WETH
address trader; // end user, for the Trade event
}
// ------------------------------------------------------------------
// Events (same signatures as v2 wherever possible)
// ------------------------------------------------------------------
event CreatePool(address indexed mint, address indexed user);
event Trade(address indexed mint, uint256 ethAmount, uint256 tokenAmount, bool isBuy, address indexed user, uint256 timestamp, uint256 virtualEthReserves, uint256 virtualTokenReserves);
/// @notice `pair` is now the REAL Uniswap v3 pool address of the token.
event LiquidityPoolCreated(address indexed mint, address pair);
event CreatorFeePaid(address indexed mint, address indexed recipient, uint256 amount);
/// @notice Emitted on every claimCreatorFees(): the 1% LP fees were
/// collected from the pool; the token side was burned, the ETH
/// side split creator/protocol. Feeds the Goldsky claim pipeline.
event CreatorFeesClaimed(
address indexed mint,
address indexed creatorRecipient,
uint256 creatorEthAmount,
uint256 protocolEthAmount,
uint256 tokensBurned,
uint256 timestamp
);
function initialize(
address _feeRecipient,
uint256 _createFee,
address _uniswapV3Factory,
address _weth
) public initializer {
__Ownable_init(msg.sender);
__UUPSUpgradeable_init();
__ReentrancyGuard_init();
require(_feeRecipient != address(0), "feeRecipient zero");
require(_uniswapV3Factory != address(0), "factory zero");
require(_weth != address(0), "weth zero");
feeRecipient = _feeRecipient;
createFee = _createFee;
uniswapV3Factory = IUniswapV3Factory(_uniswapV3Factory);
weth = IWETH9(_weth);
creatorFeeBasisPoint = 5000; // 50% of claimed LP fees to the creator
graduationEth = 4.2 ether; // off-chain migration threshold (net ETH in pool)
}
// ------------------------------------------------------------------
// Pool creation
// ------------------------------------------------------------------
function createPool(
address token,
uint256 amount
) external payable nonReentrant {
_createPool(token, amount, msg.sender, address(0));
}
/// @notice Pool creation on behalf of `buyer` (typically called by the
/// factory so the initial buy goes to the end user, not the
/// factory). `creatorFeeRecipient_` (optional, address(0) =
/// defaults to `buyer`, the creator) receives `creatorFeeBasisPoint`
/// bps of the ETH LP fees on every claim, forever, set once at
/// creation. There is therefore always a creator recipient.
function createPoolFor(
address token,
uint256 amount,
address buyer,
address creatorFeeRecipient_
) external payable nonReentrant {
require(buyer != address(0), "CreatePool: buyer zero");
_createPool(token, amount, buyer, creatorFeeRecipient_);
}
function _createPool(
address token,
uint256 amount,
address buyer,
address creatorFeeRecipient_
) internal {
require(feeRecipient != address(0), "CreatePool: Non Zero Address");
require(!pools[token].exists, "CreatePool: already exists");
require(amount > 0, "CreatePool: amount zero");
// The launched token must sort AFTER WETH so it is always token1 and
// the launch price/ticks are the same for every pool. The factory
// guarantees this by salt-mining the token address.
require(token > address(weth), "CreatePool: token must sort after WETH");
require(msg.value >= createFee, "CreatePool: Value Amount");
uint256 effectiveEthAmount = msg.value - createFee;
IERC20(token).transferFrom(msg.sender, address(this), amount);
if (createFee > 0) {
(bool success,) = feeRecipient.call{value: createFee}("");
require(success, "Transfer failed");
}
// The creator always gets their share: when no wallet is provided, the
// default recipient is the creator themselves (`buyer`). There is thus
// ALWAYS a creatorFeeRecipient → the protocol keeps 0.5% (50% of the 1%)
// on every token, never the full 1%.
tokenCreatorFeeRecipient[token] = creatorFeeRecipient_ != address(0)
? creatorFeeRecipient_
: buyer;
// Snapshot the split this token launches with — it stays fixed for this
// token even if setCreatorFeeBasisPoint() later changes the global default.
tokenCreatorFeeBps[token] = creatorFeeBasisPoint;
// Create + initialize the pool at the launch price (top of range).
address pool = uniswapV3Factory.createPool(address(weth), token, POOL_FEE);
IUniswapV3Pool(pool).initialize(START_SQRT_PRICE_X96);
// One-sided position over [TICK_LOWER, TICK_UPPER] holding the whole
// `amount` (1B tokens from the factory) and zero WETH:
// L = amount1 * Q96 / (sqrtP_upper - sqrtP_lower)
// (mint rounds the required amount1 up, which by floor(L) stays <= amount).
uint128 liquidity = uint128(
Math.mulDiv(amount, Q96, START_SQRT_PRICE_X96 - SQRT_PRICE_LOWER_X96)
);
require(liquidity > 0, "CreatePool: zero liquidity");
TokenPool storage p = pools[token];
p.pool = pool;
p.exists = true;
p.positionLiquidity = liquidity;
poolToToken[pool] = token;
expectedCallbackPool = pool;
(uint256 used0, uint256 used1) = IUniswapV3Pool(pool).mint(
address(this),
TICK_LOWER,
TICK_UPPER,
liquidity,
abi.encode(token)
);
expectedCallbackPool = address(0);
require(used0 == 0, "CreatePool: unexpected WETH owed");
require(used1 <= amount, "CreatePool: mint overdraw");
emit CreatePool(token, buyer);
emit LiquidityPoolCreated(token, pool);
// First buy with the ETH left after the creation fee, credited to the
// buyer, in the same tx (Trade + Swap logs come after PoolCreated /
// LiquidityPoolCreated, so the indexer always knows the pool first).
if (effectiveEthAmount > 0) {
_buy(token, effectiveEthAmount, buyer, 0);
}
}
// ------------------------------------------------------------------
// Trading (thin wrappers over the v3 pool; anyone can also trade the
// pool directly through any v3 router — those swaps are indexed from the
// pool's own Swap events)
// ------------------------------------------------------------------
function buy(address token) external payable nonReentrant {
_buy(token, msg.value, msg.sender, 0);
}
/// @notice Buy with slippage protection: reverts if fewer than
/// `minTokensOut` tokens would be received for `msg.value`.
function buyWithSlippage(address token, uint256 minTokensOut) external payable nonReentrant {
_buy(token, msg.value, msg.sender, minTokensOut);
}
function _buy(address token, uint256 ethAmount, address recipient, uint256 minTokensOut) internal {
TokenPool storage p = pools[token];
require(ethAmount > 0, "buy: Should send ETH");
require(p.exists, "buy: unknown token");
weth.deposit{value: ethAmount}();
expectedCallbackPool = p.pool;
(int256 amount0, int256 amount1) = IUniswapV3Pool(p.pool).swap(
recipient,
true, // WETH (token0) in, token (token1) out
int256(ethAmount),
MIN_SQRT_RATIO + 1,
abi.encode(SwapCallbackData({token: token, payer: address(this), trader: recipient}))
);
expectedCallbackPool = address(0);
uint256 ethSpent = uint256(amount0);
uint256 tokensOut = uint256(-amount1);
require(tokensOut > 0, "buy: No tokens to buy");
require(tokensOut >= minTokensOut, "buy: slippage");
// ETH the pool could not absorb (price limit edge) is refunded.
uint256 refundAmount = ethAmount - ethSpent;
if (refundAmount > 0) {
weth.withdraw(refundAmount);
(bool success,) = recipient.call{value: refundAmount}("");
require(success, "Transfer failed");
}
}
function sell(address token, uint256 amount) external nonReentrant {
_sell(token, amount, 0);
}
/// @notice Sell with slippage protection: reverts if less than `minEthOut`
/// ETH would be received for `amount` tokens.
function sellWithSlippage(address token, uint256 amount, uint256 minEthOut) external nonReentrant {
_sell(token, amount, minEthOut);
}
function _sell(address token, uint256 amount, uint256 minEthOut) internal {
TokenPool storage p = pools[token];
require(p.exists, "sell: unknown token");
require(amount > 0, "sell: Should Larger than zero");
// Tokens are pulled straight from the seller to the pool inside the
// swap callback (single transfer, needs prior approval to this
// contract). WETH lands here and is unwrapped to the seller.
expectedCallbackPool = p.pool;
(int256 amount0, int256 amount1) = IUniswapV3Pool(p.pool).swap(
address(this),
false, // token (token1) in, WETH (token0) out
int256(amount),
MAX_SQRT_RATIO - 1,
abi.encode(SwapCallbackData({token: token, payer: msg.sender, trader: msg.sender}))
);
expectedCallbackPool = address(0);
uint256 tokensUsed = uint256(amount1);
uint256 ethOut = uint256(-amount0);
require(tokensUsed > 0, "sell: nothing sold");
require(ethOut >= minEthOut, "sell: slippage");
if (ethOut > 0) {
weth.withdraw(ethOut);
(bool success,) = msg.sender.call{value: ethOut}("");
require(success, "Transfer failed");
}
}
// ------------------------------------------------------------------
// Uniswap v3 callbacks
// ------------------------------------------------------------------
function uniswapV3MintCallback(uint256 amount0Owed, uint256 amount1Owed, bytes calldata data) external {
require(msg.sender == expectedCallbackPool && msg.sender != address(0), "MintCallback: bad caller");
address token = abi.decode(data, (address));
require(amount0Owed == 0, "MintCallback: WETH owed");
if (amount1Owed > 0) {
IERC20(token).transfer(msg.sender, amount1Owed);
}
}
function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external {
require(msg.sender == expectedCallbackPool && msg.sender != address(0), "SwapCallback: bad caller");
SwapCallbackData memory cb = abi.decode(data, (SwapCallbackData));
bool isBuy = amount0Delta > 0; // we owe WETH => buy
if (isBuy) {
weth.transfer(msg.sender, uint256(amount0Delta));
} else {
// Sell: pull the tokens straight from the seller to the pool.
IERC20(cb.token).transferFrom(cb.payer, msg.sender, uint256(amount1Delta));
}
// Emit the enriched Trade event from INSIDE the callback: the pool's
// own Swap event is emitted after the callback returns, so in the tx
// logs Trade always precedes Swap — the indexer processes the
// launchpad trade (with the real end user) before the raw pool swap.
// slot0/liquidity are already updated at callback time; expose the
// equivalent CPMM virtual reserves (vEth = L/sqrtP, vTok = L*sqrtP)
// so price = vEth/vTok keeps working unchanged off-chain.
(uint160 sqrtP,,,,,,) = IUniswapV3Pool(msg.sender).slot0();
uint128 liq = IUniswapV3Pool(msg.sender).liquidity();
// At the exact top of the range (price back at the launch tick) the
// position reads as out-of-range and pool.liquidity() is 0; fall back
// to the position's own liquidity so the reserves stay meaningful.
if (liq == 0) liq = pools[cb.token].positionLiquidity;
uint256 vEth = Math.mulDiv(liq, Q96, sqrtP);
uint256 vToken = Math.mulDiv(liq, sqrtP, Q96);
uint256 ethAmount = isBuy ? uint256(amount0Delta) : uint256(-amount0Delta);
uint256 tokenAmount = isBuy ? uint256(-amount1Delta) : uint256(amount1Delta);
emit Trade(cb.token, ethAmount, tokenAmount, isBuy, cb.trader, block.timestamp, vEth, vToken);
}
// ------------------------------------------------------------------
// Creator fees (the 1% LP fee of the launchpad-owned position)
// ------------------------------------------------------------------
/// @notice Collects the LP fees accrued by the launchpad-owned position of
/// `token`, burns the token side, and splits the ETH side between
/// the token's creator fee recipient (creatorFeeBasisPoint bps,
/// default 50%) and the protocol treasury. Callable by anyone
/// (payouts always go to the fixed recipients); the frontend shows
/// the claim button to the creator.
/// @return creatorEth ETH sent to the creator fee recipient
/// @return protocolEth ETH sent to the protocol treasury
/// @return tokensBurned token-side fees burned
function claimCreatorFees(address token)
external
nonReentrant
returns (uint256 creatorEth, uint256 protocolEth, uint256 tokensBurned)
{
TokenPool storage p = pools[token];
require(p.exists, "claim: unknown token");
IUniswapV3Pool pool = IUniswapV3Pool(p.pool);
// Poke the position (burn 0) so tokensOwed reflects all accrued fees,
// then collect everything owed to this contract.
pool.burn(TICK_LOWER, TICK_UPPER, 0);
(uint128 collected0, uint128 collected1) = pool.collect(
address(this),
TICK_LOWER,
TICK_UPPER,
type(uint128).max,
type(uint128).max
);
// Burn the token-side fees.
tokensBurned = collected1;
if (tokensBurned > 0) {
IERC20(token).transfer(BURN_ADDRESS, tokensBurned);
}
// Split the ETH-side fees creator/protocol.
uint256 ethCollected = collected0;
if (ethCollected > 0) {
weth.withdraw(ethCollected);
address creatorRecipient = tokenCreatorFeeRecipient[token];
uint256 creatorBps = (creatorRecipient != address(0)) ? _creatorBps(token) : 0;
creatorEth = ethCollected * creatorBps / 10000;
if (creatorEth > 0) {
// Best-effort with bounded gas: a reverting recipient must not
// block the protocol side — its share then goes to the treasury.
(bool okCreator,) = creatorRecipient.call{value: creatorEth, gas: 50000}("");
if (okCreator) {
tokenCreatorFeesPaid[token] += creatorEth;
emit CreatorFeePaid(token, creatorRecipient, creatorEth);
} else {
creatorEth = 0;
}
}
protocolEth = ethCollected - creatorEth;
if (protocolEth > 0) {
(bool success,) = feeRecipient.call{value: protocolEth}("");
require(success, "Transfer failed");
}
}
emit CreatorFeesClaimed(
token,
tokenCreatorFeeRecipient[token],
creatorEth,
protocolEth,
tokensBurned,
block.timestamp
);
}
/// @notice Fees currently claimable for `token` (accrued but uncollected
/// LP fees of the launchpad position). `creatorEth`/`protocolEth`
/// is the split the creator/protocol would receive if
/// claimCreatorFees() were called now. Static-callable by the
/// frontend for the claim button.
function getClaimableCreatorFees(address token)
external
view
returns (uint256 creatorEth, uint256 protocolEth, uint256 tokenFees)
{
TokenPool storage p = pools[token];
require(p.exists, "claim: unknown token");
// tokensOwed only reflects fees up to the last poke; the frontend uses
// eth_call on claimCreatorFees for an exact live preview. This view is
// the cheap approximation (post-poke state).
bytes32 key = keccak256(abi.encodePacked(address(this), TICK_LOWER, TICK_UPPER));
(, , , uint128 owed0, uint128 owed1) = IUniswapV3Pool(p.pool).positions(key);
uint256 creatorBps = (tokenCreatorFeeRecipient[token] != address(0)) ? _creatorBps(token) : 0;
creatorEth = uint256(owed0) * creatorBps / 10000;
protocolEth = uint256(owed0) - creatorEth;
tokenFees = owed1;
}
// ------------------------------------------------------------------
// Views (v1/v2-compatible)
// ------------------------------------------------------------------
function getBondingCurve(address mint) public view returns (CurveInfo memory info) {
TokenPool storage p = pools[mint];
if (!p.exists) return info;
IUniswapV3Pool pool = IUniswapV3Pool(p.pool);
(uint160 sqrtP,,,,,,) = pool.slot0();
uint128 liq = pool.liquidity();
// Out-of-range at the launch tick => 0; use the position's liquidity.
if (liq == 0) liq = p.positionLiquidity;
info.tokenMint = mint;
info.tokenTotalSupply = 1_000_000_000 ether;
info.virtualTotalSupply = 1_000_000_000 ether;
info.mcapLimit = graduationEth;
info.uniswapV2Pair = p.pool; // real v3 pool address now
// Equivalent CPMM virtual reserves at the current price.
info.virtualEthReserves = Math.mulDiv(liq, Q96, sqrtP);
info.virtualTokenReserves = Math.mulDiv(liq, sqrtP, Q96);
// Real reserves straight from the pool balances (WETH side includes
// uncollected LP fees, so this slightly overstates the raise — the
// backend keeps the exact number by summing Swap events).
info.realTokenReserves = IERC20(mint).balanceOf(p.pool);
info.realEthReserves = weth.balanceOf(p.pool);
// Approximate on-chain view of the off-chain migration flag.
info.complete = info.realEthReserves >= graduationEth;
}
function calculateEthCostForBuy(CurveInfo memory token, uint256 tokenAmount) public pure returns (uint256) {
uint256 virtualTokenReserves = token.virtualTokenReserves;
uint256 pricePerToken = virtualTokenReserves - tokenAmount;
uint256 totalLiquidity = token.virtualEthReserves * token.virtualTokenReserves;
uint256 newEthReserves = totalLiquidity/pricePerToken;
uint256 ethCost = newEthReserves - token.virtualEthReserves;
return ethCost;
}
function calculateEthCostForSell(CurveInfo memory token, uint256 tokenAmount) public pure returns (uint256) {
uint256 virtualTokenReserves = token.virtualTokenReserves;
uint256 pricePerToken = virtualTokenReserves + tokenAmount;
uint256 totalLiquidity = token.virtualEthReserves * token.virtualTokenReserves;
uint256 newEthReserves = totalLiquidity/pricePerToken;
uint256 ethCost = token.virtualEthReserves - newEthReserves;
return ethCost;
}
function estimateEthForBuy(address token, uint256 tokenAmount) public view returns (uint256) {
return calculateEthCostForBuy(getBondingCurve(token), tokenAmount);
}
function estimateEthForSell(address token, uint256 tokenAmount) public view returns (uint256) {
return calculateEthCostForSell(getBondingCurve(token), tokenAmount);
}
/// @notice v3 pool address of a launched token.
function getPool(address token) external view returns (address) {
require(pools[token].exists, "unknown token");
return pools[token].pool;
}
/// @notice Reverse lookup for the indexer: launched token of a v3 pool
/// (address(0) if the pool is not one of ours).
function tokenForPool(address pool) external view returns (address) {
return poolToToken[pool];
}
/// @notice Liquidity of the launchpad-owned position of a token.
function getPositionLiquidity(address token) external view returns (uint128) {
require(pools[token].exists, "unknown token");
return pools[token].positionLiquidity;
}
// ------------------------------------------------------------------
// Admin
// ------------------------------------------------------------------
/// @notice Sweeps dust (mint rounding leftovers) held by the launchpad.
function withdraw(address token) external onlyOwner nonReentrant {
uint256 tokenAmount = IERC20(token).balanceOf(address(this));
if (tokenAmount > 0) {
IERC20(token).transfer(msg.sender, tokenAmount);
}
}
function withdrawEth() external onlyOwner nonReentrant {
(bool success,) = msg.sender.call{value: address(this).balance}("");
require(success, "Transfer failed");
}
function setFeeRecipient(address newAddr) external onlyOwner {
require(newAddr != address(0), "Non zero Address");
feeRecipient = newAddr;
}
/// @notice Flat fee (in wei) charged when creating a new pool. Can be 0.
function setCreateFee(uint256 newCreateFee) external onlyOwner {
createFee = newCreateFee;
}
/// @notice Share of the claimed ETH LP fees (in bps) sent to the creator
/// fee recipient on claimCreatorFees(). 5000 = 50/50 split.
function setCreatorFeeBasisPoint(uint256 newBasisPoint) external onlyOwner {
require(newBasisPoint <= 10000, "Fee too high");
creatorFeeBasisPoint = newBasisPoint;
}
/// @notice Reference net-ETH threshold for the off-chain migration status.
function setGraduationEth(uint256 newGraduationEth) external onlyOwner {
require(newGraduationEth > 0, "Should Larger than zero");
graduationEth = newGraduationEth;
}
function getCreateFee() external view returns(uint256){
return createFee;
}
/// @notice Trade fee in bps of the traded ETH. In v3 this is the pool's
/// 1% LP fee tier (kept as a view for backend compatibility).
function getTradeFeeBasisPoint() external view returns(uint256){
return POOL_FEE / 100;
}
function getCreatorFeeBasisPoint() external view returns(uint256){
return creatorFeeBasisPoint;
}
/// @dev Effective creator-fee split for a token: its snapshot if it launched
/// after the per-token upgrade (non-zero), else the current global.
function _creatorBps(address token) internal view returns (uint256) {
uint256 b = tokenCreatorFeeBps[token];
return b == 0 ? creatorFeeBasisPoint : b;
}
/// @notice Creator-fee split (bps) actually applied to `token` on claim —
/// its creation-time snapshot, or the global default for tokens
/// created before the per-token upgrade. Used by the backend for
/// per-token referral netting.
function getCreatorFeeBasisPointForToken(address token) external view returns(uint256){
return _creatorBps(token);
}
function getCreatorFeeRecipient(address token) external view returns(address){
return tokenCreatorFeeRecipient[token];
}
/// @notice Cumulative creator fees paid out for a token (wei).
function getCreatorFeesPaid(address token) external view returns(uint256){
return tokenCreatorFeesPaid[token];
}
function getGraduationEth() external view returns(uint256){
return graduationEth;
}
function getUniswapV3Factory() external view returns(address){
return address(uniswapV3Factory);
}
function getWeth() external view returns(address){
return address(weth);
}
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
}[
{
"name": "AddressEmptyCode",
"type": "error",
"inputs": [
{
"name": "target",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "ERC1967InvalidImplementation",
"type": "error",
"inputs": [
{
"name": "implementation",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "ERC1967NonPayable",
"type": "error",
"inputs": []
},
{
"name": "FailedCall",
"type": "error",
"inputs": []
},
{
"name": "InvalidInitialization",
"type": "error",
"inputs": []
},
{
"name": "NotInitializing",
"type": "error",
"inputs": []
},
{
"name": "OwnableInvalidOwner",
"type": "error",
"inputs": [
{
"name": "owner",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "OwnableUnauthorizedAccount",
"type": "error",
"inputs": [
{
"name": "account",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "ReentrancyGuardReentrantCall",
"type": "error",
"inputs": []
},
{
"name": "UUPSUnauthorizedCallContext",
"type": "error",
"inputs": []
},
{
"name": "UUPSUnsupportedProxiableUUID",
"type": "error",
"inputs": [
{
"name": "slot",
"type": "bytes32",
"internalType": "bytes32"
}
]
},
{
"name": "CreatePool",
"type": "event",
"inputs": [
{
"name": "mint",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "user",
"type": "address",
"indexed": true,
"internalType": "address"
}
],
"anonymous": false
},
{
"name": "CreatorFeePaid",
"type": "event",
"inputs": [
{
"name": "mint",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "recipient",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "amount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "CreatorFeesClaimed",
"type": "event",
"inputs": [
{
"name": "mint",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "creatorRecipient",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "creatorEthAmount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "protocolEthAmount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "tokensBurned",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "timestamp",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "Initialized",
"type": "event",
"inputs": [
{
"name": "version",
"type": "uint64",
"indexed": false,
"internalType": "uint64"
}
],
"anonymous": false
},
{
"name": "LiquidityPoolCreated",
"type": "event",
"inputs": [
{
"name": "mint",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "pair",
"type": "address",
"indexed": false,
"internalType": "address"
}
],
"anonymous": false
},
{
"name": "OwnershipTransferred",
"type": "event",
"inputs": [
{
"name": "previousOwner",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "newOwner",
"type": "address",
"indexed": true,
"internalType": "address"
}
],
"anonymous": false
},
{
"name": "Trade",
"type": "event",
"inputs": [
{
"name": "mint",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "ethAmount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "tokenAmount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "isBuy",
"type": "bool",
"indexed": false,
"internalType": "bool"
},
{
"name": "user",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "timestamp",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "virtualEthReserves",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "virtualTokenReserves",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "Upgraded",
"type": "event",
"inputs": [
{
"name": "implementation",
"type": "address",
"indexed": true,
"internalType": "address"
}
],
"anonymous": false
},
{
"name": "BUILD_TAG",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "string",
"internalType": "string"
}
],
"stateMutability": "view"
},
{
"name": "BURN_ADDRESS",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "POOL_FEE",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint24",
"internalType": "uint24"
}
],
"stateMutability": "view"
},
{
"name": "SQRT_PRICE_LOWER_X96",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint160",
"internalType": "uint160"
}
],
"stateMutability": "view"
},
{
"name": "START_SQRT_PRICE_X96",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint160",
"internalType": "uint160"
}
],
"stateMutability": "view"
},
{
"name": "TICK_LOWER",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "int24",
"internalType": "int24"
}
],
"stateMutability": "view"
},
{
"name": "TICK_SPACING",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "int24",
"internalType": "int24"
}
],
"stateMutability": "view"
},
{
"name": "TICK_UPPER",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "int24",
"internalType": "int24"
}
],
"stateMutability": "view"
},
{
"name": "UPGRADE_INTERFACE_VERSION",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "string",
"internalType": "string"
}
],
"stateMutability": "view"
},
{
"name": "buy",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "payable"
},
{
"name": "buyWithSlippage",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
},
{
"name": "minTokensOut",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "payable"
},
{
"name": "calculateEthCostForBuy",
"type": "function",
"inputs": [
{
"name": "token",
"type": "tuple",
"components": [
{
"name": "tokenMint",
"type": "address",
"internalType": "address"
},
{
"name": "virtualTokenReserves",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "virtualEthReserves",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "realTokenReserves",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "realEthReserves",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "tokenTotalSupply",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "virtualTotalSupply",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "mcapLimit",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "complete",
"type": "bool",
"internalType": "bool"
},
{
"name": "uniswapV2Pair",
"type": "address",
"internalType": "address"
}
],
"internalType": "struct LeaveHood.CurveInfo"
},
{
"name": "tokenAmount",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "pure"
},
{
"name": "calculateEthCostForSell",
"type": "function",
"inputs": [
{
"name": "token",
"type": "tuple",
"components": [
{
"name": "tokenMint",
"type": "address",
"internalType": "address"
},
{
"name": "virtualTokenReserves",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "virtualEthReserves",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "realTokenReserves",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "realEthReserves",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "tokenTotalSupply",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "virtualTotalSupply",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "mcapLimit",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "complete",
"type": "bool",
"internalType": "bool"
},
{
"name": "uniswapV2Pair",
"type": "address",
"internalType": "address"
}
],
"internalType": "struct LeaveHood.CurveInfo"
},
{
"name": "tokenAmount",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "pure"
},
{
"name": "claimCreatorFees",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "creatorEth",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "protocolEth",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "tokensBurned",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "nonpayable"
},
{
"name": "createPool",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
},
{
"name": "amount",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "payable"
},
{
"name": "createPoolFor",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
},
{
"name": "amount",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "buyer",
"type": "address",
"internalType": "address"
},
{
"name": "creatorFeeRecipient_",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "payable"
},
{
"name": "estimateEthForBuy",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
},
{
"name": "tokenAmount",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "estimateEthForSell",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
},
{
"name": "tokenAmount",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "getBondingCurve",
"type": "function",
"inputs": [
{
"name": "mint",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "info",
"type": "tuple",
"components": [
{
"name": "tokenMint",
"type": "address",
"internalType": "address"
},
{
"name": "virtualTokenReserves",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "virtualEthReserves",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "realTokenReserves",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "realEthReserves",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "tokenTotalSupply",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "virtualTotalSupply",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "mcapLimit",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "complete",
"type": "bool",
"internalType": "bool"
},
{
"name": "uniswapV2Pair",
"type": "address",
"internalType": "address"
}
],
"internalType": "struct LeaveHood.CurveInfo"
}
],
"stateMutability": "view"
},
{
"name": "getClaimableCreatorFees",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "creatorEth",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "protocolEth",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "tokenFees",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "getCreateFee",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "getCreatorFeeBasisPoint",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "getCreatorFeeBasisPointForToken",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "getCreatorFeeRecipient",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "getCreatorFeesPaid",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "getGraduationEth",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "getPool",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "getPositionLiquidity",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint128",
"internalType": "uint128"
}
],
"stateMutability": "view"
},
{
"name": "getTradeFeeBasisPoint",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "getUniswapV3Factory",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "getWeth",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "initialize",
"type": "function",
"inputs": [
{
"name": "_feeRecipient",
"type": "address",
"internalType": "address"
},
{
"name": "_createFee",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "_uniswapV3Factory",
"type": "address",
"internalType": "address"
},
{
"name": "_weth",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "owner",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "proxiableUUID",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "bytes32",
"internalType": "bytes32"
}
],
"stateMutability": "view"
},
{
"name": "renounceOwnership",
"type": "function",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "sell",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
},
{
"name": "amount",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "sellWithSlippage",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
},
{
"name": "amount",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "minEthOut",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "setCreateFee",
"type": "function",
"inputs": [
{
"name": "newCreateFee",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "setCreatorFeeBasisPoint",
"type": "function",
"inputs": [
{
"name": "newBasisPoint",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "setFeeRecipient",
"type": "function",
"inputs": [
{
"name": "newAddr",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "setGraduationEth",
"type": "function",
"inputs": [
{
"name": "newGraduationEth",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "tokenForPool",
"type": "function",
"inputs": [
{
"name": "pool",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "transferOwnership",
"type": "function",
"inputs": [
{
"name": "newOwner",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "uniswapV3MintCallback",
"type": "function",
"inputs": [
{
"name": "amount0Owed",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amount1Owed",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "data",
"type": "bytes",
"internalType": "bytes"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "uniswapV3SwapCallback",
"type": "function",
"inputs": [
{
"name": "amount0Delta",
"type": "int256",
"internalType": "int256"
},
{
"name": "amount1Delta",
"type": "int256",
"internalType": "int256"
},
{
"name": "data",
"type": "bytes",
"internalType": "bytes"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "upgradeToAndCall",
"type": "function",
"inputs": [
{
"name": "newImplementation",
"type": "address",
"internalType": "address"
},
{
"name": "data",
"type": "bytes",
"internalType": "bytes"
}
],
"outputs": [],
"stateMutability": "payable"
},
{
"name": "withdraw",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "withdrawEth",
"type": "function",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "receive",
"stateMutability": "payable"
}
]0x60a080604052346029573060805261397b908161002e8239608051818181612004015261220b0152f35b5f80fdfe6080604052600436101561001a575b3615610018575f80fd5b005b5f803560e01c80630dda52f614612af2578063107c279f14612ac957806312d3617114612710578063239f3af7146126f257806326a53e1114612692578063358394d8146124075780634244a6e2146123e957806346ca626b146123cd57806347377d92146123ae5780634f1ef2861461218f57806351cff8d91461205857806352d1902d14611ff15780635d201b5114611fd35780636291484914611fb05780636618b10014611f805780636784ad1e14611ceb5780636c197ff514611a66578063715018a6146119fd5780637f6434bb146119e3578063838e2d3f146119c557806383db2a21146119265780638da5cb5b146118f1578063a0ef91df146118bd578063a7e6daf714611222578063aaef5342146111cc578063ad3cb1cc14611183578063aefadc7a14611123578063af7c621b14610f7b578063af9b1f3514610f61578063b081983b14610f38578063b904b2b514610f14578063bb8769a714610eeb578063bbe4f6db14610e90578063c5cf847b14610e4f578063c7c37e8814610e16578063c81e0e0c14610da8578063d348799714610c25578063d5c0ad4614610bed578063d6ae6e44146107cb578063d816d3301461078a578063dd1b9c4a1461076d578063de308afb14610751578063e74b981b146106d6578063ea6cab52146106b6578063f088d54714610679578063f2fde38b1461064c578063fa461e33146102545763fccc281314610235575061000e565b34610251578060031936011261025157602060405161dead8152f35b80fd5b50346102515760603660031901126102515760243560043560443567ffffffffffffffff81116105fa5761028c903690600401612e86565b600a546001600160a01b0316331480610643575b156105fe5781606091810103126105fa57604051926102be84612d34565b6102c782612cd2565b928385526102e960406102dc60208601612cd2565b9485602089015201612cd2565b60408601908152938682139383851561056e57505060035460405163a9059cbb60e01b8152336004820152602481018490529150602090829060449082908b906001600160a01b03165af1801561052657610531575b505b604051633850c7bd60e01b815260e081600481335afa9081156105265787916104f1575b50604051630d34328160e11b8152602081600481335afa9081156104e657889161047c575b507f671f6af1a2244f88c1a5e6c6310f86653d313027950723ffc12387348a9ed8b39460c0949392916001600160801b03811615610453575b6001600160801b0316916103ea906001600160a01b03166103e48185613715565b936137ba565b92811561044457935b811561043e5761040290613423565b975b51965160408051958652602086019990995297840152426060840152608083015260a08201526001600160a01b039485169490931692a380f35b97610404565b61044d90613423565b936103f3565b5087516001600160a01b03168952600460205260408920600101546001600160801b03166103c3565b93929190506020843d6020116104de575b8161049a60209383612d81565b810103126104da577f671f6af1a2244f88c1a5e6c6310f86653d313027950723ffc12387348a9ed8b3946104cf60c095612fd8565b91929394509461038a565b8780fd5b3d915061048d565b6040513d8a823e3d90fd5b610513915060e03d60e01161051f575b61050b8183612d81565b810190612f67565b5050505050505f610365565b503d610501565b6040513d89823e3d90fd5b6020813d602011610566575b8161054a60209383612d81565b810103126105625761055b90612eb4565b505f61033f565b8680fd5b3d915061053d565b6040516323b872dd60e01b81526001600160a01b0390921660048301523360248301526044820152906020908290818a816064810103926001600160a01b03165af18015610526576105c1575b50610341565b6020813d6020116105f2575b816105da60209383612d81565b81010312610562576105eb90612eb4565b505f6105bb565b3d91506105cd565b8380fd5b60405162461bcd60e51b815260206004820152601860248201527f5377617043616c6c6261636b3a206261642063616c6c657200000000000000006044820152606490fd5b503315156102a0565b503461025157602036600319011261025157610676610669612cbc565b610671613507565b6133b2565b80f35b506020366003190112610251576106a2610691612cbc565b610699613433565b3390349061353a565b60015f805160206139068339815191525580f35b50346102515780600319360112610251576020604051640100eed0b48152f35b5034610251576020366003190112610251576106f0612cbc565b6106f8613507565b6001600160a01b031680156107195781546001600160a01b03191617815580f35b60405162461bcd60e51b815260206004820152601060248201526f4e6f6e207a65726f204164647265737360801b6044820152606490fd5b5034610251578060031936011261025157602060405160648152f35b503461025157806003193601126102515760206040516127108152f35b5034610251576020366003190112610251576020906001600160a01b036107af612cbc565b16815260058252604060018060a01b0391205416604051908152f35b5034610251576020366003190112610251576107e5612cbc565b6107ed613433565b8182809260018060a01b038116908183526004602052604083205461081760ff8260a01c16613335565b6040805163a34123a760e01b8152620d899f19600482015262031da8602482015260448101869052916001600160a01b0316908260648188855af1918215610be257604092610bb6575b5060a48251809681936309e3d67b60e31b8352306004840152620d899f19602484015262031da860448401526001600160801b0360648401526001600160801b0360848401525af18015610bab5786938791610b58575b506001600160801b03169283610adf575b6001600160801b03169081610965575b50508481610961949596526007602052604060018060a01b0391205416907f51ad8a78d6a70d23d7b8093afe4cbc2217fc9d2237d088c1fc3ec48e5c38ffa06080604051878152886020820152856040820152426060820152a360015f8051602061390683398151915255604051938493846040919493926060820195825260208201520152565b0390f35b600354919550935085906001600160a01b0316803b15610adb57818091602460405180948193632e1a7d4d60e01b83528b60048401525af18015610ad057610ab7575b50819052600760205260408520546001600160a01b0316928315610aaa576109db6109d561271092613819565b86612ee2565b049283610a29575b506109f2836109619495612f13565b9485610a02575b9493925f6108d9565b610a24818080808a60018060a01b038254165af1610a1e61328c565b506132bb565b6109f9565b85808080878561c350f1610a3b61328c565b5015610a99578361096194956109f292848952600860205260408920610a62848254612ec1565b9055847f37f367d4b24fa07d94199e5a6182293a8ae4d3b3986782251a6a467a04b6788a6020604051868152a35b955093506109e3565b5061096192506109f2858095610a90565b506127106109db866109d5565b81610ac191612d81565b610acc57845f6109a8565b8480fd5b6040513d84823e3d90fd5b5080fd5b60405163a9059cbb60e01b815261dead600482015260248101859052906020826044818b885af180156104e657610b18575b90506108c9565b6020823d602011610b50575b81610b3160209383612d81565b810103126104da57610b4a6001600160801b0392612eb4565b50610b11565b3d9150610b24565b9350506040833d604011610ba3575b81610b7460409383612d81565b81010312610b9f576001600160801b03610b996020610b9286612fd8565b9501612fd8565b906108b8565b8580fd5b3d9150610b67565b6040513d88823e3d90fd5b610bd590833d8511610bdb575b610bcd8183612d81565b81019061339c565b50610861565b503d610bc3565b6040513d87823e3d90fd5b5034610251576040366003190112610251576020610c1d610c0c612cbc565b610c1860243591612fec565b613378565b604051908152f35b50346102515760603660031901126102515760243560443567ffffffffffffffff8111610d5657610c5a903690600401612e86565b600a546001600160a01b0316331480610d9f575b15610d5a578160209181010312610d5657356001600160a01b03811690819003610d5657600435610d1157818392610ca4575050f35b60405163a9059cbb60e01b815233600482015260248101919091529160209183916044918391905af18015610ad057610cdb575080f35b6020813d602011610d09575b81610cf460209383612d81565b81010312610adb57610d0590612eb4565b5080f35b3d9150610ce7565b60405162461bcd60e51b815260206004820152601760248201527f4d696e7443616c6c6261636b3a2057455448206f7765640000000000000000006044820152606490fd5b8280fd5b60405162461bcd60e51b815260206004820152601860248201527f4d696e7443616c6c6261636b3a206261642063616c6c657200000000000000006044820152606490fd5b50331515610c6e565b503461025157602036600319011261025157600435610dc5613507565b8015610dd15760095580f35b60405162461bcd60e51b815260206004820152601760248201527f53686f756c64204c6172676572207468616e207a65726f0000000000000000006044820152606490fd5b5034610251576020366003190112610251576020906040906001600160a01b03610e3e612cbc565b168152600883522054604051908152f35b5034610251576020366003190112610251576020906001600160a01b03610e74612cbc565b16815260078252604060018060a01b0391205416604051908152f35b5034610251576020366003190112610251576020906001600160a01b03610eb5612cbc565b1680825260048352610ed060ff604084205460a01c166132f9565b815260048252604060018060a01b0391205416604051908152f35b503461025157806003193601126102515760206040516d6a17b32fc5d4d48f7124aa2fdba08152f35b5034610251576020366003190112610251576020610c1d610f33612cbc565b613819565b50346102515780600319360112610251576002546040516001600160a01b039091168152602090f35b5034610251576020610c1d610f7536612dbf565b90613378565b503461025157602036600319011261025157610f95612cbc565b6001600160a01b038116808352600460205260408320549091610fbe60a083901c60ff16613335565b6040513060601b60208201908152620793b360ed1b60348301526163b560eb1b6037830152601a825260a091610ff5603a82612d81565b51902060246040518095819363514ea4bf60e01b83526004830152600180861b03165afa92831561111857849285946110a2575b508452600760205260408420546001600160801b0394610961939261107c92612710926110749289926001600160a01b03161561109b5761106a9150613819565b945b169384612ee2565b048092612f13565b6040519485941691846040919493926060820195825260208201520152565b509461106c565b9250925060a0823d60a011611110575b816110bf60a09383612d81565b810103126105fa579061107c6127106110746001600160801b038097610961966110e887612fd8565b5061110160806110fa60608a01612fd8565b9801612fd8565b98955095965097505050611029565b3d91506110b2565b6040513d86823e3d90fd5b5034610251576020366003190112610251576020906001600160801b03906001906040906001600160a01b03611157612cbc565b168082526004865261117160ff8484205460a01c166132f9565b81526004855220015416604051908152f35b5034610251578060031936011261025157506109616040516111a6604082612d81565b60058152640352e302e360dc1b6020820152604051918291602083526020830190612e62565b5034610251578060031936011261025157506109616040516111ef604082612d81565b60128152713632b0bb32b437b7b216bb1996b2b716b91960711b6020820152604051918291602083526020830190612e62565b5061122c36612ce6565b9091611236613433565b6001600160a01b038316801561187f5785546001600160a01b03161561183a576001600160a01b0385168087526004602052604087205490929060a01c60ff166117f55780156117b0576003546001600160a01b031683111561175c57600154803410611717576112a79034612f13565b6040516323b872dd60e01b8152336004820152306024820152604481018390529094906020816064818c895af18015611608576116dc575b5060015488816116b6575b50506001600160a01b038116156116af575b838852600760209081526040808a2080546001600160a01b0319166001600160a01b03948516179055600654868b52600b8352818b2055600254600354915163a167129560e01b815291841660048301526024820187905261271060448301529092839160649183918d91165af19081156104e657889161166d575b506001600160a01b031690813b156104da5760405163f637731d60e01b81526d6a17b32fc5d4d48f7124aa2fdba060048201528890818160248183885af18015610ad057611658575b506001600160801b0390506113e46d6a17b32fc5d4d48f7123a9410aec83613715565b16801561161357848952600460209081526040808b20805460ff60a01b1987166001600160a81b031990911617600160a01b17815560010180546001600160801b03191684179055848b5260058252808b2080546001600160a01b03199081168917909155600a80549091168617905580518083018890529182526114b0929091906114708383612d81565b82519384928392633c8a7d8d60e01b8452306004850152620d899f19602485015262031da86044850152606484015260a0608484015260a4830190612e62565b03818c875af19081156116085789908a926115e6575b50600a80546001600160a01b03191690556115a2571161155d577f3366ddec6d22baedae5089cdef368ab66cbf7cc63aec389ca0d4b54e447baa1b9160209160405191857fdbd2a1ea6808362e6adbec4db4969cbc11e3b0b28fb6c74cb342defaaf1daada8b80a38152a28061154c575b8360015f805160206139068339815191525580f35b6115559261353a565b5f8080611537565b60405162461bcd60e51b815260206004820152601960248201527f437265617465506f6f6c3a206d696e74206f76657264726177000000000000006044820152606490fd5b606460405162461bcd60e51b815260206004820152602060248201527f437265617465506f6f6c3a20756e65787065637465642057455448206f7765646044820152fd5b9050611601915060403d604011610bdb57610bcd8183612d81565b905f6114c6565b6040513d8b823e3d90fd5b60405162461bcd60e51b815260206004820152601a60248201527f437265617465506f6f6c3a207a65726f206c69717569646974790000000000006044820152606490fd5b8161166291612d81565b6104da57875f6113c1565b90506020813d6020116116a7575b8161168860209383612d81565b810103126104da57516001600160a01b03811681036104da575f611378565b3d915061167b565b50846112fc565b80546116d5928291829182916001600160a01b03165af1610a1e61328c565b5f886112ea565b6020813d60201161170f575b816116f560209383612d81565b8101031261170b5761170690612eb4565b6112df565b8880fd5b3d91506116e8565b60405162461bcd60e51b815260206004820152601860248201527f437265617465506f6f6c3a2056616c756520416d6f756e7400000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152602660248201527f437265617465506f6f6c3a20746f6b656e206d75737420736f727420616674656044820152650e440ae8aa8960d31b6064820152608490fd5b60405162461bcd60e51b815260206004820152601760248201527f437265617465506f6f6c3a20616d6f756e74207a65726f0000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601a60248201527f437265617465506f6f6c3a20616c7265616479206578697374730000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601c60248201527f437265617465506f6f6c3a204e6f6e205a65726f2041646472657373000000006044820152606490fd5b60405162461bcd60e51b8152602060048201526016602482015275437265617465506f6f6c3a206275796572207a65726f60501b6044820152606490fd5b50346102515780600319360112610251576118d6613507565b6118de613433565b6106a28180808047335af1610a1e61328c565b50346102515780600319360112610251575f805160206138c6833981519152546040516001600160a01b039091168152602090f35b50346102515760203660031901126102515761014061194b611946612cbc565b612fec565b6040519060018060a01b0381511682526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e0830152610100810151151561010083015261012060018060a01b0391015116610120820152f35b50346102515780600319360112610251576020600954604051908152f35b5034610251576020610c1d6119f736612dbf565b90612f20565b5034610251578060031936011261025157611a16613507565b5f805160206138c683398151915280546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b503461025157604036600319011261025157611a80612cbc565b60243590611a8c613433565b6001600160a01b03168083526004602052604083208054919260a083901c60ff1615611cb0578015611c6b57600a80546001600160a01b0319166001600160a01b03948516179055905460408051611b52959194611b279493169273fffd8963efd1fc6a506488495d951d5263988d25928892611b3591611b0c82612d34565b8152336020820152338882015287519687916020830161346b565b03601f198101875286612d81565b8551630251596160e31b815296879586948593306004860161349a565b03925af1908115610ad05782908392611c47575b50600a80546001600160a01b0319169055611b8090613423565b9015611c0d5780611ba1575b5060015f805160206139068339815191525580f35b60035482906001600160a01b0316803b15610adb57818091602460405180948193632e1a7d4d60e01b83528860048401525af18015610ad057611bf8575b50808080611bf294335af1610a1e61328c565b5f611b8c565b611c03828092612d81565b610251575f611bdf565b60405162461bcd60e51b81526020600482015260126024820152711cd95b1b0e881b9bdd1a1a5b99c81cdbdb1960721b6044820152606490fd5b611b809250611c65915060403d604011610bdb57610bcd8183612d81565b91611b66565b60405162461bcd60e51b815260206004820152601d60248201527f73656c6c3a2053686f756c64204c6172676572207468616e207a65726f0000006044820152606490fd5b60405162461bcd60e51b815260206004820152601360248201527239b2b6361d103ab735b737bbb7103a37b5b2b760691b6044820152606490fd5b50604036600319011261025157611d00612cbc565b611d08613433565b6001600160a01b0316808252600460205260408220903415611f445760ff825460a01c1615611f0a576003548392906001600160a01b0316803b15611f05578360049160405192838092630d0e30db60e41b825234905af1908115611118578491611eec575b50508054600a80546001600160a01b0319166001600160a01b039283161790559054604080519093611df6939290921691611dcb91611dd991611db082612d34565b8152306020820152338682015285519283916020830161346b565b03601f198101835282612d81565b8351948580948193630251596160e31b83523433600485016134d2565b03925af18015610ad05782918391611ec7575b50600a80546001600160a01b0319169055611e2390613423565b8015611e8a5760243511611e5557611e3b9034612f13565b80611ba1575060015f805160206139068339815191525580f35b60405162461bcd60e51b815260206004820152600d60248201526c6275793a20736c69707061676560981b6044820152606490fd5b60405162461bcd60e51b81526020600482015260156024820152746275793a204e6f20746f6b656e7320746f2062757960581b6044820152606490fd5b611e239250611ee5915060403d604011610bdb57610bcd8183612d81565b9091611e09565b81611ef691612d81565b611f0157825f611d6e565b5050fd5b505050fd5b60405162461bcd60e51b8152602060048201526012602482015271313abc9d103ab735b737bbb7103a37b5b2b760711b6044820152606490fd5b60405162461bcd60e51b81526020600482015260146024820152730c4eaf27440a6d0deead8c840e6cadcc8408aa8960631b6044820152606490fd5b5034610251576040366003190112610251576020610c1d611f9f612cbc565b611fab60243591612fec565b612f20565b503461025157602036600319011261025157611fca613507565b60043560015580f35b50346102515780600319360112610251576020600654604051908152f35b50346102515780600319360112610251577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036120495760206040515f805160206138e68339815191528152f35b63703e46dd60e11b8152600490fd5b50346102515760203660031901126102515780612073612cbc565b61207b613507565b612083613433565b6040516370a0823160e01b81523060048201526001600160a01b039190911690602081602481855afa90811561218457839161214b575b50806120d6575b8260015f805160206139068339815191525580f35b60405163a9059cbb60e01b815233600482015260248101919091529160209183916044918391905af18015610ad057612112575b8082916120c1565b6020813d602011612143575b8161212b60209383612d81565b81010312610adb5761213c90612eb4565b505f61210a565b3d915061211e565b9250506020823d60201161217c575b8161216760209383612d81565b81010312612178578291515f6120ba565b5f80fd5b3d915061215a565b6040513d85823e3d90fd5b506040366003190112610251576121a4612cbc565b6024359067ffffffffffffffff8211610d565736602383011215610d5657816004013590836121d283612da3565b936121e06040519586612d81565b83855260208501933660248284010111610d5657806024602093018637850101526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630811490811561238c575b5061237d57612243613507565b6040516352d1902d60e01b81526001600160a01b0382169390602081600481885afa869181612349575b5061228657634c9c8ce360e01b86526004859052602486fd5b93845f805160206138e68339815191528796036123375750823b15612325575f805160206138e683398151915280546001600160a01b031916821790558491907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8380a280511561230a57610d059382915190845af461230461328c565b91613867565b50505050346123165780f35b63b398979f60e01b8152600490fd5b634c9c8ce360e01b8552600452602484fd5b632a87526960e21b8652600452602485fd5b9091506020813d602011612375575b8161236560209383612d81565b810103126105625751905f61226d565b3d9150612358565b63703e46dd60e11b8452600484fd5b5f805160206138e6833981519152546001600160a01b0316141590505f612236565b50346102515780600319360112610251576020604051620d899f198152f35b5034610251578060031936011261025157602060405160c88152f35b50346102515780600319360112610251576020600154604051908152f35b50346102515761241636612ce6565b90915f80516020613926833981519152549360ff8560401c16159467ffffffffffffffff81168015908161268a575b6001149081612680575b159081612677575b506126685767ffffffffffffffff1981166001175f80516020613926833981519152558561263c575b5061248961383c565b61249161383c565b61249a336133b2565b6124a261383c565b6124aa61383c565b6124b261383c565b60015f80516020613906833981519152556001600160a01b0316928315612603576001600160a01b03169182156125cf576001600160a01b031692831561259e576001600160601b0360a01b8654161785556001556001600160601b0360a01b60025416176002556001600160601b0360a01b6003541617600355611388600655673a4965bf58a400006009556125465780f35b68ff0000000000000000195f8051602061392683398151915254165f80516020613926833981519152557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b60405162461bcd60e51b815260206004820152600960248201526877657468207a65726f60b81b6044820152606490fd5b60405162461bcd60e51b815260206004820152600c60248201526b666163746f7279207a65726f60a01b6044820152606490fd5b60405162461bcd60e51b8152602060048201526011602482015270666565526563697069656e74207a65726f60781b6044820152606490fd5b68ffffffffffffffffff191668010000000000000001175f80516020613926833981519152555f612480565b63f92ee8a960e01b8752600487fd5b9050155f612457565b303b15915061244f565b879150612445565b5034610251576020366003190112610251576004356126af613507565b61271081116126be5760065580f35b60405162461bcd60e51b815260206004820152600c60248201526b08ccaca40e8dede40d0d2ced60a31b6044820152606490fd5b5034610251578060031936011261025157602060405162031da88152f35b50604036600319011261025157612725612cbc565b60243590612731613433565b82546001600160a01b03161561183a576001600160a01b0381168084526004602052604084205460a01c60ff166117f55782156117b0576003546001600160a01b031681111561175c576001548034106117175761278f9034612f13565b6040516323b872dd60e01b81523360048201523060248201526044810185905290939060208160648189875af18015610bab57612a92575b506001548581612a6c575b505081855260076020908152604080872080546001600160a01b03191633179055600654848852600b835281882055600254600354915163a167129560e01b81526001600160a01b0392831660048201526024810186905261271060448201529291839160649183918b91165af1908115610bab578691612a2a575b506001600160a01b031690813b15610b9f5760405163f637731d60e01b81526d6a17b32fc5d4d48f7124aa2fdba060048201528690818160248183885af18015610ad057612a15575b506001600160801b0390506128ba6d6a17b32fc5d4d48f7123a9410aec83613715565b16801561161357838752600460209081526040808920805460ff60a01b1987166001600160a81b031990911617600160a01b17815560010180546001600160801b031916841790558489526005825280892080546001600160a01b03199081168817909155600a8054909116861790558051808301879052918252612946929091906114708383612d81565b03818a875af190811561052657879088926129f3575b50600a80546001600160a01b03191690556115a2571161155d5760207f3366ddec6d22baedae5089cdef368ab66cbf7cc63aec389ca0d4b54e447baa1b916040519033857fdbd2a1ea6808362e6adbec4db4969cbc11e3b0b28fb6c74cb342defaaf1daada8a80a38152a2816129e1578260015f805160206139068339815191525580f35b6129ec91339161353a565b5f806120c1565b9050612a0e915060403d604011610bdb57610bcd8183612d81565b905f61295c565b81612a1f91612d81565b610b9f57855f612897565b90506020813d602011612a64575b81612a4560209383612d81565b81010312610b9f57516001600160a01b0381168103610b9f575f61284e565b3d9150612a38565b8054612a8b928291829182916001600160a01b03165af1610a1e61328c565b5f856127d2565b6020813d602011612ac1575b81612aab60209383612d81565b81010312610b9f57612abc90612eb4565b6127c7565b3d9150612a9e565b50346102515780600319360112610251576003546040516001600160a01b039091168152602090f35b503461217857606036600319011261217857612b0c612cbc565b60243590612b18613433565b6001600160a01b03165f8181526004602052604090208054919260a083901c60ff1615611cb0578015611c6b57600a80546001600160a01b0319166001600160a01b03948516179055905460408051612b99959194611b279493169273fffd8963efd1fc6a506488495d951d5263988d25925f92611b3591611b0c82612d34565b03925af1908115612c57575f905f92612c98575b50600a80546001600160a01b0319169055612bc790613423565b9015611c0d576044358110612c625780612bf0575060015f805160206139068339815191525580f35b6003546001600160a01b0316803b15612178575f8091602460405180948193632e1a7d4d60e01b83528760048401525af18015612c5757612c40575b5081808080611bf294335af1610a1e61328c565b612c4d9192505f90612d81565b5f90611bf2612c2c565b6040513d5f823e3d90fd5b60405162461bcd60e51b815260206004820152600e60248201526d73656c6c3a20736c69707061676560901b6044820152606490fd5b612bc79250612cb6915060403d604011610bdb57610bcd8183612d81565b91612bad565b600435906001600160a01b038216820361217857565b35906001600160a01b038216820361217857565b6080906003190112612178576004356001600160a01b03811681036121785790602435906044356001600160a01b038116810361217857906064356001600160a01b03811681036121785790565b6060810190811067ffffffffffffffff821117612d5057604052565b634e487b7160e01b5f52604160045260245ffd5b610140810190811067ffffffffffffffff821117612d5057604052565b90601f8019910116810190811067ffffffffffffffff821117612d5057604052565b67ffffffffffffffff8111612d5057601f01601f191660200190565b600319016101608112612178576101401361217857604051612de081612d64565b6004356001600160a01b0381168103612178578152602435602082015260443560408201526064356060820152608435608082015260a43560a082015260c43560c082015260e43560e082015261010435801515810361217857610100820152610124356001600160a01b038116810361217857610120820152906101443590565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b9181601f840112156121785782359167ffffffffffffffff8311612178576020838186019501011161217857565b5190811515820361217857565b91908201809211612ece57565b634e487b7160e01b5f52601160045260245ffd5b81810292918115918404141715612ece57565b8115612eff570490565b634e487b7160e01b5f52601260045260245ffd5b91908203918211612ece57565b90612f4e612f5592612f496040612f3c60208401958651612ec1565b9201938451905190612ee2565b612ef5565b9051612f13565b90565b519061ffff8216820361217857565b908160e09103126121785780516001600160a01b0381168103612178579160208201518060020b81036121785791612fa160408201612f58565b91612fae60608301612f58565b91612fbb60808201612f58565b9160a082015160ff811681036121785760c0612f55919301612eb4565b51906001600160801b038216820361217857565b90604051612ff981612d64565b5f81525f60208201525f60408201525f60608201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f610120820152809260018060a01b0316805f52600460205260405f209182549060ff8260a01c16156132855750604051633850c7bd60e01b81526001600160a01b0391909116919060e081600481865afa908115612c57575f91613260575b50604051630d34328160e11b815293602085600481875afa948515612c57575f95613224575b506001600160801b0385161561320e575b508161312d60209260249489526b033b2e3c9fd0803ce800000060a08a01526b033b2e3c9fd0803ce800000060c08a01526001600160801b03600954978860e08c0152876101208c0152169060018060a01b0316906131238282613715565b60408b01526137ba565b82880152604051928380926370a0823160e01b82528660048301525afa908115612c57575f916131dc575b5060608501526003546040516370a0823160e01b81526004810192909252602090829060249082906001600160a01b03165afa908115612c57575f916131aa575b508060808501521015610100830152565b90506020813d6020116131d4575b816131c560209383612d81565b8101031261217857515f613199565b3d91506131b8565b90506020813d602011613206575b816131f760209383612d81565b8101031261217857515f613158565b3d91506131ea565b600101546001600160801b0316935060246130c4565b9094506020813d602011613258575b8161324060209383612d81565b810103126121785761325190612fd8565b935f6130b3565b3d9150613233565b613279915060e03d60e01161051f5761050b8183612d81565b5050505050505f61308d565b9450505050565b3d156132b6573d9061329d82612da3565b916132ab6040519384612d81565b82523d5f602084013e565b606090565b156132c257565b60405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b6044820152606490fd5b1561330057565b60405162461bcd60e51b815260206004820152600d60248201526c3ab735b737bbb7103a37b5b2b760991b6044820152606490fd5b1561333c57565b60405162461bcd60e51b815260206004820152601460248201527331b630b4b69d103ab735b737bbb7103a37b5b2b760611b6044820152606490fd5b90613394612f5592612f496040612f3c60208401958651612f13565b905190612f13565b9190826040910312612178576020825192015190565b6001600160a01b03168015613410575f805160206138c683398151915280546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b631e4fbdf760e01b5f525f60045260245ffd5b600160ff1b8114612ece575f0390565b60025f80516020613906833981519152541461345c5760025f8051602061390683398151915255565b633ee5aeb560e01b5f5260045ffd5b81516001600160a01b039081168252602080840151821690830152604092830151169181019190915260600190565b6001600160a01b0391821681525f60208201526040810192909252909116606082015260a060808201819052612f5592910190612e62565b612f55939260a092600180851b031682526001602083015260408201526401000276a460608201528160808201520190612e62565b5f805160206138c6833981519152546001600160a01b0316330361352757565b63118cdaa760e01b5f523360045260245ffd5b6001600160a01b03165f818152600460205260408120919290918115611f445760ff815460a01c1615611f0a576003546001600160a01b0316803b15612178575f8391600460405180948193630d0e30db60e41b83525af18015612c57576136f4575b508054600a80546001600160a01b0319166001600160a01b03928316179055905460408051949586959193613620931691611dcb9161360391906135e082612d34565b815230602082015260018060a01b038a168682015285519283916020830161346b565b8351958680948193630251596160e31b8352888c600485016134d2565b03925af1801561218457839284916136cf575b50600a80546001600160a01b031916905561364d90613423565b15611e8a5761365c9250612f13565b80613665575050565b6003546001600160a01b0316803b1561217857604051632e1a7d4d60e01b815260048101839052925f84602481835a968197f1938415612c57576136b8946136ba575b5081809381925af1610a1e61328c565b565b6136c79192505f90612d81565b5f905f6136a8565b61364d93506136ed915060403d604011610bdb57610bcd8183612d81565b9092613633565b60409193506136039461370a5f61362093612d81565b94505f93915061359d565b5f19600160601b8209918160601b918280851094039380850394146137ae5783821115613796578190600160601b9009815f0382168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b50634e487b715f52156003026011186020526024601cfd5b5090612f559250612ef5565b5f91905f19828209918082029384808510940393808503941461380f57600160601b8410156137fd5750600160601b910990828211900360a01b910360601c1790565b634e487b71905260116020526024601cfd5b5050505060601c90565b6001600160a01b03165f908152600b602052604090205480612f55575060065490565b60ff5f805160206139268339815191525460401c161561385857565b631afcd79f60e31b5f5260045ffd5b9061388b575080511561387c57602081519101fd5b63d6bda27560e01b5f5260045ffd5b815115806138bc575b61389c575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561389456fe9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a264697066735822122089399c131aa53115c24697b6273b0ee9f8c4350dfef580b9965a14ae377bf05a64736f6c634300081a0033
0x6080604052600436101561001a575b3615610018575f80fd5b005b5f803560e01c80630dda52f614612af2578063107c279f14612ac957806312d3617114612710578063239f3af7146126f257806326a53e1114612692578063358394d8146124075780634244a6e2146123e957806346ca626b146123cd57806347377d92146123ae5780634f1ef2861461218f57806351cff8d91461205857806352d1902d14611ff15780635d201b5114611fd35780636291484914611fb05780636618b10014611f805780636784ad1e14611ceb5780636c197ff514611a66578063715018a6146119fd5780637f6434bb146119e3578063838e2d3f146119c557806383db2a21146119265780638da5cb5b146118f1578063a0ef91df146118bd578063a7e6daf714611222578063aaef5342146111cc578063ad3cb1cc14611183578063aefadc7a14611123578063af7c621b14610f7b578063af9b1f3514610f61578063b081983b14610f38578063b904b2b514610f14578063bb8769a714610eeb578063bbe4f6db14610e90578063c5cf847b14610e4f578063c7c37e8814610e16578063c81e0e0c14610da8578063d348799714610c25578063d5c0ad4614610bed578063d6ae6e44146107cb578063d816d3301461078a578063dd1b9c4a1461076d578063de308afb14610751578063e74b981b146106d6578063ea6cab52146106b6578063f088d54714610679578063f2fde38b1461064c578063fa461e33146102545763fccc281314610235575061000e565b34610251578060031936011261025157602060405161dead8152f35b80fd5b50346102515760603660031901126102515760243560043560443567ffffffffffffffff81116105fa5761028c903690600401612e86565b600a546001600160a01b0316331480610643575b156105fe5781606091810103126105fa57604051926102be84612d34565b6102c782612cd2565b928385526102e960406102dc60208601612cd2565b9485602089015201612cd2565b60408601908152938682139383851561056e57505060035460405163a9059cbb60e01b8152336004820152602481018490529150602090829060449082908b906001600160a01b03165af1801561052657610531575b505b604051633850c7bd60e01b815260e081600481335afa9081156105265787916104f1575b50604051630d34328160e11b8152602081600481335afa9081156104e657889161047c575b507f671f6af1a2244f88c1a5e6c6310f86653d313027950723ffc12387348a9ed8b39460c0949392916001600160801b03811615610453575b6001600160801b0316916103ea906001600160a01b03166103e48185613715565b936137ba565b92811561044457935b811561043e5761040290613423565b975b51965160408051958652602086019990995297840152426060840152608083015260a08201526001600160a01b039485169490931692a380f35b97610404565b61044d90613423565b936103f3565b5087516001600160a01b03168952600460205260408920600101546001600160801b03166103c3565b93929190506020843d6020116104de575b8161049a60209383612d81565b810103126104da577f671f6af1a2244f88c1a5e6c6310f86653d313027950723ffc12387348a9ed8b3946104cf60c095612fd8565b91929394509461038a565b8780fd5b3d915061048d565b6040513d8a823e3d90fd5b610513915060e03d60e01161051f575b61050b8183612d81565b810190612f67565b5050505050505f610365565b503d610501565b6040513d89823e3d90fd5b6020813d602011610566575b8161054a60209383612d81565b810103126105625761055b90612eb4565b505f61033f565b8680fd5b3d915061053d565b6040516323b872dd60e01b81526001600160a01b0390921660048301523360248301526044820152906020908290818a816064810103926001600160a01b03165af18015610526576105c1575b50610341565b6020813d6020116105f2575b816105da60209383612d81565b81010312610562576105eb90612eb4565b505f6105bb565b3d91506105cd565b8380fd5b60405162461bcd60e51b815260206004820152601860248201527f5377617043616c6c6261636b3a206261642063616c6c657200000000000000006044820152606490fd5b503315156102a0565b503461025157602036600319011261025157610676610669612cbc565b610671613507565b6133b2565b80f35b506020366003190112610251576106a2610691612cbc565b610699613433565b3390349061353a565b60015f805160206139068339815191525580f35b50346102515780600319360112610251576020604051640100eed0b48152f35b5034610251576020366003190112610251576106f0612cbc565b6106f8613507565b6001600160a01b031680156107195781546001600160a01b03191617815580f35b60405162461bcd60e51b815260206004820152601060248201526f4e6f6e207a65726f204164647265737360801b6044820152606490fd5b5034610251578060031936011261025157602060405160648152f35b503461025157806003193601126102515760206040516127108152f35b5034610251576020366003190112610251576020906001600160a01b036107af612cbc565b16815260058252604060018060a01b0391205416604051908152f35b5034610251576020366003190112610251576107e5612cbc565b6107ed613433565b8182809260018060a01b038116908183526004602052604083205461081760ff8260a01c16613335565b6040805163a34123a760e01b8152620d899f19600482015262031da8602482015260448101869052916001600160a01b0316908260648188855af1918215610be257604092610bb6575b5060a48251809681936309e3d67b60e31b8352306004840152620d899f19602484015262031da860448401526001600160801b0360648401526001600160801b0360848401525af18015610bab5786938791610b58575b506001600160801b03169283610adf575b6001600160801b03169081610965575b50508481610961949596526007602052604060018060a01b0391205416907f51ad8a78d6a70d23d7b8093afe4cbc2217fc9d2237d088c1fc3ec48e5c38ffa06080604051878152886020820152856040820152426060820152a360015f8051602061390683398151915255604051938493846040919493926060820195825260208201520152565b0390f35b600354919550935085906001600160a01b0316803b15610adb57818091602460405180948193632e1a7d4d60e01b83528b60048401525af18015610ad057610ab7575b50819052600760205260408520546001600160a01b0316928315610aaa576109db6109d561271092613819565b86612ee2565b049283610a29575b506109f2836109619495612f13565b9485610a02575b9493925f6108d9565b610a24818080808a60018060a01b038254165af1610a1e61328c565b506132bb565b6109f9565b85808080878561c350f1610a3b61328c565b5015610a99578361096194956109f292848952600860205260408920610a62848254612ec1565b9055847f37f367d4b24fa07d94199e5a6182293a8ae4d3b3986782251a6a467a04b6788a6020604051868152a35b955093506109e3565b5061096192506109f2858095610a90565b506127106109db866109d5565b81610ac191612d81565b610acc57845f6109a8565b8480fd5b6040513d84823e3d90fd5b5080fd5b60405163a9059cbb60e01b815261dead600482015260248101859052906020826044818b885af180156104e657610b18575b90506108c9565b6020823d602011610b50575b81610b3160209383612d81565b810103126104da57610b4a6001600160801b0392612eb4565b50610b11565b3d9150610b24565b9350506040833d604011610ba3575b81610b7460409383612d81565b81010312610b9f576001600160801b03610b996020610b9286612fd8565b9501612fd8565b906108b8565b8580fd5b3d9150610b67565b6040513d88823e3d90fd5b610bd590833d8511610bdb575b610bcd8183612d81565b81019061339c565b50610861565b503d610bc3565b6040513d87823e3d90fd5b5034610251576040366003190112610251576020610c1d610c0c612cbc565b610c1860243591612fec565b613378565b604051908152f35b50346102515760603660031901126102515760243560443567ffffffffffffffff8111610d5657610c5a903690600401612e86565b600a546001600160a01b0316331480610d9f575b15610d5a578160209181010312610d5657356001600160a01b03811690819003610d5657600435610d1157818392610ca4575050f35b60405163a9059cbb60e01b815233600482015260248101919091529160209183916044918391905af18015610ad057610cdb575080f35b6020813d602011610d09575b81610cf460209383612d81565b81010312610adb57610d0590612eb4565b5080f35b3d9150610ce7565b60405162461bcd60e51b815260206004820152601760248201527f4d696e7443616c6c6261636b3a2057455448206f7765640000000000000000006044820152606490fd5b8280fd5b60405162461bcd60e51b815260206004820152601860248201527f4d696e7443616c6c6261636b3a206261642063616c6c657200000000000000006044820152606490fd5b50331515610c6e565b503461025157602036600319011261025157600435610dc5613507565b8015610dd15760095580f35b60405162461bcd60e51b815260206004820152601760248201527f53686f756c64204c6172676572207468616e207a65726f0000000000000000006044820152606490fd5b5034610251576020366003190112610251576020906040906001600160a01b03610e3e612cbc565b168152600883522054604051908152f35b5034610251576020366003190112610251576020906001600160a01b03610e74612cbc565b16815260078252604060018060a01b0391205416604051908152f35b5034610251576020366003190112610251576020906001600160a01b03610eb5612cbc565b1680825260048352610ed060ff604084205460a01c166132f9565b815260048252604060018060a01b0391205416604051908152f35b503461025157806003193601126102515760206040516d6a17b32fc5d4d48f7124aa2fdba08152f35b5034610251576020366003190112610251576020610c1d610f33612cbc565b613819565b50346102515780600319360112610251576002546040516001600160a01b039091168152602090f35b5034610251576020610c1d610f7536612dbf565b90613378565b503461025157602036600319011261025157610f95612cbc565b6001600160a01b038116808352600460205260408320549091610fbe60a083901c60ff16613335565b6040513060601b60208201908152620793b360ed1b60348301526163b560eb1b6037830152601a825260a091610ff5603a82612d81565b51902060246040518095819363514ea4bf60e01b83526004830152600180861b03165afa92831561111857849285946110a2575b508452600760205260408420546001600160801b0394610961939261107c92612710926110749289926001600160a01b03161561109b5761106a9150613819565b945b169384612ee2565b048092612f13565b6040519485941691846040919493926060820195825260208201520152565b509461106c565b9250925060a0823d60a011611110575b816110bf60a09383612d81565b810103126105fa579061107c6127106110746001600160801b038097610961966110e887612fd8565b5061110160806110fa60608a01612fd8565b9801612fd8565b98955095965097505050611029565b3d91506110b2565b6040513d86823e3d90fd5b5034610251576020366003190112610251576020906001600160801b03906001906040906001600160a01b03611157612cbc565b168082526004865261117160ff8484205460a01c166132f9565b81526004855220015416604051908152f35b5034610251578060031936011261025157506109616040516111a6604082612d81565b60058152640352e302e360dc1b6020820152604051918291602083526020830190612e62565b5034610251578060031936011261025157506109616040516111ef604082612d81565b60128152713632b0bb32b437b7b216bb1996b2b716b91960711b6020820152604051918291602083526020830190612e62565b5061122c36612ce6565b9091611236613433565b6001600160a01b038316801561187f5785546001600160a01b03161561183a576001600160a01b0385168087526004602052604087205490929060a01c60ff166117f55780156117b0576003546001600160a01b031683111561175c57600154803410611717576112a79034612f13565b6040516323b872dd60e01b8152336004820152306024820152604481018390529094906020816064818c895af18015611608576116dc575b5060015488816116b6575b50506001600160a01b038116156116af575b838852600760209081526040808a2080546001600160a01b0319166001600160a01b03948516179055600654868b52600b8352818b2055600254600354915163a167129560e01b815291841660048301526024820187905261271060448301529092839160649183918d91165af19081156104e657889161166d575b506001600160a01b031690813b156104da5760405163f637731d60e01b81526d6a17b32fc5d4d48f7124aa2fdba060048201528890818160248183885af18015610ad057611658575b506001600160801b0390506113e46d6a17b32fc5d4d48f7123a9410aec83613715565b16801561161357848952600460209081526040808b20805460ff60a01b1987166001600160a81b031990911617600160a01b17815560010180546001600160801b03191684179055848b5260058252808b2080546001600160a01b03199081168917909155600a80549091168617905580518083018890529182526114b0929091906114708383612d81565b82519384928392633c8a7d8d60e01b8452306004850152620d899f19602485015262031da86044850152606484015260a0608484015260a4830190612e62565b03818c875af19081156116085789908a926115e6575b50600a80546001600160a01b03191690556115a2571161155d577f3366ddec6d22baedae5089cdef368ab66cbf7cc63aec389ca0d4b54e447baa1b9160209160405191857fdbd2a1ea6808362e6adbec4db4969cbc11e3b0b28fb6c74cb342defaaf1daada8b80a38152a28061154c575b8360015f805160206139068339815191525580f35b6115559261353a565b5f8080611537565b60405162461bcd60e51b815260206004820152601960248201527f437265617465506f6f6c3a206d696e74206f76657264726177000000000000006044820152606490fd5b606460405162461bcd60e51b815260206004820152602060248201527f437265617465506f6f6c3a20756e65787065637465642057455448206f7765646044820152fd5b9050611601915060403d604011610bdb57610bcd8183612d81565b905f6114c6565b6040513d8b823e3d90fd5b60405162461bcd60e51b815260206004820152601a60248201527f437265617465506f6f6c3a207a65726f206c69717569646974790000000000006044820152606490fd5b8161166291612d81565b6104da57875f6113c1565b90506020813d6020116116a7575b8161168860209383612d81565b810103126104da57516001600160a01b03811681036104da575f611378565b3d915061167b565b50846112fc565b80546116d5928291829182916001600160a01b03165af1610a1e61328c565b5f886112ea565b6020813d60201161170f575b816116f560209383612d81565b8101031261170b5761170690612eb4565b6112df565b8880fd5b3d91506116e8565b60405162461bcd60e51b815260206004820152601860248201527f437265617465506f6f6c3a2056616c756520416d6f756e7400000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152602660248201527f437265617465506f6f6c3a20746f6b656e206d75737420736f727420616674656044820152650e440ae8aa8960d31b6064820152608490fd5b60405162461bcd60e51b815260206004820152601760248201527f437265617465506f6f6c3a20616d6f756e74207a65726f0000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601a60248201527f437265617465506f6f6c3a20616c7265616479206578697374730000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601c60248201527f437265617465506f6f6c3a204e6f6e205a65726f2041646472657373000000006044820152606490fd5b60405162461bcd60e51b8152602060048201526016602482015275437265617465506f6f6c3a206275796572207a65726f60501b6044820152606490fd5b50346102515780600319360112610251576118d6613507565b6118de613433565b6106a28180808047335af1610a1e61328c565b50346102515780600319360112610251575f805160206138c6833981519152546040516001600160a01b039091168152602090f35b50346102515760203660031901126102515761014061194b611946612cbc565b612fec565b6040519060018060a01b0381511682526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e0830152610100810151151561010083015261012060018060a01b0391015116610120820152f35b50346102515780600319360112610251576020600954604051908152f35b5034610251576020610c1d6119f736612dbf565b90612f20565b5034610251578060031936011261025157611a16613507565b5f805160206138c683398151915280546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b503461025157604036600319011261025157611a80612cbc565b60243590611a8c613433565b6001600160a01b03168083526004602052604083208054919260a083901c60ff1615611cb0578015611c6b57600a80546001600160a01b0319166001600160a01b03948516179055905460408051611b52959194611b279493169273fffd8963efd1fc6a506488495d951d5263988d25928892611b3591611b0c82612d34565b8152336020820152338882015287519687916020830161346b565b03601f198101875286612d81565b8551630251596160e31b815296879586948593306004860161349a565b03925af1908115610ad05782908392611c47575b50600a80546001600160a01b0319169055611b8090613423565b9015611c0d5780611ba1575b5060015f805160206139068339815191525580f35b60035482906001600160a01b0316803b15610adb57818091602460405180948193632e1a7d4d60e01b83528860048401525af18015610ad057611bf8575b50808080611bf294335af1610a1e61328c565b5f611b8c565b611c03828092612d81565b610251575f611bdf565b60405162461bcd60e51b81526020600482015260126024820152711cd95b1b0e881b9bdd1a1a5b99c81cdbdb1960721b6044820152606490fd5b611b809250611c65915060403d604011610bdb57610bcd8183612d81565b91611b66565b60405162461bcd60e51b815260206004820152601d60248201527f73656c6c3a2053686f756c64204c6172676572207468616e207a65726f0000006044820152606490fd5b60405162461bcd60e51b815260206004820152601360248201527239b2b6361d103ab735b737bbb7103a37b5b2b760691b6044820152606490fd5b50604036600319011261025157611d00612cbc565b611d08613433565b6001600160a01b0316808252600460205260408220903415611f445760ff825460a01c1615611f0a576003548392906001600160a01b0316803b15611f05578360049160405192838092630d0e30db60e41b825234905af1908115611118578491611eec575b50508054600a80546001600160a01b0319166001600160a01b039283161790559054604080519093611df6939290921691611dcb91611dd991611db082612d34565b8152306020820152338682015285519283916020830161346b565b03601f198101835282612d81565b8351948580948193630251596160e31b83523433600485016134d2565b03925af18015610ad05782918391611ec7575b50600a80546001600160a01b0319169055611e2390613423565b8015611e8a5760243511611e5557611e3b9034612f13565b80611ba1575060015f805160206139068339815191525580f35b60405162461bcd60e51b815260206004820152600d60248201526c6275793a20736c69707061676560981b6044820152606490fd5b60405162461bcd60e51b81526020600482015260156024820152746275793a204e6f20746f6b656e7320746f2062757960581b6044820152606490fd5b611e239250611ee5915060403d604011610bdb57610bcd8183612d81565b9091611e09565b81611ef691612d81565b611f0157825f611d6e565b5050fd5b505050fd5b60405162461bcd60e51b8152602060048201526012602482015271313abc9d103ab735b737bbb7103a37b5b2b760711b6044820152606490fd5b60405162461bcd60e51b81526020600482015260146024820152730c4eaf27440a6d0deead8c840e6cadcc8408aa8960631b6044820152606490fd5b5034610251576040366003190112610251576020610c1d611f9f612cbc565b611fab60243591612fec565b612f20565b503461025157602036600319011261025157611fca613507565b60043560015580f35b50346102515780600319360112610251576020600654604051908152f35b50346102515780600319360112610251577f0000000000000000000000007c038f2c5f5bd2547a94cc4e393d3c7fcb1deacc6001600160a01b031630036120495760206040515f805160206138e68339815191528152f35b63703e46dd60e11b8152600490fd5b50346102515760203660031901126102515780612073612cbc565b61207b613507565b612083613433565b6040516370a0823160e01b81523060048201526001600160a01b039190911690602081602481855afa90811561218457839161214b575b50806120d6575b8260015f805160206139068339815191525580f35b60405163a9059cbb60e01b815233600482015260248101919091529160209183916044918391905af18015610ad057612112575b8082916120c1565b6020813d602011612143575b8161212b60209383612d81565b81010312610adb5761213c90612eb4565b505f61210a565b3d915061211e565b9250506020823d60201161217c575b8161216760209383612d81565b81010312612178578291515f6120ba565b5f80fd5b3d915061215a565b6040513d85823e3d90fd5b506040366003190112610251576121a4612cbc565b6024359067ffffffffffffffff8211610d565736602383011215610d5657816004013590836121d283612da3565b936121e06040519586612d81565b83855260208501933660248284010111610d5657806024602093018637850101526001600160a01b037f0000000000000000000000007c038f2c5f5bd2547a94cc4e393d3c7fcb1deacc1630811490811561238c575b5061237d57612243613507565b6040516352d1902d60e01b81526001600160a01b0382169390602081600481885afa869181612349575b5061228657634c9c8ce360e01b86526004859052602486fd5b93845f805160206138e68339815191528796036123375750823b15612325575f805160206138e683398151915280546001600160a01b031916821790558491907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8380a280511561230a57610d059382915190845af461230461328c565b91613867565b50505050346123165780f35b63b398979f60e01b8152600490fd5b634c9c8ce360e01b8552600452602484fd5b632a87526960e21b8652600452602485fd5b9091506020813d602011612375575b8161236560209383612d81565b810103126105625751905f61226d565b3d9150612358565b63703e46dd60e11b8452600484fd5b5f805160206138e6833981519152546001600160a01b0316141590505f612236565b50346102515780600319360112610251576020604051620d899f198152f35b5034610251578060031936011261025157602060405160c88152f35b50346102515780600319360112610251576020600154604051908152f35b50346102515761241636612ce6565b90915f80516020613926833981519152549360ff8560401c16159467ffffffffffffffff81168015908161268a575b6001149081612680575b159081612677575b506126685767ffffffffffffffff1981166001175f80516020613926833981519152558561263c575b5061248961383c565b61249161383c565b61249a336133b2565b6124a261383c565b6124aa61383c565b6124b261383c565b60015f80516020613906833981519152556001600160a01b0316928315612603576001600160a01b03169182156125cf576001600160a01b031692831561259e576001600160601b0360a01b8654161785556001556001600160601b0360a01b60025416176002556001600160601b0360a01b6003541617600355611388600655673a4965bf58a400006009556125465780f35b68ff0000000000000000195f8051602061392683398151915254165f80516020613926833981519152557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b60405162461bcd60e51b815260206004820152600960248201526877657468207a65726f60b81b6044820152606490fd5b60405162461bcd60e51b815260206004820152600c60248201526b666163746f7279207a65726f60a01b6044820152606490fd5b60405162461bcd60e51b8152602060048201526011602482015270666565526563697069656e74207a65726f60781b6044820152606490fd5b68ffffffffffffffffff191668010000000000000001175f80516020613926833981519152555f612480565b63f92ee8a960e01b8752600487fd5b9050155f612457565b303b15915061244f565b879150612445565b5034610251576020366003190112610251576004356126af613507565b61271081116126be5760065580f35b60405162461bcd60e51b815260206004820152600c60248201526b08ccaca40e8dede40d0d2ced60a31b6044820152606490fd5b5034610251578060031936011261025157602060405162031da88152f35b50604036600319011261025157612725612cbc565b60243590612731613433565b82546001600160a01b03161561183a576001600160a01b0381168084526004602052604084205460a01c60ff166117f55782156117b0576003546001600160a01b031681111561175c576001548034106117175761278f9034612f13565b6040516323b872dd60e01b81523360048201523060248201526044810185905290939060208160648189875af18015610bab57612a92575b506001548581612a6c575b505081855260076020908152604080872080546001600160a01b03191633179055600654848852600b835281882055600254600354915163a167129560e01b81526001600160a01b0392831660048201526024810186905261271060448201529291839160649183918b91165af1908115610bab578691612a2a575b506001600160a01b031690813b15610b9f5760405163f637731d60e01b81526d6a17b32fc5d4d48f7124aa2fdba060048201528690818160248183885af18015610ad057612a15575b506001600160801b0390506128ba6d6a17b32fc5d4d48f7123a9410aec83613715565b16801561161357838752600460209081526040808920805460ff60a01b1987166001600160a81b031990911617600160a01b17815560010180546001600160801b031916841790558489526005825280892080546001600160a01b03199081168817909155600a8054909116861790558051808301879052918252612946929091906114708383612d81565b03818a875af190811561052657879088926129f3575b50600a80546001600160a01b03191690556115a2571161155d5760207f3366ddec6d22baedae5089cdef368ab66cbf7cc63aec389ca0d4b54e447baa1b916040519033857fdbd2a1ea6808362e6adbec4db4969cbc11e3b0b28fb6c74cb342defaaf1daada8a80a38152a2816129e1578260015f805160206139068339815191525580f35b6129ec91339161353a565b5f806120c1565b9050612a0e915060403d604011610bdb57610bcd8183612d81565b905f61295c565b81612a1f91612d81565b610b9f57855f612897565b90506020813d602011612a64575b81612a4560209383612d81565b81010312610b9f57516001600160a01b0381168103610b9f575f61284e565b3d9150612a38565b8054612a8b928291829182916001600160a01b03165af1610a1e61328c565b5f856127d2565b6020813d602011612ac1575b81612aab60209383612d81565b81010312610b9f57612abc90612eb4565b6127c7565b3d9150612a9e565b50346102515780600319360112610251576003546040516001600160a01b039091168152602090f35b503461217857606036600319011261217857612b0c612cbc565b60243590612b18613433565b6001600160a01b03165f8181526004602052604090208054919260a083901c60ff1615611cb0578015611c6b57600a80546001600160a01b0319166001600160a01b03948516179055905460408051612b99959194611b279493169273fffd8963efd1fc6a506488495d951d5263988d25925f92611b3591611b0c82612d34565b03925af1908115612c57575f905f92612c98575b50600a80546001600160a01b0319169055612bc790613423565b9015611c0d576044358110612c625780612bf0575060015f805160206139068339815191525580f35b6003546001600160a01b0316803b15612178575f8091602460405180948193632e1a7d4d60e01b83528760048401525af18015612c5757612c40575b5081808080611bf294335af1610a1e61328c565b612c4d9192505f90612d81565b5f90611bf2612c2c565b6040513d5f823e3d90fd5b60405162461bcd60e51b815260206004820152600e60248201526d73656c6c3a20736c69707061676560901b6044820152606490fd5b612bc79250612cb6915060403d604011610bdb57610bcd8183612d81565b91612bad565b600435906001600160a01b038216820361217857565b35906001600160a01b038216820361217857565b6080906003190112612178576004356001600160a01b03811681036121785790602435906044356001600160a01b038116810361217857906064356001600160a01b03811681036121785790565b6060810190811067ffffffffffffffff821117612d5057604052565b634e487b7160e01b5f52604160045260245ffd5b610140810190811067ffffffffffffffff821117612d5057604052565b90601f8019910116810190811067ffffffffffffffff821117612d5057604052565b67ffffffffffffffff8111612d5057601f01601f191660200190565b600319016101608112612178576101401361217857604051612de081612d64565b6004356001600160a01b0381168103612178578152602435602082015260443560408201526064356060820152608435608082015260a43560a082015260c43560c082015260e43560e082015261010435801515810361217857610100820152610124356001600160a01b038116810361217857610120820152906101443590565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b9181601f840112156121785782359167ffffffffffffffff8311612178576020838186019501011161217857565b5190811515820361217857565b91908201809211612ece57565b634e487b7160e01b5f52601160045260245ffd5b81810292918115918404141715612ece57565b8115612eff570490565b634e487b7160e01b5f52601260045260245ffd5b91908203918211612ece57565b90612f4e612f5592612f496040612f3c60208401958651612ec1565b9201938451905190612ee2565b612ef5565b9051612f13565b90565b519061ffff8216820361217857565b908160e09103126121785780516001600160a01b0381168103612178579160208201518060020b81036121785791612fa160408201612f58565b91612fae60608301612f58565b91612fbb60808201612f58565b9160a082015160ff811681036121785760c0612f55919301612eb4565b51906001600160801b038216820361217857565b90604051612ff981612d64565b5f81525f60208201525f60408201525f60608201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f610120820152809260018060a01b0316805f52600460205260405f209182549060ff8260a01c16156132855750604051633850c7bd60e01b81526001600160a01b0391909116919060e081600481865afa908115612c57575f91613260575b50604051630d34328160e11b815293602085600481875afa948515612c57575f95613224575b506001600160801b0385161561320e575b508161312d60209260249489526b033b2e3c9fd0803ce800000060a08a01526b033b2e3c9fd0803ce800000060c08a01526001600160801b03600954978860e08c0152876101208c0152169060018060a01b0316906131238282613715565b60408b01526137ba565b82880152604051928380926370a0823160e01b82528660048301525afa908115612c57575f916131dc575b5060608501526003546040516370a0823160e01b81526004810192909252602090829060249082906001600160a01b03165afa908115612c57575f916131aa575b508060808501521015610100830152565b90506020813d6020116131d4575b816131c560209383612d81565b8101031261217857515f613199565b3d91506131b8565b90506020813d602011613206575b816131f760209383612d81565b8101031261217857515f613158565b3d91506131ea565b600101546001600160801b0316935060246130c4565b9094506020813d602011613258575b8161324060209383612d81565b810103126121785761325190612fd8565b935f6130b3565b3d9150613233565b613279915060e03d60e01161051f5761050b8183612d81565b5050505050505f61308d565b9450505050565b3d156132b6573d9061329d82612da3565b916132ab6040519384612d81565b82523d5f602084013e565b606090565b156132c257565b60405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b6044820152606490fd5b1561330057565b60405162461bcd60e51b815260206004820152600d60248201526c3ab735b737bbb7103a37b5b2b760991b6044820152606490fd5b1561333c57565b60405162461bcd60e51b815260206004820152601460248201527331b630b4b69d103ab735b737bbb7103a37b5b2b760611b6044820152606490fd5b90613394612f5592612f496040612f3c60208401958651612f13565b905190612f13565b9190826040910312612178576020825192015190565b6001600160a01b03168015613410575f805160206138c683398151915280546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b631e4fbdf760e01b5f525f60045260245ffd5b600160ff1b8114612ece575f0390565b60025f80516020613906833981519152541461345c5760025f8051602061390683398151915255565b633ee5aeb560e01b5f5260045ffd5b81516001600160a01b039081168252602080840151821690830152604092830151169181019190915260600190565b6001600160a01b0391821681525f60208201526040810192909252909116606082015260a060808201819052612f5592910190612e62565b612f55939260a092600180851b031682526001602083015260408201526401000276a460608201528160808201520190612e62565b5f805160206138c6833981519152546001600160a01b0316330361352757565b63118cdaa760e01b5f523360045260245ffd5b6001600160a01b03165f818152600460205260408120919290918115611f445760ff815460a01c1615611f0a576003546001600160a01b0316803b15612178575f8391600460405180948193630d0e30db60e41b83525af18015612c57576136f4575b508054600a80546001600160a01b0319166001600160a01b03928316179055905460408051949586959193613620931691611dcb9161360391906135e082612d34565b815230602082015260018060a01b038a168682015285519283916020830161346b565b8351958680948193630251596160e31b8352888c600485016134d2565b03925af1801561218457839284916136cf575b50600a80546001600160a01b031916905561364d90613423565b15611e8a5761365c9250612f13565b80613665575050565b6003546001600160a01b0316803b1561217857604051632e1a7d4d60e01b815260048101839052925f84602481835a968197f1938415612c57576136b8946136ba575b5081809381925af1610a1e61328c565b565b6136c79192505f90612d81565b5f905f6136a8565b61364d93506136ed915060403d604011610bdb57610bcd8183612d81565b9092613633565b60409193506136039461370a5f61362093612d81565b94505f93915061359d565b5f19600160601b8209918160601b918280851094039380850394146137ae5783821115613796578190600160601b9009815f0382168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b50634e487b715f52156003026011186020526024601cfd5b5090612f559250612ef5565b5f91905f19828209918082029384808510940393808503941461380f57600160601b8410156137fd5750600160601b910990828211900360a01b910360601c1790565b634e487b71905260116020526024601cfd5b5050505060601c90565b6001600160a01b03165f908152600b602052604090205480612f55575060065490565b60ff5f805160206139268339815191525460401c161561385857565b631afcd79f60e31b5f5260045ffd5b9061388b575080511561387c57602081519101fd5b63d6bda27560e01b5f5260045ffd5b815115806138bc575b61389c575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561389456fe9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a264697066735822122089399c131aa53115c24697b6273b0ee9f8c4350dfef580b9965a14ae377bf05a64736f6c634300081a0033
| Token | Symbol | Balance | Price | Value |
|---|---|---|---|---|
| no token holdings | ||||
| Type | Age | Block | Details |
|---|---|---|---|
| no cross-chain L1↔L2 transactions for this address | |||
| Txn Hash | Age | Event | Topics / Data |
|---|---|---|---|
| no event logs emitted by this address | |||
| Transaction Hash | Method | Block | Age | From | To | Type | Item | ||
|---|---|---|---|---|---|---|---|---|---|
| no NFT transfers for this address yet | |||||||||
| Transaction Hash | Method | Block | Age | From | To | Amount | Token | ||
|---|---|---|---|---|---|---|---|---|---|
| no token transfers for this address yet | |||||||||
| Transaction Hash | Method ? | Block | Age | From | To | Amount | Txn Fee ? | ||
|---|---|---|---|---|---|---|---|---|---|
| No direct transactions — this address is only ever reached via internal calls (common for a contract only invoked through a router or proxy). View Internal Transactions → | |||||||||
| Block | Age | Parent Transaction Hash | Type | Method | From | To | Value | |
|---|---|---|---|---|---|---|---|---|
| 9,576,925 | 34 days agoTue, 14 Jul 2026 13:48:09 UTC | 0x7c206f…abe133 | DELEGATECALL | deployERC20TokenWithOptions | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00001 ETH |
| 9,575,733 | 34 days agoTue, 14 Jul 2026 13:46:09 UTC | 0xfdaa05…4d0632 | DELEGATECALL | deployERC20TokenWithOptions | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00001 ETH |
| 9,573,827 | 34 days agoTue, 14 Jul 2026 13:42:59 UTC | 0x372022…3c62ab | DELEGATECALL | deployERC20TokenWithOptions | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00001 ETH |
| 9,571,212 | 34 days agoTue, 14 Jul 2026 13:38:36 UTC | 0xc000ef…6b8177 | DELEGATECALL | deployERC20TokenWithOptions | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00001 ETH |
| 9,566,584 | 34 days agoTue, 14 Jul 2026 13:30:52 UTC | 0x8a1e6b…13a9fa | DELEGATECALL | deployERC20TokenWithOptions | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00001 ETH |
| 9,564,183 | 34 days agoTue, 14 Jul 2026 13:26:52 UTC | 0x61c51f…916b73 | DELEGATECALL | deployERC20TokenWithOptions | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00001 ETH |
| 9,562,455 | 34 days agoTue, 14 Jul 2026 13:23:58 UTC | 0xc51cdc…4e2476 | DELEGATECALL | deployERC20TokenWithOptions | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00001 ETH |
| 9,561,403 | 34 days agoTue, 14 Jul 2026 13:22:14 UTC | 0xeab7b9…f580ba | DELEGATECALL | sellWithSlippage | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00490 ETH |
| 9,561,336 | 34 days agoTue, 14 Jul 2026 13:22:07 UTC | 0xd01719…bf90d9 | DELEGATECALL | deployERC20TokenWithOptions | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00001 ETH |
| 9,560,800 | 34 days agoTue, 14 Jul 2026 13:21:13 UTC | 0xb386fe…f91fa6 | DELEGATECALL | sellWithSlippage | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00735 ETH |
| 9,558,374 | 34 days agoTue, 14 Jul 2026 13:17:11 UTC | 0x7c8740…4f9aa2 | DELEGATECALL | deployERC20TokenWithOptions | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00001 ETH |
| 9,556,853 | 34 days agoTue, 14 Jul 2026 13:14:38 UTC | 0x9e8e90…be5c81 | DELEGATECALL | deployERC20TokenWithOptions | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00001 ETH |
| 9,555,408 | 34 days agoTue, 14 Jul 2026 13:12:13 UTC | 0xd6b5f0…6b2fbc | DELEGATECALL | buyWithSlippage | 0x5090…89e3 | IN | 0x7c03…eacc | 0.001 ETH |
| 9,554,069 | 34 days agoTue, 14 Jul 2026 13:10:00 UTC | 0x89ee8e…6be215 | DELEGATECALL | deployERC20TokenWithOptions | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00001 ETH |
| 9,552,734 | 34 days agoTue, 14 Jul 2026 13:07:46 UTC | 0x70ecb9…0194ed | DELEGATECALL | deployERC20TokenWithOptions | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00001 ETH |
| 9,552,164 | 34 days agoTue, 14 Jul 2026 13:06:48 UTC | 0x74704e…98f44d | DELEGATECALL | buyWithSlippage | 0x5090…89e3 | IN | 0x7c03…eacc | 0.01 ETH |
| 9,549,518 | 34 days agoTue, 14 Jul 2026 13:02:24 UTC | 0xafab1b…334ee5 | DELEGATECALL | sellWithSlippage | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00098 ETH |
| 9,549,270 | 34 days agoTue, 14 Jul 2026 13:01:59 UTC | 0x3669a7…28d010 | DELEGATECALL | claimCreatorFees | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00013 ETH |
| 9,547,997 | 34 days agoTue, 14 Jul 2026 12:59:51 UTC | 0x22f796…79daf1 | DELEGATECALL | sellWithSlippage | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00221 ETH |
| 9,547,168 | 34 days agoTue, 14 Jul 2026 12:58:28 UTC | 0x837c3a…eab50a | DELEGATECALL | sellWithSlippage | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00072 ETH |
| 9,546,487 | 34 days agoTue, 14 Jul 2026 12:57:21 UTC | 0x2c4f52…b33595 | DELEGATECALL | sellWithSlippage | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00984 ETH |
| 9,545,808 | 34 days agoTue, 14 Jul 2026 12:56:13 UTC | 0x133766…f73aa2 | DELEGATECALL | deployERC20TokenWithOptions | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00001 ETH |
| 9,541,689 | 34 days agoTue, 14 Jul 2026 12:49:20 UTC | 0x4bb301…b2794e | DELEGATECALL | deployERC20TokenWithOptions | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00001 ETH |
| 9,540,191 | 34 days agoTue, 14 Jul 2026 12:46:49 UTC | 0x58e303…ee9be4 | DELEGATECALL | deployERC20TokenWithOptions | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00001 ETH |
| 9,538,968 | 34 days agoTue, 14 Jul 2026 12:44:48 UTC | 0x735c2f…c035ea | DELEGATECALL | deployERC20TokenWithOptions | 0x5090…89e3 | IN | 0x7c03…eacc | 0.00001 ETH |