false
true
0

Contract Address Details

0x0D092ef2cE72A93A07Ba94d72Ba3BF51bE627d69

Contract Name
PoolMgmt
Creator
0x41c831–d18765 at 0x24d133–f82495
Balance
0 PLS ( )
Tokens
Fetching tokens...
Transactions
25 Transactions
Transfers
36,326 Transfers
Gas Used
4,968,279
Last Balance Update
26062588
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
PoolMgmt




Optimization enabled
true
Compiler version
v0.8.17+commit.8df45f5f




Optimization runs
999999
EVM Version
default




Verified at
2023-05-25T14:43:13.954872Z

poolMgmt.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

interface IERC20 {
    

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

    /**
     * @dev Sets `amount` 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 amount) external returns (bool);

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


import "./safeMath.sol";
import "./pool.sol";

interface IToken {
    function registerPool(address poolAddress, bool isPool) external;
    function mintSupply(address account, uint256 amount) external;
    function transfer(address account, uint256 amount) external;
    function balanceOf(address account) external view returns(uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function DEAD_ADDRESS() external view returns (address);
}

enum DepthChangeEnum {
    Maintain,
    Increase,
    NoAction
}

interface IMath {

    function calcOutputAmountSwapTokensToTokens(uint256 amountX, uint256 poolX, uint256 poolY, uint256 taxNum, uint256 taxDen) external pure returns (uint256 amountY);
    function checkIfDepthShouldBeAdjusted(uint256 poolErc20Mean, uint256 poolTokenMean, uint256 erc20Reserves) external returns (DepthChangeEnum action, uint256 erc20Load, uint256 tokenLoad, uint256 liquidity);
    function TargetPoolDepth() external view returns (uint256);
    function sqrt(uint256 y) external pure returns (uint256);
    function calcOptimalErc20Load(uint256 targetPoolDepth, uint256 avgPoolDepth) external returns (uint256 optimalErc20Load);
}

interface IErc20FeesReceiver {
    function claimErc20() external;
}

/**
 * @dev Abstract contract to manage owner access to contract
 */
abstract contract Owner {
    address public CONTRACT_DEFINER;
    address public POOL_MNGR;

    modifier mod_onlyContractDefiner() {
        require(msg.sender == CONTRACT_DEFINER, "Wrong sender.");
        _;
    }

    modifier mod_onlyPoolMngr() {
        require(msg.sender == POOL_MNGR, "Wrong sender.");
        _;
    }

    function renounceOwnership() external mod_onlyContractDefiner {
        CONTRACT_DEFINER = address(0x0);
    }

    function changeOwnershipPoolMngr(address newOwner) external mod_onlyPoolMngr {
        POOL_MNGR = newOwner;
    }
}

/**
 * @dev Abstract contract with base variables
 */
abstract contract Base is Owner {

    IERC20 public ERC20_CONTRACT;
    address public UNISWAP_ROUTER;
    IMath public MATH_CONTRACT;
    IToken public TOKEN_CONTRACT;
    IErc20FeesReceiver public ERC20_FEES_RECEIVER;
    address public UNISWAP_PAIR;
    
    uint256 public DEFAULT_TOKEN_ERC20_RATIO = 100;

    uint256 public TRADE_TAX = 3;

    function updateTradeTax(uint256 tradeTax) mod_onlyPoolMngr external {
        TRADE_TAX = tradeTax;
    }
}

/**
 * @dev Abstract contract to manage pool creation
 */
abstract contract PoolCreation is Base {
    using SafeMath for uint256;

    /**
     * @dev Checks if the pool has already been created
     */
    function hasPoolBeenCreated() public view returns (bool) {
        return pool.hasPoolBeenCreated(UNISWAP_ROUTER, address(TOKEN_CONTRACT), address(ERC20_CONTRACT));
    }

    /**
     * @dev Creates the pool
     */
    function createPool() internal {
        if (!hasPoolBeenCreated()) {
            UNISWAP_PAIR = pool.createPool(UNISWAP_ROUTER, address(ERC20_CONTRACT), address(TOKEN_CONTRACT));
            TOKEN_CONTRACT.registerPool(UNISWAP_PAIR, true);
        }
    }

    /**
     * @dev This function is called only once to start the pool
     */
    function startPool(uint256 erc20Amount) external  {
        require(msg.sender == address(TOKEN_CONTRACT), "Not authorized");
        require(!hasPoolBeenCreated(), "Pool already created");

        require(ERC20_CONTRACT.balanceOf(msg.sender) >= erc20Amount, "Account does not have enough ERC20");
        require(ERC20_CONTRACT.transferFrom(msg.sender, address(this), erc20Amount), "Unable to transfer required ERC20");

        createPool();

        uint256 tokensToMint = erc20Amount.mul(DEFAULT_TOKEN_ERC20_RATIO);
        TOKEN_CONTRACT.mintSupply(address(this), tokensToMint);

        pool.addLiquidity(
            address(TOKEN_CONTRACT),
            address(ERC20_CONTRACT),
            address(TOKEN_CONTRACT.DEAD_ADDRESS()),
            address(UNISWAP_ROUTER),
            tokensToMint,
            erc20Amount,
            block.timestamp + 10000
        );
    }
}

/**
 * @dev Abstract contract that provides stats about the pool
 */
abstract contract PoolStatsMgmt is PoolCreation {
    using SafeMath for uint256;
    struct PricePair {
        uint256 token;
        uint256 erc20;
    }

    uint256 public poolTokenMean = 0;
    uint256 public poolErc20Mean = 0;

    PricePair[] public prices;
    uint256 public pricePos = 0;
    uint256 public maxSize = 5;
    uint256 public lastPriceAvgTimestamp = 0;

    /**
     * @dev Returns the difference in minutes between the two timestamps
     */
    function diffMinutes(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _minutes) {
        require(fromTimestamp <= toTimestamp, "From must be before to");
        _minutes = (toTimestamp - fromTimestamp) / 60;
    }

    function erc20WethReserves() public view returns (uint256 erc20Amount, uint256 wethAmount) {
        address pair = pool.getPairWithWETH(UNISWAP_ROUTER, address(ERC20_CONTRACT));
        (uint256 erc20, uint256 weth) = pool.getPoolReserves(address(ERC20_CONTRACT), pair);
        return (erc20, weth);
    }

    /**
     * @dev Returns the exact pool reserves of TOKEN and ERC20 from the pool. It is called by multiple contracts, including TOKEN and Auctions
     */
    function poolReserves() public view returns (uint256 tokenAmount, uint256 erc20Amount) {
        (uint256 token, uint256 erc20) = pool.getPoolReserves(address(TOKEN_CONTRACT), UNISWAP_PAIR);
        if (token == 0 || erc20 == 0) return (0, 1);
        return (token, erc20);
    }

    //consider dropping this implementation. Since it does an average, the average values can easily fall outside of the actual market maker curve
    function updatePoolPriceAvgs() public {
        (uint256 tokenAmount, uint256 erc20Amount) = poolReserves();

        if (tokenAmount == 0 || erc20Amount == 0) return;

        //if prices have been collected
        //and either the recorded timestamp is later than the block.timestamp or less than 3 minutes have elapsed, don't allow the registation
        if(prices.length > 0 && (lastPriceAvgTimestamp >= block.timestamp || diffMinutes(lastPriceAvgTimestamp, block.timestamp) <= 3)) {
            return;
        }

        //update the timestamp to the current time
        lastPriceAvgTimestamp = block.timestamp;

        //if the length of the array of prices is smaller than the allowed maximum, push a new value into the array
        if (prices.length < maxSize) {
            PricePair memory newPricePair = PricePair(tokenAmount, erc20Amount);
            prices.push(newPricePair);
        } 
        //otherwise, write over the current pricePos in prices, and increase pricePos. If pricePos overflows the maxSize, move it back to zero
        //this basically cycles the array of prices
        else {
            PricePair memory newPricePair =  PricePair(tokenAmount, erc20Amount);
            prices[pricePos++] = newPricePair;
            if (pricePos >= maxSize) pricePos = 0;
        }

        

        uint256 poolTokenSum = 0;
        uint256 poolErc20Sum = 0;

        //sum all values in the array to calculate the average
        for (uint256 i = 0; i < prices.length; i++) {
            poolTokenSum = poolTokenSum.add(prices[i].token);
            poolErc20Sum = poolErc20Sum.add(prices[i].erc20);
        }

        poolTokenMean = poolTokenSum.div(prices.length);
        poolErc20Mean = poolErc20Sum.div(prices.length);
    }

    function currentPoolDepth() public view returns (uint256) {
        (uint256 tokenAmount, uint256 erc20Amount) = poolReserves();
        return tokenAmount.mul(erc20Amount);
    }

    function avgPoolDepth() public view returns (uint256) {
        return poolErc20Mean.mul(poolTokenMean);
    }



    function calcOutputAmountSwapErc20ToToken(uint256 amountErc20, uint256 taxNum) public view returns (uint256 amountToken) {
        (uint256 tokenReserves, uint256 erc20Reserves) = poolReserves();
        return MATH_CONTRACT.calcOutputAmountSwapTokensToTokens(amountErc20, erc20Reserves, tokenReserves, taxNum, 100);
    }

    function calcOutputAmountSwapTokenToErc20(uint256 amountToken, uint256 taxNum) public view returns (uint256 amountErc20) {
        (uint256 tokenReserves, uint256 erc20Reserves) = poolReserves();
        return MATH_CONTRACT.calcOutputAmountSwapTokensToTokens(amountToken, tokenReserves, erc20Reserves, taxNum, 100);
    }

    function calcOutputAmountSwapWETHtoErc20(uint256 amountWeth, uint256 taxNum) public view returns (uint256 amountErc20) {
        (uint256 erc20Reserves, uint256 wethReserves) = erc20WethReserves();
        return MATH_CONTRACT.calcOutputAmountSwapTokensToTokens(amountWeth, wethReserves, erc20Reserves, taxNum, 100);
    }

}



interface IContractsManager {
    function find(string memory contractName) external view returns (address, bool);
}

/**
 * @dev Pool management contract.
 */

contract PoolMgmt is PoolStatsMgmt {
    using SafeMath for uint256;

    uint256 public totalErc20TaxedOnBuys;
    uint256 public totalErc20UsedForTokenLiquidity;
    uint256 public totalErc20UsedForBuybacks;
    uint256 public totalTokenBurnedFromBuybacks;
    


    uint256 public tokensForPoolAccounting;
    uint256 public erc20ForPoolAccounting;

    /**
     * @dev Increases the liquidity of the pool according to the amounts provided by the mathematical function
     */
    function tryIncreasePoolDepth() external {

        uint256 erc20Reserves = erc20ForPoolAccounting;

        //if you've got values to work with, otherwise do nothing
        if (poolErc20Mean > 0 && poolTokenMean > 0) {
            (DepthChangeEnum depthChange, uint256 erc20Load, uint256 tokenLoad, ) = 
                MATH_CONTRACT.checkIfDepthShouldBeAdjusted(poolErc20Mean, poolTokenMean, erc20Reserves);

            if (depthChange == DepthChangeEnum.NoAction) return;

            if (depthChange == DepthChangeEnum.Increase) {
                //check how much tokens the contract has
                uint256 tokenAmountBeforeAdd = TOKEN_CONTRACT.balanceOf(address(this));
                //determine how much needs to be minted
                uint256 tokenAmountToMint = tokenLoad > tokenAmountBeforeAdd ? tokenLoad - tokenAmountBeforeAdd : 0;

                if(tokenAmountToMint > 0)
                    TOKEN_CONTRACT.mintSupply(address(this), tokenAmountToMint);

                //check how much the contract holds in erc20 before the liquidity transfer
                uint256 erc20AmountBeforeAdd = ERC20_CONTRACT.balanceOf(address(this));

                //transfer liquidity
                pool.addLiquidity(
                    address(TOKEN_CONTRACT),
                    address(ERC20_CONTRACT),
                    address(TOKEN_CONTRACT.DEAD_ADDRESS()), 
                    address(UNISWAP_ROUTER),
                    tokenLoad,
                    erc20Load,
                    block.timestamp + 10000
                );

                //check how much the contract holds in erc20 after the liquidity transfer
                uint256 erc20AmountAfterAdd = ERC20_CONTRACT.balanceOf(address(this));

                //what is the net difference
                uint256 erc20Diff = erc20AmountBeforeAdd.sub(erc20AmountAfterAdd);
                //update the amount available
                erc20ForPoolAccounting = erc20ForPoolAccounting.sub(erc20Diff);

                //increase the total erc20 used for liquidity
                totalErc20UsedForTokenLiquidity = totalErc20UsedForTokenLiquidity.add(erc20Diff);
            }
        }
    }

    /**
     * @dev This function is used to add to the accounting value the amount of tokens that the TOKEN contract transferred to this contract
     */
    function addTokensForPoolAccounting(uint256 numTokens) external {
        require(msg.sender == address(TOKEN_CONTRACT), "Not authorized");
        tokensForPoolAccounting = tokensForPoolAccounting.add(numTokens);
    }

    /**
     * @dev This function sells the total amount of TOKEN tokens it has acquired to convert them fully into ERC20
     * These token funds are obtained from buy fees
     */
    function trySwapTokenFeesForErc20() external {

        if(tokensForPoolAccounting < 20e18) return;

        //check values before swap
        uint256 tokenBalance = TOKEN_CONTRACT.balanceOf(address(this));
        uint256 erc20Balance = ERC20_CONTRACT.balanceOf(address(this));
        TOKEN_CONTRACT.approve(UNISWAP_ROUTER, tokensForPoolAccounting);

        //swap tokens for ERC20
        //calculates the output that should come from the trade with an extra tax deduction for pool taxes
        uint256 minOutputErc20Amount = calcOutputAmountSwapTokenToErc20(tokensForPoolAccounting, TRADE_TAX);

        pool.swapTokens(
            address(ERC20_FEES_RECEIVER), //receiver needs to be another contract to avoid uniswapPairV2 invalid_to
            tokensForPoolAccounting,
            minOutputErc20Amount,
            address(TOKEN_CONTRACT),
            address(ERC20_CONTRACT),
            UNISWAP_ROUTER,
            block.timestamp + 10000
        );

        //claim the erc20 sent to the receiver
        ERC20_FEES_RECEIVER.claimErc20();

        //check values after swap
        uint256 erc20BalanceAfterSwap = ERC20_CONTRACT.balanceOf(address(this));
        uint256 tokenBalanceAfterSwap = TOKEN_CONTRACT.balanceOf(address(this));

        //determine how much was actually swapped
        uint256 tokensSent = tokenBalance.sub(tokenBalanceAfterSwap);
        uint256 erc20Received = erc20BalanceAfterSwap.sub(erc20Balance);

        //update the erc20 available for the pool
        erc20ForPoolAccounting = erc20ForPoolAccounting.add(erc20Received);
        //update the tokens available for future sells
        tokensForPoolAccounting = tokensForPoolAccounting.sub(tokensSent);

        //update the total erc20 received from token sales
        totalErc20TaxedOnBuys = totalErc20TaxedOnBuys.add(erc20Received);
    }

    /**
     * @dev This function uses pool funds to execute a buyback and burn. Can only be triggered by the poolMngr
     */
    function executeBuyBackAndBurn(uint256 amountErc20) mod_onlyPoolMngr external {

        require(amountErc20 <= erc20ForPoolAccounting, "Amount erc20 is higher than available");

        uint256 amountErc20BeforeTrade = ERC20_CONTRACT.balanceOf(address(this));
        uint256 amountTokensBeforeTrade = TOKEN_CONTRACT.balanceOf(address(this));

        //doesn't need to support fees because pool mgmt contract is excluded
        ERC20_CONTRACT.approve(UNISWAP_ROUTER, amountErc20);
        
        //calculates the output that should come from the trade with an extra tax deduction for pool taxes
        uint256 minOutputTokenAmount = calcOutputAmountSwapErc20ToToken(amountErc20, TRADE_TAX);
        pool.swapTokens(
                address(this),
                amountErc20,
                minOutputTokenAmount,
                address(ERC20_CONTRACT),
                address(TOKEN_CONTRACT),
                UNISWAP_ROUTER,
                block.timestamp + 10000
            );

        //check the erc20 balance after the trade
        uint256 amountErc20AfterTrade = ERC20_CONTRACT.balanceOf(address(this));
        //check the net difference
        uint256 erc20Diff = amountErc20BeforeTrade.sub(amountErc20AfterTrade);
        //deduct the difference from the accounting
        erc20ForPoolAccounting = erc20ForPoolAccounting.sub(erc20Diff);
        //increase the total erc20 used for buybacks
        totalErc20UsedForBuybacks = totalErc20UsedForBuybacks.add(erc20Diff);

        //check the token balance after the trade
        uint256 amountTokensAfterTrade = TOKEN_CONTRACT.balanceOf(address(this));
        //check the net difference
        uint256 tokenDiff = amountTokensAfterTrade.sub(amountTokensBeforeTrade);
        //burn the difference
        TOKEN_CONTRACT.transfer(TOKEN_CONTRACT.DEAD_ADDRESS(), tokenDiff);
        //increase the total token burned from buybacks
        totalTokenBurnedFromBuybacks = totalTokenBurnedFromBuybacks.add(tokenDiff);
    }


    

    function setContracts(address contractsManager) external mod_onlyContractDefiner {

        //Token contract
        (address ctr, bool found) = IContractsManager(contractsManager).find("TOKEN_CONTRACT");
        require(found, "Contract not found");
        TOKEN_CONTRACT = IToken(ctr);

        //Math contract
        (ctr, found) = IContractsManager(contractsManager).find("MATH_CONTRACT");
        require(found, "Contract not found");
        MATH_CONTRACT = IMath(ctr);

        //Erc20 Fees Receiver contract
        (ctr, found) = IContractsManager(contractsManager).find("ERC20_FEES_RECEIVER");
        require(found, "Contract not found");
        ERC20_FEES_RECEIVER = IErc20FeesReceiver(ctr);

        //Uniswap Router
        (ctr, found) = IContractsManager(contractsManager).find("UNISWAP_ROUTER");
        require(found, "Contract not found");
        UNISWAP_ROUTER = ctr;

        //Erc20 contract
        (ctr, found) = IContractsManager(contractsManager).find("ERC20_CONTRACT");
        require(found, "Contract not found");
        ERC20_CONTRACT = IERC20(ctr);
    }


    constructor() {
        CONTRACT_DEFINER = msg.sender;
        POOL_MNGR = msg.sender;
    }
}
        

pool.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

interface IPoolToken {
    function approve(address spender, uint256 amount) external returns (bool);
}

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

    function getPair(address tokenA, address tokenB) external view returns (address pair);
}

interface IUniswapV2Pair {
    function token0() external view returns (address);

    function approve(address spender, uint256 amount) external returns (bool);

    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
}

interface IUniswapV2Router02 {
    function factory() external pure returns (address);
    function WPLS() 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 removeLiquidity(
        address tokenA,
        address tokenB,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB);

    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        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 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;
}

library pool {

    function getPairWithWETH(address router, address tokenAddress) internal view returns (address pair) {
        IUniswapV2Factory factory = IUniswapV2Factory((IUniswapV2Router02(router)).factory());
        return factory.getPair(IUniswapV2Router02(router).WPLS(), tokenAddress);
    }

    function getPair(address router, address tokenAddress, address otherTokenAddress) internal view returns (address pair) {
        return
            IUniswapV2Factory((IUniswapV2Router02(router)).factory()).getPair(
                tokenAddress,
                otherTokenAddress
            );
    }

    function hasPoolBeenCreated(
        address router,
        address tokenAddress,
        address otherTokenAddress
    ) internal view returns (bool) {
        return
            IUniswapV2Factory((IUniswapV2Router02(router)).factory()).getPair(
                tokenAddress,
                otherTokenAddress
            ) != address(0x0);
    }

    function createPool(
        address router,
        address tokenAddress,
        address otherTokenAddress
    ) internal returns (address) {
        return
            IUniswapV2Factory((IUniswapV2Router02(router)).factory())
                .createPair(tokenAddress, otherTokenAddress);
    }

    function addLiquidity(
        address tokenAddress,
        address otherTokenAddress,
        address lpTokensReceiver,
        address router,
        uint256 tokenAmount,
        uint256 otherTokenAmount,
        uint256 deadline
    ) internal {
        IPoolToken(tokenAddress).approve(router, tokenAmount);
        IPoolToken(otherTokenAddress).approve(router, otherTokenAmount);

        IUniswapV2Router02(router).addLiquidity(
            tokenAddress,
            otherTokenAddress,
            tokenAmount,
            otherTokenAmount,
            0,
            0,
            lpTokensReceiver,
            deadline
        );
    }

    function removeLiquidity(
        address tokenAddress,
        address otherTokenAddress,
        address liquidityReceiver,
        address router,
        address pair,
        uint256 lpTokens,
        uint256 deadline
    ) internal {
        IUniswapV2Pair(pair).approve(router, lpTokens);

        IUniswapV2Router02(router).removeLiquidity(
            tokenAddress,
            otherTokenAddress,
            lpTokens,
            0,
            0,
            liquidityReceiver,
            deadline
        );
    }

    function swapTokens(
        address receiver,
        uint256 tokenAmount,
        uint256 outputMinAmount,
        address originTokenAddress,
        address destinationTokenAddress,
        address router,
        uint256 deadline
    ) internal {
        address[] memory path = new address[](2);
        path[0] = originTokenAddress;
        path[1] = destinationTokenAddress;

        IUniswapV2Router02(router).swapExactTokensForTokens(
            tokenAmount,
            outputMinAmount,
            path,
            receiver,
            deadline
        );
    }

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        address receiver,
        uint256 tokenAmount,
        address originTokenAddress,
        address destinationTokenAddress,
        address router,
        uint256 deadline
    ) internal {
        address[] memory path = new address[](2);
        path[0] = originTokenAddress;
        path[1] = destinationTokenAddress;

        IUniswapV2Router02(router).swapExactTokensForTokensSupportingFeeOnTransferTokens(
            tokenAmount,
            0,
            path,
            receiver,
            deadline
        );
    }

    function swapEthForTokens(
        uint256 MESSAGE_VALUE,
        uint256 outputMinAmount,
        address receiver,
        address originAddress,
        address destinationAddress,
        address router,
        uint256 deadline
    ) internal {
        address[] memory path = new address[](2);
        path[0] = originAddress;
        path[1] = destinationAddress;

        IUniswapV2Router02(router).swapExactETHForTokens{value: MESSAGE_VALUE}(
            outputMinAmount,
            path,
            receiver,
            deadline
        );
    }

    function getPoolReserves(address tokenAddress, address pair)
        internal
        view
        returns (uint256 tokenAmount, uint256 otherTokenAmount)
    {
        IUniswapV2Pair uniswapPair = IUniswapV2Pair(pair);
        (uint256 reserveIn, uint256 reserveOut, ) = uniswapPair.getReserves(); // reserveIn SHOULD be TOKEN, may be ERC20

        if (uniswapPair.token0() == tokenAddress) {
            tokenAmount = reserveIn;
            otherTokenAmount = reserveOut;
        } else {
            tokenAmount = reserveOut;
            otherTokenAmount = reserveIn;
        }

        return (tokenAmount, otherTokenAmount);
    }
}
          

safeMath.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }
}
          

Contract ABI

[{"type":"constructor","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"CONTRACT_DEFINER","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"DEFAULT_TOKEN_ERC20_RATIO","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20"}],"name":"ERC20_CONTRACT","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IErc20FeesReceiver"}],"name":"ERC20_FEES_RECEIVER","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IMath"}],"name":"MATH_CONTRACT","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"POOL_MNGR","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IToken"}],"name":"TOKEN_CONTRACT","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"TRADE_TAX","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"UNISWAP_PAIR","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"UNISWAP_ROUTER","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addTokensForPoolAccounting","inputs":[{"type":"uint256","name":"numTokens","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"avgPoolDepth","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"amountToken","internalType":"uint256"}],"name":"calcOutputAmountSwapErc20ToToken","inputs":[{"type":"uint256","name":"amountErc20","internalType":"uint256"},{"type":"uint256","name":"taxNum","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"amountErc20","internalType":"uint256"}],"name":"calcOutputAmountSwapTokenToErc20","inputs":[{"type":"uint256","name":"amountToken","internalType":"uint256"},{"type":"uint256","name":"taxNum","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"amountErc20","internalType":"uint256"}],"name":"calcOutputAmountSwapWETHtoErc20","inputs":[{"type":"uint256","name":"amountWeth","internalType":"uint256"},{"type":"uint256","name":"taxNum","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"changeOwnershipPoolMngr","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"currentPoolDepth","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"erc20ForPoolAccounting","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"erc20Amount","internalType":"uint256"},{"type":"uint256","name":"wethAmount","internalType":"uint256"}],"name":"erc20WethReserves","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeBuyBackAndBurn","inputs":[{"type":"uint256","name":"amountErc20","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasPoolBeenCreated","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastPriceAvgTimestamp","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxSize","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"poolErc20Mean","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"tokenAmount","internalType":"uint256"},{"type":"uint256","name":"erc20Amount","internalType":"uint256"}],"name":"poolReserves","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"poolTokenMean","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"pricePos","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"token","internalType":"uint256"},{"type":"uint256","name":"erc20","internalType":"uint256"}],"name":"prices","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setContracts","inputs":[{"type":"address","name":"contractsManager","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"startPool","inputs":[{"type":"uint256","name":"erc20Amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"tokensForPoolAccounting","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalErc20TaxedOnBuys","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalErc20UsedForBuybacks","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalErc20UsedForTokenLiquidity","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalTokenBurnedFromBuybacks","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"tryIncreasePoolDepth","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"trySwapTokenFeesForErc20","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updatePoolPriceAvgs","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateTradeTax","inputs":[{"type":"uint256","name":"tradeTax","internalType":"uint256"}]}]
              

Contract Creation Code

0x6080604052606460085560036009556000600a556000600b556000600d556005600e556000600f5534801561003357600080fd5b5060008054336001600160a01b0319918216811783556001805490921617905561395f90819061006390396000f3fe608060405234801561001057600080fd5b50600436106102c85760003560e01c8063715018a61161017b578063b651ae17116100d8578063cdac6fda1161008c578063d826492011610071578063d82649201461055e578063e72e4caf1461057e578063e7c0b2281461059e57600080fd5b8063cdac6fda14610543578063cea050151461055657600080fd5b8063bc31c1c1116100bd578063bc31c1c114610514578063bf9a6bda14610527578063c9b71e3b1461053a57600080fd5b8063b651ae17146104f9578063b95924111461050157600080fd5b80639d5d8b851161012f578063a539d66311610114578063a539d663146104be578063a80230de146104c6578063a901d15c146104e657600080fd5b80639d5d8b85146104a25780639ff01cee146104b557600080fd5b8063840a1c2a11610160578063840a1c2a146104715780638ad7f9db14610479578063923d4b151461048257600080fd5b8063715018a6146104615780637334cccd1461046957600080fd5b806335e07c21116102295780634fb886e3116101dd57806369dc5814116101c257806369dc58141461040e5780636b9f69b4146104215780636ba631cf1461044157600080fd5b80634fb886e3146103e35780635a2e2f47146103fb57600080fd5b80633baae36d1161020e5780633baae36d146103be578063444809f9146103c757806344ff54f7146103da57600080fd5b806335e07c2114610395578063363393881461039e57600080fd5b80632565b1591161028057806329265da71161026557806329265da71461032a578063292b7fd214610347578063325e2fd11461035057600080fd5b80632565b1591461031957806325782dcc1461032257600080fd5b80631375f83c116102b15780631375f83c146102f25780631edeeb00146102fb57806320ff46c11461030457600080fd5b80630152551e146102cd57806307a94a2d146102e9575b600080fd5b6102d6600a5481565b6040519081526020015b60405180910390f35b6102d6600f5481565b6102d660125481565b6102d660085481565b610317610312366004613418565b6105a7565b005b6102d6600e5481565b6102d6610674565b610332610697565b604080519283526020830191909152016102e0565b6102d660155481565b6001546103709073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102e0565b6102d660115481565b6005546103709073ffffffffffffffffffffffffffffffffffffffff1681565b6102d660105481565b6103176103d5366004613435565b6106f5565b6102d660145481565b6103eb610789565b60405190151581526020016102e0565b610317610409366004613418565b6107c1565b6102d661041c36600461344e565b610f16565b6002546103709073ffffffffffffffffffffffffffffffffffffffff1681565b6007546103709073ffffffffffffffffffffffffffffffffffffffff1681565b610317610fe3565b61031761108e565b6102d6611293565b6102d6600d5481565b6004546103709073ffffffffffffffffffffffffffffffffffffffff1681565b6102d66104b036600461344e565b6112ac565b6102d660135481565b610332611331565b6000546103709073ffffffffffffffffffffffffffffffffffffffff1681565b6103176104f4366004613435565b611398565b610317611850565b6102d661050f36600461344e565b611cca565b610332610522366004613435565b611cd7565b610317610535366004613435565b611d05565b6102d6600b5481565b610317610551366004613435565b6122dc565b610317612362565b6003546103709073ffffffffffffffffffffffffffffffffffffffff1681565b6006546103709073ffffffffffffffffffffffffffffffffffffffff1681565b6102d660095481565b60015473ffffffffffffffffffffffffffffffffffffffff16331461062d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f57726f6e672073656e6465722e0000000000000000000000000000000000000060448201526064015b60405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6000806000610681610697565b909250905061069082826127a3565b9250505090565b6005546007546000918291829182916106c99173ffffffffffffffffffffffffffffffffffffffff9081169116612862565b9150915081600014806106da575080155b156106ec575060009360019350915050565b90939092509050565b60055473ffffffffffffffffffffffffffffffffffffffff163314610776576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f7420617574686f72697a65640000000000000000000000000000000000006044820152606401610624565b60145461078390826129be565b60145550565b6003546005546002546000926107bc9273ffffffffffffffffffffffffffffffffffffffff918216929082169116612a37565b905090565b60005473ffffffffffffffffffffffffffffffffffffffff163314610842576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f57726f6e672073656e6465722e000000000000000000000000000000000000006044820152606401610624565b6040517f82b7b50000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f544f4b454e5f434f4e54524143540000000000000000000000000000000000006044820152600090819073ffffffffffffffffffffffffffffffffffffffff8416906382b7b500906064016040805180830381865afa1580156108de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109029190613485565b915091508061096d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f436f6e7472616374206e6f7420666f756e6400000000000000000000000000006044820152606401610624565b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff848116919091179091556040517f82b7b50000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4d4154485f434f4e5452414354000000000000000000000000000000000000006044820152908416906382b7b500906064016040805180830381865afa158015610a35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a599190613485565b909250905080610ac5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f436f6e7472616374206e6f7420666f756e6400000000000000000000000000006044820152606401610624565b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8481169190911782556040517f82b7b500000000000000000000000000000000000000000000000000000000008152602092810192909252601360248301527f45524332305f464545535f52454345495645520000000000000000000000000060448301528416906382b7b500906064016040805180830381865afa158015610b8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb19190613485565b909250905080610c1d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f436f6e7472616374206e6f7420666f756e6400000000000000000000000000006044820152606401610624565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff848116919091179091556040517f82b7b50000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f554e49535741505f524f555445520000000000000000000000000000000000006044820152908416906382b7b500906064016040805180830381865afa158015610ce5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d099190613485565b909250905080610d75576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f436f6e7472616374206e6f7420666f756e6400000000000000000000000000006044820152606401610624565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff848116919091179091556040517f82b7b50000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f45524332305f434f4e54524143540000000000000000000000000000000000006044820152908416906382b7b500906064016040805180830381865afa158015610e3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e619190613485565b909250905080610ecd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f436f6e7472616374206e6f7420666f756e6400000000000000000000000000006044820152606401610624565b50600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905550565b6000806000610f23610697565b600480546040517f4f84245100000000000000000000000000000000000000000000000000000000815291820189905260248201839052604482018490526064808301899052608483015292945090925073ffffffffffffffffffffffffffffffffffffffff90911690634f8424519060a4015b602060405180830381865afa158015610fb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fd891906134ba565b925050505b92915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611064576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f57726f6e672073656e6465722e000000000000000000000000000000000000006044820152606401610624565b600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b600080611099610697565b9150915081600014806110aa575080155b156110b3575050565b600c54158015906110dc575042600f541015806110dc575060036110d9600f5442612b79565b11155b156110e5575050565b42600f55600e54600c541015611170576040805180820190915282815260208101828152600c805460018101825560009190915291517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7600290930292830155517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c8909101556111df565b6040805180820190915282815260208101829052600d80548291600c9190600061119983613502565b91905055815481106111ad576111ad61353a565b60009182526020918290208351600290920201908155910151600190910155600e54600d54106111dd576000600d555b505b60008060005b600c5481101561126a5761121d600c82815481106112055761120561353a565b600091825260209091206002909102015484906129be565b9250611256600c82815481106112355761123561353a565b906000526020600020906002020160010154836129be90919063ffffffff16565b91508061126281613502565b9150506111e5565b50600c54611279908390612bfb565b600a55600c5461128a908290612bfb565b600b5550505050565b60006107bc600a54600b546127a390919063ffffffff16565b60008060006112b9610697565b600480546040517f4f84245100000000000000000000000000000000000000000000000000000000815291820189905260248201849052604482018390526064808301899052608483015292945090925073ffffffffffffffffffffffffffffffffffffffff90911690634f8424519060a401610f97565b600354600254600091829182916113619173ffffffffffffffffffffffffffffffffffffffff9182169116612c3d565b600254909150600090819061138c9073ffffffffffffffffffffffffffffffffffffffff1684612862565b90969095509350505050565b60055473ffffffffffffffffffffffffffffffffffffffff163314611419576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f7420617574686f72697a65640000000000000000000000000000000000006044820152606401610624565b611421610789565b15611488576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f506f6f6c20616c726561647920637265617465640000000000000000000000006044820152606401610624565b6002546040517f70a08231000000000000000000000000000000000000000000000000000000008152336004820152829173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156114f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061151a91906134ba565b10156115a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f4163636f756e7420646f6573206e6f74206861766520656e6f7567682045524360448201527f32300000000000000000000000000000000000000000000000000000000000006064820152608401610624565b6002546040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810183905273ffffffffffffffffffffffffffffffffffffffff909116906323b872dd906064016020604051808303816000875af1158015611625573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116499190613569565b6116d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f556e61626c6520746f207472616e73666572207265717569726564204552433260448201527f30000000000000000000000000000000000000000000000000000000000000006064820152608401610624565b6116dd612dd9565b60006116f4600854836127a390919063ffffffff16565b6005546040517fe742806a0000000000000000000000000000000000000000000000000000000081523060048201526024810183905291925073ffffffffffffffffffffffffffffffffffffffff169063e742806a90604401600060405180830381600087803b15801561176757600080fd5b505af115801561177b573d6000803e3d6000fd5b5050600554600254604080517f4e6fd6c4000000000000000000000000000000000000000000000000000000008152905161184c955073ffffffffffffffffffffffffffffffffffffffff938416945092909116918391634e6fd6c49160048083019260209291908290030181865afa1580156117fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118209190613584565b60035473ffffffffffffffffffffffffffffffffffffffff168587611847426127106135a1565b612ecd565b5050565b601554600b541580159061186657506000600a54115b15611cc75760048054600b54600a546040517fc718eeb7000000000000000000000000000000000000000000000000000000008152938401919091526024830152604482018390526000918291829173ffffffffffffffffffffffffffffffffffffffff9091169063c718eeb7906064016080604051808303816000875af11580156118f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061191a91906135b4565b50919450925090506002836002811115611936576119366135f7565b036119415750505050565b6001836002811115611955576119556135f7565b03611cc3576005546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156119c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ed91906134ba565b905060008183116119ff576000611a09565b611a098284613626565b90508015611a9c576005546040517fe742806a0000000000000000000000000000000000000000000000000000000081523060048201526024810183905273ffffffffffffffffffffffffffffffffffffffff9091169063e742806a90604401600060405180830381600087803b158015611a8357600080fd5b505af1158015611a97573d6000803e3d6000fd5b505050505b6002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611b0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b2f91906134ba565b600554600254604080517f4e6fd6c40000000000000000000000000000000000000000000000000000000081529051939450611bf99373ffffffffffffffffffffffffffffffffffffffff93841693909216918391634e6fd6c49160048083019260209291908290030181865afa158015611bae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd29190613584565b60035473ffffffffffffffffffffffffffffffffffffffff16888a611847426127106135a1565b6002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611c68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c8c91906134ba565b90506000611c9a83836130d3565b601554909150611caa90826130d3565b601555601154611cba90826129be565b60115550505050505b5050505b50565b6000806000610f23611331565b600c8181548110611ce757600080fd5b60009182526020909120600290910201805460019091015490915082565b60015473ffffffffffffffffffffffffffffffffffffffff163314611d86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f57726f6e672073656e6465722e000000000000000000000000000000000000006044820152606401610624565b601554811115611e18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f416d6f756e7420657263323020697320686967686572207468616e206176616960448201527f6c61626c650000000000000000000000000000000000000000000000000000006064820152608401610624565b6002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611e87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eab91906134ba565b6005546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291925060009173ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa158015611f1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4391906134ba565b6002546003546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015260248101879052929350169063095ea7b3906044016020604051808303816000875af1158015611fc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fe49190613569565b506000611ff384600954610f16565b6002546005546003549293506120389230928892869273ffffffffffffffffffffffffffffffffffffffff928316929182169116612033426127106135a1565b613115565b6002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156120a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120cb91906134ba565b905060006120d985836130d3565b6015549091506120e990826130d3565b6015556012546120f990826129be565b6012556005546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa15801561216b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218f91906134ba565b9050600061219d82876130d3565b600554604080517f4e6fd6c4000000000000000000000000000000000000000000000000000000008152905192935073ffffffffffffffffffffffffffffffffffffffff9091169163a9059cbb918391634e6fd6c4916004808201926020929091908290030181865afa158015612218573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061223c9190613584565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015260248101849052604401600060405180830381600087803b1580156122a957600080fd5b505af11580156122bd573d6000803e3d6000fd5b50506013546122cf92509050826129be565b6013555050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461235d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f57726f6e672073656e6465722e000000000000000000000000000000000000006044820152606401610624565b600955565b6801158e460913d00000601454101561237757565b6005546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156123e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061240a91906134ba565b6002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291925060009173ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa15801561247e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a291906134ba565b6005546003546014546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff92831660048201526024810191909152929350169063095ea7b3906044016020604051808303816000875af1158015612523573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125479190613569565b5060006125586014546009546112ac565b60065460145460055460025460035494955061259c9473ffffffffffffffffffffffffffffffffffffffff94851694879381169281169116612033426127106135a1565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638e4fa5a26040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561260657600080fd5b505af115801561261a573d6000803e3d6000fd5b50506002546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000935073ffffffffffffffffffffffffffffffffffffffff90911691506370a0823190602401602060405180830381865afa15801561268f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126b391906134ba565b6005546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291925060009173ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa158015612727573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274b91906134ba565b9050600061275986836130d3565b9050600061276784876130d3565b60155490915061277790826129be565b60155560145461278790836130d3565b60145560105461279790826129be565b60105550505050505050565b6000826000036127b557506000610fdd565b60006127c18385613639565b9050826127ce8583613650565b1461285b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60448201527f77000000000000000000000000000000000000000000000000000000000000006064820152608401610624565b9392505050565b60008060008390506000808273ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156128b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128dc91906136a9565b506dffffffffffffffffffffffffffff1691506dffffffffffffffffffffffffffff1691508673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612963573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129879190613584565b73ffffffffffffffffffffffffffffffffffffffff16036129ad578194508093506129b4565b8094508193505b5050509250929050565b6000806129cb83856135a1565b90508381101561285b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401610624565b60008073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612abf9190613584565b6040517fe6a4390500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301528581166024830152919091169063e6a4390590604401602060405180830381865afa158015612b35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b599190613584565b73ffffffffffffffffffffffffffffffffffffffff161415949350505050565b600081831115612be5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f46726f6d206d757374206265206265666f726520746f000000000000000000006044820152606401610624565b603c612bf18484613626565b61285b9190613650565b600061285b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613271565b6000808373ffffffffffffffffffffffffffffffffffffffff1663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612caf9190613584565b90508073ffffffffffffffffffffffffffffffffffffffff1663e6a439058573ffffffffffffffffffffffffffffffffffffffff1663ef8ef56f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d3c9190613584565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff91821660048201529086166024820152604401602060405180830381865afa158015612dad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dd19190613584565b949350505050565b612de1610789565b612ecb57600354600254600554612e149273ffffffffffffffffffffffffffffffffffffffff90811692811691166132c2565b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9283169081179091556005546040517f3526c0bd00000000000000000000000000000000000000000000000000000000815260048101929092526001602483015290911690633526c0bd90604401600060405180830381600087803b158015612eb757600080fd5b505af1158015611cc3573d6000803e3d6000fd5b565b6040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526024820185905288169063095ea7b3906044016020604051808303816000875af1158015612f42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f669190613569565b506040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526024820184905287169063095ea7b3906044016020604051808303816000875af1158015612fdc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130009190613569565b506040517fe8e3370000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301528781166024830152604482018590526064820184905260006084830181905260a483015286811660c483015260e4820183905285169063e8e3370090610104016060604051808303816000875af11580156130a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130c791906136f9565b50505050505050505050565b600061285b83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506133ab565b604080516002808252606082018352600092602083019080368337019050509050848160008151811061314a5761314a61353a565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505083816001815181106131985761319861353a565b73ffffffffffffffffffffffffffffffffffffffff92831660209182029290920101526040517f38ed1739000000000000000000000000000000000000000000000000000000008152908416906338ed173990613201908a908a9086908e908990600401613756565b6000604051808303816000875af1158015613220573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261326691908101906137e1565b505050505050505050565b600081836132ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161062491906138bd565b5060006132b98486613650565b95945050505050565b60008373ffffffffffffffffffffffffffffffffffffffff1663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa15801561330f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133339190613584565b6040517fc9c6539600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301528481166024830152919091169063c9c65396906044016020604051808303816000875af1158015612dad573d6000803e3d6000fd5b600081848411156133e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161062491906138bd565b5060006132b98486613626565b73ffffffffffffffffffffffffffffffffffffffff81168114611cc757600080fd5b60006020828403121561342a57600080fd5b813561285b816133f6565b60006020828403121561344757600080fd5b5035919050565b6000806040838503121561346157600080fd5b50508035926020909101359150565b8051801515811461348057600080fd5b919050565b6000806040838503121561349857600080fd5b82516134a3816133f6565b91506134b160208401613470565b90509250929050565b6000602082840312156134cc57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613533576135336134d3565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561357b57600080fd5b61285b82613470565b60006020828403121561359657600080fd5b815161285b816133f6565b80820180821115610fdd57610fdd6134d3565b600080600080608085870312156135ca57600080fd5b8451600381106135d957600080fd5b60208601516040870151606090970151919890975090945092505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b81810381811115610fdd57610fdd6134d3565b8082028115828204841417610fdd57610fdd6134d3565b600082613686577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b80516dffffffffffffffffffffffffffff8116811461348057600080fd5b6000806000606084860312156136be57600080fd5b6136c78461368b565b92506136d56020850161368b565b9150604084015163ffffffff811681146136ee57600080fd5b809150509250925092565b60008060006060848603121561370e57600080fd5b8351925060208401519150604084015190509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060a082018783526020878185015260a0604085015281875180845260c086019150828901935060005b818110156137b357845173ffffffffffffffffffffffffffffffffffffffff1683529383019391830191600101613781565b505073ffffffffffffffffffffffffffffffffffffffff969096166060850152505050608001529392505050565b600060208083850312156137f457600080fd5b825167ffffffffffffffff8082111561380c57600080fd5b818501915085601f83011261382057600080fd5b81518181111561383257613832613727565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110858211171561387557613875613727565b60405291825284820192508381018501918883111561389357600080fd5b938501935b828510156138b157845184529385019392850192613898565b98975050505050505050565b600060208083528351808285015260005b818110156138ea578581018301518582016040015282016138ce565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116850101925050509291505056fea264697066735822122022109c587634049b96e310baa780c707f0e6daedfe3eb9b02d03ee77f05c586764736f6c63430008110033

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106102c85760003560e01c8063715018a61161017b578063b651ae17116100d8578063cdac6fda1161008c578063d826492011610071578063d82649201461055e578063e72e4caf1461057e578063e7c0b2281461059e57600080fd5b8063cdac6fda14610543578063cea050151461055657600080fd5b8063bc31c1c1116100bd578063bc31c1c114610514578063bf9a6bda14610527578063c9b71e3b1461053a57600080fd5b8063b651ae17146104f9578063b95924111461050157600080fd5b80639d5d8b851161012f578063a539d66311610114578063a539d663146104be578063a80230de146104c6578063a901d15c146104e657600080fd5b80639d5d8b85146104a25780639ff01cee146104b557600080fd5b8063840a1c2a11610160578063840a1c2a146104715780638ad7f9db14610479578063923d4b151461048257600080fd5b8063715018a6146104615780637334cccd1461046957600080fd5b806335e07c21116102295780634fb886e3116101dd57806369dc5814116101c257806369dc58141461040e5780636b9f69b4146104215780636ba631cf1461044157600080fd5b80634fb886e3146103e35780635a2e2f47146103fb57600080fd5b80633baae36d1161020e5780633baae36d146103be578063444809f9146103c757806344ff54f7146103da57600080fd5b806335e07c2114610395578063363393881461039e57600080fd5b80632565b1591161028057806329265da71161026557806329265da71461032a578063292b7fd214610347578063325e2fd11461035057600080fd5b80632565b1591461031957806325782dcc1461032257600080fd5b80631375f83c116102b15780631375f83c146102f25780631edeeb00146102fb57806320ff46c11461030457600080fd5b80630152551e146102cd57806307a94a2d146102e9575b600080fd5b6102d6600a5481565b6040519081526020015b60405180910390f35b6102d6600f5481565b6102d660125481565b6102d660085481565b610317610312366004613418565b6105a7565b005b6102d6600e5481565b6102d6610674565b610332610697565b604080519283526020830191909152016102e0565b6102d660155481565b6001546103709073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102e0565b6102d660115481565b6005546103709073ffffffffffffffffffffffffffffffffffffffff1681565b6102d660105481565b6103176103d5366004613435565b6106f5565b6102d660145481565b6103eb610789565b60405190151581526020016102e0565b610317610409366004613418565b6107c1565b6102d661041c36600461344e565b610f16565b6002546103709073ffffffffffffffffffffffffffffffffffffffff1681565b6007546103709073ffffffffffffffffffffffffffffffffffffffff1681565b610317610fe3565b61031761108e565b6102d6611293565b6102d6600d5481565b6004546103709073ffffffffffffffffffffffffffffffffffffffff1681565b6102d66104b036600461344e565b6112ac565b6102d660135481565b610332611331565b6000546103709073ffffffffffffffffffffffffffffffffffffffff1681565b6103176104f4366004613435565b611398565b610317611850565b6102d661050f36600461344e565b611cca565b610332610522366004613435565b611cd7565b610317610535366004613435565b611d05565b6102d6600b5481565b610317610551366004613435565b6122dc565b610317612362565b6003546103709073ffffffffffffffffffffffffffffffffffffffff1681565b6006546103709073ffffffffffffffffffffffffffffffffffffffff1681565b6102d660095481565b60015473ffffffffffffffffffffffffffffffffffffffff16331461062d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f57726f6e672073656e6465722e0000000000000000000000000000000000000060448201526064015b60405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6000806000610681610697565b909250905061069082826127a3565b9250505090565b6005546007546000918291829182916106c99173ffffffffffffffffffffffffffffffffffffffff9081169116612862565b9150915081600014806106da575080155b156106ec575060009360019350915050565b90939092509050565b60055473ffffffffffffffffffffffffffffffffffffffff163314610776576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f7420617574686f72697a65640000000000000000000000000000000000006044820152606401610624565b60145461078390826129be565b60145550565b6003546005546002546000926107bc9273ffffffffffffffffffffffffffffffffffffffff918216929082169116612a37565b905090565b60005473ffffffffffffffffffffffffffffffffffffffff163314610842576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f57726f6e672073656e6465722e000000000000000000000000000000000000006044820152606401610624565b6040517f82b7b50000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f544f4b454e5f434f4e54524143540000000000000000000000000000000000006044820152600090819073ffffffffffffffffffffffffffffffffffffffff8416906382b7b500906064016040805180830381865afa1580156108de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109029190613485565b915091508061096d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f436f6e7472616374206e6f7420666f756e6400000000000000000000000000006044820152606401610624565b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff848116919091179091556040517f82b7b50000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4d4154485f434f4e5452414354000000000000000000000000000000000000006044820152908416906382b7b500906064016040805180830381865afa158015610a35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a599190613485565b909250905080610ac5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f436f6e7472616374206e6f7420666f756e6400000000000000000000000000006044820152606401610624565b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8481169190911782556040517f82b7b500000000000000000000000000000000000000000000000000000000008152602092810192909252601360248301527f45524332305f464545535f52454345495645520000000000000000000000000060448301528416906382b7b500906064016040805180830381865afa158015610b8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb19190613485565b909250905080610c1d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f436f6e7472616374206e6f7420666f756e6400000000000000000000000000006044820152606401610624565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff848116919091179091556040517f82b7b50000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f554e49535741505f524f555445520000000000000000000000000000000000006044820152908416906382b7b500906064016040805180830381865afa158015610ce5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d099190613485565b909250905080610d75576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f436f6e7472616374206e6f7420666f756e6400000000000000000000000000006044820152606401610624565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff848116919091179091556040517f82b7b50000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f45524332305f434f4e54524143540000000000000000000000000000000000006044820152908416906382b7b500906064016040805180830381865afa158015610e3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e619190613485565b909250905080610ecd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f436f6e7472616374206e6f7420666f756e6400000000000000000000000000006044820152606401610624565b50600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905550565b6000806000610f23610697565b600480546040517f4f84245100000000000000000000000000000000000000000000000000000000815291820189905260248201839052604482018490526064808301899052608483015292945090925073ffffffffffffffffffffffffffffffffffffffff90911690634f8424519060a4015b602060405180830381865afa158015610fb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fd891906134ba565b925050505b92915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611064576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f57726f6e672073656e6465722e000000000000000000000000000000000000006044820152606401610624565b600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b600080611099610697565b9150915081600014806110aa575080155b156110b3575050565b600c54158015906110dc575042600f541015806110dc575060036110d9600f5442612b79565b11155b156110e5575050565b42600f55600e54600c541015611170576040805180820190915282815260208101828152600c805460018101825560009190915291517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7600290930292830155517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c8909101556111df565b6040805180820190915282815260208101829052600d80548291600c9190600061119983613502565b91905055815481106111ad576111ad61353a565b60009182526020918290208351600290920201908155910151600190910155600e54600d54106111dd576000600d555b505b60008060005b600c5481101561126a5761121d600c82815481106112055761120561353a565b600091825260209091206002909102015484906129be565b9250611256600c82815481106112355761123561353a565b906000526020600020906002020160010154836129be90919063ffffffff16565b91508061126281613502565b9150506111e5565b50600c54611279908390612bfb565b600a55600c5461128a908290612bfb565b600b5550505050565b60006107bc600a54600b546127a390919063ffffffff16565b60008060006112b9610697565b600480546040517f4f84245100000000000000000000000000000000000000000000000000000000815291820189905260248201849052604482018390526064808301899052608483015292945090925073ffffffffffffffffffffffffffffffffffffffff90911690634f8424519060a401610f97565b600354600254600091829182916113619173ffffffffffffffffffffffffffffffffffffffff9182169116612c3d565b600254909150600090819061138c9073ffffffffffffffffffffffffffffffffffffffff1684612862565b90969095509350505050565b60055473ffffffffffffffffffffffffffffffffffffffff163314611419576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f7420617574686f72697a65640000000000000000000000000000000000006044820152606401610624565b611421610789565b15611488576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f506f6f6c20616c726561647920637265617465640000000000000000000000006044820152606401610624565b6002546040517f70a08231000000000000000000000000000000000000000000000000000000008152336004820152829173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156114f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061151a91906134ba565b10156115a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f4163636f756e7420646f6573206e6f74206861766520656e6f7567682045524360448201527f32300000000000000000000000000000000000000000000000000000000000006064820152608401610624565b6002546040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810183905273ffffffffffffffffffffffffffffffffffffffff909116906323b872dd906064016020604051808303816000875af1158015611625573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116499190613569565b6116d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f556e61626c6520746f207472616e73666572207265717569726564204552433260448201527f30000000000000000000000000000000000000000000000000000000000000006064820152608401610624565b6116dd612dd9565b60006116f4600854836127a390919063ffffffff16565b6005546040517fe742806a0000000000000000000000000000000000000000000000000000000081523060048201526024810183905291925073ffffffffffffffffffffffffffffffffffffffff169063e742806a90604401600060405180830381600087803b15801561176757600080fd5b505af115801561177b573d6000803e3d6000fd5b5050600554600254604080517f4e6fd6c4000000000000000000000000000000000000000000000000000000008152905161184c955073ffffffffffffffffffffffffffffffffffffffff938416945092909116918391634e6fd6c49160048083019260209291908290030181865afa1580156117fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118209190613584565b60035473ffffffffffffffffffffffffffffffffffffffff168587611847426127106135a1565b612ecd565b5050565b601554600b541580159061186657506000600a54115b15611cc75760048054600b54600a546040517fc718eeb7000000000000000000000000000000000000000000000000000000008152938401919091526024830152604482018390526000918291829173ffffffffffffffffffffffffffffffffffffffff9091169063c718eeb7906064016080604051808303816000875af11580156118f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061191a91906135b4565b50919450925090506002836002811115611936576119366135f7565b036119415750505050565b6001836002811115611955576119556135f7565b03611cc3576005546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156119c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ed91906134ba565b905060008183116119ff576000611a09565b611a098284613626565b90508015611a9c576005546040517fe742806a0000000000000000000000000000000000000000000000000000000081523060048201526024810183905273ffffffffffffffffffffffffffffffffffffffff9091169063e742806a90604401600060405180830381600087803b158015611a8357600080fd5b505af1158015611a97573d6000803e3d6000fd5b505050505b6002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611b0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b2f91906134ba565b600554600254604080517f4e6fd6c40000000000000000000000000000000000000000000000000000000081529051939450611bf99373ffffffffffffffffffffffffffffffffffffffff93841693909216918391634e6fd6c49160048083019260209291908290030181865afa158015611bae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd29190613584565b60035473ffffffffffffffffffffffffffffffffffffffff16888a611847426127106135a1565b6002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611c68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c8c91906134ba565b90506000611c9a83836130d3565b601554909150611caa90826130d3565b601555601154611cba90826129be565b60115550505050505b5050505b50565b6000806000610f23611331565b600c8181548110611ce757600080fd5b60009182526020909120600290910201805460019091015490915082565b60015473ffffffffffffffffffffffffffffffffffffffff163314611d86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f57726f6e672073656e6465722e000000000000000000000000000000000000006044820152606401610624565b601554811115611e18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f416d6f756e7420657263323020697320686967686572207468616e206176616960448201527f6c61626c650000000000000000000000000000000000000000000000000000006064820152608401610624565b6002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611e87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eab91906134ba565b6005546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291925060009173ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa158015611f1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4391906134ba565b6002546003546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015260248101879052929350169063095ea7b3906044016020604051808303816000875af1158015611fc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fe49190613569565b506000611ff384600954610f16565b6002546005546003549293506120389230928892869273ffffffffffffffffffffffffffffffffffffffff928316929182169116612033426127106135a1565b613115565b6002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156120a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120cb91906134ba565b905060006120d985836130d3565b6015549091506120e990826130d3565b6015556012546120f990826129be565b6012556005546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa15801561216b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218f91906134ba565b9050600061219d82876130d3565b600554604080517f4e6fd6c4000000000000000000000000000000000000000000000000000000008152905192935073ffffffffffffffffffffffffffffffffffffffff9091169163a9059cbb918391634e6fd6c4916004808201926020929091908290030181865afa158015612218573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061223c9190613584565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015260248101849052604401600060405180830381600087803b1580156122a957600080fd5b505af11580156122bd573d6000803e3d6000fd5b50506013546122cf92509050826129be565b6013555050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461235d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f57726f6e672073656e6465722e000000000000000000000000000000000000006044820152606401610624565b600955565b6801158e460913d00000601454101561237757565b6005546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156123e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061240a91906134ba565b6002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291925060009173ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa15801561247e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a291906134ba565b6005546003546014546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff92831660048201526024810191909152929350169063095ea7b3906044016020604051808303816000875af1158015612523573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125479190613569565b5060006125586014546009546112ac565b60065460145460055460025460035494955061259c9473ffffffffffffffffffffffffffffffffffffffff94851694879381169281169116612033426127106135a1565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638e4fa5a26040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561260657600080fd5b505af115801561261a573d6000803e3d6000fd5b50506002546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000935073ffffffffffffffffffffffffffffffffffffffff90911691506370a0823190602401602060405180830381865afa15801561268f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126b391906134ba565b6005546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291925060009173ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa158015612727573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274b91906134ba565b9050600061275986836130d3565b9050600061276784876130d3565b60155490915061277790826129be565b60155560145461278790836130d3565b60145560105461279790826129be565b60105550505050505050565b6000826000036127b557506000610fdd565b60006127c18385613639565b9050826127ce8583613650565b1461285b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60448201527f77000000000000000000000000000000000000000000000000000000000000006064820152608401610624565b9392505050565b60008060008390506000808273ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156128b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128dc91906136a9565b506dffffffffffffffffffffffffffff1691506dffffffffffffffffffffffffffff1691508673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612963573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129879190613584565b73ffffffffffffffffffffffffffffffffffffffff16036129ad578194508093506129b4565b8094508193505b5050509250929050565b6000806129cb83856135a1565b90508381101561285b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401610624565b60008073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612abf9190613584565b6040517fe6a4390500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301528581166024830152919091169063e6a4390590604401602060405180830381865afa158015612b35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b599190613584565b73ffffffffffffffffffffffffffffffffffffffff161415949350505050565b600081831115612be5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f46726f6d206d757374206265206265666f726520746f000000000000000000006044820152606401610624565b603c612bf18484613626565b61285b9190613650565b600061285b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613271565b6000808373ffffffffffffffffffffffffffffffffffffffff1663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612caf9190613584565b90508073ffffffffffffffffffffffffffffffffffffffff1663e6a439058573ffffffffffffffffffffffffffffffffffffffff1663ef8ef56f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d3c9190613584565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff91821660048201529086166024820152604401602060405180830381865afa158015612dad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dd19190613584565b949350505050565b612de1610789565b612ecb57600354600254600554612e149273ffffffffffffffffffffffffffffffffffffffff90811692811691166132c2565b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9283169081179091556005546040517f3526c0bd00000000000000000000000000000000000000000000000000000000815260048101929092526001602483015290911690633526c0bd90604401600060405180830381600087803b158015612eb757600080fd5b505af1158015611cc3573d6000803e3d6000fd5b565b6040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526024820185905288169063095ea7b3906044016020604051808303816000875af1158015612f42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f669190613569565b506040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526024820184905287169063095ea7b3906044016020604051808303816000875af1158015612fdc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130009190613569565b506040517fe8e3370000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301528781166024830152604482018590526064820184905260006084830181905260a483015286811660c483015260e4820183905285169063e8e3370090610104016060604051808303816000875af11580156130a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130c791906136f9565b50505050505050505050565b600061285b83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506133ab565b604080516002808252606082018352600092602083019080368337019050509050848160008151811061314a5761314a61353a565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505083816001815181106131985761319861353a565b73ffffffffffffffffffffffffffffffffffffffff92831660209182029290920101526040517f38ed1739000000000000000000000000000000000000000000000000000000008152908416906338ed173990613201908a908a9086908e908990600401613756565b6000604051808303816000875af1158015613220573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261326691908101906137e1565b505050505050505050565b600081836132ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161062491906138bd565b5060006132b98486613650565b95945050505050565b60008373ffffffffffffffffffffffffffffffffffffffff1663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa15801561330f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133339190613584565b6040517fc9c6539600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301528481166024830152919091169063c9c65396906044016020604051808303816000875af1158015612dad573d6000803e3d6000fd5b600081848411156133e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161062491906138bd565b5060006132b98486613626565b73ffffffffffffffffffffffffffffffffffffffff81168114611cc757600080fd5b60006020828403121561342a57600080fd5b813561285b816133f6565b60006020828403121561344757600080fd5b5035919050565b6000806040838503121561346157600080fd5b50508035926020909101359150565b8051801515811461348057600080fd5b919050565b6000806040838503121561349857600080fd5b82516134a3816133f6565b91506134b160208401613470565b90509250929050565b6000602082840312156134cc57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613533576135336134d3565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561357b57600080fd5b61285b82613470565b60006020828403121561359657600080fd5b815161285b816133f6565b80820180821115610fdd57610fdd6134d3565b600080600080608085870312156135ca57600080fd5b8451600381106135d957600080fd5b60208601516040870151606090970151919890975090945092505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b81810381811115610fdd57610fdd6134d3565b8082028115828204841417610fdd57610fdd6134d3565b600082613686577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b80516dffffffffffffffffffffffffffff8116811461348057600080fd5b6000806000606084860312156136be57600080fd5b6136c78461368b565b92506136d56020850161368b565b9150604084015163ffffffff811681146136ee57600080fd5b809150509250925092565b60008060006060848603121561370e57600080fd5b8351925060208401519150604084015190509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060a082018783526020878185015260a0604085015281875180845260c086019150828901935060005b818110156137b357845173ffffffffffffffffffffffffffffffffffffffff1683529383019391830191600101613781565b505073ffffffffffffffffffffffffffffffffffffffff969096166060850152505050608001529392505050565b600060208083850312156137f457600080fd5b825167ffffffffffffffff8082111561380c57600080fd5b818501915085601f83011261382057600080fd5b81518181111561383257613832613727565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110858211171561387557613875613727565b60405291825284820192508381018501918883111561389357600080fd5b938501935b828510156138b157845184529385019392850192613898565b98975050505050505050565b600060208083528351808285015260005b818110156138ea578581018301518582016040015282016138ce565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116850101925050509291505056fea264697066735822122022109c587634049b96e310baa780c707f0e6daedfe3eb9b02d03ee77f05c586764736f6c63430008110033