ETH Price: $2,695.19 (-0.07%)

Token

SCALE (SCALE)
 

Overview

Max Total Supply

844,283,075,054.200761026 SCALE

Holders

222

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 9 Decimals)

Balance
1,093,226,790.089301249 SCALE

Value
$0.00
0x4ce89bc3d9ab8721168115e0605b96e23fba5fdc
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
SCALE

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 25 : SCALE.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/interfaces/IERC20.sol";
import "@openzeppelin/contracts/interfaces/IERC165.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable2Step.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol";
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import "./interfaces/IWETH9.sol";
import "./interfaces/IDragonX.sol";
import "./lib/FullMath.sol";
import "./lib/constants.sol";

contract SCALE is ERC20, Ownable2Step, IERC165 {
    using SafeERC20 for IERC20;

    // --------------------------- STATE VARIABLES --------------------------- //

    address public heliosVault;
    address public dragonXVault;
    address public devWallet;
    address public marketingWallet;
    address public shedContract;
    address public bdxBuyBurnAddress;

    /// @notice Basis point percentage of SCALE tokens sent to caller as a reward for calling distributeReserve.
    uint16 public incentiveFee = 30;

    /// @notice Basis point percentage of SCALE token reflections.
    uint16 public reflectionFee = 150;

    /// @notice Total SCALE tokens burned to date.
    uint256 public totalBurned;

    /// @notice Minimum size of the Reserve to be available for distribution.
    uint256 public minReserveDistribution = 1_000_000 * 10 ** 9;

    /// @notice <aximum size of the Reserve to be used for distribution.
    uint256 public maxReserveDistribution = 500_000_000 * 10 ** 9;

    /// @notice TitanX tokens allocated for ecosystem token purchases.
    uint256 public titanLpPool;

    /// @notice TitanX tokens used in ecosystem token purchases.
    uint256 public totalLpPoolUsed;

    /// @notice Scale tokens allocated for creation of the LPs.
    uint256 public scaleLpPool;

    /// @notice TitanX tokens allocated for swaps to DragonX and transfer to BDX Buy & Burn.
    uint256 public bdxBuyBurnPool;

    /// @notice DragonX tokens allocated for transfer to BDX Buy & Burn.
    uint256 public buyBurnDragonXAllocation;

    /// @notice Total LPs created.
    uint8 public totalLPsCreated;

    /// @notice Number of performed purchases for the BDX Buy & Burn.
    uint8 public buyBurnPurchases;

    /// @notice Number of purchases required for TitanX/DragonX & TitanX/BDX swaps.
    /// @dev Can only be changed before the presale is finalized.
    uint8 public purchasesRequired = 10;

    /// @notice Timestamp in seconds of the presale end date.
    uint256 public presaleEnd;

    /// @notice Has the presale been finalized.
    bool public presaleFinalized;

    /// @notice Have all token purchases for the LPs been performed.
    bool public lpPurchaseFinished;

    /// @notice Is trading enabled.
    bool public tradingEnabled;

    /// @notice Returns the total amount of ecosystem tokens purchased for LP creation for a specific token.
    mapping(address token => uint256) public tokenPool;

    /// @notice Total number of purchases performed per each ecosystem token.
    mapping(address token => uint8) public lpPurchases;

    /// @notice Percent of the lpPool to calculate the allocation per ecosystem token purchases.
    mapping(address token => uint8) public tokenLpPercent;

    uint256 private _totalMinted;
    bytes32 private _merkleRoot;

    mapping(address => uint256) private _tOwned;
    mapping(address => uint256) private _rOwned;
    mapping(address => bool) private _isExcludedFromReflections;
    address[] private _excluded;

    uint256 private _tTotal = 100 * 10 ** 12 * 10 ** 9;
    uint256 private _rTotal = (MAX_VALUE - (MAX_VALUE % _tTotal));

    // --------------------------- ERRORS --------------------------- //

    error ZeroInput();
    error ZeroAddress();
    error PresaleInactive();
    error PresaleActive();
    error MaxSupply();
    error TradingDisabled();
    error Prohibited();
    error DuplicateToken();
    error IncorrectPercentage();
    error IncorrectTokenNumber();
    error IncorrectBonus();
    error InsuffucientBalance();
    error ExcludedAddress();

    // ------------------------ EVENTS & MODIFIERS ----------------------- //

    event PresaleStarted();
    event TradingEnabled();
    event ReserveDistributed();

    modifier onlyPresale() {
        if (!isPresaleActive()) revert PresaleInactive();
        _;
    }

    // --------------------------- CONSTRUCTOR --------------------------- //

    constructor(
        address _owner,
        address _devWallet,
        address _marketingWallet,
        address _heliosVault,
        address _dragonxVault,
        address _bdxBuyBurnAddress,
        address[] memory _ecosystemTokens,
        uint8[] memory _lpPercentages
    ) ERC20("SCALE", "SCALE") Ownable(_owner) {
        if (_ecosystemTokens.length != NUM_ECOSYSTEM_TOKENS) revert IncorrectTokenNumber();
        if (_lpPercentages.length != NUM_ECOSYSTEM_TOKENS) revert IncorrectTokenNumber();
        if (_owner == address(0)) revert ZeroAddress();
        if (_devWallet == address(0)) revert ZeroAddress();
        if (_marketingWallet == address(0)) revert ZeroAddress();
        if (_heliosVault == address(0)) revert ZeroAddress();
        if (_dragonxVault == address(0)) revert ZeroAddress();
        if (_bdxBuyBurnAddress == address(0)) revert ZeroAddress();

        _rOwned[address(this)] = _rTotal;
        devWallet = _devWallet;
        marketingWallet = _marketingWallet;
        heliosVault = _heliosVault;
        dragonXVault = _dragonxVault;
        bdxBuyBurnAddress = _bdxBuyBurnAddress;

        uint8 totalPercentage;
        for (uint256 i = 0; i < _ecosystemTokens.length; i++) {
            address token = _ecosystemTokens[i];
            uint8 allocation = _lpPercentages[i];
            if (token == address(0)) revert ZeroAddress();
            if (allocation == 0) revert ZeroInput();
            if (tokenLpPercent[token] != 0) revert DuplicateToken();
            tokenLpPercent[token] = allocation;
            totalPercentage += allocation;
        }
        if (totalPercentage != 100) revert IncorrectPercentage();
    }

    // --------------------------- PUBLIC FUNCTIONS --------------------------- //

    /// @notice Allows users to mint tokens during the presale using TitanX tokens.
    /// @param amount The amount of SCALE tokens to mint.
    /// @param bonus Bonus percentage for the user.
    /// @param merkleProof Proof for the user.
    function mintWithTitanX(uint256 amount, uint16 bonus, bytes32[] memory merkleProof) external onlyPresale {
        if (amount == 0) revert ZeroInput();
        IERC20(TITANX).safeTransferFrom(msg.sender, address(this), amount * 10 ** 9);
        amount = _processBonus(amount, bonus, merkleProof);
        if ((_totalMinted + amount) * 135 / 100 > _tTotal) revert MaxSupply();
        _rMint(msg.sender, amount);
    }

    /// @notice Allows users to purchase tokens during the presale using ETH.
    /// @param amount The amount of SCALE tokens to mint.
    /// @param bonus Bonus percentage for the user.
    /// @param merkleProof Proof for the user.
    /// @param deadline Deadline for executing the swap.
    function mintWithETH(uint256 amount, uint16 bonus, bytes32[] memory merkleProof, uint256 deadline)
        external
        payable
        onlyPresale
    {
        if (amount == 0) revert ZeroInput();
        uint256 titanXAmount = amount * 10 ** 9;
        uint256 swappedAmount = _swapETHForTitanX(titanXAmount, deadline);
        if (swappedAmount > titanXAmount) IERC20(TITANX).safeTransfer(msg.sender, swappedAmount - titanXAmount);
        amount = _processBonus(amount, bonus, merkleProof);
        if ((_totalMinted + amount) * 135 / 100 > _tTotal) revert MaxSupply();
        _rMint(msg.sender, amount);
    }

    /// @notice Burns SCALE from user's wallet.
    /// @param amount The amount of SCALE tokens to burn.
    function burn(uint256 amount) public {
        if (!tradingEnabled) revert TradingDisabled();
        _rBurn(msg.sender, amount);
    }

    /// @notice Reflects SCALE tokens to all holders from user's wallet.
    /// @param amount The amount of SCALE tokens to reflect.
    function reflect(uint256 amount) public {
        if (!tradingEnabled) revert TradingDisabled();
        address sender = msg.sender;
        if (_isExcludedFromReflections[sender]) revert ExcludedAddress();
        uint256 rAmount = amount * _getRate();
        _balanceCheck(sender, rAmount, amount);
        _rOwned[sender] -= rAmount;
        _rTotal -= rAmount;
    }

    /// @notice Distributes the accumulated reserve.
    /// @param minDragonXAmount The minimum amount of DragonX tokens received for BDX Buy & Burn.
    /// @param deadline Deadline for executing the swap.
    function distributeReserve(uint256 minDragonXAmount, uint256 deadline) external {
        if (!tradingEnabled) revert TradingDisabled();
        uint256 balance = balanceOf(address(this));
        if (balance < minReserveDistribution) revert InsuffucientBalance();
        uint256 distribution = balance > maxReserveDistribution ? maxReserveDistribution : balance;
        distribution = _processIncentiveFee(msg.sender, distribution);

        uint256 buyBurnShare = distribution / 2;
        _swapScaleToDragonX(buyBurnShare, minDragonXAmount, deadline);

        uint256 quarter = distribution / 4;

        uint256 rTransferAmount = reflectionFromToken(quarter);
        _rOwned[address(this)] -= rTransferAmount;
        _rOwned[marketingWallet] += rTransferAmount;
        if (_isExcludedFromReflections[marketingWallet]) _tOwned[marketingWallet] += quarter;
        _rBurn(address(this), quarter);
        emit ReserveDistributed();
    }

    // --------------------------- PRESALE MANAGEMENT FUNCTIONS --------------------------- //

    /// @notice Starts the presale for the SCALE token.
    function startPresale() external onlyOwner {
        if (presaleEnd != 0) revert Prohibited();
        if (_merkleRoot == bytes32(0)) revert IncorrectBonus();
        unchecked {
            presaleEnd = block.timestamp + PRESALE_LENGTH;
        }
        emit PresaleStarted();
    }

    /// @notice Finalizes the presale and distributes liquidity pool tokens.
    function finalizePresale() external onlyOwner {
        if (presaleEnd == 0) revert PresaleInactive();
        if (isPresaleActive()) revert PresaleActive();
        if (shedContract == address(0)) revert ZeroAddress();
        if (presaleFinalized) revert Prohibited();

        _distributeTokens();

        // burn not minted
        uint256 tBurn = _tTotal - _totalMinted - scaleLpPool;
        uint256 rBurn = tBurn * _getRate();
        _rOwned[address(this)] -= rBurn;
        _rTotal -= rBurn;
        _tTotal = _totalMinted + scaleLpPool;

        presaleFinalized = true;
        emit Transfer(address(0), address(this), scaleLpPool);
    }

    /// @notice Allows the owner to purchase tokens for liquidity pool allocation.
    /// @param token The address of the token to purchase.
    /// @param minAmountOut The minimum amount of tokens to receive from the swap.
    /// @param deadline The deadline for the swap transaction.
    function purchaseTokenForLP(address token, uint256 minAmountOut, uint256 deadline) external onlyOwner {
        if (!presaleFinalized) revert PresaleActive();
        if (lpPurchaseFinished) revert Prohibited();
        uint256 requiredAmount = token == BDX_ADDRESS ? purchasesRequired : 1;
        if (lpPurchases[token] == requiredAmount) revert Prohibited();
        uint256 allocation = tokenLpPercent[token];
        if (allocation == 0) revert Prohibited();
        uint256 amountToSwap = FullMath.mulDiv(titanLpPool, allocation, 100 * requiredAmount);
        totalLpPoolUsed += amountToSwap;
        uint256 swappedAmount = _swapTitanXToToken(token, amountToSwap, minAmountOut, deadline);
        unchecked {
            tokenPool[token] += swappedAmount;
            lpPurchases[token]++;
            // account for rounding error
            if (totalLpPoolUsed >= titanLpPool - NUM_ECOSYSTEM_TOKENS - purchasesRequired) lpPurchaseFinished = true;
        }
    }

    /// @notice Allows the owner to purchase DragonX tokens for the BDX Buy & Burn contract.
    /// @param minAmountOut The minimum amount of DragonX tokens to receive from the swap.
    /// @param deadline The deadline for the swap transaction.
    function purchaseDragonXForBuyBurn(uint256 minAmountOut, uint256 deadline) external onlyOwner {
        if (!presaleFinalized) revert PresaleActive();
        if (buyBurnPurchases == purchasesRequired) revert Prohibited();

        uint256 amountToSwap = bdxBuyBurnPool / purchasesRequired;
        uint256 swappedAmount = _swapTitanXToToken(DRAGONX_ADDRESS, amountToSwap, minAmountOut, deadline);
        unchecked {
            buyBurnDragonXAllocation += swappedAmount;
            buyBurnPurchases++;
        }
        if (buyBurnPurchases == purchasesRequired) {
            IERC20(DRAGONX_ADDRESS).safeTransfer(bdxBuyBurnAddress, buyBurnDragonXAllocation);
        }
    }

    /// @notice Deploys a liquidity pool for SCALE tokens paired with another token.
    /// @param tokenAddress The address of the token to pair with SCALE in the liquidity pool.
    function deployLiquidityPool(address tokenAddress) external onlyOwner {
        if (!lpPurchaseFinished) revert Prohibited();
        uint256 tokenAmount = tokenPool[tokenAddress];
        if (tokenAmount == 0) revert Prohibited();
        uint256 scaleAllocation = FullMath.mulDiv(scaleLpPool, tokenLpPercent[tokenAddress], 100);

        _addLiquidity(tokenAddress, tokenAmount, scaleAllocation);
        tokenPool[tokenAddress] = 0;
        unchecked {
            totalLPsCreated++;
        }
        if (totalLPsCreated == NUM_ECOSYSTEM_TOKENS) _enableTrading();
    }

    /// @notice Claim any leftover dust from divisions when performing TitanX swaps.
    /// @dev Can only be claimed after all purchases have been made.
    function claimDust() external onlyOwner {
        if (!tradingEnabled || buyBurnPurchases != purchasesRequired) revert Prohibited();
        IERC20 titanX = IERC20(TITANX);
        titanX.safeTransfer(msg.sender, titanX.balanceOf(address(this)));
    }

    // --------------------------- ADMINISTRATIVE FUNCTIONS --------------------------- //

    /// @notice Excludes the account from receiving reflections.
    /// @param account Address of the account to be excluded.
    function excludeAccountFromReflections(address account) public onlyOwner {
        if (_isExcludedFromReflections[account]) revert ExcludedAddress();
        if (_excluded.length == 22) revert Prohibited();
        if (account == address(this)) revert Prohibited();
        if (_rOwned[account] > 0) {
            _tOwned[account] = tokenFromReflection(_rOwned[account]);
        }
        _isExcludedFromReflections[account] = true;
        _excluded.push(account);
    }

    /// @notice Includes the account back to receiving reflections.
    /// @param account Address of the account to be included.
    function includeAccountToReflections(address account) public onlyOwner {
        if (!_isExcludedFromReflections[account]) revert ExcludedAddress();
        uint256 difference = _rOwned[account] - (_getRate() * _tOwned[account]);
        for (uint256 i = 0; i < _excluded.length; i++) {
            if (_excluded[i] == account) {
                _excluded[i] = _excluded[_excluded.length - 1];
                _tOwned[account] = 0;
                _rOwned[account] -= difference;
                _rTotal -= difference;
                _isExcludedFromReflections[account] = false;
                _excluded.pop();
                break;
            }
        }
    }

    /// @notice Sets the amount of purchases for tokens.
    /// @param amount Number of purchases needed for each token.
    /// @dev Can only be called by the owner before presale if finalized.
    function setPurchasesRequired(uint8 amount) external onlyOwner {
        if (amount == 0) revert ZeroInput();
        if (amount > 50) revert Prohibited();
        if (presaleFinalized) revert Prohibited();
        purchasesRequired = amount;
    }

    /// @notice Sets the DragonX Vault address.
    /// @param _address The address of the DragonX Vault.
    /// @dev Can only be called by the owner.
    function setDragonXVault(address _address) external onlyOwner {
        if (_address == address(0)) revert ZeroAddress();
        dragonXVault = _address;
    }

    /// @notice Sets the Helios Vault address.
    /// @param _address The address of the Helios Vault.
    /// @dev Can only be called by the owner.
    function setHeliosVault(address _address) external onlyOwner {
        if (_address == address(0)) revert ZeroAddress();
        heliosVault = _address;
    }

    /// @notice Sets the Developer wallet address.
    /// @param _address The address of the Developer wallet.
    /// @dev Can only be called by the owner.
    function setDevWallet(address _address) external onlyOwner {
        if (_address == address(0)) revert ZeroAddress();
        devWallet = _address;
    }

    /// @notice Sets the Marketing wallet address.
    /// @param _address The address of the Marketing wallet.
    /// @dev Can only be called by the owner.
    function setMarketingWallet(address _address) external onlyOwner {
        if (_address == address(0)) revert ZeroAddress();
        marketingWallet = _address;
    }

    /// @notice Sets the SHED contract address.
    /// @param _address The address of the SHED contract.
    /// @dev Can only be called by the owner.
    function setSHED(address _address) external onlyOwner {
        if (_address == address(0)) revert ZeroAddress();
        shedContract = _address;
    }

    /// @notice Sets the BDX Buy & Burn contract address.
    /// @param _address The address of the BDX Buy & Burn contract.
    /// @dev Can only be called by the owner.
    function setBDXBuyBurn(address _address) external onlyOwner {
        if (_address == address(0)) revert ZeroAddress();
        bdxBuyBurnAddress = _address;
    }

    /// @notice Sets the merkle root for minting bonuses.
    /// @param root The merkle root.
    /// @dev Can only be called by the owner.
    function setMerkleRoot(bytes32 root) external onlyOwner {
        if (root == bytes32(0)) revert ZeroInput();
        _merkleRoot = root;
    }

    /// @notice Sets the reflection fee size.
    /// @param bps Reflection fee in basis points (150 = 1.5%).
    /// @dev Can only be called by the owner.
    function setReflectionFee(uint16 bps) external onlyOwner {
        if (bps != 150 && bps != 300 && bps != 450 && bps != 600) revert Prohibited();
        reflectionFee = bps;
    }

    /// @notice Sets the Incentive fee size.
    /// @param bps Incentive fee in basis points (30 = 0.3%).
    /// @dev Can only be called by the owner.
    function setIncentiveFee(uint16 bps) external onlyOwner {
        if (bps < 30 || bps > 500) revert Prohibited();
        incentiveFee = bps;
    }

    /// @notice Sets the minimum Reserve distribution size.
    /// @param limit Reserve limit size.
    /// @dev Can only be called by the owner.
    function setMinReserveDistribution(uint256 limit) external onlyOwner {
        if (limit < 100 || limit > maxReserveDistribution) revert Prohibited();
        minReserveDistribution = limit;
    }

    /// @notice Sets the maximum Reserve distribution size.
    /// @param limit Reserve limit size.
    /// @dev Can only be called by the owner.
    function setMaxReserveDistribution(uint256 limit) external onlyOwner {
        if (limit < minReserveDistribution || limit > _tTotal) revert Prohibited();
        maxReserveDistribution = limit;
    }

    // --------------------------- VIEW FUNCTIONS --------------------------- //

    /// @notice Checks if the presale is currently active.
    /// @return A boolean indicating whether the presale is active.
    function isPresaleActive() public view returns (bool) {
        return presaleEnd > block.timestamp;
    }

    function decimals() public pure override returns (uint8) {
        return 9;
    }

    function totalSupply() public view override returns (uint256) {
        if (!presaleFinalized) return _totalMinted;
        return _tTotal;
    }

    function balanceOf(address account) public view override returns (uint256) {
        if (!presaleFinalized && account == address(this)) return 0;
        if (_isExcludedFromReflections[account]) return _tOwned[account];
        return tokenFromReflection(_rOwned[account]);
    }

    function isExcluded(address account) public view returns (bool) {
        return _isExcludedFromReflections[account];
    }

    function reflectionFromToken(uint256 tAmount) public view returns (uint256) {
        if (tAmount > _tTotal) revert MaxSupply();
        uint256 rAmount = tAmount * _getRate();
        return rAmount;
    }

    function tokenFromReflection(uint256 rAmount) public view returns (uint256) {
        if (rAmount > _rTotal) revert MaxSupply();
        return rAmount / _getRate();
    }

    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC20).interfaceId || interfaceId == type(IERC165).interfaceId;
    }

    // --------------------------- INTERNAL FUNCTIONS --------------------------- //

    function _processBonus(uint256 amount, uint16 bonus, bytes32[] memory merkleProof)
        internal
        view
        returns (uint256)
    {
        if (bonus > 0) {
            bytes32 leaf = keccak256(abi.encodePacked(msg.sender, bonus));
            if (!MerkleProof.verify(merkleProof, _merkleRoot, leaf)) revert IncorrectBonus();
            uint256 bonusAmount = amount * bonus / 10000;
            amount += bonusAmount;
        }
        return amount;
    }

    function _processIncentiveFee(address receiver, uint256 amount) internal returns (uint256) {
        uint256 rValue = reflectionFromToken(amount);
        uint256 rIncentive = FullMath.mulDiv(rValue, incentiveFee, 10000);
        uint256 tIncentive = FullMath.mulDiv(amount, incentiveFee, 10000);
        _rOwned[address(this)] -= rIncentive;
        _rOwned[receiver] += rIncentive;
        if (_isExcludedFromReflections[receiver]) _tOwned[receiver] += tIncentive;
        return amount - tIncentive;
    }

    function _distributeTokens() internal {
        IERC20 titanX = IERC20(TITANX);
        uint256 availableTitanX = titanX.balanceOf(address(this));
        titanLpPool = availableTitanX * LP_POOL_PERCENT / 100;
        scaleLpPool = titanLpPool / 10 ** 9;
        bdxBuyBurnPool = availableTitanX * BDX_BUY_BURN_PERCENT / 100;
        uint256 dragonVaultAmount = availableTitanX * DRAGONX_VAULT_PERCENT / 100;
        uint256 heliosVaultAmount = availableTitanX * HELIOS_VAULT_PERCENT / 100;
        uint256 devAmount = availableTitanX * DEV_PERCENT / 100;
        uint256 genesisAmount = availableTitanX * GENESIS_PERCENT / 100;
        uint256 shedAmount = availableTitanX - titanLpPool - bdxBuyBurnPool - dragonVaultAmount - heliosVaultAmount
            - devAmount - genesisAmount;

        titanX.safeTransfer(dragonXVault, dragonVaultAmount);
        titanX.safeTransfer(heliosVault, heliosVaultAmount);
        titanX.safeTransfer(devWallet, devAmount);
        titanX.safeTransfer(owner(), genesisAmount);
        titanX.safeTransfer(shedContract, shedAmount);
        IDragonX(dragonXVault).updateVault();
    }

    function _addLiquidity(address tokenAddress, uint256 tokenAmount, uint256 scaleAmount) internal {
        (uint256 pairBalance, address pairAddress) = _checkPoolValidity(tokenAddress);
        if (pairBalance > 0) _fixPool(pairAddress, tokenAmount, scaleAmount, pairBalance);

        if (tokenAddress == BDX_ADDRESS) {
            if (pairAddress == address(0)) {
                pairAddress = IUniswapV2Factory(UNISWAP_V2_FACTORY).createPair(address(this), tokenAddress);
            }
            excludeAccountFromReflections(pairAddress);
        }
        if (pairBalance > 0) {
            _update(address(this), pairAddress, scaleAmount);
            IERC20(tokenAddress).transfer(pairAddress, tokenAmount);
            IUniswapV2Pair(pairAddress).mint(address(0));
        } else {
            IERC20(address(this)).safeIncreaseAllowance(UNISWAP_V2_ROUTER, scaleAmount);
            IERC20(tokenAddress).safeIncreaseAllowance(UNISWAP_V2_ROUTER, tokenAmount);
            IUniswapV2Router02(UNISWAP_V2_ROUTER).addLiquidity(
                address(this),
                tokenAddress,
                scaleAmount,
                tokenAmount,
                scaleAmount,
                tokenAmount,
                address(0), //send governance tokens directly to zero address
                block.timestamp
            );
        }
    }

    function _checkPoolValidity(address target) internal returns (uint256, address) {
        address pairAddress = IUniswapV2Factory(UNISWAP_V2_FACTORY).getPair(address(this), target);
        if (pairAddress == address(0)) return (0, pairAddress);
        IUniswapV2Pair pair = IUniswapV2Pair(pairAddress);

        pair.skim(owner());
        (uint112 reserve0, uint112 reserve1,) = pair.getReserves();
        if (reserve0 != 0) return (reserve0, pairAddress);
        if (reserve1 != 0) return (reserve1, pairAddress);
        return (0, pairAddress);
    }

    function _fixPool(address pairAddress, uint256 tokenAmount, uint256 scaleAmount, uint256 currentBalance) internal {
        uint256 requiredScale = currentBalance * scaleAmount / tokenAmount;
        if (requiredScale == 0) requiredScale = 1;
        uint256 rAmount = requiredScale * _getRate();
        _rOwned[pairAddress] += rAmount;
        if (_isExcludedFromReflections[pairAddress]) _tOwned[pairAddress] += requiredScale;
        _rTotal += rAmount;
        _tTotal += requiredScale;
        emit Transfer(address(0), pairAddress, requiredScale);
        IUniswapV2Pair(pairAddress).sync();
    }

    function _enableTrading() internal {
        tradingEnabled = true;
        emit TradingEnabled();
    }

    // --------------------------- SWAP FUNCTIONS --------------------------- //

    function _swapETHForTitanX(uint256 minAmountOut, uint256 deadline) internal returns (uint256) {
        IWETH9(WETH9).deposit{value: msg.value}();

        ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
            tokenIn: WETH9,
            tokenOut: TITANX,
            fee: POOL_FEE_1PERCENT,
            recipient: address(this),
            deadline: deadline,
            amountIn: msg.value,
            amountOutMinimum: minAmountOut,
            sqrtPriceLimitX96: 0
        });
        IERC20(WETH9).safeIncreaseAllowance(UNISWAP_V3_ROUTER, msg.value);
        uint256 amountOut = ISwapRouter(UNISWAP_V3_ROUTER).exactInputSingle(params);
        return amountOut;
    }

    function _swapScaleToDragonX(uint256 amountIn, uint256 minAmountOut, uint256 deadline) internal {
        IERC20(address(this)).safeIncreaseAllowance(UNISWAP_V2_ROUTER, amountIn);
        address[] memory path = new address[](2);
        path[0] = address(this);
        path[1] = DRAGONX_ADDRESS;

        IUniswapV2Router02(UNISWAP_V2_ROUTER).swapExactTokensForTokensSupportingFeeOnTransferTokens(
            amountIn, minAmountOut, path, bdxBuyBurnAddress, deadline
        );
    }

    function _swapTitanXToToken(address outputToken, uint256 amount, uint256 minAmountOut, uint256 deadline)
        internal
        returns (uint256)
    {
        if (outputToken == DRAGONX_ADDRESS) return _swapUniswapV3Pool(outputToken, amount, minAmountOut, deadline);
        if (outputToken == E280_ADDRESS) return _swapUniswapV2Pool(outputToken, amount, minAmountOut, deadline);
        return _swapMultihop(outputToken, DRAGONX_ADDRESS, amount, minAmountOut, deadline);
    }

    function _swapUniswapV3Pool(address outputToken, uint256 amountIn, uint256 minAmountOut, uint256 deadline)
        internal
        returns (uint256)
    {
        ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
            tokenIn: TITANX,
            tokenOut: outputToken,
            fee: POOL_FEE_1PERCENT,
            recipient: address(this),
            deadline: deadline,
            amountIn: amountIn,
            amountOutMinimum: minAmountOut,
            sqrtPriceLimitX96: 0
        });
        IERC20(TITANX).safeIncreaseAllowance(UNISWAP_V3_ROUTER, amountIn);
        uint256 amountOut = ISwapRouter(UNISWAP_V3_ROUTER).exactInputSingle(params);
        return amountOut;
    }

    function _swapUniswapV2Pool(address outputToken, uint256 amountIn, uint256 minAmountOut, uint256 deadline)
        internal
        returns (uint256)
    {
        IERC20(TITANX).safeIncreaseAllowance(UNISWAP_V2_ROUTER, amountIn);
        uint256 previous = IERC20(outputToken).balanceOf(address(this));
        address[] memory path = new address[](2);
        path[0] = TITANX;
        path[1] = outputToken;

        IUniswapV2Router02(UNISWAP_V2_ROUTER).swapExactTokensForTokensSupportingFeeOnTransferTokens(
            amountIn, minAmountOut, path, address(this), deadline
        );

        return IERC20(outputToken).balanceOf(address(this)) - previous;
    }

    function _swapMultihop(
        address outputToken,
        address midToken,
        uint256 amountIn,
        uint256 minAmountOut,
        uint256 deadline
    ) internal returns (uint256) {
        bytes memory path = abi.encodePacked(TITANX, POOL_FEE_1PERCENT, midToken, POOL_FEE_1PERCENT, outputToken);

        ISwapRouter.ExactInputParams memory params = ISwapRouter.ExactInputParams({
            path: path,
            recipient: address(this),
            deadline: deadline,
            amountIn: amountIn,
            amountOutMinimum: minAmountOut
        });
        IERC20(TITANX).safeIncreaseAllowance(UNISWAP_V3_ROUTER, amountIn);
        uint256 amoutOut = ISwapRouter(UNISWAP_V3_ROUTER).exactInput(params);
        return amoutOut;
    }

    // --------------------------- REFLECTIONS FUNCTIONS --------------------------- //

    function _rMint(address account, uint256 tAmount) internal {
        uint256 rAmount = tAmount * _getRate();
        _rOwned[address(this)] -= rAmount;
        _rOwned[msg.sender] += rAmount;
        if (_isExcludedFromReflections[account]) _tOwned[msg.sender] += tAmount;
        _totalMinted += tAmount;
        emit Transfer(address(0), account, tAmount);
    }

    function _rBurn(address account, uint256 tAmount) internal {
        uint256 rBurn = tAmount * _getRate();
        _balanceCheck(account, rBurn, tAmount);
        _rOwned[account] -= rBurn;
        if (_isExcludedFromReflections[account]) _tOwned[account] -= tAmount;
        _rTotal -= rBurn;
        _tTotal -= tAmount;
        totalBurned += tAmount;
        emit Transfer(account, address(0), tAmount);
    }

    function _update(address from, address to, uint256 value) internal override {
        if (tradingEnabled) {
            (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 rReserve, uint256 tTransferAmount) =
                _getValues(value);
            _balanceCheck(from, rAmount, value);
            _rOwned[from] -= rAmount;
            if (_isExcludedFromReflections[from]) _tOwned[from] -= value;
            _rOwned[to] += rTransferAmount;
            if (_isExcludedFromReflections[to]) _tOwned[to] += tTransferAmount;
            _rOwned[address(this)] += rReserve;
            _reflectFee(rFee);
            emit Transfer(from, to, tTransferAmount);
        } else {
            if (from != address(this)) revert TradingDisabled();
            // no fees during LP deployment
            uint256 rValue = value * _getRate();
            _rOwned[from] -= rValue;
            _rOwned[to] += rValue;
            if (_isExcludedFromReflections[to]) _tOwned[to] += value;
            emit Transfer(from, to, value);
        }
    }

    function _balanceCheck(address from, uint256 rAmount, uint256 value) internal view {
        uint256 fromBalance = _rOwned[from];
        if (fromBalance < rAmount) {
            revert ERC20InsufficientBalance(from, tokenFromReflection(fromBalance), value);
        }
    }

    function _reflectFee(uint256 rFee) private {
        _rTotal -= rFee;
    }

    function _getValues(uint256 tAmount) private view returns (uint256, uint256, uint256, uint256, uint256) {
        (uint256 tTransferAmount, uint256 tFee, uint256 tReserve) = _getTValues(tAmount);
        uint256 currentRate = _getRate();
        (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 rReserve) =
            _getRValues(tAmount, tFee, tReserve, currentRate);
        return (rAmount, rTransferAmount, rFee, rReserve, tTransferAmount);
    }

    function _getTValues(uint256 tAmount) private view returns (uint256, uint256, uint256) {
        uint256 tFee = FullMath.mulDivRoundingUp(tAmount, reflectionFee, 10000);
        uint256 tReserve = tAmount / 100;
        uint256 tTransferAmount = tAmount - tFee - tReserve;
        return (tTransferAmount, tFee, tReserve);
    }

    function _getRValues(uint256 tAmount, uint256 tFee, uint256 tReserve, uint256 currentRate)
        private
        pure
        returns (uint256, uint256, uint256, uint256)
    {
        uint256 rAmount = tAmount * currentRate;
        uint256 rFee = tFee * currentRate;
        uint256 rReserve = tReserve * currentRate;
        uint256 rTransferAmount = rAmount - rFee - rReserve;
        return (rAmount, rTransferAmount, rFee, rReserve);
    }

    function _getRate() private view returns (uint256) {
        (uint256 rSupply, uint256 tSupply) = _getCurrentSupply();
        return rSupply / tSupply;
    }

    function _getCurrentSupply() private view returns (uint256, uint256) {
        uint256 rSupply = _rTotal;
        uint256 tSupply = _tTotal;
        for (uint256 i = 0; i < _excluded.length; i++) {
            address account = _excluded[i];
            uint256 rValue = _rOwned[account];
            uint256 tValue = _tOwned[account];
            if (rValue > rSupply || tValue > tSupply) return (_rTotal, _tTotal);
            rSupply -= rValue;
            tSupply -= tValue;
        }
        if (rSupply < _rTotal / _tTotal) return (_rTotal, _tTotal);
        return (rSupply, tSupply);
    }
}

File 2 of 25 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 3 of 25 : Ownable2Step.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.20;

import {Ownable} from "./Ownable.sol";

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is specified at deployment time in the constructor for `Ownable`. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2Step is Ownable {
    address private _pendingOwner;

    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        if (pendingOwner() != sender) {
            revert OwnableUnauthorizedAccount(sender);
        }
        _transferOwnership(sender);
    }
}

File 4 of 25 : draft-IERC6093.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;

/**
 * @dev Standard ERC20 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
 */
interface IERC20Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC20InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC20InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     * @param allowance Amount of tokens a `spender` is allowed to operate with.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC20InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC20InvalidSpender(address spender);
}

/**
 * @dev Standard ERC721 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
 */
interface IERC721Errors {
    /**
     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
     * Used in balance queries.
     * @param owner Address of the current owner of a token.
     */
    error ERC721InvalidOwner(address owner);

    /**
     * @dev Indicates a `tokenId` whose `owner` is the zero address.
     * @param tokenId Identifier number of a token.
     */
    error ERC721NonexistentToken(uint256 tokenId);

    /**
     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param tokenId Identifier number of a token.
     * @param owner Address of the current owner of a token.
     */
    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC721InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC721InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param tokenId Identifier number of a token.
     */
    error ERC721InsufficientApproval(address operator, uint256 tokenId);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC721InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC721InvalidOperator(address operator);
}

/**
 * @dev Standard ERC1155 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
 */
interface IERC1155Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     * @param tokenId Identifier number of a token.
     */
    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC1155InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC1155InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param owner Address of the current owner of a token.
     */
    error ERC1155MissingApprovalForAll(address operator, address owner);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC1155InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC1155InvalidOperator(address operator);

    /**
     * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
     * Used in batch transfers.
     * @param idsLength Length of the array of token identifiers
     * @param valuesLength Length of the array of token amounts
     */
    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}

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

pragma solidity ^0.8.20;

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

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

pragma solidity ^0.8.20;

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

File 7 of 25 : ERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 */
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
    mapping(address account => uint256) private _balances;

    mapping(address account => mapping(address spender => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the default value returned by this function, unless
     * it's overridden.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `value`.
     */
    function transfer(address to, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, value);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, value);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `value`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `value`.
     */
    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, value);
        _transfer(from, to, value);
        return true;
    }

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _transfer(address from, address to, uint256 value) internal {
        if (from == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        if (to == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(from, to, value);
    }

    /**
     * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
     * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
     * this function.
     *
     * Emits a {Transfer} event.
     */
    function _update(address from, address to, uint256 value) internal virtual {
        if (from == address(0)) {
            // Overflow check required: The rest of the code assumes that totalSupply never overflows
            _totalSupply += value;
        } else {
            uint256 fromBalance = _balances[from];
            if (fromBalance < value) {
                revert ERC20InsufficientBalance(from, fromBalance, value);
            }
            unchecked {
                // Overflow not possible: value <= fromBalance <= totalSupply.
                _balances[from] = fromBalance - value;
            }
        }

        if (to == address(0)) {
            unchecked {
                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                _totalSupply -= value;
            }
        } else {
            unchecked {
                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                _balances[to] += value;
            }
        }

        emit Transfer(from, to, value);
    }

    /**
     * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
     * Relies on the `_update` mechanism
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _mint(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(address(0), account, value);
    }

    /**
     * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
     * Relies on the `_update` mechanism.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead
     */
    function _burn(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        _update(account, address(0), value);
    }

    /**
     * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     *
     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
     */
    function _approve(address owner, address spender, uint256 value) internal {
        _approve(owner, spender, value, true);
    }

    /**
     * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
     *
     * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
     * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
     * `Approval` event during `transferFrom` operations.
     *
     * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
     * true using the following override:
     * ```
     * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
     *     super._approve(owner, spender, value, true);
     * }
     * ```
     *
     * Requirements are the same as {_approve}.
     */
    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
        if (owner == address(0)) {
            revert ERC20InvalidApprover(address(0));
        }
        if (spender == address(0)) {
            revert ERC20InvalidSpender(address(0));
        }
        _allowances[owner][spender] = value;
        if (emitEvent) {
            emit Approval(owner, spender, value);
        }
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `value`.
     *
     * Does not update the allowance value in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Does not emit an {Approval} event.
     */
    function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            if (currentAllowance < value) {
                revert ERC20InsufficientAllowance(spender, currentAllowance, value);
            }
            unchecked {
                _approve(owner, spender, currentAllowance - value, false);
            }
        }
    }
}

File 8 of 25 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 9 of 25 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
        external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 10 of 25 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

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

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

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

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

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

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

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

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

File 11 of 25 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";

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

    /**
     * @dev An operation with an ERC20 token failed.
     */
    error SafeERC20FailedOperation(address token);

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

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

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

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

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

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
    }
}

File 12 of 25 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert AddressInsufficientBalance(address(this));
        }

        (bool success,) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {FailedInnerCall} error.
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(address target, bool success, bytes memory returndata)
        internal
        view
        returns (bytes memory)
    {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert FailedInnerCall();
        }
    }
}

File 13 of 25 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

File 14 of 25 : MerkleProof.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MerkleProof.sol)

pragma solidity ^0.8.20;

/**
 * @dev These functions deal with verification of Merkle Tree proofs.
 *
 * The tree and the proofs can be generated using our
 * https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
 * You will find a quickstart guide in the readme.
 *
 * WARNING: You should avoid using leaf values that are 64 bytes long prior to
 * hashing, or use a hash function other than keccak256 for hashing leaves.
 * This is because the concatenation of a sorted pair of internal nodes in
 * the Merkle tree could be reinterpreted as a leaf value.
 * OpenZeppelin's JavaScript library generates Merkle trees that are safe
 * against this attack out of the box.
 */
library MerkleProof {
    /**
     * @dev The multiproof provided is not valid.
     */
    error MerkleProofInvalidMultiproof();

    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }

    /**
     * @dev Calldata version of {verify}
     */
    function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
        return processProofCalldata(proof, leaf) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. When processing the proof, the pairs
     * of leafs & pre-images are assumed to be sorted.
     */
    function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Calldata version of {processProof}
     */
    function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by
     * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     */
    function multiProofVerify(bytes32[] memory proof, bool[] memory proofFlags, bytes32 root, bytes32[] memory leaves)
        internal
        pure
        returns (bool)
    {
        return processMultiProof(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Calldata version of {multiProofVerify}
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     */
    function multiProofVerifyCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProofCalldata(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
     * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
     * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
     * respectively.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
     * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
     * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
     */
    function processMultiProof(bytes32[] memory proof, bool[] memory proofFlags, bytes32[] memory leaves)
        internal
        pure
        returns (bytes32 merkleRoot)
    {
        // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the Merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 proofLen = proof.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        if (leavesLen + proofLen != totalHashes + 1) {
            revert MerkleProofInvalidMultiproof();
        }

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b =
                proofFlags[i] ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            if (proofPos != proofLen) {
                revert MerkleProofInvalidMultiproof();
            }
            unchecked {
                return hashes[totalHashes - 1];
            }
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Calldata version of {processMultiProof}.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     */
    function processMultiProofCalldata(bytes32[] calldata proof, bool[] calldata proofFlags, bytes32[] memory leaves)
        internal
        pure
        returns (bytes32 merkleRoot)
    {
        // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the Merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 proofLen = proof.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        if (leavesLen + proofLen != totalHashes + 1) {
            revert MerkleProofInvalidMultiproof();
        }

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b =
                proofFlags[i] ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            if (proofPos != proofLen) {
                revert MerkleProofInvalidMultiproof();
            }
            unchecked {
                return hashes[totalHashes - 1];
            }
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Sorts the pair (a, b) and hashes the result.
     */
    function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
        return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
    }

    /**
     * @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory.
     */
    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}

File 15 of 25 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

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

File 16 of 25 : IUniswapV2Factory.sol
pragma solidity >=0.5.0;

interface IUniswapV2Factory {
    event PairCreated(address indexed token0, address indexed token1, address pair, uint256);

    function feeTo() external view returns (address);
    function feeToSetter() external view returns (address);

    function getPair(address tokenA, address tokenB) external view returns (address pair);
    function allPairs(uint256) external view returns (address pair);
    function allPairsLength() external view returns (uint256);

    function createPair(address tokenA, address tokenB) external returns (address pair);

    function setFeeTo(address) external;
    function setFeeToSetter(address) external;
}

File 17 of 25 : IUniswapV2Pair.sol
pragma solidity >=0.5.0;

interface IUniswapV2Pair {
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event Transfer(address indexed from, address indexed to, uint256 value);

    function name() external pure returns (string memory);
    function symbol() external pure returns (string memory);
    function decimals() external pure returns (uint8);
    function totalSupply() external view returns (uint256);
    function balanceOf(address owner) external view returns (uint256);
    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 value) external returns (bool);
    function transfer(address to, uint256 value) external returns (bool);
    function transferFrom(address from, address to, uint256 value) external returns (bool);

    function DOMAIN_SEPARATOR() external view returns (bytes32);
    function PERMIT_TYPEHASH() external pure returns (bytes32);
    function nonces(address owner) external view returns (uint256);

    function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
        external;

    event Mint(address indexed sender, uint256 amount0, uint256 amount1);
    event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);
    event Swap(
        address indexed sender,
        uint256 amount0In,
        uint256 amount1In,
        uint256 amount0Out,
        uint256 amount1Out,
        address indexed to
    );
    event Sync(uint112 reserve0, uint112 reserve1);

    function MINIMUM_LIQUIDITY() external pure returns (uint256);
    function factory() external view returns (address);
    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
    function price0CumulativeLast() external view returns (uint256);
    function price1CumulativeLast() external view returns (uint256);
    function kLast() external view returns (uint256);

    function mint(address to) external returns (uint256 liquidity);
    function burn(address to) external returns (uint256 amount0, uint256 amount1);
    function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;
    function skim(address to) external;
    function sync() external;

    function initialize(address, address) external;
}

File 18 of 25 : IUniswapV2Router01.sol
pragma solidity >=0.6.2;

interface IUniswapV2Router01 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);
    function addLiquidityETH(
        address token,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);
    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB);
    function removeLiquidityETH(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountToken, uint256 amountETH);
    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountA, uint256 amountB);
    function removeLiquidityETHWithPermit(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountToken, uint256 amountETH);
    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);
    function swapTokensForExactTokens(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);
    function swapExactETHForTokens(uint256 amountOutMin, address[] calldata path, address to, uint256 deadline)
        external
        payable
        returns (uint256[] memory amounts);
    function swapTokensForExactETH(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);
    function swapExactTokensForETH(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);
    function swapETHForExactTokens(uint256 amountOut, address[] calldata path, address to, uint256 deadline)
        external
        payable
        returns (uint256[] memory amounts);

    function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB);
    function getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut)
        external
        pure
        returns (uint256 amountOut);
    function getAmountIn(uint256 amountOut, uint256 reserveIn, uint256 reserveOut)
        external
        pure
        returns (uint256 amountIn);
    function getAmountsOut(uint256 amountIn, address[] calldata path)
        external
        view
        returns (uint256[] memory amounts);
    function getAmountsIn(uint256 amountOut, address[] calldata path)
        external
        view
        returns (uint256[] memory amounts);
}

File 19 of 25 : IUniswapV2Router02.sol
pragma solidity >=0.6.2;

import "./IUniswapV2Router01.sol";

interface IUniswapV2Router02 is IUniswapV2Router01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountETH);
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external;
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable;
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external;
}

File 20 of 25 : IUniswapV3SwapCallback.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Callback for IUniswapV3PoolActions#swap
/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface
interface IUniswapV3SwapCallback {
    /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.
    /// @dev In the implementation you must pay the pool tokens owed for the swap.
    /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.
    /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.
    /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
    /// the end of the swap. If positive, the callback must send that amount of token0 to the pool.
    /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
    /// the end of the swap. If positive, the callback must send that amount of token1 to the pool.
    /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call
    function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external;
}

File 21 of 25 : ISwapRouter.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
pragma abicoder v2;

import "@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol";

/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Uniswap V3
interface ISwapRouter is IUniswapV3SwapCallback {
    struct ExactInputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 deadline;
        uint256 amountIn;
        uint256 amountOutMinimum;
        uint160 sqrtPriceLimitX96;
    }

    /// @notice Swaps `amountIn` of one token for as much as possible of another token
    /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
    /// @return amountOut The amount of the received token
    function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);

    struct ExactInputParams {
        bytes path;
        address recipient;
        uint256 deadline;
        uint256 amountIn;
        uint256 amountOutMinimum;
    }

    /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
    /// @return amountOut The amount of the received token
    function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);

    struct ExactOutputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 deadline;
        uint256 amountOut;
        uint256 amountInMaximum;
        uint160 sqrtPriceLimitX96;
    }

    /// @notice Swaps as little as possible of one token for `amountOut` of another token
    /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
    /// @return amountIn The amount of the input token
    function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);

    struct ExactOutputParams {
        bytes path;
        address recipient;
        uint256 deadline;
        uint256 amountOut;
        uint256 amountInMaximum;
    }

    /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
    /// @return amountIn The amount of the input token
    function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
}

File 22 of 25 : IDragonX.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

interface IDragonX {
    function updateVault() external;
}

File 23 of 25 : IWETH9.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.10;

import "@openzeppelin/contracts/interfaces/IERC20.sol";

/// @title Interface for WETH9
interface IWETH9 is IERC20 {
    /// @notice Deposit ether to get wrapped ether
    function deposit() external payable;

    /// @notice Withdraw wrapped ether to get ether
    function withdraw(uint256) external;
}

File 24 of 25 : constants.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

// ===================== Contract Addresses =====================================
uint8 constant NUM_ECOSYSTEM_TOKENS = 5;

address constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address constant TITANX = 0xF19308F923582A6f7c465e5CE7a9Dc1BEC6665B1;
address constant DRAGONX_ADDRESS = 0x96a5399D07896f757Bd4c6eF56461F58DB951862;
address constant BDX_ADDRESS = 0x9f278Dc799BbC61ecB8e5Fb8035cbfA29803623B;
address constant HYDRA_ADDRESS = 0xCC7ed2ab6c3396DdBc4316D2d7C1b59ff9d2091F;
address constant E280_ADDRESS = 0xe9A53C43a0B58706e67341C4055de861e29Ee943;

address constant DRAGONX_HYDRA_POOL = 0xF8F0Ef9f6A12336A1e035adDDbD634F3B0962F54;
address constant TITANX_DRAGONX_POOL = 0x25215d9ba4403b3DA77ce50606b54577a71b7895;

// ===================== Presale ================================================
uint256 constant MAX_VALUE = ~uint256(0);
uint256 constant PRESALE_LENGTH = 14 days;

// ===================== Presale Allocations ====================================
uint256 constant LP_POOL_PERCENT = 35;
uint256 constant BDX_BUY_BURN_PERCENT = 35;
uint256 constant DRAGONX_VAULT_PERCENT = 5;
uint256 constant HELIOS_VAULT_PERCENT = 5;
uint256 constant SHED_PERCENT = 11;
uint256 constant DEV_PERCENT = 8;
uint256 constant GENESIS_PERCENT = 1;

// ===================== HYDRA Interface ========================================
uint256 constant START_MAX_MINT_COST = 1e11 ether;
uint256 constant MAX_MINT_POWER_CAP = 10_000;
uint256 constant MAX_MINT_LENGTH = 88;
uint256 constant MAX_MINT_PER_WALLET = 1000;
uint8 constant MAX_AVAILABLE_MINERS = 20;
uint8 constant MIN_AVAILABLE_MINERS = 4;

// ===================== UNISWAP Interface ======================================

address constant UNISWAP_V2_FACTORY = 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f;
address constant UNISWAP_V2_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
address constant UNISWAP_V3_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564;
uint24 constant POOL_FEE_1PERCENT = 10000;

File 25 of 25 : FullMath.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {
    /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    function mulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = a * b
            // Compute the product mod 2**256 and mod 2**256 - 1
            // then use the Chinese Remainder Theorem to reconstruct
            // the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2**256 + prod0
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(a, b, not(0))
                prod0 := mul(a, b)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division
            if (prod1 == 0) {
                require(denominator > 0);
                assembly {
                    result := div(prod0, denominator)
                }
                return result;
            }

            // Make sure the result is less than 2**256.
            // Also prevents denominator == 0
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0]
            // Compute remainder using mulmod
            uint256 remainder;
            assembly {
                remainder := mulmod(a, b, denominator)
            }
            // Subtract 256 bit number from 512 bit number
            assembly {
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator
            // Compute largest power of two divisor of denominator.
            // Always >= 1.
            uint256 twos = (0 - denominator) & denominator;
            // Divide denominator by power of two
            assembly {
                denominator := div(denominator, twos)
            }

            // Divide [prod1 prod0] by the factors of two
            assembly {
                prod0 := div(prod0, twos)
            }
            // Shift in bits from prod1 into prod0. For this we need
            // to flip `twos` such that it is 2**256 / twos.
            // If twos is zero, then it becomes one
            assembly {
                twos := add(div(sub(0, twos), twos), 1)
            }
            prod0 |= prod1 * twos;

            // Invert denominator mod 2**256
            // Now that denominator is an odd number, it has an inverse
            // modulo 2**256 such that denominator * inv = 1 mod 2**256.
            // Compute the inverse by starting with a seed that is correct
            // correct for four bits. That is, denominator * inv = 1 mod 2**4
            uint256 inv = (3 * denominator) ^ 2;
            // Now use Newton-Raphson iteration to improve the precision.
            // Thanks to Hensel's lifting lemma, this also works in modular
            // arithmetic, doubling the correct bits in each step.
            inv *= 2 - denominator * inv; // inverse mod 2**8
            inv *= 2 - denominator * inv; // inverse mod 2**16
            inv *= 2 - denominator * inv; // inverse mod 2**32
            inv *= 2 - denominator * inv; // inverse mod 2**64
            inv *= 2 - denominator * inv; // inverse mod 2**128
            inv *= 2 - denominator * inv; // inverse mod 2**256

            // Because the division is now exact we can divide by multiplying
            // with the modular inverse of denominator. This will give us the
            // correct result modulo 2**256. Since the precoditions guarantee
            // that the outcome is less than 2**256, this is the final result.
            // We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inv;
            return result;
        }
    }

    /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    function mulDivRoundingUp(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            result = mulDiv(a, b, denominator);
            if (mulmod(a, b, denominator) > 0) {
                require(result < type(uint256).max);
                result++;
            }
        }
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_devWallet","type":"address"},{"internalType":"address","name":"_marketingWallet","type":"address"},{"internalType":"address","name":"_heliosVault","type":"address"},{"internalType":"address","name":"_dragonxVault","type":"address"},{"internalType":"address","name":"_bdxBuyBurnAddress","type":"address"},{"internalType":"address[]","name":"_ecosystemTokens","type":"address[]"},{"internalType":"uint8[]","name":"_lpPercentages","type":"uint8[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"DuplicateToken","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[],"name":"ExcludedAddress","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"IncorrectBonus","type":"error"},{"inputs":[],"name":"IncorrectPercentage","type":"error"},{"inputs":[],"name":"IncorrectTokenNumber","type":"error"},{"inputs":[],"name":"InsuffucientBalance","type":"error"},{"inputs":[],"name":"MaxSupply","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"PresaleActive","type":"error"},{"inputs":[],"name":"PresaleInactive","type":"error"},{"inputs":[],"name":"Prohibited","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"TradingDisabled","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroInput","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[],"name":"PresaleStarted","type":"event"},{"anonymous":false,"inputs":[],"name":"ReserveDistributed","type":"event"},{"anonymous":false,"inputs":[],"name":"TradingEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bdxBuyBurnAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bdxBuyBurnPool","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"buyBurnDragonXAllocation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"buyBurnPurchases","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimDust","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"deployLiquidityPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"devWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"minDragonXAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"distributeReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"dragonXVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"excludeAccountFromReflections","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finalizePresale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"heliosVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"incentiveFee","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"includeAccountToReflections","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isExcluded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPresaleActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpPurchaseFinished","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"lpPurchases","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketingWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxReserveDistribution","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minReserveDistribution","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint16","name":"bonus","type":"uint16"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"mintWithETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint16","name":"bonus","type":"uint16"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"name":"mintWithTitanX","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"presaleEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"presaleFinalized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"purchaseDragonXForBuyBurn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"purchaseTokenForLP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"purchasesRequired","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"reflect","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reflectionFee","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tAmount","type":"uint256"}],"name":"reflectionFromToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"scaleLpPool","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"setBDXBuyBurn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"setDevWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"setDragonXVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"setHeliosVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"bps","type":"uint16"}],"name":"setIncentiveFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"setMarketingWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"setMaxReserveDistribution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"root","type":"bytes32"}],"name":"setMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"setMinReserveDistribution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"amount","type":"uint8"}],"name":"setPurchasesRequired","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"bps","type":"uint16"}],"name":"setReflectionFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"setSHED","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shedContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startPresale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"titanLpPool","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"rAmount","type":"uint256"}],"name":"tokenFromReflection","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"tokenLpPercent","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"tokenPool","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBurned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalLPsCreated","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalLpPoolUsed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tradingEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6080604052600c805463ffffffff60a01b1916624b000f60a11b17905566038d7ea4c68000600e556706f05b59d3b20000600f556015805462ff00001916620a000017905569152d02c7e14af68000006021819055620000629060001962000495565b6200007090600019620004ce565b6022553480156200008057600080fd5b506040516200532938038062005329833981016040819052620000a391620005fe565b6040805180820182526005808252645343414c4560d81b602080840182905284518086019095529184529083015289916003620000e18382620007d0565b506004620000f08282620007d0565b5050506001600160a01b0381166200012257604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200012d8162000425565b5081516005146200015157604051638bf93bc160e01b815260040160405180910390fd5b80516005146200017457604051638bf93bc160e01b815260040160405180910390fd5b6001600160a01b0388166200019c5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038716620001c45760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038616620001ec5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038516620002145760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0384166200023c5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038316620002645760405163d92e233d60e01b815260040160405180910390fd5b602254306000908152601e6020526040812091909155600980546001600160a01b03199081166001600160a01b038b811691909117909255600a805482168a8416179055600780548216898416179055600880548216888416179055600c8054909116918616919091179055805b8351811015620003f0576000848281518110620002f357620002f36200089c565b6020026020010151905060008483815181106200031457620003146200089c565b6020026020010151905060006001600160a01b0316826001600160a01b031603620003525760405163d92e233d60e01b815260040160405180910390fd5b8060ff16600003620003775760405163af458c0760e01b815260040160405180910390fd5b6001600160a01b0382166000908152601a602052604090205460ff1615620003b2576040516323271fb560e11b815260040160405180910390fd5b6001600160a01b0382166000908152601a60205260409020805460ff191660ff8316179055620003e38185620008b2565b93505050600101620002d2565b508060ff166064146200041657604051633f8f2cc960e11b815260040160405180910390fd5b505050505050505050620008ce565b600680546001600160a01b0319169055620004408162000443565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600082620004b357634e487b7160e01b600052601260045260246000fd5b500690565b634e487b7160e01b600052601160045260246000fd5b81810381811115620004e457620004e4620004b8565b92915050565b80516001600160a01b03811681146200050257600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171562000548576200054862000507565b604052919050565b60006001600160401b038211156200056c576200056c62000507565b5060051b60200190565b600082601f8301126200058857600080fd5b81516020620005a16200059b8362000550565b6200051d565b8083825260208201915060208460051b870101935086841115620005c457600080fd5b602086015b84811015620005f357805160ff81168114620005e55760008081fd5b8352918301918301620005c9565b509695505050505050565b600080600080600080600080610100898b0312156200061c57600080fd5b6200062789620004ea565b9750602062000638818b01620004ea565b97506200064860408b01620004ea565b96506200065860608b01620004ea565b95506200066860808b01620004ea565b94506200067860a08b01620004ea565b60c08b01519094506001600160401b03808211156200069657600080fd5b818c0191508c601f830112620006ab57600080fd5b8151620006bc6200059b8262000550565b81815260059190911b8301840190848101908f831115620006dc57600080fd5b938501935b828510156200070557620006f585620004ea565b82529385019390850190620006e1565b60e08f015190975094505050808311156200071f57600080fd5b50506200072f8b828c0162000576565b9150509295985092959890939650565b600181811c908216806200075457607f821691505b6020821081036200077557634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620007cb576000816000526020600020601f850160051c81016020861015620007a65750805b601f850160051c820191505b81811015620007c757828155600101620007b2565b5050505b505050565b81516001600160401b03811115620007ec57620007ec62000507565b6200080481620007fd84546200073f565b846200077b565b602080601f8311600181146200083c5760008415620008235750858301515b600019600386901b1c1916600185901b178555620007c7565b600085815260208120601f198616915b828110156200086d578886015182559484019460019091019084016200084c565b50858210156200088c5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052603260045260246000fd5b60ff8181168382160190811115620004e457620004e4620004b8565b614a4b80620008de6000396000f3fe6080604052600436106104055760003560e01c80636d49809311610213578063a0a6e94011610123578063df90ebe8116100ab578063eefc1ea81161007a578063eefc1ea814610c11578063f2fde38b14610c41578063f468fa0714610c61578063f8d9beca14610c80578063fe22441614610ca057600080fd5b8063df90ebe814610bab578063e0360bf214610bc0578063e30c397814610bd3578063e823744714610bf157600080fd5b8063cba0e996116100f2578063cba0e99614610ad6578063d1fe848414610b0f578063d89135cd14610b2f578063d9b8924414610b45578063dd62ed3e14610b6557600080fd5b8063a0a6e94014610a61578063a9059cbb14610a76578063b0c7d44c14610a96578063b380e85414610ab657600080fd5b80637f3de26d116101a6578063847e7fe611610175578063847e7fe6146109ce5780638da5cb5b146109ee5780638ea5220f14610a0c57806395d89b4114610a2c5780639a69f3c014610a4157600080fd5b80637f3de26d1461094957806381432b98146109695780638238e9da1461097f57806383ad7994146109ac57600080fd5b806372637791116101e257806372637791146108d457806375f0a874146108f457806379ba5097146109145780637cb647591461092957600080fd5b80636d498093146108655780636e360be11461087f57806370a082311461089f578063715018a6146108bf57600080fd5b8063313ce567116103195780635d098b38116102a15780635fb064d0116102705780635fb064d0146107d857806360d938dc146107f857806363841a5f1461080f57806366f5fe4f1461082f578063676e0e1b1461084f57600080fd5b80635d098b38146107685780635d61456d146107885780635ee2230a146107a25780635f72c3c3146107b857600080fd5b80633e2dd012116102e85780633e2dd012146106d257806342966c68146106e857806347e836e0146107085780634ada218b1461072857806351410bef1461074857600080fd5b8063313ce567146106285780633394e5bb1461064a57806334eecc661461066a5780633d5e6a3f146106a257600080fd5b80631392c0861161039c5780631f53ac021161036b5780631f53ac021461059257806321ae2a09146105b2578063229f3e29146105d257806323b872dd146105e85780632d8381191461060857600080fd5b80631392c086146105275780631812dbab1461054757806318160ddd146105675780631b4af2211461057c57600080fd5b8063053ab182116103d8578063053ab1821461049057806306903900146104b057806306fdde03146104e5578063095ea7b31461050757600080fd5b80630133bb8a1461040a57806301ffc9a7146104335780630447d4a91461046357806304c98b2b14610479575b600080fd5b34801561041657600080fd5b50610420600f5481565b6040519081526020015b60405180910390f35b34801561043f57600080fd5b5061045361044e36600461433e565b610cbf565b604051901515815260200161042a565b34801561046f57600080fd5b5061042060125481565b34801561048557600080fd5b5061048e610cf6565b005b34801561049c57600080fd5b5061048e6104ab366004614368565b610d73565b3480156104bc57600080fd5b50600c546104d290600160a01b900461ffff1681565b60405161ffff909116815260200161042a565b3480156104f157600080fd5b506104fa610e39565b60405161042a91906143d1565b34801561051357600080fd5b506104536105223660046143f9565b610ecb565b34801561053357600080fd5b50610420610542366004614368565b610ee3565b34801561055357600080fd5b5061048e610562366004614425565b610f23565b34801561057357600080fd5b5061042061100c565b34801561058857600080fd5b5061042060145481565b34801561059e57600080fd5b5061048e6105ad366004614425565b611027565b3480156105be57600080fd5b5061048e6105cd366004614368565b611078565b3480156105de57600080fd5b5061042060165481565b3480156105f457600080fd5b50610453610603366004614442565b6110b3565b34801561061457600080fd5b50610420610623366004614368565b6110d7565b34801561063457600080fd5b5060095b60405160ff909116815260200161042a565b34801561065657600080fd5b5061048e610665366004614425565b61110e565b34801561067657600080fd5b5060075461068a906001600160a01b031681565b6040516001600160a01b03909116815260200161042a565b3480156106ae57600080fd5b506106386106bd366004614425565b60196020526000908152604090205460ff1681565b3480156106de57600080fd5b5061042060105481565b3480156106f457600080fd5b5061048e610703366004614368565b611304565b34801561071457600080fd5b5061048e610723366004614425565b61133a565b34801561073457600080fd5b506017546104539062010000900460ff1681565b34801561075457600080fd5b5061048e610763366004614483565b61138b565b34801561077457600080fd5b5061048e610783366004614425565b611552565b34801561079457600080fd5b506015546106389060ff1681565b3480156107ae57600080fd5b5061042060115481565b3480156107c457600080fd5b5061048e6107d3366004614425565b6115a3565b3480156107e457600080fd5b5061048e6107f3366004614368565b6115f4565b34801561080457600080fd5b506016544210610453565b34801561081b57600080fd5b5061048e61082a366004614425565b611630565b34801561083b57600080fd5b50600b5461068a906001600160a01b031681565b34801561085b57600080fd5b50610420600e5481565b34801561087157600080fd5b506017546104539060ff1681565b34801561088b57600080fd5b5061048e61089a3660046144cf565b61177d565b3480156108ab57600080fd5b506104206108ba366004614425565b611804565b3480156108cb57600080fd5b5061048e61188e565b3480156108e057600080fd5b5061048e6108ef3660046144cf565b6118a2565b34801561090057600080fd5b50600a5461068a906001600160a01b031681565b34801561092057600080fd5b5061048e611902565b34801561093557600080fd5b5061048e610944366004614368565b611948565b34801561095557600080fd5b5061048e610964366004614425565b611973565b34801561097557600080fd5b5061042060135481565b34801561098b57600080fd5b5061042061099a366004614425565b60186020526000908152604090205481565b3480156109b857600080fd5b50600c546104d290600160b01b900461ffff1681565b3480156109da57600080fd5b506015546106389062010000900460ff1681565b3480156109fa57600080fd5b506005546001600160a01b031661068a565b348015610a1857600080fd5b5060095461068a906001600160a01b031681565b348015610a3857600080fd5b506104fa6119c4565b348015610a4d57600080fd5b5061048e610a5c366004614425565b6119d3565b348015610a6d57600080fd5b5061048e611a24565b348015610a8257600080fd5b50610453610a913660046143f9565b611b92565b348015610aa257600080fd5b5061048e610ab1366004614593565b611ba0565b348015610ac257600080fd5b5061048e610ad13660046145ea565b611c71565b348015610ae257600080fd5b50610453610af1366004614425565b6001600160a01b03166000908152601f602052604090205460ff1690565b348015610b1b57600080fd5b5061048e610b2a36600461460c565b611d87565b348015610b3b57600080fd5b50610420600d5481565b348015610b5157600080fd5b5061048e610b603660046145ea565b611e1a565b348015610b7157600080fd5b50610420610b8036600461462f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b348015610bb757600080fd5b5061048e611fb1565b61048e610bce366004614668565b61208e565b348015610bdf57600080fd5b506006546001600160a01b031661068a565b348015610bfd57600080fd5b5060085461068a906001600160a01b031681565b348015610c1d57600080fd5b50610638610c2c366004614425565b601a6020526000908152604090205460ff1681565b348015610c4d57600080fd5b5061048e610c5c366004614425565b612189565b348015610c6d57600080fd5b5060175461045390610100900460ff1681565b348015610c8c57600080fd5b50600c5461068a906001600160a01b031681565b348015610cac57600080fd5b5060155461063890610100900460ff1681565b60006001600160e01b031982166336372b0760e01b1480610cf057506001600160e01b031982166301ffc9a760e01b145b92915050565b610cfe6121fa565b60165415610d1f57604051632b0039c760e21b815260040160405180910390fd5b601c54610d3f57604051636397109b60e11b815260040160405180910390fd5b4262127500016016556040517f17c3338141363aab2512c08f8a7764328ca95979f7057663eb93f7e250139b4c90600090a1565b60175462010000900460ff16610d9c5760405163bcb8b8fb60e01b815260040160405180910390fd5b336000818152601f602052604090205460ff1615610dcd5760405163c87d620b60e01b815260040160405180910390fd5b6000610dd7612227565b610de190846146dd565b9050610dee82828561224a565b6001600160a01b0382166000908152601e602052604081208054839290610e169084906146f4565b925050819055508060226000828254610e2f91906146f4565b9091555050505050565b606060038054610e4890614707565b80601f0160208091040260200160405190810160405280929190818152602001828054610e7490614707565b8015610ec15780601f10610e9657610100808354040283529160200191610ec1565b820191906000526020600020905b815481529060010190602001808311610ea457829003601f168201915b5050505050905090565b600033610ed98185856122a6565b5060019392505050565b6000602154821115610f0857604051632cdb04a160e21b815260040160405180910390fd5b6000610f12612227565b610f1c90846146dd565b9392505050565b610f2b6121fa565b601754610100900460ff16610f5357604051632b0039c760e21b815260040160405180910390fd5b6001600160a01b03811660009081526018602052604081205490819003610f8d57604051632b0039c760e21b815260040160405180910390fd5b6012546001600160a01b0383166000908152601a60205260408120549091610fb99160ff1660646122b3565b9050610fc6838383612365565b6001600160a01b0383166000908152601860205260408120556015805460ff8082166001011660ff1990911681179091556004190161100757611007612640565b505050565b60175460009060ff166110205750601b5490565b5060215490565b61102f6121fa565b6001600160a01b0381166110565760405163d92e233d60e01b815260040160405180910390fd5b600980546001600160a01b0319166001600160a01b0392909216919091179055565b6110806121fa565b60648110806110905750600f5481115b156110ae57604051632b0039c760e21b815260040160405180910390fd5b600e55565b6000336110c185828561267c565b6110cc8585856126f4565b506001949350505050565b60006022548211156110fc57604051632cdb04a160e21b815260040160405180910390fd5b611104612227565b610cf09083614757565b6111166121fa565b6001600160a01b0381166000908152601f602052604090205460ff1661114f5760405163c87d620b60e01b815260040160405180910390fd5b6001600160a01b0381166000908152601d6020526040812054611170612227565b61117a91906146dd565b6001600160a01b0383166000908152601e602052604090205461119d91906146f4565b905060005b60205481101561100757826001600160a01b0316602082815481106111c9576111c9614779565b6000918252602090912001546001600160a01b0316036112fc57602080546111f3906001906146f4565b8154811061120357611203614779565b9060005260206000200160009054906101000a90046001600160a01b03166020828154811061123457611234614779565b600091825260208083209190910180546001600160a01b0319166001600160a01b039485161790559185168152601d82526040808220829055601e90925290812080548492906112859084906146f4565b92505081905550816022600082825461129e91906146f4565b90915550506001600160a01b0383166000908152601f60209081526040909120805460ff191690558054806112d5576112d561478f565b600082815260209020810160001990810180546001600160a01b0319169055019055505050565b6001016111a2565b60175462010000900460ff1661132d5760405163bcb8b8fb60e01b815260040160405180910390fd5b6113373382612753565b50565b6113426121fa565b6001600160a01b0381166113695760405163d92e233d60e01b815260040160405180910390fd5b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b6113936121fa565b60175460ff166113b657604051630dc5d0f360e31b815260040160405180910390fd5b601754610100900460ff16156113df57604051632b0039c760e21b815260040160405180910390fd5b60006001600160a01b038416739f278dc799bbc61ecb8e5fb8035cbfa29803623b1461140c576001611419565b60155462010000900460ff165b6001600160a01b03851660009081526019602052604090205460ff91821692501681900361145a57604051632b0039c760e21b815260040160405180910390fd5b6001600160a01b0384166000908152601a602052604081205460ff169081900361149757604051632b0039c760e21b815260040160405180910390fd5b60006114b2601054838560646114ad91906146dd565b6122b3565b905080601160008282546114c691906147a5565b90915550600090506114da8783888861286e565b6001600160a01b038816600090815260186020908152604080832080548501905560199091529020805460ff19811660ff918216600101821617909155601554601054601154939450600419620100009092049092169091030111611549576017805461ff0019166101001790555b50505050505050565b61155a6121fa565b6001600160a01b0381166115815760405163d92e233d60e01b815260040160405180910390fd5b600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6115ab6121fa565b6001600160a01b0381166115d25760405163d92e233d60e01b815260040160405180910390fd5b600780546001600160a01b0319166001600160a01b0392909216919091179055565b6115fc6121fa565b600e5481108061160d575060215481115b1561162b57604051632b0039c760e21b815260040160405180910390fd5b600f55565b6116386121fa565b6001600160a01b0381166000908152601f602052604090205460ff16156116725760405163c87d620b60e01b815260040160405180910390fd5b60205460160361169557604051632b0039c760e21b815260040160405180910390fd5b306001600160a01b038216036116be57604051632b0039c760e21b815260040160405180910390fd5b6001600160a01b0381166000908152601e602052604090205415611718576001600160a01b0381166000908152601e60205260409020546116fe906110d7565b6001600160a01b0382166000908152601d60205260409020555b6001600160a01b03166000818152601f602090815260408220805460ff191660019081179091558154908101825591527fc97bfaf2f8ee708c303a06d134f5ecd8389ae0432af62dc132a24118292866bb0180546001600160a01b0319169091179055565b6117856121fa565b8061ffff166096141580156117a057508061ffff1661012c14155b80156117b257508061ffff166101c214155b80156117c457508061ffff1661025814155b156117e257604051632b0039c760e21b815260040160405180910390fd5b600c805461ffff909216600160b01b0261ffff60b01b19909216919091179055565b60175460009060ff1615801561182257506001600160a01b03821630145b1561182f57506000919050565b6001600160a01b0382166000908152601f602052604090205460ff161561186c57506001600160a01b03166000908152601d602052604090205490565b6001600160a01b0382166000908152601e6020526040902054610cf0906110d7565b6118966121fa565b6118a06000612905565b565b6118aa6121fa565b601e8161ffff1610806118c257506101f48161ffff16115b156118e057604051632b0039c760e21b815260040160405180910390fd5b600c805461ffff909216600160a01b0261ffff60a01b19909216919091179055565b60065433906001600160a01b0316811461193f5760405163118cdaa760e01b81526001600160a01b03821660048201526024015b60405180910390fd5b61133781612905565b6119506121fa565b8061196e5760405163af458c0760e01b815260040160405180910390fd5b601c55565b61197b6121fa565b6001600160a01b0381166119a25760405163d92e233d60e01b815260040160405180910390fd5b600880546001600160a01b0319166001600160a01b0392909216919091179055565b606060048054610e4890614707565b6119db6121fa565b6001600160a01b038116611a025760405163d92e233d60e01b815260040160405180910390fd5b600c80546001600160a01b0319166001600160a01b0392909216919091179055565b611a2c6121fa565b601654600003611a4f576040516335c33e8160e01b815260040160405180910390fd5b601654421015611a7257604051630dc5d0f360e31b815260040160405180910390fd5b600b546001600160a01b0316611a9b5760405163d92e233d60e01b815260040160405180910390fd5b60175460ff1615611abf57604051632b0039c760e21b815260040160405180910390fd5b611ac761291e565b6000601254601b54602154611adc91906146f4565b611ae691906146f4565b90506000611af2612227565b611afc90836146dd565b306000908152601e6020526040812080549293508392909190611b209084906146f4565b925050819055508060226000828254611b3991906146f4565b9091555050601254601b54611b4e91906147a5565b6021556017805460ff1916600117905560125460405130916000916000805160206149f683398151915291611b869190815260200190565b60405180910390a35050565b600033610ed98185856126f4565b6016544210611bc2576040516335c33e8160e01b815260040160405180910390fd5b82600003611be35760405163af458c0760e01b815260040160405180910390fd5b611c133330611bf686633b9aca006146dd565b73f19308f923582a6f7c465e5ce7a9dc1bec6665b1929190612b97565b611c1e838383612bfe565b9250602154606484601b54611c3391906147a5565b611c3e9060876146dd565b611c489190614757565b1115611c6757604051632cdb04a160e21b815260040160405180910390fd5b6110073384612cb7565b611c796121fa565b60175460ff16611c9c57604051630dc5d0f360e31b815260040160405180910390fd5b60155460ff62010000820481166101009092041603611cce57604051632b0039c760e21b815260040160405180910390fd5b601554601354600091611ceb916201000090910460ff1690614757565b90506000611d0f7396a5399d07896f757bd4c6ef56461f58db95186283868661286e565b60148054820190556015805460ff61010080830482166001018216810261ff001990931692909217928390559293506201000082048316910490911603611d8157600c54601454611d81917396a5399d07896f757bd4c6ef56461f58db951862916001600160a01b0390911690612da1565b50505050565b611d8f6121fa565b8060ff16600003611db35760405163af458c0760e01b815260040160405180910390fd5b60328160ff161115611dd857604051632b0039c760e21b815260040160405180910390fd5b60175460ff1615611dfc57604051632b0039c760e21b815260040160405180910390fd5b6015805460ff909216620100000262ff000019909216919091179055565b60175462010000900460ff16611e435760405163bcb8b8fb60e01b815260040160405180910390fd5b6000611e4e30611804565b9050600e54811015611e7357604051638cf6ea4760e01b815260040160405180910390fd5b6000600f548211611e845781611e88565b600f545b9050611e943382612dd2565b90506000611ea3600283614757565b9050611eb0818686612edb565b6000611ebd600484614757565b90506000611eca82610ee3565b306000908152601e6020526040812080549293508392909190611eee9084906146f4565b9091555050600a546001600160a01b03166000908152601e602052604081208054839290611f1d9084906147a5565b9091555050600a546001600160a01b03166000908152601f602052604090205460ff1615611f7557600a546001600160a01b03166000908152601d602052604081208054849290611f6f9084906147a5565b90915550505b611f7f3083612753565b6040517fe73cd0ae9190252ead6bdd36344196cf2785eab9dc5a6d93d662b616d735e2b990600090a150505050505050565b611fb96121fa565b60175462010000900460ff161580611fe45750601554610100810460ff908116620100009092041614155b1561200257604051632b0039c760e21b815260040160405180910390fd5b6040516370a0823160e01b815230600482015273f19308f923582a6f7c465e5ce7a9dc1bec6665b19061133790339083906370a0823190602401602060405180830381865afa158015612059573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061207d91906147b8565b6001600160a01b0384169190612da1565b60165442106120b0576040516335c33e8160e01b815260040160405180910390fd5b836000036120d15760405163af458c0760e01b815260040160405180910390fd5b60006120e185633b9aca006146dd565b905060006120ef8284612ffe565b905081811115612123576121233361210784846146f4565b73f19308f923582a6f7c465e5ce7a9dc1bec6665b19190612da1565b61212e868686612bfe565b9550602154606487601b5461214391906147a5565b61214e9060876146dd565b6121589190614757565b111561217757604051632cdb04a160e21b815260040160405180910390fd5b6121813387612cb7565b505050505050565b6121916121fa565b600680546001600160a01b0383166001600160a01b031990911681179091556121c26005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6005546001600160a01b031633146118a05760405163118cdaa760e01b8152336004820152602401611936565b600080600061223461317b565b90925090506122438183614757565b9250505090565b6001600160a01b0383166000908152601e602052604090205482811015611d815783612275826110d7565b60405163391434e360e21b81526001600160a01b039092166004830152602482015260448101839052606401611936565b6110078383836001613256565b60008080600019858709858702925082811083820303915050806000036122ec57600084116122e157600080fd5b508290049050610f1c565b8084116122f857600080fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b6000806123718561332b565b90925090508115612388576123888185858561350d565b739f278dc799bbc61ecb8e5fb8035cbfa29803623a196001600160a01b0386160161244b576001600160a01b038116612442576040516364e329cb60e11b81523060048201526001600160a01b0386166024820152735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f9063c9c65396906044016020604051808303816000875af115801561241b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243f91906147d1565b90505b61244b81611630565b81156125415761245c308285613681565b60405163a9059cbb60e01b81526001600160a01b0382811660048301526024820186905286169063a9059cbb906044016020604051808303816000875af11580156124ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124cf91906147ee565b506040516335313c2160e11b8152600060048201526001600160a01b03821690636a627842906024016020604051808303816000875af1158015612517573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061253b91906147b8565b50612639565b61256030737a250d5630b4cf539739df2c5dacb4c659f2488d85613941565b6125886001600160a01b038616737a250d5630b4cf539739df2c5dacb4c659f2488d86613941565b60405162e8e33760e81b81523060048201526001600160a01b038616602482015260448101849052606481018590526084810184905260a48101859052600060c48201524260e4820152737a250d5630b4cf539739df2c5dacb4c659f2488d9063e8e3370090610104016060604051808303816000875af1158015612611573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126359190614810565b5050505b5050505050565b6017805462ff00001916620100001790556040517f799663458a5ef2936f7fa0c99b3336c69c25890f82974f04e811e5bb359186c790600090a1565b6001600160a01b038381166000908152600160209081526040808320938616835292905220546000198114611d8157818110156126e557604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401611936565b611d8184848484036000613256565b6001600160a01b03831661271e57604051634b637e8f60e11b815260006004820152602401611936565b6001600160a01b0382166127485760405163ec442f0560e01b815260006004820152602401611936565b611007838383613681565b600061275d612227565b61276790836146dd565b905061277483828461224a565b6001600160a01b0383166000908152601e60205260408120805483929061279c9084906146f4565b90915550506001600160a01b0383166000908152601f602052604090205460ff16156127f0576001600160a01b0383166000908152601d6020526040812080548492906127ea9084906146f4565b90915550505b806022600082825461280291906146f4565b92505081905550816021600082825461281b91906146f4565b9250508190555081600d600082825461283491906147a5565b90915550506040518281526000906001600160a01b038516906000805160206149f6833981519152906020015b60405180910390a3505050565b60007396a5399d07896f757bd4c6ef56461f58db951861196001600160a01b038616016128a8576128a1858585856139cb565b90506128fd565b73e9a53c43a0b58706e67341c4055de861e29ee942196001600160a01b038616016128d9576128a185858585613ad3565b6128fa857396a5399d07896f757bd4c6ef56461f58db951862868686613cf2565b90505b949350505050565b600680546001600160a01b031916905561133781613e42565b6040516370a0823160e01b815230600482015273f19308f923582a6f7c465e5ce7a9dc1bec6665b19060009082906370a0823190602401602060405180830381865afa158015612972573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061299691906147b8565b905060646129a56023836146dd565b6129af9190614757565b60108190556129c390633b9aca0090614757565b60125560646129d36023836146dd565b6129dd9190614757565b601355600060646129ef6005846146dd565b6129f99190614757565b905060006064612a0a6005856146dd565b612a149190614757565b905060006064612a256008866146dd565b612a2f9190614757565b905060006064612a406001876146dd565b612a4a9190614757565b90506000818385876013546010548b612a6391906146f4565b612a6d91906146f4565b612a7791906146f4565b612a8191906146f4565b612a8b91906146f4565b612a9591906146f4565b600854909150612ab2906001600160a01b03898116911687612da1565b600754612acc906001600160a01b03898116911686612da1565b600954612ae6906001600160a01b03898116911685612da1565b612b0c612afb6005546001600160a01b031690565b6001600160a01b0389169084612da1565b600b54612b26906001600160a01b03898116911683612da1565b600860009054906101000a90046001600160a01b03166001600160a01b0316637196e8416040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612b7657600080fd5b505af1158015612b8a573d6000803e3d6000fd5b5050505050505050505050565b6040516001600160a01b038481166024830152838116604483015260648201839052611d819186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050613e94565b600061ffff831615612caf576040516bffffffffffffffffffffffff193360601b1660208201526001600160f01b031960f085901b166034820152600090603601604051602081830303815290604052805190602001209050612c6483601c5483613ef7565b612c8157604051636397109b60e11b815260040160405180910390fd5b6000612710612c9461ffff8716886146dd565b612c9e9190614757565b9050612caa81876147a5565b955050505b509192915050565b6000612cc1612227565b612ccb90836146dd565b306000908152601e6020526040812080549293508392909190612cef9084906146f4565b9091555050336000908152601e602052604081208054839290612d139084906147a5565b90915550506001600160a01b0383166000908152601f602052604090205460ff1615612d5e57336000908152601d602052604081208054849290612d589084906147a5565b90915550505b81601b6000828254612d7091906147a5565b90915550506040518281526001600160a01b038416906000906000805160206149f683398151915290602001612861565b6040516001600160a01b0383811660248301526044820183905261100791859182169063a9059cbb90606401612bcc565b600080612dde83610ee3565b600c54909150600090612e00908390600160a01b900461ffff166127106122b3565b600c54909150600090612e22908690600160a01b900461ffff166127106122b3565b306000908152601e6020526040812080549293508492909190612e469084906146f4565b90915550506001600160a01b0386166000908152601e602052604081208054849290612e739084906147a5565b90915550506001600160a01b0386166000908152601f602052604090205460ff1615612ec7576001600160a01b0386166000908152601d602052604081208054839290612ec19084906147a5565b90915550505b612ed181866146f4565b9695505050505050565b612efa30737a250d5630b4cf539739df2c5dacb4c659f2488d85613941565b6040805160028082526060820183526000926020830190803683370190505090503081600081518110612f2f57612f2f614779565b60200260200101906001600160a01b031690816001600160a01b0316815250507396a5399d07896f757bd4c6ef56461f58db95186281600181518110612f7757612f77614779565b6001600160a01b039283166020918202929092010152600c54604051635c11d79560e01b8152737a250d5630b4cf539739df2c5dacb4c659f2488d92635c11d79592612fd092899289928892911690899060040161483e565b600060405180830381600087803b158015612fea57600080fd5b505af1158015612635573d6000803e3d6000fd5b600073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561304f57600080fd5b505af1158015613063573d6000803e3d6000fd5b5050604080516101008101825273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc280825273f19308f923582a6f7c465e5ce7a9dc1bec6665b1602083015261271092820192909252306060820152608081018790523460a0820181905260c08201899052600060e08301529094506130f5935090915073e592427a0aece92de3edee1f18e0157c0586156490613941565b60405163414bf38960e01b815260009073e592427a0aece92de3edee1f18e0157c058615649063414bf3899061312f9085906004016148b1565b6020604051808303816000875af115801561314e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061317291906147b8565b95945050505050565b6022546021546000918291825b602054811015613225576000602082815481106131a7576131a7614779565b60009182526020808320909101546001600160a01b0316808352601e8252604080842054601d9093529092205491925090858211806131e557508481115b156131fe57602254602154975097505050505050509091565b61320882876146f4565b955061321481866146f4565b945050600190920191506131889050565b506021546022546132369190614757565b82101561324d576022546021549350935050509091565b90939092509050565b6001600160a01b0384166132805760405163e602df0560e01b815260006004820152602401611936565b6001600160a01b0383166132aa57604051634a1406b160e11b815260006004820152602401611936565b6001600160a01b0380851660009081526001602090815260408083209387168352929052208290558015611d8157826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161331d91815260200190565b60405180910390a350505050565b60405163e6a4390560e01b81523060048201526001600160a01b038216602482015260009081908190735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f9063e6a4390590604401602060405180830381865afa158015613390573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133b491906147d1565b90506001600160a01b0381166133cf57600094909350915050565b806001600160a01b03811663bc25cf776133f16005546001600160a01b031690565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401600060405180830381600087803b15801561343257600080fd5b505af1158015613446573d6000803e3d6000fd5b50505050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa15801561348b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134af9190614931565b5091509150816001600160701b03166000146134da57506001600160701b0316959194509092505050565b6001600160701b038116156134fe576001600160701b031696929550919350505050565b50600096929550919350505050565b60008361351a84846146dd565b6135249190614757565b905080600003613532575060015b600061353c612227565b61354690836146dd565b6001600160a01b0387166000908152601e60205260408120805492935083929091906135739084906147a5565b90915550506001600160a01b0386166000908152601f602052604090205460ff16156135c7576001600160a01b0386166000908152601d6020526040812080548492906135c19084906147a5565b90915550505b80602260008282546135d991906147a5565b9250508190555081602160008282546135f291906147a5565b90915550506040518281526001600160a01b038716906000906000805160206149f68339815191529060200160405180910390a3856001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561366157600080fd5b505af1158015613675573d6000803e3d6000fd5b50505050505050505050565b60175462010000900460ff16156138235760008060008060006136a386613f0d565b945094509450945094506136b888868861224a565b6001600160a01b0388166000908152601e6020526040812080548792906136e09084906146f4565b90915550506001600160a01b0388166000908152601f602052604090205460ff1615613734576001600160a01b0388166000908152601d60205260408120805488929061372e9084906146f4565b90915550505b6001600160a01b0387166000908152601e60205260408120805486929061375c9084906147a5565b90915550506001600160a01b0387166000908152601f602052604090205460ff16156137b0576001600160a01b0387166000908152601d6020526040812080548392906137aa9084906147a5565b90915550505b306000908152601e6020526040812080548492906137cf9084906147a5565b909155506137de905083613f63565b866001600160a01b0316886001600160a01b03166000805160206149f68339815191528360405161381191815260200190565b60405180910390a35050505050505050565b6001600160a01b038316301461384c5760405163bcb8b8fb60e01b815260040160405180910390fd5b6000613856612227565b61386090836146dd565b6001600160a01b0385166000908152601e602052604081208054929350839290919061388d9084906146f4565b90915550506001600160a01b0383166000908152601e6020526040812080548392906138ba9084906147a5565b90915550506001600160a01b0383166000908152601f602052604090205460ff161561390e576001600160a01b0383166000908152601d6020526040812080548492906139089084906147a5565b90915550505b826001600160a01b0316846001600160a01b03166000805160206149f68339815191528460405161331d91815260200190565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015613991573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139b591906147b8565b9050611d8184846139c685856147a5565b613f7d565b604080516101008101825273f19308f923582a6f7c465e5ce7a9dc1bec6665b18082526001600160a01b0387166020830152612710928201929092523060608201526080810183905260a0810185905260c08101849052600060e0820181905291613a4b9073e592427a0aece92de3edee1f18e0157c0586156487613941565b60405163414bf38960e01b815260009073e592427a0aece92de3edee1f18e0157c058615649063414bf38990613a859085906004016148b1565b6020604051808303816000875af1158015613aa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ac891906147b8565b979650505050505050565b6000613b0873f19308f923582a6f7c465e5ce7a9dc1bec6665b1737a250d5630b4cf539739df2c5dacb4c659f2488d86613941565b6040516370a0823160e01b81523060048201526000906001600160a01b038716906370a0823190602401602060405180830381865afa158015613b4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b7391906147b8565b604080516002808252606082018352929350600092909160208301908036833701905050905073f19308f923582a6f7c465e5ce7a9dc1bec6665b181600081518110613bc157613bc1614779565b60200260200101906001600160a01b031690816001600160a01b0316815250508681600181518110613bf557613bf5614779565b6001600160a01b0390921660209283029190910190910152604051635c11d79560e01b8152737a250d5630b4cf539739df2c5dacb4c659f2488d90635c11d79590613c4c9089908990869030908b9060040161483e565b600060405180830381600087803b158015613c6657600080fd5b505af1158015613c7a573d6000803e3d6000fd5b50506040516370a0823160e01b81523060048201528492506001600160a01b038a1691506370a0823190602401602060405180830381865afa158015613cc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce891906147b8565b613ac891906146f4565b60405173f19308f923582a6f7c465e5ce7a9dc1bec6665b160601b602082015261027160ec1b60348201819052606086811b6bffffffffffffffffffffffff199081166037850152604b84019290925287901b16604e820152600090819060620160408051601f1981840301815260a08301825280835230602084015290820185905260608201879052608082018690529150613db873f19308f923582a6f7c465e5ce7a9dc1bec6665b173e592427a0aece92de3edee1f18e0157c0586156488613941565b60405163c04b8d5960e01b815260009073e592427a0aece92de3edee1f18e0157c058615649063c04b8d5990613df2908590600401614981565b6020604051808303816000875af1158015613e11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e3591906147b8565b9998505050505050505050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000613ea96001600160a01b0384168361400d565b90508051600014158015613ece575080806020019051810190613ecc91906147ee565b155b1561100757604051635274afe760e01b81526001600160a01b0384166004820152602401611936565b600082613f04858461401b565b14949350505050565b600080600080600080600080613f228961405e565b9250925092506000613f32612227565b9050600080600080613f468e8888886140bb565b929f50909d509b5099509697505050505050505091939590929450565b8060226000828254613f7591906146f4565b909155505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052613fce8482614114565b611d81576040516001600160a01b0384811660248301526000604483015261400391869182169063095ea7b390606401612bcc565b611d818482613e94565b6060610f1c838360006141b7565b600081815b84518110156140565761404c8286838151811061403f5761403f614779565b602002602001015161424a565b9150600101614020565b509392505050565b60008060008061408585600c60169054906101000a900461ffff1661ffff16612710614279565b90506000614094606487614757565b90506000816140a384896146f4565b6140ad91906146f4565b979296509094509092505050565b6000808080806140cb868a6146dd565b905060006140d9878a6146dd565b905060006140e7888a6146dd565b90506000816140f684866146f4565b61410091906146f4565b939c939b5091995097509095505050505050565b6000806000846001600160a01b03168460405161413191906149d9565b6000604051808303816000865af19150503d806000811461416e576040519150601f19603f3d011682016040523d82523d6000602084013e614173565b606091505b509150915081801561419d57508051158061419d57508080602001905181019061419d91906147ee565b80156131725750505050506001600160a01b03163b151590565b6060814710156141dc5760405163cd78605960e01b8152306004820152602401611936565b600080856001600160a01b031684866040516141f891906149d9565b60006040518083038185875af1925050503d8060008114614235576040519150601f19603f3d011682016040523d82523d6000602084013e61423a565b606091505b5091509150612ed18683836142b9565b6000818310614266576000828152602084905260409020610f1c565b6000838152602083905260409020610f1c565b60006142868484846122b3565b90506000828061429857614298614741565b8486091115610f1c5760001981106142af57600080fd5b6001019392505050565b6060826142ce576142c982614315565b610f1c565b81511580156142e557506001600160a01b0384163b155b1561430e57604051639996b31560e01b81526001600160a01b0385166004820152602401611936565b5080610f1c565b8051156143255780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b60006020828403121561435057600080fd5b81356001600160e01b031981168114610f1c57600080fd5b60006020828403121561437a57600080fd5b5035919050565b60005b8381101561439c578181015183820152602001614384565b50506000910152565b600081518084526143bd816020860160208601614381565b601f01601f19169290920160200192915050565b602081526000610f1c60208301846143a5565b6001600160a01b038116811461133757600080fd5b6000806040838503121561440c57600080fd5b8235614417816143e4565b946020939093013593505050565b60006020828403121561443757600080fd5b8135610f1c816143e4565b60008060006060848603121561445757600080fd5b8335614462816143e4565b92506020840135614472816143e4565b929592945050506040919091013590565b60008060006060848603121561449857600080fd5b83356144a3816143e4565b95602085013595506040909401359392505050565b803561ffff811681146144ca57600080fd5b919050565b6000602082840312156144e157600080fd5b610f1c826144b8565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261451157600080fd5b8135602067ffffffffffffffff8083111561452e5761452e6144ea565b8260051b604051601f19603f83011681018181108482111715614553576145536144ea565b604052938452602081870181019490810192508785111561457357600080fd5b6020870191505b84821015613ac85781358352918301919083019061457a565b6000806000606084860312156145a857600080fd5b833592506145b8602085016144b8565b9150604084013567ffffffffffffffff8111156145d457600080fd5b6145e086828701614500565b9150509250925092565b600080604083850312156145fd57600080fd5b50508035926020909101359150565b60006020828403121561461e57600080fd5b813560ff81168114610f1c57600080fd5b6000806040838503121561464257600080fd5b823561464d816143e4565b9150602083013561465d816143e4565b809150509250929050565b6000806000806080858703121561467e57600080fd5b8435935061468e602086016144b8565b9250604085013567ffffffffffffffff8111156146aa57600080fd5b6146b687828801614500565b949793965093946060013593505050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610cf057610cf06146c7565b81810381811115610cf057610cf06146c7565b600181811c9082168061471b57607f821691505b60208210810361473b57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601260045260246000fd5b60008261477457634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b80820180821115610cf057610cf06146c7565b6000602082840312156147ca57600080fd5b5051919050565b6000602082840312156147e357600080fd5b8151610f1c816143e4565b60006020828403121561480057600080fd5b81518015158114610f1c57600080fd5b60008060006060848603121561482557600080fd5b8351925060208401519150604084015190509250925092565b600060a08201878352602087602085015260a0604085015281875180845260c08601915060208901935060005b818110156148905784516001600160a01b03168352938301939183019160010161486b565b50506001600160a01b03969096166060850152505050608001529392505050565b81516001600160a01b03908116825260208084015182169083015260408084015162ffffff16908301526060808401518216908301526080808401519083015260a0838101519083015260c0808401519083015260e09283015116918101919091526101000190565b80516001600160701b03811681146144ca57600080fd5b60008060006060848603121561494657600080fd5b61494f8461491a565b925061495d6020850161491a565b9150604084015163ffffffff8116811461497657600080fd5b809150509250925092565b602081526000825160a0602084015261499d60c08401826143a5565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b600082516149eb818460208701614381565b919091019291505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212202fad6dd8a99467f3a9b6773d40626d59b49b0be087206ec078a8f280993e7a4364736f6c634300081800330000000000000000000000009b3ba6b585188d5b0510ddbb26681cf7233c96b000000000000000000000000019dd7ded6efecfc977c0e0394bfa247e4349cd4a000000000000000000000000ad6e32a8d0463c32297208c5c107a5571aea2f95000000000000000000000000a2d21205aa7273baddfc8e9551e05e23bb49ce4600000000000000000000000096a5399d07896f757bd4c6ef56461f58db951862000000000000000000000000836cad9ea4e47c6a8969c2f48f908b32864a6617000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000050000000000000000000000009f278dc799bbc61ecb8e5fb8035cbfa29803623b00000000000000000000000096a5399d07896f757bd4c6ef56461f58db951862000000000000000000000000cc7ed2ab6c3396ddbc4316d2d7c1b59ff9d2091f000000000000000000000000a99afcc6aa4530d01dfff8e55ec66e4c424c048c000000000000000000000000e9a53c43a0b58706e67341c4055de861e29ee9430000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000a

Deployed Bytecode

0x6080604052600436106104055760003560e01c80636d49809311610213578063a0a6e94011610123578063df90ebe8116100ab578063eefc1ea81161007a578063eefc1ea814610c11578063f2fde38b14610c41578063f468fa0714610c61578063f8d9beca14610c80578063fe22441614610ca057600080fd5b8063df90ebe814610bab578063e0360bf214610bc0578063e30c397814610bd3578063e823744714610bf157600080fd5b8063cba0e996116100f2578063cba0e99614610ad6578063d1fe848414610b0f578063d89135cd14610b2f578063d9b8924414610b45578063dd62ed3e14610b6557600080fd5b8063a0a6e94014610a61578063a9059cbb14610a76578063b0c7d44c14610a96578063b380e85414610ab657600080fd5b80637f3de26d116101a6578063847e7fe611610175578063847e7fe6146109ce5780638da5cb5b146109ee5780638ea5220f14610a0c57806395d89b4114610a2c5780639a69f3c014610a4157600080fd5b80637f3de26d1461094957806381432b98146109695780638238e9da1461097f57806383ad7994146109ac57600080fd5b806372637791116101e257806372637791146108d457806375f0a874146108f457806379ba5097146109145780637cb647591461092957600080fd5b80636d498093146108655780636e360be11461087f57806370a082311461089f578063715018a6146108bf57600080fd5b8063313ce567116103195780635d098b38116102a15780635fb064d0116102705780635fb064d0146107d857806360d938dc146107f857806363841a5f1461080f57806366f5fe4f1461082f578063676e0e1b1461084f57600080fd5b80635d098b38146107685780635d61456d146107885780635ee2230a146107a25780635f72c3c3146107b857600080fd5b80633e2dd012116102e85780633e2dd012146106d257806342966c68146106e857806347e836e0146107085780634ada218b1461072857806351410bef1461074857600080fd5b8063313ce567146106285780633394e5bb1461064a57806334eecc661461066a5780633d5e6a3f146106a257600080fd5b80631392c0861161039c5780631f53ac021161036b5780631f53ac021461059257806321ae2a09146105b2578063229f3e29146105d257806323b872dd146105e85780632d8381191461060857600080fd5b80631392c086146105275780631812dbab1461054757806318160ddd146105675780631b4af2211461057c57600080fd5b8063053ab182116103d8578063053ab1821461049057806306903900146104b057806306fdde03146104e5578063095ea7b31461050757600080fd5b80630133bb8a1461040a57806301ffc9a7146104335780630447d4a91461046357806304c98b2b14610479575b600080fd5b34801561041657600080fd5b50610420600f5481565b6040519081526020015b60405180910390f35b34801561043f57600080fd5b5061045361044e36600461433e565b610cbf565b604051901515815260200161042a565b34801561046f57600080fd5b5061042060125481565b34801561048557600080fd5b5061048e610cf6565b005b34801561049c57600080fd5b5061048e6104ab366004614368565b610d73565b3480156104bc57600080fd5b50600c546104d290600160a01b900461ffff1681565b60405161ffff909116815260200161042a565b3480156104f157600080fd5b506104fa610e39565b60405161042a91906143d1565b34801561051357600080fd5b506104536105223660046143f9565b610ecb565b34801561053357600080fd5b50610420610542366004614368565b610ee3565b34801561055357600080fd5b5061048e610562366004614425565b610f23565b34801561057357600080fd5b5061042061100c565b34801561058857600080fd5b5061042060145481565b34801561059e57600080fd5b5061048e6105ad366004614425565b611027565b3480156105be57600080fd5b5061048e6105cd366004614368565b611078565b3480156105de57600080fd5b5061042060165481565b3480156105f457600080fd5b50610453610603366004614442565b6110b3565b34801561061457600080fd5b50610420610623366004614368565b6110d7565b34801561063457600080fd5b5060095b60405160ff909116815260200161042a565b34801561065657600080fd5b5061048e610665366004614425565b61110e565b34801561067657600080fd5b5060075461068a906001600160a01b031681565b6040516001600160a01b03909116815260200161042a565b3480156106ae57600080fd5b506106386106bd366004614425565b60196020526000908152604090205460ff1681565b3480156106de57600080fd5b5061042060105481565b3480156106f457600080fd5b5061048e610703366004614368565b611304565b34801561071457600080fd5b5061048e610723366004614425565b61133a565b34801561073457600080fd5b506017546104539062010000900460ff1681565b34801561075457600080fd5b5061048e610763366004614483565b61138b565b34801561077457600080fd5b5061048e610783366004614425565b611552565b34801561079457600080fd5b506015546106389060ff1681565b3480156107ae57600080fd5b5061042060115481565b3480156107c457600080fd5b5061048e6107d3366004614425565b6115a3565b3480156107e457600080fd5b5061048e6107f3366004614368565b6115f4565b34801561080457600080fd5b506016544210610453565b34801561081b57600080fd5b5061048e61082a366004614425565b611630565b34801561083b57600080fd5b50600b5461068a906001600160a01b031681565b34801561085b57600080fd5b50610420600e5481565b34801561087157600080fd5b506017546104539060ff1681565b34801561088b57600080fd5b5061048e61089a3660046144cf565b61177d565b3480156108ab57600080fd5b506104206108ba366004614425565b611804565b3480156108cb57600080fd5b5061048e61188e565b3480156108e057600080fd5b5061048e6108ef3660046144cf565b6118a2565b34801561090057600080fd5b50600a5461068a906001600160a01b031681565b34801561092057600080fd5b5061048e611902565b34801561093557600080fd5b5061048e610944366004614368565b611948565b34801561095557600080fd5b5061048e610964366004614425565b611973565b34801561097557600080fd5b5061042060135481565b34801561098b57600080fd5b5061042061099a366004614425565b60186020526000908152604090205481565b3480156109b857600080fd5b50600c546104d290600160b01b900461ffff1681565b3480156109da57600080fd5b506015546106389062010000900460ff1681565b3480156109fa57600080fd5b506005546001600160a01b031661068a565b348015610a1857600080fd5b5060095461068a906001600160a01b031681565b348015610a3857600080fd5b506104fa6119c4565b348015610a4d57600080fd5b5061048e610a5c366004614425565b6119d3565b348015610a6d57600080fd5b5061048e611a24565b348015610a8257600080fd5b50610453610a913660046143f9565b611b92565b348015610aa257600080fd5b5061048e610ab1366004614593565b611ba0565b348015610ac257600080fd5b5061048e610ad13660046145ea565b611c71565b348015610ae257600080fd5b50610453610af1366004614425565b6001600160a01b03166000908152601f602052604090205460ff1690565b348015610b1b57600080fd5b5061048e610b2a36600461460c565b611d87565b348015610b3b57600080fd5b50610420600d5481565b348015610b5157600080fd5b5061048e610b603660046145ea565b611e1a565b348015610b7157600080fd5b50610420610b8036600461462f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b348015610bb757600080fd5b5061048e611fb1565b61048e610bce366004614668565b61208e565b348015610bdf57600080fd5b506006546001600160a01b031661068a565b348015610bfd57600080fd5b5060085461068a906001600160a01b031681565b348015610c1d57600080fd5b50610638610c2c366004614425565b601a6020526000908152604090205460ff1681565b348015610c4d57600080fd5b5061048e610c5c366004614425565b612189565b348015610c6d57600080fd5b5060175461045390610100900460ff1681565b348015610c8c57600080fd5b50600c5461068a906001600160a01b031681565b348015610cac57600080fd5b5060155461063890610100900460ff1681565b60006001600160e01b031982166336372b0760e01b1480610cf057506001600160e01b031982166301ffc9a760e01b145b92915050565b610cfe6121fa565b60165415610d1f57604051632b0039c760e21b815260040160405180910390fd5b601c54610d3f57604051636397109b60e11b815260040160405180910390fd5b4262127500016016556040517f17c3338141363aab2512c08f8a7764328ca95979f7057663eb93f7e250139b4c90600090a1565b60175462010000900460ff16610d9c5760405163bcb8b8fb60e01b815260040160405180910390fd5b336000818152601f602052604090205460ff1615610dcd5760405163c87d620b60e01b815260040160405180910390fd5b6000610dd7612227565b610de190846146dd565b9050610dee82828561224a565b6001600160a01b0382166000908152601e602052604081208054839290610e169084906146f4565b925050819055508060226000828254610e2f91906146f4565b9091555050505050565b606060038054610e4890614707565b80601f0160208091040260200160405190810160405280929190818152602001828054610e7490614707565b8015610ec15780601f10610e9657610100808354040283529160200191610ec1565b820191906000526020600020905b815481529060010190602001808311610ea457829003601f168201915b5050505050905090565b600033610ed98185856122a6565b5060019392505050565b6000602154821115610f0857604051632cdb04a160e21b815260040160405180910390fd5b6000610f12612227565b610f1c90846146dd565b9392505050565b610f2b6121fa565b601754610100900460ff16610f5357604051632b0039c760e21b815260040160405180910390fd5b6001600160a01b03811660009081526018602052604081205490819003610f8d57604051632b0039c760e21b815260040160405180910390fd5b6012546001600160a01b0383166000908152601a60205260408120549091610fb99160ff1660646122b3565b9050610fc6838383612365565b6001600160a01b0383166000908152601860205260408120556015805460ff8082166001011660ff1990911681179091556004190161100757611007612640565b505050565b60175460009060ff166110205750601b5490565b5060215490565b61102f6121fa565b6001600160a01b0381166110565760405163d92e233d60e01b815260040160405180910390fd5b600980546001600160a01b0319166001600160a01b0392909216919091179055565b6110806121fa565b60648110806110905750600f5481115b156110ae57604051632b0039c760e21b815260040160405180910390fd5b600e55565b6000336110c185828561267c565b6110cc8585856126f4565b506001949350505050565b60006022548211156110fc57604051632cdb04a160e21b815260040160405180910390fd5b611104612227565b610cf09083614757565b6111166121fa565b6001600160a01b0381166000908152601f602052604090205460ff1661114f5760405163c87d620b60e01b815260040160405180910390fd5b6001600160a01b0381166000908152601d6020526040812054611170612227565b61117a91906146dd565b6001600160a01b0383166000908152601e602052604090205461119d91906146f4565b905060005b60205481101561100757826001600160a01b0316602082815481106111c9576111c9614779565b6000918252602090912001546001600160a01b0316036112fc57602080546111f3906001906146f4565b8154811061120357611203614779565b9060005260206000200160009054906101000a90046001600160a01b03166020828154811061123457611234614779565b600091825260208083209190910180546001600160a01b0319166001600160a01b039485161790559185168152601d82526040808220829055601e90925290812080548492906112859084906146f4565b92505081905550816022600082825461129e91906146f4565b90915550506001600160a01b0383166000908152601f60209081526040909120805460ff191690558054806112d5576112d561478f565b600082815260209020810160001990810180546001600160a01b0319169055019055505050565b6001016111a2565b60175462010000900460ff1661132d5760405163bcb8b8fb60e01b815260040160405180910390fd5b6113373382612753565b50565b6113426121fa565b6001600160a01b0381166113695760405163d92e233d60e01b815260040160405180910390fd5b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b6113936121fa565b60175460ff166113b657604051630dc5d0f360e31b815260040160405180910390fd5b601754610100900460ff16156113df57604051632b0039c760e21b815260040160405180910390fd5b60006001600160a01b038416739f278dc799bbc61ecb8e5fb8035cbfa29803623b1461140c576001611419565b60155462010000900460ff165b6001600160a01b03851660009081526019602052604090205460ff91821692501681900361145a57604051632b0039c760e21b815260040160405180910390fd5b6001600160a01b0384166000908152601a602052604081205460ff169081900361149757604051632b0039c760e21b815260040160405180910390fd5b60006114b2601054838560646114ad91906146dd565b6122b3565b905080601160008282546114c691906147a5565b90915550600090506114da8783888861286e565b6001600160a01b038816600090815260186020908152604080832080548501905560199091529020805460ff19811660ff918216600101821617909155601554601054601154939450600419620100009092049092169091030111611549576017805461ff0019166101001790555b50505050505050565b61155a6121fa565b6001600160a01b0381166115815760405163d92e233d60e01b815260040160405180910390fd5b600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6115ab6121fa565b6001600160a01b0381166115d25760405163d92e233d60e01b815260040160405180910390fd5b600780546001600160a01b0319166001600160a01b0392909216919091179055565b6115fc6121fa565b600e5481108061160d575060215481115b1561162b57604051632b0039c760e21b815260040160405180910390fd5b600f55565b6116386121fa565b6001600160a01b0381166000908152601f602052604090205460ff16156116725760405163c87d620b60e01b815260040160405180910390fd5b60205460160361169557604051632b0039c760e21b815260040160405180910390fd5b306001600160a01b038216036116be57604051632b0039c760e21b815260040160405180910390fd5b6001600160a01b0381166000908152601e602052604090205415611718576001600160a01b0381166000908152601e60205260409020546116fe906110d7565b6001600160a01b0382166000908152601d60205260409020555b6001600160a01b03166000818152601f602090815260408220805460ff191660019081179091558154908101825591527fc97bfaf2f8ee708c303a06d134f5ecd8389ae0432af62dc132a24118292866bb0180546001600160a01b0319169091179055565b6117856121fa565b8061ffff166096141580156117a057508061ffff1661012c14155b80156117b257508061ffff166101c214155b80156117c457508061ffff1661025814155b156117e257604051632b0039c760e21b815260040160405180910390fd5b600c805461ffff909216600160b01b0261ffff60b01b19909216919091179055565b60175460009060ff1615801561182257506001600160a01b03821630145b1561182f57506000919050565b6001600160a01b0382166000908152601f602052604090205460ff161561186c57506001600160a01b03166000908152601d602052604090205490565b6001600160a01b0382166000908152601e6020526040902054610cf0906110d7565b6118966121fa565b6118a06000612905565b565b6118aa6121fa565b601e8161ffff1610806118c257506101f48161ffff16115b156118e057604051632b0039c760e21b815260040160405180910390fd5b600c805461ffff909216600160a01b0261ffff60a01b19909216919091179055565b60065433906001600160a01b0316811461193f5760405163118cdaa760e01b81526001600160a01b03821660048201526024015b60405180910390fd5b61133781612905565b6119506121fa565b8061196e5760405163af458c0760e01b815260040160405180910390fd5b601c55565b61197b6121fa565b6001600160a01b0381166119a25760405163d92e233d60e01b815260040160405180910390fd5b600880546001600160a01b0319166001600160a01b0392909216919091179055565b606060048054610e4890614707565b6119db6121fa565b6001600160a01b038116611a025760405163d92e233d60e01b815260040160405180910390fd5b600c80546001600160a01b0319166001600160a01b0392909216919091179055565b611a2c6121fa565b601654600003611a4f576040516335c33e8160e01b815260040160405180910390fd5b601654421015611a7257604051630dc5d0f360e31b815260040160405180910390fd5b600b546001600160a01b0316611a9b5760405163d92e233d60e01b815260040160405180910390fd5b60175460ff1615611abf57604051632b0039c760e21b815260040160405180910390fd5b611ac761291e565b6000601254601b54602154611adc91906146f4565b611ae691906146f4565b90506000611af2612227565b611afc90836146dd565b306000908152601e6020526040812080549293508392909190611b209084906146f4565b925050819055508060226000828254611b3991906146f4565b9091555050601254601b54611b4e91906147a5565b6021556017805460ff1916600117905560125460405130916000916000805160206149f683398151915291611b869190815260200190565b60405180910390a35050565b600033610ed98185856126f4565b6016544210611bc2576040516335c33e8160e01b815260040160405180910390fd5b82600003611be35760405163af458c0760e01b815260040160405180910390fd5b611c133330611bf686633b9aca006146dd565b73f19308f923582a6f7c465e5ce7a9dc1bec6665b1929190612b97565b611c1e838383612bfe565b9250602154606484601b54611c3391906147a5565b611c3e9060876146dd565b611c489190614757565b1115611c6757604051632cdb04a160e21b815260040160405180910390fd5b6110073384612cb7565b611c796121fa565b60175460ff16611c9c57604051630dc5d0f360e31b815260040160405180910390fd5b60155460ff62010000820481166101009092041603611cce57604051632b0039c760e21b815260040160405180910390fd5b601554601354600091611ceb916201000090910460ff1690614757565b90506000611d0f7396a5399d07896f757bd4c6ef56461f58db95186283868661286e565b60148054820190556015805460ff61010080830482166001018216810261ff001990931692909217928390559293506201000082048316910490911603611d8157600c54601454611d81917396a5399d07896f757bd4c6ef56461f58db951862916001600160a01b0390911690612da1565b50505050565b611d8f6121fa565b8060ff16600003611db35760405163af458c0760e01b815260040160405180910390fd5b60328160ff161115611dd857604051632b0039c760e21b815260040160405180910390fd5b60175460ff1615611dfc57604051632b0039c760e21b815260040160405180910390fd5b6015805460ff909216620100000262ff000019909216919091179055565b60175462010000900460ff16611e435760405163bcb8b8fb60e01b815260040160405180910390fd5b6000611e4e30611804565b9050600e54811015611e7357604051638cf6ea4760e01b815260040160405180910390fd5b6000600f548211611e845781611e88565b600f545b9050611e943382612dd2565b90506000611ea3600283614757565b9050611eb0818686612edb565b6000611ebd600484614757565b90506000611eca82610ee3565b306000908152601e6020526040812080549293508392909190611eee9084906146f4565b9091555050600a546001600160a01b03166000908152601e602052604081208054839290611f1d9084906147a5565b9091555050600a546001600160a01b03166000908152601f602052604090205460ff1615611f7557600a546001600160a01b03166000908152601d602052604081208054849290611f6f9084906147a5565b90915550505b611f7f3083612753565b6040517fe73cd0ae9190252ead6bdd36344196cf2785eab9dc5a6d93d662b616d735e2b990600090a150505050505050565b611fb96121fa565b60175462010000900460ff161580611fe45750601554610100810460ff908116620100009092041614155b1561200257604051632b0039c760e21b815260040160405180910390fd5b6040516370a0823160e01b815230600482015273f19308f923582a6f7c465e5ce7a9dc1bec6665b19061133790339083906370a0823190602401602060405180830381865afa158015612059573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061207d91906147b8565b6001600160a01b0384169190612da1565b60165442106120b0576040516335c33e8160e01b815260040160405180910390fd5b836000036120d15760405163af458c0760e01b815260040160405180910390fd5b60006120e185633b9aca006146dd565b905060006120ef8284612ffe565b905081811115612123576121233361210784846146f4565b73f19308f923582a6f7c465e5ce7a9dc1bec6665b19190612da1565b61212e868686612bfe565b9550602154606487601b5461214391906147a5565b61214e9060876146dd565b6121589190614757565b111561217757604051632cdb04a160e21b815260040160405180910390fd5b6121813387612cb7565b505050505050565b6121916121fa565b600680546001600160a01b0383166001600160a01b031990911681179091556121c26005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6005546001600160a01b031633146118a05760405163118cdaa760e01b8152336004820152602401611936565b600080600061223461317b565b90925090506122438183614757565b9250505090565b6001600160a01b0383166000908152601e602052604090205482811015611d815783612275826110d7565b60405163391434e360e21b81526001600160a01b039092166004830152602482015260448101839052606401611936565b6110078383836001613256565b60008080600019858709858702925082811083820303915050806000036122ec57600084116122e157600080fd5b508290049050610f1c565b8084116122f857600080fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b6000806123718561332b565b90925090508115612388576123888185858561350d565b739f278dc799bbc61ecb8e5fb8035cbfa29803623a196001600160a01b0386160161244b576001600160a01b038116612442576040516364e329cb60e11b81523060048201526001600160a01b0386166024820152735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f9063c9c65396906044016020604051808303816000875af115801561241b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243f91906147d1565b90505b61244b81611630565b81156125415761245c308285613681565b60405163a9059cbb60e01b81526001600160a01b0382811660048301526024820186905286169063a9059cbb906044016020604051808303816000875af11580156124ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124cf91906147ee565b506040516335313c2160e11b8152600060048201526001600160a01b03821690636a627842906024016020604051808303816000875af1158015612517573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061253b91906147b8565b50612639565b61256030737a250d5630b4cf539739df2c5dacb4c659f2488d85613941565b6125886001600160a01b038616737a250d5630b4cf539739df2c5dacb4c659f2488d86613941565b60405162e8e33760e81b81523060048201526001600160a01b038616602482015260448101849052606481018590526084810184905260a48101859052600060c48201524260e4820152737a250d5630b4cf539739df2c5dacb4c659f2488d9063e8e3370090610104016060604051808303816000875af1158015612611573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126359190614810565b5050505b5050505050565b6017805462ff00001916620100001790556040517f799663458a5ef2936f7fa0c99b3336c69c25890f82974f04e811e5bb359186c790600090a1565b6001600160a01b038381166000908152600160209081526040808320938616835292905220546000198114611d8157818110156126e557604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401611936565b611d8184848484036000613256565b6001600160a01b03831661271e57604051634b637e8f60e11b815260006004820152602401611936565b6001600160a01b0382166127485760405163ec442f0560e01b815260006004820152602401611936565b611007838383613681565b600061275d612227565b61276790836146dd565b905061277483828461224a565b6001600160a01b0383166000908152601e60205260408120805483929061279c9084906146f4565b90915550506001600160a01b0383166000908152601f602052604090205460ff16156127f0576001600160a01b0383166000908152601d6020526040812080548492906127ea9084906146f4565b90915550505b806022600082825461280291906146f4565b92505081905550816021600082825461281b91906146f4565b9250508190555081600d600082825461283491906147a5565b90915550506040518281526000906001600160a01b038516906000805160206149f6833981519152906020015b60405180910390a3505050565b60007396a5399d07896f757bd4c6ef56461f58db951861196001600160a01b038616016128a8576128a1858585856139cb565b90506128fd565b73e9a53c43a0b58706e67341c4055de861e29ee942196001600160a01b038616016128d9576128a185858585613ad3565b6128fa857396a5399d07896f757bd4c6ef56461f58db951862868686613cf2565b90505b949350505050565b600680546001600160a01b031916905561133781613e42565b6040516370a0823160e01b815230600482015273f19308f923582a6f7c465e5ce7a9dc1bec6665b19060009082906370a0823190602401602060405180830381865afa158015612972573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061299691906147b8565b905060646129a56023836146dd565b6129af9190614757565b60108190556129c390633b9aca0090614757565b60125560646129d36023836146dd565b6129dd9190614757565b601355600060646129ef6005846146dd565b6129f99190614757565b905060006064612a0a6005856146dd565b612a149190614757565b905060006064612a256008866146dd565b612a2f9190614757565b905060006064612a406001876146dd565b612a4a9190614757565b90506000818385876013546010548b612a6391906146f4565b612a6d91906146f4565b612a7791906146f4565b612a8191906146f4565b612a8b91906146f4565b612a9591906146f4565b600854909150612ab2906001600160a01b03898116911687612da1565b600754612acc906001600160a01b03898116911686612da1565b600954612ae6906001600160a01b03898116911685612da1565b612b0c612afb6005546001600160a01b031690565b6001600160a01b0389169084612da1565b600b54612b26906001600160a01b03898116911683612da1565b600860009054906101000a90046001600160a01b03166001600160a01b0316637196e8416040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612b7657600080fd5b505af1158015612b8a573d6000803e3d6000fd5b5050505050505050505050565b6040516001600160a01b038481166024830152838116604483015260648201839052611d819186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050613e94565b600061ffff831615612caf576040516bffffffffffffffffffffffff193360601b1660208201526001600160f01b031960f085901b166034820152600090603601604051602081830303815290604052805190602001209050612c6483601c5483613ef7565b612c8157604051636397109b60e11b815260040160405180910390fd5b6000612710612c9461ffff8716886146dd565b612c9e9190614757565b9050612caa81876147a5565b955050505b509192915050565b6000612cc1612227565b612ccb90836146dd565b306000908152601e6020526040812080549293508392909190612cef9084906146f4565b9091555050336000908152601e602052604081208054839290612d139084906147a5565b90915550506001600160a01b0383166000908152601f602052604090205460ff1615612d5e57336000908152601d602052604081208054849290612d589084906147a5565b90915550505b81601b6000828254612d7091906147a5565b90915550506040518281526001600160a01b038416906000906000805160206149f683398151915290602001612861565b6040516001600160a01b0383811660248301526044820183905261100791859182169063a9059cbb90606401612bcc565b600080612dde83610ee3565b600c54909150600090612e00908390600160a01b900461ffff166127106122b3565b600c54909150600090612e22908690600160a01b900461ffff166127106122b3565b306000908152601e6020526040812080549293508492909190612e469084906146f4565b90915550506001600160a01b0386166000908152601e602052604081208054849290612e739084906147a5565b90915550506001600160a01b0386166000908152601f602052604090205460ff1615612ec7576001600160a01b0386166000908152601d602052604081208054839290612ec19084906147a5565b90915550505b612ed181866146f4565b9695505050505050565b612efa30737a250d5630b4cf539739df2c5dacb4c659f2488d85613941565b6040805160028082526060820183526000926020830190803683370190505090503081600081518110612f2f57612f2f614779565b60200260200101906001600160a01b031690816001600160a01b0316815250507396a5399d07896f757bd4c6ef56461f58db95186281600181518110612f7757612f77614779565b6001600160a01b039283166020918202929092010152600c54604051635c11d79560e01b8152737a250d5630b4cf539739df2c5dacb4c659f2488d92635c11d79592612fd092899289928892911690899060040161483e565b600060405180830381600087803b158015612fea57600080fd5b505af1158015612635573d6000803e3d6000fd5b600073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561304f57600080fd5b505af1158015613063573d6000803e3d6000fd5b5050604080516101008101825273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc280825273f19308f923582a6f7c465e5ce7a9dc1bec6665b1602083015261271092820192909252306060820152608081018790523460a0820181905260c08201899052600060e08301529094506130f5935090915073e592427a0aece92de3edee1f18e0157c0586156490613941565b60405163414bf38960e01b815260009073e592427a0aece92de3edee1f18e0157c058615649063414bf3899061312f9085906004016148b1565b6020604051808303816000875af115801561314e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061317291906147b8565b95945050505050565b6022546021546000918291825b602054811015613225576000602082815481106131a7576131a7614779565b60009182526020808320909101546001600160a01b0316808352601e8252604080842054601d9093529092205491925090858211806131e557508481115b156131fe57602254602154975097505050505050509091565b61320882876146f4565b955061321481866146f4565b945050600190920191506131889050565b506021546022546132369190614757565b82101561324d576022546021549350935050509091565b90939092509050565b6001600160a01b0384166132805760405163e602df0560e01b815260006004820152602401611936565b6001600160a01b0383166132aa57604051634a1406b160e11b815260006004820152602401611936565b6001600160a01b0380851660009081526001602090815260408083209387168352929052208290558015611d8157826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161331d91815260200190565b60405180910390a350505050565b60405163e6a4390560e01b81523060048201526001600160a01b038216602482015260009081908190735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f9063e6a4390590604401602060405180830381865afa158015613390573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133b491906147d1565b90506001600160a01b0381166133cf57600094909350915050565b806001600160a01b03811663bc25cf776133f16005546001600160a01b031690565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401600060405180830381600087803b15801561343257600080fd5b505af1158015613446573d6000803e3d6000fd5b50505050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa15801561348b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134af9190614931565b5091509150816001600160701b03166000146134da57506001600160701b0316959194509092505050565b6001600160701b038116156134fe576001600160701b031696929550919350505050565b50600096929550919350505050565b60008361351a84846146dd565b6135249190614757565b905080600003613532575060015b600061353c612227565b61354690836146dd565b6001600160a01b0387166000908152601e60205260408120805492935083929091906135739084906147a5565b90915550506001600160a01b0386166000908152601f602052604090205460ff16156135c7576001600160a01b0386166000908152601d6020526040812080548492906135c19084906147a5565b90915550505b80602260008282546135d991906147a5565b9250508190555081602160008282546135f291906147a5565b90915550506040518281526001600160a01b038716906000906000805160206149f68339815191529060200160405180910390a3856001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561366157600080fd5b505af1158015613675573d6000803e3d6000fd5b50505050505050505050565b60175462010000900460ff16156138235760008060008060006136a386613f0d565b945094509450945094506136b888868861224a565b6001600160a01b0388166000908152601e6020526040812080548792906136e09084906146f4565b90915550506001600160a01b0388166000908152601f602052604090205460ff1615613734576001600160a01b0388166000908152601d60205260408120805488929061372e9084906146f4565b90915550505b6001600160a01b0387166000908152601e60205260408120805486929061375c9084906147a5565b90915550506001600160a01b0387166000908152601f602052604090205460ff16156137b0576001600160a01b0387166000908152601d6020526040812080548392906137aa9084906147a5565b90915550505b306000908152601e6020526040812080548492906137cf9084906147a5565b909155506137de905083613f63565b866001600160a01b0316886001600160a01b03166000805160206149f68339815191528360405161381191815260200190565b60405180910390a35050505050505050565b6001600160a01b038316301461384c5760405163bcb8b8fb60e01b815260040160405180910390fd5b6000613856612227565b61386090836146dd565b6001600160a01b0385166000908152601e602052604081208054929350839290919061388d9084906146f4565b90915550506001600160a01b0383166000908152601e6020526040812080548392906138ba9084906147a5565b90915550506001600160a01b0383166000908152601f602052604090205460ff161561390e576001600160a01b0383166000908152601d6020526040812080548492906139089084906147a5565b90915550505b826001600160a01b0316846001600160a01b03166000805160206149f68339815191528460405161331d91815260200190565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015613991573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139b591906147b8565b9050611d8184846139c685856147a5565b613f7d565b604080516101008101825273f19308f923582a6f7c465e5ce7a9dc1bec6665b18082526001600160a01b0387166020830152612710928201929092523060608201526080810183905260a0810185905260c08101849052600060e0820181905291613a4b9073e592427a0aece92de3edee1f18e0157c0586156487613941565b60405163414bf38960e01b815260009073e592427a0aece92de3edee1f18e0157c058615649063414bf38990613a859085906004016148b1565b6020604051808303816000875af1158015613aa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ac891906147b8565b979650505050505050565b6000613b0873f19308f923582a6f7c465e5ce7a9dc1bec6665b1737a250d5630b4cf539739df2c5dacb4c659f2488d86613941565b6040516370a0823160e01b81523060048201526000906001600160a01b038716906370a0823190602401602060405180830381865afa158015613b4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b7391906147b8565b604080516002808252606082018352929350600092909160208301908036833701905050905073f19308f923582a6f7c465e5ce7a9dc1bec6665b181600081518110613bc157613bc1614779565b60200260200101906001600160a01b031690816001600160a01b0316815250508681600181518110613bf557613bf5614779565b6001600160a01b0390921660209283029190910190910152604051635c11d79560e01b8152737a250d5630b4cf539739df2c5dacb4c659f2488d90635c11d79590613c4c9089908990869030908b9060040161483e565b600060405180830381600087803b158015613c6657600080fd5b505af1158015613c7a573d6000803e3d6000fd5b50506040516370a0823160e01b81523060048201528492506001600160a01b038a1691506370a0823190602401602060405180830381865afa158015613cc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce891906147b8565b613ac891906146f4565b60405173f19308f923582a6f7c465e5ce7a9dc1bec6665b160601b602082015261027160ec1b60348201819052606086811b6bffffffffffffffffffffffff199081166037850152604b84019290925287901b16604e820152600090819060620160408051601f1981840301815260a08301825280835230602084015290820185905260608201879052608082018690529150613db873f19308f923582a6f7c465e5ce7a9dc1bec6665b173e592427a0aece92de3edee1f18e0157c0586156488613941565b60405163c04b8d5960e01b815260009073e592427a0aece92de3edee1f18e0157c058615649063c04b8d5990613df2908590600401614981565b6020604051808303816000875af1158015613e11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e3591906147b8565b9998505050505050505050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000613ea96001600160a01b0384168361400d565b90508051600014158015613ece575080806020019051810190613ecc91906147ee565b155b1561100757604051635274afe760e01b81526001600160a01b0384166004820152602401611936565b600082613f04858461401b565b14949350505050565b600080600080600080600080613f228961405e565b9250925092506000613f32612227565b9050600080600080613f468e8888886140bb565b929f50909d509b5099509697505050505050505091939590929450565b8060226000828254613f7591906146f4565b909155505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052613fce8482614114565b611d81576040516001600160a01b0384811660248301526000604483015261400391869182169063095ea7b390606401612bcc565b611d818482613e94565b6060610f1c838360006141b7565b600081815b84518110156140565761404c8286838151811061403f5761403f614779565b602002602001015161424a565b9150600101614020565b509392505050565b60008060008061408585600c60169054906101000a900461ffff1661ffff16612710614279565b90506000614094606487614757565b90506000816140a384896146f4565b6140ad91906146f4565b979296509094509092505050565b6000808080806140cb868a6146dd565b905060006140d9878a6146dd565b905060006140e7888a6146dd565b90506000816140f684866146f4565b61410091906146f4565b939c939b5091995097509095505050505050565b6000806000846001600160a01b03168460405161413191906149d9565b6000604051808303816000865af19150503d806000811461416e576040519150601f19603f3d011682016040523d82523d6000602084013e614173565b606091505b509150915081801561419d57508051158061419d57508080602001905181019061419d91906147ee565b80156131725750505050506001600160a01b03163b151590565b6060814710156141dc5760405163cd78605960e01b8152306004820152602401611936565b600080856001600160a01b031684866040516141f891906149d9565b60006040518083038185875af1925050503d8060008114614235576040519150601f19603f3d011682016040523d82523d6000602084013e61423a565b606091505b5091509150612ed18683836142b9565b6000818310614266576000828152602084905260409020610f1c565b6000838152602083905260409020610f1c565b60006142868484846122b3565b90506000828061429857614298614741565b8486091115610f1c5760001981106142af57600080fd5b6001019392505050565b6060826142ce576142c982614315565b610f1c565b81511580156142e557506001600160a01b0384163b155b1561430e57604051639996b31560e01b81526001600160a01b0385166004820152602401611936565b5080610f1c565b8051156143255780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b60006020828403121561435057600080fd5b81356001600160e01b031981168114610f1c57600080fd5b60006020828403121561437a57600080fd5b5035919050565b60005b8381101561439c578181015183820152602001614384565b50506000910152565b600081518084526143bd816020860160208601614381565b601f01601f19169290920160200192915050565b602081526000610f1c60208301846143a5565b6001600160a01b038116811461133757600080fd5b6000806040838503121561440c57600080fd5b8235614417816143e4565b946020939093013593505050565b60006020828403121561443757600080fd5b8135610f1c816143e4565b60008060006060848603121561445757600080fd5b8335614462816143e4565b92506020840135614472816143e4565b929592945050506040919091013590565b60008060006060848603121561449857600080fd5b83356144a3816143e4565b95602085013595506040909401359392505050565b803561ffff811681146144ca57600080fd5b919050565b6000602082840312156144e157600080fd5b610f1c826144b8565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261451157600080fd5b8135602067ffffffffffffffff8083111561452e5761452e6144ea565b8260051b604051601f19603f83011681018181108482111715614553576145536144ea565b604052938452602081870181019490810192508785111561457357600080fd5b6020870191505b84821015613ac85781358352918301919083019061457a565b6000806000606084860312156145a857600080fd5b833592506145b8602085016144b8565b9150604084013567ffffffffffffffff8111156145d457600080fd5b6145e086828701614500565b9150509250925092565b600080604083850312156145fd57600080fd5b50508035926020909101359150565b60006020828403121561461e57600080fd5b813560ff81168114610f1c57600080fd5b6000806040838503121561464257600080fd5b823561464d816143e4565b9150602083013561465d816143e4565b809150509250929050565b6000806000806080858703121561467e57600080fd5b8435935061468e602086016144b8565b9250604085013567ffffffffffffffff8111156146aa57600080fd5b6146b687828801614500565b949793965093946060013593505050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610cf057610cf06146c7565b81810381811115610cf057610cf06146c7565b600181811c9082168061471b57607f821691505b60208210810361473b57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601260045260246000fd5b60008261477457634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b80820180821115610cf057610cf06146c7565b6000602082840312156147ca57600080fd5b5051919050565b6000602082840312156147e357600080fd5b8151610f1c816143e4565b60006020828403121561480057600080fd5b81518015158114610f1c57600080fd5b60008060006060848603121561482557600080fd5b8351925060208401519150604084015190509250925092565b600060a08201878352602087602085015260a0604085015281875180845260c08601915060208901935060005b818110156148905784516001600160a01b03168352938301939183019160010161486b565b50506001600160a01b03969096166060850152505050608001529392505050565b81516001600160a01b03908116825260208084015182169083015260408084015162ffffff16908301526060808401518216908301526080808401519083015260a0838101519083015260c0808401519083015260e09283015116918101919091526101000190565b80516001600160701b03811681146144ca57600080fd5b60008060006060848603121561494657600080fd5b61494f8461491a565b925061495d6020850161491a565b9150604084015163ffffffff8116811461497657600080fd5b809150509250925092565b602081526000825160a0602084015261499d60c08401826143a5565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b600082516149eb818460208701614381565b919091019291505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212202fad6dd8a99467f3a9b6773d40626d59b49b0be087206ec078a8f280993e7a4364736f6c63430008180033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000009b3ba6b585188d5b0510ddbb26681cf7233c96b000000000000000000000000019dd7ded6efecfc977c0e0394bfa247e4349cd4a000000000000000000000000ad6e32a8d0463c32297208c5c107a5571aea2f95000000000000000000000000a2d21205aa7273baddfc8e9551e05e23bb49ce4600000000000000000000000096a5399d07896f757bd4c6ef56461f58db951862000000000000000000000000836cad9ea4e47c6a8969c2f48f908b32864a6617000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000050000000000000000000000009f278dc799bbc61ecb8e5fb8035cbfa29803623b00000000000000000000000096a5399d07896f757bd4c6ef56461f58db951862000000000000000000000000cc7ed2ab6c3396ddbc4316d2d7c1b59ff9d2091f000000000000000000000000a99afcc6aa4530d01dfff8e55ec66e4c424c048c000000000000000000000000e9a53c43a0b58706e67341c4055de861e29ee9430000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000a

-----Decoded View---------------
Arg [0] : _owner (address): 0x9B3ba6b585188d5b0510DDbB26681CF7233c96B0
Arg [1] : _devWallet (address): 0x19dD7ded6eFEcfC977c0e0394bfa247e4349Cd4a
Arg [2] : _marketingWallet (address): 0xAd6e32a8d0463c32297208C5c107A5571aea2F95
Arg [3] : _heliosVault (address): 0xA2d21205Aa7273BadDFC8E9551e05E23bB49ce46
Arg [4] : _dragonxVault (address): 0x96a5399D07896f757Bd4c6eF56461F58DB951862
Arg [5] : _bdxBuyBurnAddress (address): 0x836CAd9eA4e47C6A8969C2F48f908B32864A6617
Arg [6] : _ecosystemTokens (address[]): 0x9f278Dc799BbC61ecB8e5Fb8035cbfA29803623B,0x96a5399D07896f757Bd4c6eF56461F58DB951862,0xCC7ed2ab6c3396DdBc4316D2d7C1b59ff9d2091F,0xa99AFcC6Aa4530d01DFFF8E55ec66E4C424c048c,0xe9A53C43a0B58706e67341C4055de861e29Ee943
Arg [7] : _lpPercentages (uint8[]): 60,10,10,10,10

-----Encoded View---------------
20 Constructor Arguments found :
Arg [0] : 0000000000000000000000009b3ba6b585188d5b0510ddbb26681cf7233c96b0
Arg [1] : 00000000000000000000000019dd7ded6efecfc977c0e0394bfa247e4349cd4a
Arg [2] : 000000000000000000000000ad6e32a8d0463c32297208c5c107a5571aea2f95
Arg [3] : 000000000000000000000000a2d21205aa7273baddfc8e9551e05e23bb49ce46
Arg [4] : 00000000000000000000000096a5399d07896f757bd4c6ef56461f58db951862
Arg [5] : 000000000000000000000000836cad9ea4e47c6a8969c2f48f908b32864a6617
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [7] : 00000000000000000000000000000000000000000000000000000000000001c0
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [9] : 0000000000000000000000009f278dc799bbc61ecb8e5fb8035cbfa29803623b
Arg [10] : 00000000000000000000000096a5399d07896f757bd4c6ef56461f58db951862
Arg [11] : 000000000000000000000000cc7ed2ab6c3396ddbc4316d2d7c1b59ff9d2091f
Arg [12] : 000000000000000000000000a99afcc6aa4530d01dfff8e55ec66e4c424c048c
Arg [13] : 000000000000000000000000e9a53c43a0b58706e67341c4055de861e29ee943
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [15] : 000000000000000000000000000000000000000000000000000000000000003c
Arg [16] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [17] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [18] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [19] : 000000000000000000000000000000000000000000000000000000000000000a


Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.