BNB Price: $719.62 (-0.06%)
Gas: 1 GWei
 

Overview

BNB Balance

BNB Smart Chain LogoBNB Smart Chain LogoBNB Smart Chain Logo0.025 BNB

BNB Value

$17.99 (@ $719.62/BNB)
Transaction Hash
Method
Block
From
To
Extend Participa...442708192024-11-23 20:20:2322 days ago1732393223IN
0xd4C3589D...a2CCcE0E9
0 BNB0.000622043
Swap439538012024-11-12 20:08:5733 days ago1731442137IN
0xd4C3589D...a2CCcE0E9
0 BNB0.001228073
Swap439504952024-11-12 17:23:3133 days ago1731432211IN
0xd4C3589D...a2CCcE0E9
0 BNB0.002324071.1
Swap433746682024-10-23 17:19:1853 days ago1729703958IN
0xd4C3589D...a2CCcE0E9
0 BNB0.001890451.1
Swap430715342024-10-13 4:41:0564 days ago1728794465IN
0xd4C3589D...a2CCcE0E9
0 BNB0.000371641.1
Swap430714642024-10-13 4:37:3564 days ago1728794255IN
0xd4C3589D...a2CCcE0E9
0 BNB0.002595681.1
Swap430648462024-10-12 23:06:3664 days ago1728774396IN
0xd4C3589D...a2CCcE0E9
0 BNB0.00039261.1
Swap406488742024-07-20 21:39:14148 days ago1721511554IN
0xd4C3589D...a2CCcE0E9
0 BNB0.000960663
Swap406488612024-07-20 21:38:35148 days ago1721511515IN
0xd4C3589D...a2CCcE0E9
0 BNB0.001214393
Swap401905802024-07-04 22:27:27164 days ago1720132047IN
0xd4C3589D...a2CCcE0E9
0 BNB0.000339621
Mint401905412024-07-04 22:25:30164 days ago1720131930IN
0xd4C3589D...a2CCcE0E9
0.001816 BNB0.0006391
Swap401905162024-07-04 22:24:15164 days ago1720131855IN
0xd4C3589D...a2CCcE0E9
0 BNB0.00031521
Swap395360362024-06-12 2:39:41187 days ago1718159981IN
0xd4C3589D...a2CCcE0E9
0 BNB0.000496021.1
Swap395337902024-06-12 0:47:06187 days ago1718153226IN
0xd4C3589D...a2CCcE0E9
0 BNB0.000450781
Swap392892942024-06-03 12:20:30196 days ago1717417230IN
0xd4C3589D...a2CCcE0E9
0.01 BNB0.000805463
Mint391336962024-05-29 2:18:46201 days ago1716949126IN
0xd4C3589D...a2CCcE0E9
0.00079 BNB0.001874561
Mint381760902024-04-25 18:34:41234 days ago1714070081IN
0xd4C3589D...a2CCcE0E9
0.001 BNB0.000678371
Extend Participa...380646882024-04-21 21:34:53238 days ago1713735293IN
0xd4C3589D...a2CCcE0E9
0 BNB0.000171841
Mint380359782024-04-20 21:36:21239 days ago1713648981IN
0xd4C3589D...a2CCcE0E9
0.001 BNB0.000470631
Mint378845392024-04-15 15:11:04245 days ago1713193864IN
0xd4C3589D...a2CCcE0E9
0.02 BNB0.002703031
Swap378832462024-04-15 14:06:15245 days ago1713189975IN
0xd4C3589D...a2CCcE0E9
0.01 BNB0.000287211
Extend Participa...378668502024-04-15 0:25:10245 days ago1713140710IN
0xd4C3589D...a2CCcE0E9
0 BNB0.000194361
Extend Participa...377894362024-04-12 7:44:53248 days ago1712907893IN
0xd4C3589D...a2CCcE0E9
0 BNB0.000176631
Swap377127502024-04-09 15:43:10251 days ago1712677390IN
0xd4C3589D...a2CCcE0E9
0.005 BNB0.000268491
Swap377087382024-04-09 12:22:25251 days ago1712665345IN
0xd4C3589D...a2CCcE0E9
0.0001 BNB0.000339471
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
448565202024-12-14 4:28:582 days ago1734150538
0xd4C3589D...a2CCcE0E9
0.00346397 BNB
448565202024-12-14 4:28:582 days ago1734150538
0xd4C3589D...a2CCcE0E9
0.00346397 BNB
439538012024-11-12 20:08:5733 days ago1731442137
0xd4C3589D...a2CCcE0E9
0.00140369 BNB
439538012024-11-12 20:08:5733 days ago1731442137
0xd4C3589D...a2CCcE0E9
0.00140369 BNB
439504952024-11-12 17:23:3133 days ago1731432211
0xd4C3589D...a2CCcE0E9
0.00299033 BNB
439504952024-11-12 17:23:3133 days ago1731432211
0xd4C3589D...a2CCcE0E9
0.00299033 BNB
430715342024-10-13 4:41:0564 days ago1728794465
0xd4C3589D...a2CCcE0E9
0.00240267 BNB
430715342024-10-13 4:41:0564 days ago1728794465
0xd4C3589D...a2CCcE0E9
0.00240267 BNB
430714642024-10-13 4:37:3564 days ago1728794255
0xd4C3589D...a2CCcE0E9
0.01077698 BNB
430714642024-10-13 4:37:3564 days ago1728794255
0xd4C3589D...a2CCcE0E9
0.01077698 BNB
430648462024-10-12 23:06:3664 days ago1728774396
0xd4C3589D...a2CCcE0E9
0.02070773 BNB
430648462024-10-12 23:06:3664 days ago1728774396
0xd4C3589D...a2CCcE0E9
0.02070773 BNB
406488742024-07-20 21:39:14148 days ago1721511554
0xd4C3589D...a2CCcE0E9
0.00900613 BNB
406488742024-07-20 21:39:14148 days ago1721511554
0xd4C3589D...a2CCcE0E9
0.00900613 BNB
401905802024-07-04 22:27:27164 days ago1720132047
0xd4C3589D...a2CCcE0E9
0.00293231 BNB
401905802024-07-04 22:27:27164 days ago1720132047
0xd4C3589D...a2CCcE0E9
0.00293231 BNB
401905412024-07-04 22:25:30164 days ago1720131930
0xd4C3589D...a2CCcE0E9
0.001816 BNB
401905162024-07-04 22:24:15164 days ago1720131855
0xd4C3589D...a2CCcE0E9
0.00191535 BNB
401905162024-07-04 22:24:15164 days ago1720131855
0xd4C3589D...a2CCcE0E9
0.00191535 BNB
395360362024-06-12 2:39:41187 days ago1718159981
0xd4C3589D...a2CCcE0E9
0.00179649 BNB
395337902024-06-12 0:47:06187 days ago1718153226
0xd4C3589D...a2CCcE0E9
0.00186363 BNB
392892942024-06-03 12:20:30196 days ago1717417230
0xd4C3589D...a2CCcE0E9
0.01 BNB
391336962024-05-29 2:18:46201 days ago1716949126
0xd4C3589D...a2CCcE0E9
0.00079 BNB
381760902024-04-25 18:34:41234 days ago1714070081
0xd4C3589D...a2CCcE0E9
0.001 BNB
380359782024-04-20 21:36:21239 days ago1713648981
0xd4C3589D...a2CCcE0E9
0.001 BNB
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Sponsor

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 2000000 runs

Other Settings:
paris EvmVersion
File 1 of 6 : Sponsor.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import "./TimeExchange.sol";

/// @title Sponsor: a TIME Token Finance smart contract to relay and monitor transactions that generate value on the platform; it rewards users accordingly, which means users' transactions are being sponsored
/// @author https://timetoken.finance
/// @notice Reward is given in the network's native token, as recurrent prizes, which are granted according to users' activity frequency and their transacted amount.
/// Please refer that interacting with this contract is solely at your own risk!
/// Also, the administrator reserves the right to claim all funds from this contract at any time at their own discretion, once they deposit their own funds here...
/// There are other ways of interacting and trading with the TIME Token Finance platform, either through the TimeExchange contract or directly through the TimeToken and TimeIsUp contracts.
/// We encourage everyone who wishes to do so if they feel uncomfortable with the functions of this contract.
contract Sponsor {
    using Math for uint256;

    enum OperationType {
        MINT,
        SWAP_TIME,
        SWAP_TUP
    }

    struct Participant {
        bool isParticipating;
        bool wasSelected;
        address previousParticipant;
        address nextParticipant;
        mapping(uint256 => uint256) interactionPoints;
        mapping(uint256 => uint256) valuePoints;
    }

    struct Winners {
        address first;
        address second;
        address third;
        address fourth;
    }

    event ParticipantAdded(address participant);
    event ParticipantRemoved(address participant);
    event ParticipantsListCleaned();
    event RoundWinner(uint256 round, address participant, uint256 earnedPrize);

    bool private _canReceiveAdditionalFunds = true;
    bool private _isOperationLocked;

    bool public isOperationTypeFlipped;

    TimeExchange public immutable timeExchange;
    ITimeToken public immutable timeToken;
    ITimeIsUp public immutable tupToken;

    address public administrator;
    address public currentLeader;
    address public firstParticipant;
    address public lastParticipant;

    uint256 private constant D = 10 ** 18;
    uint256 public constant TIME_BURNING_RATE = 5_000;
    uint256 public constant MININUM_NUMBER_OF_PARTICIPANTS = 5;
    uint256 public constant NUMBER_OF_SELECTED_WINNERS = 4;

    uint256 private CURRENT_FEES_PERCENTAGE;
    uint256 private PERCENTAGE_PROFIT_TARGET = 11_000;
    uint256 private REBATE_PERCENTAGE = 100;

    uint256 public accumulatedPrize;
    uint256 public currentAdditionalPrize;
    uint256 public currentPrize;
    uint256 public currentRebate;
    uint256 public currentTarget;
    uint256 public currentValueMoved;
    uint256 public maxInteractionPoints;
    uint256 public minAmountToEarnPoints;
    uint256 public numberOfParticipants;
    uint256 public round;

    mapping(address => uint256) private _currentBlock;

    mapping(address => uint256) public lastBlock;
    mapping(address => uint256) public prizeToClaim;
    mapping(address => uint256) public remainingTime;

    mapping(uint256 => Winners winners) public roundWinners;

    mapping(address => Participant participant) public participants;

    constructor(address timeTokenAddress, address tupTokenAddress, address timeExchangeAddress) {
        administrator = msg.sender;
        timeToken = ITimeToken(payable(timeTokenAddress));
        tupToken = ITimeIsUp(payable(tupTokenAddress));
        timeExchange = TimeExchange(payable(timeExchangeAddress));
        setCurrentFeesPercentage(timeExchange.FEE());
        setMinAmountToEarnPoints(0.1 ether);
        round = 1;
    }

    receive() external payable {
        _depositPrize(0, msg.value);
    }

    fallback() external payable {
        require(msg.data.length == 0);
        _depositPrize(0, msg.value);
    }

    /// @notice Modifier to allow only administrator access
    modifier admin() {
        require(msg.sender == administrator, "Sponsor: only admin allowed");
        _;
    }

    /// @notice Modifier to allow registering additional funds to prize when receiveing native token of the network
    modifier canReceiveAdditional() {
        _canReceiveAdditionalFunds = true;
        _;
        _canReceiveAdditionalFunds = false;
    }

    /// @notice Modifier to disallow registering additional funds to prize when receiveing native token of the network
    modifier cannotReceiveAdditional() {
        _canReceiveAdditionalFunds = false;
        _;
        _canReceiveAdditionalFunds = true;
    }

    /// @notice Verifies if the current round can be finished
    modifier checkEndOfRound() {
        _;
        if (queryAmountRemainingForPrize() == 0 && currentPrize > 0 && numberOfParticipants >= MININUM_NUMBER_OF_PARTICIPANTS) {
            _rewardWinnersAndCloseRound();
        }
    }

    /// @notice Modifier to make a function runs only once per block
    modifier onlyOncePerBlock() {
        require(block.number != _currentBlock[tx.origin], "Sponsor: you cannot perform this operation again in this block");
        _currentBlock[tx.origin] = block.number;
        _;
    }

    /// @notice Implement security to avoid reentrancy attacks
    modifier nonReentrant() {
        require(!_isOperationLocked, "Sponsor: this operation is locked");
        _isOperationLocked = true;
        _;
        _isOperationLocked = false;
    }

    /// @notice Modifier used when the status of the current participant should be checked and updated
    /// @dev Called together with mint(), swap(), and extendParticipationPeriod() functions
    modifier update() {
        if ((lastBlock[msg.sender] == 0 && block.number != 0) || remainingTime[msg.sender] == 0) {
            lastBlock[msg.sender] = block.number;
        }
        uint256 elapsedTime = block.number - lastBlock[msg.sender];
        if (elapsedTime > remainingTime[msg.sender] && participants[msg.sender].isParticipating) {
            _removeParticipant(msg.sender);
        }
        _;
        remainingTime[msg.sender] = (elapsedTime > remainingTime[msg.sender]) ? 0 : remainingTime[msg.sender] - elapsedTime;
        lastBlock[msg.sender] = block.number;
        if (remainingTime[msg.sender] >= elapsedTime && remainingTime[msg.sender] > 0 && !participants[msg.sender].isParticipating) {
            _addParticipant(msg.sender);
        }
    }

    //
    /// @notice Add a participant and adjusts the participants chained list
    /// @dev The current participant added is sent to the end of the list
    /// @param participant The address of the participant
    function _addParticipant(address participant) private {
        if (participant != address(0) && !participants[participant].isParticipating) {
            participants[participant].previousParticipant = lastParticipant;
            participants[participant].nextParticipant = address(0);
            if (firstParticipant == address(0)) {
                firstParticipant = participant;
            }
            if (lastParticipant != address(0)) {
                participants[lastParticipant].nextParticipant = participant;
            }
            lastParticipant = participant;
            participants[participant].isParticipating = true;
            numberOfParticipants++;
            emit ParticipantAdded(participant);
        }
    }

    /// @notice Burn some TIME tokens in order to regulate the market inflation
    /// @dev It runs with try { } catch to not revert in case of being unsuccessful
    function _burnTime() private {
        uint256 balanceInTime = timeToken.balanceOf(address(this));
        if (balanceInTime > 0) {
            try timeToken.burn(balanceInTime.mulDiv(TIME_BURNING_RATE, 10_000)) { } catch { }
        }
    }

    /// @notice Resets the entire list of participants in the contract
    /// @dev It also should clean the participants' score/pontuation, if the case
    function _cleanParticipantsList() private {
        address currentParticipant = firstParticipant;
        address nextParticipant;
        while (currentParticipant != address(0)) {
            nextParticipant = participants[currentParticipant].nextParticipant;
            participants[currentParticipant].previousParticipant = address(0);
            participants[currentParticipant].nextParticipant = address(0);
            participants[currentParticipant].isParticipating = false;
            participants[currentParticipant].wasSelected = false;
            participants[currentParticipant].interactionPoints[round] = 0;
            participants[currentParticipant].valuePoints[round] = 0;
            remainingTime[currentParticipant] = 0;
            lastBlock[currentParticipant] = block.number;
            currentParticipant = nextParticipant;
        }
        firstParticipant = address(0);
        lastParticipant = address(0);
        numberOfParticipants = 0;
        emit ParticipantsListCleaned();
    }

    /// @notice Deposits the resources used as prizes (main and additional)
    /// @dev Indirectly called by admins and third parties (as additional deposit)
    /// @param amount The main deposit amount
    /// @param additionalAmount The additional deposit amount
    function _depositPrize(uint256 amount, uint256 additionalAmount) private {
        require(msg.value > 0, "Sponsor: please deposit some amount");
        if (_canReceiveAdditionalFunds) {
            if (amount > 0) {
                accumulatedPrize += amount;
                if (currentPrize == 0) {
                    currentPrize = accumulatedPrize / 2;
                    currentTarget = (currentPrize + currentPrize.mulDiv(PERCENTAGE_PROFIT_TARGET, 10_000)).mulDiv(10_000, CURRENT_FEES_PERCENTAGE);
                }
            }
            if (additionalAmount > 0) {
                uint256 halfAdditionalAmount = (additionalAmount / 2);
                accumulatedPrize += additionalAmount;
                currentAdditionalPrize += halfAdditionalAmount;
                currentRebate += halfAdditionalAmount.mulDiv(REBATE_PERCENTAGE, 10_000);
            }
        }
    }

    /// @notice Receives additional resources from the TIME and TUP contracts
    /// @dev It calls the TUP contract indirectly, using Claimer
    function _earnAdditionalResources() private canReceiveAdditional {
        if (timeToken.withdrawableShareBalance(address(this)) > 0) {
            try timeToken.withdrawShare() { } catch { }
        }
        if (tupToken.queryPublicReward() > 0) {
            try tupToken.splitSharesWithReward() { } catch { }
        }
    }

    /// @notice Calculates and storage the received points of a participant, but only if the negotiated amount is above the minimum established
    /// @dev It classifies operations according to its relevance for the protocol
    /// @param participant The address of participant to register points
    /// @param operation Type of the operation called by a participant and relayed to the TimeExchange contract
    /// @param amount The amount of native tokens moved by the participant
    function _registerPoints(address participant, OperationType operation, uint256 amount) private {
        if (amount >= minAmountToEarnPoints && participant != address(0)) {
            uint256 weight = isOperationTypeFlipped ? (uint256(type(OperationType).max) - uint256(operation)) + 1 : uint256(operation) + 1;
            participants[participant].interactionPoints[round] += weight;
            participants[participant].valuePoints[round] += (amount * weight);
            if (participants[participant].interactionPoints[round] > maxInteractionPoints) {
                maxInteractionPoints = participants[participant].interactionPoints[round];
                currentLeader = participant;
            }
        }
    }

    /// @notice Remove a participant and adjusts the participants chained list of the contract
    /// @dev It concatenates the right next participant of the current participant with the previous one
    /// @param participant The address of a participant which will be removed of the chained list
    function _removeParticipant(address participant) private {
        if (participant != address(0) && participants[participant].isParticipating) {
            address previousParticipant = participants[participant].previousParticipant;
            address nextParticipant = participants[participant].nextParticipant;
            if (lastParticipant == participant) {
                lastParticipant = previousParticipant;
            }
            if (firstParticipant == participant) {
                firstParticipant = nextParticipant;
            }
            if (previousParticipant != address(0)) {
                participants[previousParticipant].nextParticipant = nextParticipant;
            }
            if (nextParticipant != address(0)) {
                participants[nextParticipant].previousParticipant = previousParticipant;
            }
            if (participant == currentLeader) {
                currentLeader = address(0);
                maxInteractionPoints = 0;
            }
            participants[participant].previousParticipant = address(0);
            participants[participant].nextParticipant = address(0);
            participants[participant].isParticipating = false;
            participants[participant].wasSelected = false;
            participants[participant].interactionPoints[round] = 0;
            participants[participant].valuePoints[round] = 0;
            numberOfParticipants--;
            emit ParticipantRemoved(participant);
        }
    }

    /// @notice Performs the reward and close the current round
    /// @dev Another round is automatically initiated
    function _rewardWinnersAndCloseRound() private nonReentrant {
        uint256 totalPrize = queryCurrentTotalPrize();
        if (totalPrize <= address(this).balance) {
            uint256 prizeShares = totalPrize / 10;
            if (!checkParticipation(currentLeader)) {
                _removeParticipant(currentLeader);
                if (numberOfParticipants < MININUM_NUMBER_OF_PARTICIPANTS) {
                    return;
                }
                currentLeader = _selectRandomWinner();
            } else {
                participants[currentLeader].wasSelected = true;
            }
            uint256 earnedPrize = (NUMBER_OF_SELECTED_WINNERS * prizeShares);
            prizeToClaim[currentLeader] += earnedPrize;
            emit RoundWinner(round, currentLeader, earnedPrize);
            address[] memory winners = _selectRoundWinners();
            for (uint256 i = 0; i < winners.length; i++) {
                earnedPrize = (winners.length - i) * prizeShares;
                prizeToClaim[winners[i]] += earnedPrize;
                emit RoundWinner(round, winners[i], earnedPrize);
            }
            roundWinners[round].first = currentLeader;
            roundWinners[round].second = winners[0];
            roundWinners[round].third = winners[1];
            roundWinners[round].fourth = winners[2];
            accumulatedPrize -= totalPrize;
            currentPrize = accumulatedPrize / 2;
            currentTarget = currentPrize > 0 ? (currentPrize + currentPrize.mulDiv(PERCENTAGE_PROFIT_TARGET, 10_000)).mulDiv(10_000, CURRENT_FEES_PERCENTAGE) : 0;
            currentAdditionalPrize = 0;
            currentRebate = 0;
            currentValueMoved = 0;
            _burnTime();
            _cleanParticipantsList();
            maxInteractionPoints = 0;
            currentLeader = address(0);
            round++;
        }
    }

    /// @notice Picks a randomly selected winner
    /// @dev It traverses the whole chained list of participants to pick those who match with a random index number. It marks the winner from that list right after the selection
    /// @return randomWinner The address of the picked random winner
    function _selectRandomWinner() private returns (address randomWinner) {
        uint256 nonce = 1;
        while (randomWinner == address(0)) {
            address currentParticipant = firstParticipant;
            uint256 randomWinnerIndex = uint256(
                keccak256(
                    abi.encode(
                        nonce++, block.number, block.timestamp, block.prevrandao, address(this), currentPrize, currentValueMoved, currentTarget
                    )
                )
            ) % numberOfParticipants;
            uint256 currentIndex;
            while (currentParticipant != address(0)) {
                if (currentIndex == randomWinnerIndex && checkParticipation(currentParticipant)) {
                    if (participants[currentParticipant].wasSelected) {
                        if (randomWinnerIndex == numberOfParticipants - 1) {
                            currentIndex = 0;
                            randomWinnerIndex = 0;
                            currentParticipant = firstParticipant;
                        } else {
                            randomWinnerIndex++;
                        }
                        continue;
                    }
                    participants[currentParticipant].wasSelected = true;
                    randomWinner = currentParticipant;
                    break;
                }
                currentIndex++;
                currentParticipant = participants[currentParticipant].nextParticipant;
            }
        }
    }

    /// @notice Select the round winners with the highest value points earned. The last winner is randomly selected
    /// @dev It traverses the whole chained list of participants to pick those with the highest earned points. It marks the winners from that list right after the selection
    /// @return winners Array containing addresses of the round winners
    function _selectRoundWinners() private returns (address[] memory winners) {
        winners = new address[](NUMBER_OF_SELECTED_WINNERS - 1);
        uint256[] memory maxPoint = new uint256[](winners.length);
        address currentParticipant;
        address nextParticipant;
        for (uint256 i = 0; i < winners.length - 1; i++) {
            currentParticipant = firstParticipant;
            while (currentParticipant != address(0)) {
                nextParticipant = participants[currentParticipant].nextParticipant;
                if (
                    participants[currentParticipant].valuePoints[round] > maxPoint[i] && checkParticipation(currentParticipant)
                        && !participants[currentParticipant].wasSelected
                ) {
                    maxPoint[i] = participants[currentParticipant].valuePoints[round];
                    winners[i] = currentParticipant;
                }
                currentParticipant = nextParticipant;
            }
            // If still has no winner, it picks randomly
            if (winners[i] == address(0)) {
                winners[i] = _selectRandomWinner();
            }
            participants[winners[i]].wasSelected = true;
        }
        // It now picks a random winner as the last winner
        winners[winners.length - 1] = _selectRandomWinner();
        return winners;
    }

    /// @notice Withdraws the total prize received by the sponsors
    /// @dev Called by a user after receiveing a prize for his address. The prize remains in the contract for an indefinite time. Non reentrant
    function claimPrize() external nonReentrant {
        require(prizeToClaim[msg.sender] > 0, "Sponsor: there is no prize to claim for the caller address");
        require(prizeToClaim[msg.sender] <= address(this).balance, "Sponsor: there is no enough amount to withdraw");
        uint256 amount = prizeToClaim[msg.sender];
        prizeToClaim[msg.sender] = 0;
        payable(msg.sender).transfer(amount);
    }

    /// @notice Informs if a participant is active in the current sponsorship round
    /// @dev It must check if the participant also has enough TIME to be consumed
    /// @param participant The participant's address
    /// @return isParticipating If the informed address is participating in the sponsorship round indeed
    function checkParticipation(address participant) public view returns (bool) {
        return ((remainingTime[participant] >= (block.number - lastBlock[participant])) && participants[participant].isParticipating);
    }

    /// @notice Deposit the main contract prize (Usually called by the sponsors - admins). The contract can receive additional funds directly from other sources
    /// @dev Only admins can call this function. It calls a private function by chaging the order of parameters, meaning that it is the main deposit
    function depositPrize() external payable admin {
        _depositPrize(msg.value, 0);
    }

    /// @notice Withdraws all the funds of the contract to the administrator address and restarts the contract variables
    /// @dev Only admin can call this function. For emergency only!
    function emergencyWithdraw() external admin {
        _cleanParticipantsList();
        accumulatedPrize = 0;
        currentAdditionalPrize = 0;
        currentPrize = 0;
        currentRebate = 0;
        currentTarget = 0;
        currentValueMoved = 0;
        currentLeader = address(0);
        maxInteractionPoints = 0;
        uint256 tupBalance = tupToken.balanceOf(address(this));
        if (tupBalance > 0) {
            try tupToken.transfer(administrator, tupBalance) { } catch { }
        }
        try timeToken.transfer(administrator, timeToken.balanceOf(address(this))) { } catch { }
        payable(administrator).transfer(address(this).balance);
    }

    /// @notice Enables participation in the sponsorship by depositing TIME
    /// @dev User must approve TIME to be spent before calling this function
    /// @param amountTime The amount of TIME the user would like to deposit in order to participate the current sponsorship round
    function extendParticipationPeriod(uint256 amountTime) external cannotReceiveAdditional checkEndOfRound update {
        require(
            timeToken.allowance(msg.sender, address(this)) >= amountTime, "Sponsor: please approve the TIME amount to extend your sponsorship period"
        );
        require(amountTime >= D, "Sponsor: you should deposit 1 TIME or more to extend your sponsorship period");
        timeToken.transferFrom(msg.sender, address(this), amountTime);
        remainingTime[msg.sender] += amountTime.mulDiv(1, D);
    }

    /// @notice Flip the operation type so the most value operation turns into the lesser one, and vice-versa
    /// @dev The isOperationTypeFlipped is used in _registerPoints() function to adjust the weight applied over the operation number
    function flipOperationType() external admin {
        isOperationTypeFlipped = !isOperationTypeFlipped;
    }

    /// @notice Performs mint of TUP tokens by demand
    /// @dev Relays the mint function to the TimeIsUp contract, but observing and registering additional information
    /// @param amountTime The amount of TIME the user wants to use to mint TUP
    function mint(uint256 amountTime) external payable cannotReceiveAdditional checkEndOfRound onlyOncePerBlock update {
        require(
            timeToken.allowance(msg.sender, address(this)) >= amountTime, "Sponsor: you should allow TIME to be spent before calling the function"
        );
        if (amountTime > 0) {
            timeToken.transferFrom(msg.sender, address(this), amountTime);
            timeToken.approve(address(tupToken), amountTime);
        }
        uint256 balanceBefore = tupToken.balanceOf(address(this));
        try tupToken.mint{ value: msg.value }(amountTime) {
            currentValueMoved += msg.value;
            uint256 balanceAfter = tupToken.balanceOf(address(this));
            tupToken.transfer(msg.sender, balanceAfter - balanceBefore);
            if (checkParticipation(msg.sender) && amountTime == 0) {
                _registerPoints(msg.sender, OperationType.MINT, msg.value);
                _earnAdditionalResources();
            }
        } catch {
            revert("Sponsor: unable to relay mint");
        }
    }

    /// @notice Query for the amount needed to unlock the prize for round winners
    /// @return amountRemaining The amount which is remaining to achieve the current target for prize unlock
    function queryAmountRemainingForPrize() public view returns (uint256) {
        return currentTarget > (currentRebate + currentValueMoved) ? currentTarget - (currentRebate + currentValueMoved) : 0;
    }

    /// @notice Query for the prize amount deposited by admins and earned by the contract
    /// @return totalPrize Current prize + additional prize earned
    function queryCurrentTotalPrize() public view returns (uint256) {
        return (currentPrize + currentAdditionalPrize);
    }

    /// @notice Query for the interaction points of a participant
    /// @return interactionPoints Informs the number of interactions (times an operation weight) a given user address interacted with the Sponsor contract
    function queryInteractionPoints(address participant) external view returns (uint256) {
        return checkParticipation(participant) ? participants[participant].interactionPoints[round] : 0;
    }

    /// @notice Query for the value points of a participant
    /// @return valuePoints Informs the amount of native tokens (times an operation weight) a given user address negotiated with the Sponsor contract
    function queryValuePoints(address participant) external view returns (uint256) {
        return checkParticipation(participant) ? participants[participant].valuePoints[round] : 0;
    }

    /// @notice Changes the new administrator address
    /// @dev Only the owner of the contract can access
    /// @param newAdministrator The new address value to be set.
    function setAdministrator(address newAdministrator) public admin {
        administrator = newAdministrator;
    }

    /// @notice Adjusts the new fees percentage charged by the protocol
    /// @dev Only the owner of the contract can access
    /// @param newCurrentFeesPercentage The new value to be set. Factor of 10_000. Example: if percentage is 1%, it should be set as 100
    function setCurrentFeesPercentage(uint256 newCurrentFeesPercentage) public admin {
        CURRENT_FEES_PERCENTAGE = newCurrentFeesPercentage;
    }

    /// @notice Adjusts the minimum amount a participant should trade to earn points in the protocol
    /// @dev Only the owner of the contract can access
    /// @param newMinAmount The new value to be set. It should be defined in terms of the native token of the underlying network
    function setMinAmountToEarnPoints(uint256 newMinAmount) public admin {
        minAmountToEarnPoints = newMinAmount;
    }

    /// @notice Adjusts the percentage of the desirable profit
    /// @dev Only the owner of the contract can access
    /// @param newProfitTargetPercentage The new value to be set. Factor of 10_000. Example: if percentage is 1%, it should be set as 100
    function setPercentageProfitTarget(uint256 newProfitTargetPercentage) external admin {
        PERCENTAGE_PROFIT_TARGET = newProfitTargetPercentage;
    }

    /// @notice Adjusts the percentage of rebates to achieve prize targets
    /// @dev Only the owner of the contract can access
    /// @param newRebatePercentage The new value to be set. Factor of 10_000. Example: if percentage is 1%, it should be set as 100
    function setRebatePercentage(uint256 newRebatePercentage) external admin {
        REBATE_PERCENTAGE = newRebatePercentage;
    }

    /// @notice It relay swaps to TimeExchange contract, but register points only for native currency to another token
    /// @dev It should inform address(0) as tokenFrom or tokenTo when considering native currency
    /// @param tokenFrom The address of the token to be swapped
    /// @param tokenTo The address of the token to be swapped
    /// @param amount The token or native currency amount to be swapped
    function swap(address tokenFrom, address tokenTo, uint256 amount)
        external
        payable
        cannotReceiveAdditional
        checkEndOfRound
        onlyOncePerBlock
        update
    {
        IERC20 tokenToTransfer;
        uint256 balanceBefore;
        if (tokenFrom != address(0)) {
            IERC20 tokenFromTransfer = IERC20(tokenFrom);
            require(tokenFromTransfer.allowance(msg.sender, address(this)) >= amount, "Sponsor: please approve the amount to swap");
            tokenFromTransfer.transferFrom(msg.sender, address(this), amount);
            tokenFromTransfer.approve(address(timeExchange), amount);
        }
        if (tokenTo != address(0)) {
            tokenToTransfer = IERC20(tokenTo);
            balanceBefore = tokenToTransfer.balanceOf(address(this));
        } else {
            balanceBefore = address(this).balance;
        }
        try timeExchange.swap{ value: msg.value }(tokenFrom, tokenTo, amount) {
            uint256 balanceAfter;
            if (tokenTo != address(0)) {
                balanceAfter = tokenToTransfer.balanceOf(address(this));
                tokenToTransfer.transfer(msg.sender, balanceAfter - balanceBefore);
            } else {
                balanceAfter = address(this).balance;
                payable(msg.sender).transfer(balanceAfter - balanceBefore);
            }
            if (tokenFrom == address(0)) {
                if (checkParticipation(msg.sender)) {
                    _registerPoints(msg.sender, tokenTo == address(timeToken) ? OperationType.SWAP_TIME : OperationType.SWAP_TUP, msg.value);
                    _earnAdditionalResources();
                }
                currentValueMoved += msg.value;
            }
        } catch {
            revert("Sponsor: unable to relay swap");
        }
    }

    /// @notice Withdraw native tokens given to address zero
    /// @dev Eventually the winners don't have remaining TIME deposited when a round is finished. When this happens, the prize goes to the address(0)
    function withdrawFromAddressZeroPrizes() external admin {
        require(prizeToClaim[address(0)] > 0, "Sponsor: there is no prize to claim for the zero address");
        require(prizeToClaim[address(0)] <= address(this).balance, "Sponsor: there is no enough amount to withdraw");
        uint256 amount = prizeToClaim[address(0)];
        prizeToClaim[address(0)] = 0;
        payable(administrator).transfer(amount);
    }
}

File 2 of 6 : TimeExchange.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "./ITimeToken.sol";
import "./ITimeIsUp.sol";

contract TimeExchange {
    using Math for uint256;

    uint256 private constant FACTOR = 10 ** 18;

    uint256 public constant FEE = 70;
    address public constant DEVELOPER_ADDRESS = 0x731591207791A93fB0Ec481186fb086E16A7d6D0;
    address public immutable timeAddress;
    address public immutable tupAddress;

    mapping(address => uint256) private _currentBlock;

    constructor(address time, address tup) {
        timeAddress = time;
        tupAddress = tup;
    }

    receive() external payable { }

    fallback() external payable {
        require(msg.data.length == 0);
    }

    /// @notice Modifier to make a function runs only once per block
    modifier onlyOncePerBlock() {
        require(block.number != _currentBlock[tx.origin], "Time Exchange: you cannot perform this operation again in this block");
        _currentBlock[tx.origin] = block.number;
        _;
    }

    /// @notice Swaps native currency for another token
    /// @dev Please refer this function is called by swap() function
    /// @param tokenTo The address of the token to be swapped
    /// @param amount The native currency amount to be swapped
    function _swapFromNativeToToken(address tokenTo, uint256 amount) private {
        IERC20 token = IERC20(tokenTo);
        uint256 comission = amount.mulDiv(FEE, 10_000);
        amount -= comission;
        payable(tokenTo).call{ value: amount }("");
        payable(DEVELOPER_ADDRESS).call{ value: comission / 2 }("");
        ITimeIsUp(payable(tupAddress)).receiveProfit{ value: comission / 2 }();
        token.transfer(msg.sender, token.balanceOf(address(this)));
    }

    /// @notice Swaps token for native currency
    /// @dev Please refer this function is called by swap() function
    /// @param tokenFrom The address of the token to be swapped
    /// @param amount The token amount to be swapped
    function _swapFromTokenToNative(address tokenFrom, uint256 amount) private {
        IERC20 token = IERC20(tokenFrom);
        token.transferFrom(msg.sender, address(this), amount);
        uint256 balanceBefore = address(this).balance;
        token.transfer(tokenFrom, amount);
        uint256 balanceAfter = address(this).balance - balanceBefore;
        uint256 comission = balanceAfter.mulDiv(FEE, 10_000);
        balanceAfter -= comission;
        payable(DEVELOPER_ADDRESS).call{ value: comission / 2 }("");
        ITimeIsUp(payable(tupAddress)).receiveProfit{ value: comission / 2 }();
        payable(msg.sender).call{ value: balanceAfter }("");
    }

    /// @notice Swaps a token for another token
    /// @dev Please refer this function is called by swap() function
    /// @param tokenFrom The address of the token to be swapped
    /// @param tokenTo The address of the token to be swapped
    /// @param amount The token amount to be swapped
    function _swapFromTokenToToken(address tokenFrom, address tokenTo, uint256 amount) private {
        IERC20 tokenFrom_ = IERC20(tokenFrom);
        IERC20 tokenTo_ = IERC20(tokenTo);
        tokenFrom_.transferFrom(msg.sender, address(this), amount);
        uint256 balanceBefore = address(this).balance;
        tokenFrom_.transfer(tokenFrom, amount);
        uint256 balanceAfter = address(this).balance - balanceBefore;
        uint256 comission = balanceAfter.mulDiv(FEE, 10_000);
        balanceAfter -= comission;
        payable(tokenTo).call{ value: balanceAfter }("");
        payable(DEVELOPER_ADDRESS).call{ value: comission / 2 }("");
        ITimeIsUp(payable(tupAddress)).receiveProfit{ value: comission / 2 }();
        tokenTo_.transfer(msg.sender, tokenTo_.balanceOf(address(this)));
    }

    /// @notice Query the price of native currency in terms of an informed token
    /// @dev Please refer this function is called by queryPrice() function and it is only for viewing
    /// @param tokenTo The address of the token to be queried
    /// @param amount The native currency amount to be queried
    /// @return price The price of tokens to be obtained given some native currency amount
    function _queryPriceFromNativeToToken(address tokenTo, uint256 amount) private view returns (uint256) {
        uint256 price;
        if (tokenTo == timeAddress) {
            price = ITimeToken(payable(tokenTo)).swapPriceNative(amount);
        } else {
            price = ITimeIsUp(payable(tokenTo)).queryPriceNative(amount);
        }
        return price;
    }

    /// @notice Query the price of an informed token in terms of native currency
    /// @dev Please refer this function is called by queryPrice() function and it is only for viewing
    /// @param tokenFrom The address of the token to be queried
    /// @param amount The token amount to be queried
    /// @return price The price of native currency to be obtained given some token amount
    function _queryPriceFromTokenToNative(address tokenFrom, uint256 amount) private view returns (uint256) {
        uint256 price;
        if (tokenFrom == timeAddress) {
            price = ITimeToken(payable(tokenFrom)).swapPriceTimeInverse(amount);
        } else {
            price = ITimeIsUp(payable(tokenFrom)).queryPriceInverse(amount);
        }
        return price;
    }

    /// @notice Query the price of an informed token in terms of another informed token
    /// @dev Please refer this function is called by queryPrice() function and it is only for viewing
    /// @param tokenFrom The address of the token to be queried
    /// @param tokenTo The address of the token to be queried
    /// @param amount The token amount to be queried
    /// @return priceTo The price of tokens to be obtained given some another token amount
    /// @return nativeAmount The amount in native currency obtained from the query
    function _queryPriceFromTokenToToken(address tokenFrom, address tokenTo, uint256 amount)
        private
        view
        returns (uint256 priceTo, uint256 nativeAmount)
    {
        uint256 priceFrom = _queryPriceFromTokenToNative(tokenFrom, amount);
        nativeAmount = amount.mulDiv(priceFrom, FACTOR);
        if (tokenTo == timeAddress) {
            priceTo = ITimeToken(payable(tokenTo)).swapPriceNative(nativeAmount);
        } else {
            priceTo = ITimeIsUp(payable(tokenTo)).queryPriceNative(nativeAmount);
        }
        return (priceTo, nativeAmount);
    }

    /// @notice Clean the contract if it has any exceeding token or native amount
    /// @dev It should pass the tokenToClean contract address
    /// @param tokenToClean The address of token contract
    function clean(address tokenToClean) public {
        if (address(this).balance > 0) {
            payable(DEVELOPER_ADDRESS).call{ value: address(this).balance }("");
        }
        if (tokenToClean != address(0)) {
            if (IERC20(tokenToClean).balanceOf(address(this)) > 0) {
                IERC20(tokenToClean).transfer(DEVELOPER_ADDRESS, IERC20(tokenToClean).balanceOf(address(this)));
            }
        }
    }

    /// @notice Swaps token or native currency for another token or native currency
    /// @dev It should inform address(0) as tokenFrom or tokenTo when considering native currency
    /// @param tokenFrom The address of the token to be swapped
    /// @param tokenTo The address of the token to be swapped
    /// @param amount The token or native currency amount to be swapped
    function swap(address tokenFrom, address tokenTo, uint256 amount) external payable onlyOncePerBlock {
        if (tokenFrom == address(0)) {
            require(tokenTo != address(0) && (tokenTo == timeAddress || tokenTo == tupAddress), "Time Exchange: unallowed token");
            require(msg.value > 0, "Time Exchange: please inform the amount to swap");
            _swapFromNativeToToken(tokenTo, msg.value);
            clean(tokenFrom);
            clean(tokenTo);
        } else if (tokenTo == address(0)) {
            require(amount > 0, "Time Exchange: please inform the amount to swap");
            require(tokenFrom == timeAddress || tokenFrom == tupAddress, "Time Exchange: unallowed token");
            require(IERC20(tokenFrom).allowance(msg.sender, address(this)) >= amount, "Time Exchange: please approve the amount to swap");
            _swapFromTokenToNative(tokenFrom, amount);
            clean(tokenFrom);
            clean(tokenTo);
        } else {
            require(amount > 0, "Time Exchange: please inform the amount to swap");
            require(tokenTo == timeAddress || tokenTo == tupAddress, "Time Exchange: unallowed token");
            require(tokenFrom == timeAddress || tokenFrom == tupAddress, "Time Exchange: unallowed token");
            require(IERC20(tokenFrom).allowance(msg.sender, address(this)) >= amount, "Time Exchange: please approve the amount to swap");
            _swapFromTokenToToken(tokenFrom, tokenTo, amount);
            clean(tokenFrom);
            clean(tokenTo);
        }
    }

    /// @notice Query the price of token or native currency in terms of another token or native currency
    /// @dev It should inform address(0) as tokenFrom or tokenTo when considering native currency
    /// @param tokenFrom The address of the token to be queried
    /// @param tokenTo The address of the token to be queried
    /// @param amount The token or native currency amount to be queried
    /// @return price The queried price
    /// @return nativeAmount The native amount in the middle of the query (if the case)
    function queryPrice(address tokenFrom, address tokenTo, uint256 amount) external view returns (uint256, uint256) {
        if (tokenFrom == address(0)) {
            require(tokenTo != address(0) && (tokenTo == timeAddress || tokenTo == tupAddress), "Time Exchange: unallowed token");
            return (_queryPriceFromNativeToToken(tokenTo, amount), 0);
        } else if (tokenTo == address(0)) {
            require(tokenFrom == timeAddress || tokenFrom == tupAddress, "Time Exchange: unallowed token");
            return (_queryPriceFromTokenToNative(tokenFrom, amount), 0);
        } else {
            require(tokenTo == timeAddress || tokenTo == tupAddress, "Time Exchange: unallowed token");
            require(tokenFrom == timeAddress || tokenFrom == tupAddress, "Time Exchange: unallowed token");
            return _queryPriceFromTokenToToken(tokenFrom, tokenTo, amount);
        }
    }
}

File 3 of 6 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

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

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

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

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

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

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

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

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

File 4 of 6 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // 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 (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

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

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

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

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

File 5 of 6 : ITimeToken.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

interface ITimeToken {
    function DEVELOPER_ADDRESS() external view returns (address);
    function BASE_FEE() external view returns (uint256);
    function COMISSION_RATE() external view returns (uint256);
    function SHARE_RATE() external view returns (uint256);
    function TIME_BASE_LIQUIDITY() external view returns (uint256);
    function TIME_BASE_FEE() external view returns (uint256);
    function TOLERANCE() external view returns (uint256);
    function dividendPerToken() external view returns (uint256);
    function firstBlock() external view returns (uint256);
    function isMiningAllowed(address account) external view returns (bool);
    function liquidityFactorNative() external view returns (uint256);
    function liquidityFactorTime() external view returns (uint256);
    function numberOfHolders() external view returns (uint256);
    function numberOfMiners() external view returns (uint256);
    function sharedBalance() external view returns (uint256);
    function poolBalance() external view returns (uint256);
    function totalMinted() external view returns (uint256);
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external pure returns (uint8);
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function burn(uint256 amount) external;
    function transfer(address to, uint256 amount) external returns (bool success);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);
    function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool success);
    function averageMiningRate() external view returns (uint256);
    function donateEth() external payable;
    function enableMining() external payable;
    function enableMiningWithTimeToken() external;
    function fee() external view returns (uint256);
    function feeInTime() external view returns (uint256);
    function mining() external;
    function saveTime() external payable returns (bool success);
    function spendTime(uint256 timeAmount) external returns (bool success);
    function swapPriceNative(uint256 amountNative) external view returns (uint256);
    function swapPriceTimeInverse(uint256 amountTime) external view returns (uint256);
    function accountShareBalance(address account) external view returns (uint256);
    function withdrawableShareBalance(address account) external view returns (uint256);
    function withdrawShare() external;
    receive() external payable;
}

File 6 of 6 : ITimeIsUp.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

interface ITimeIsUp {
    function FLASH_MINT_FEE() external view returns (uint256);
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address to, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
    function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);
    function accountShareBalance(address account) external view returns (uint256);
    function burn(uint256 amount) external;
    function mint(uint256 timeAmount) external payable;
    function queryAmountExternalLP(uint256 amountNative) external view returns (uint256);
    function queryAmountInternalLP(uint256 amountNative) external view returns (uint256);
    function queryAmountOptimal(uint256 amountNative) external view returns (uint256);
    function queryNativeAmount(uint256 d2Amount) external view returns (uint256);
    function queryNativeFromTimeAmount(uint256 timeAmount) external view returns (uint256);
    function queryPriceNative(uint256 amountNative) external view returns (uint256);
    function queryPriceInverse(uint256 d2Amount) external view returns (uint256);
    function queryRate() external view returns (uint256);
    function queryPublicReward() external view returns (uint256);
    function returnNative() external payable returns (bool);
    function splitSharesWithReward() external;
    function buy() external payable returns (bool success);
    function sell(uint256 d2Amount) external returns (bool success);
    function flashMint(uint256 d2AmountToBorrow, bytes calldata data) external;
    function payFlashMintFee() external payable;
    function poolBalance() external view returns (uint256);
    function toBeShared() external view returns (uint256);
    function receiveProfit() external payable;
}

Settings
{
  "remappings": [
    "@layerzerolabs/=lib/solidity-examples/",
    "@aave/core-v3/=lib/aave-v3-core/",
    "@chainlink/=lib/chainlink/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "aave-v3-core/=lib/aave-v3-core/",
    "chainlink/=lib/chainlink/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "layerzero/=lib/layerzero/contracts/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "solidity-examples/=lib/solidity-examples/contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 2000000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"timeTokenAddress","type":"address"},{"internalType":"address","name":"tupTokenAddress","type":"address"},{"internalType":"address","name":"timeExchangeAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"MathOverflowedMulDiv","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"participant","type":"address"}],"name":"ParticipantAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"participant","type":"address"}],"name":"ParticipantRemoved","type":"event"},{"anonymous":false,"inputs":[],"name":"ParticipantsListCleaned","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"},{"indexed":false,"internalType":"address","name":"participant","type":"address"},{"indexed":false,"internalType":"uint256","name":"earnedPrize","type":"uint256"}],"name":"RoundWinner","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"MININUM_NUMBER_OF_PARTICIPANTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NUMBER_OF_SELECTED_WINNERS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TIME_BURNING_RATE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accumulatedPrize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"administrator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"participant","type":"address"}],"name":"checkParticipation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimPrize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentAdditionalPrize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentLeader","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentPrize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentRebate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentTarget","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentValueMoved","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositPrize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountTime","type":"uint256"}],"name":"extendParticipationPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"firstParticipant","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flipOperationType","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isOperationTypeFlipped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastParticipant","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxInteractionPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minAmountToEarnPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountTime","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"numberOfParticipants","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"participants","outputs":[{"internalType":"bool","name":"isParticipating","type":"bool"},{"internalType":"bool","name":"wasSelected","type":"bool"},{"internalType":"address","name":"previousParticipant","type":"address"},{"internalType":"address","name":"nextParticipant","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"prizeToClaim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"queryAmountRemainingForPrize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"queryCurrentTotalPrize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"participant","type":"address"}],"name":"queryInteractionPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"participant","type":"address"}],"name":"queryValuePoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"remainingTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"round","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"roundWinners","outputs":[{"internalType":"address","name":"first","type":"address"},{"internalType":"address","name":"second","type":"address"},{"internalType":"address","name":"third","type":"address"},{"internalType":"address","name":"fourth","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAdministrator","type":"address"}],"name":"setAdministrator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCurrentFeesPercentage","type":"uint256"}],"name":"setCurrentFeesPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMinAmount","type":"uint256"}],"name":"setMinAmountToEarnPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newProfitTargetPercentage","type":"uint256"}],"name":"setPercentageProfitTarget","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newRebatePercentage","type":"uint256"}],"name":"setRebatePercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenFrom","type":"address"},{"internalType":"address","name":"tokenTo","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"swap","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"timeExchange","outputs":[{"internalType":"contract TimeExchange","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timeToken","outputs":[{"internalType":"contract ITimeToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tupToken","outputs":[{"internalType":"contract ITimeIsUp","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawFromAddressZeroPrizes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60e06040526000805460ff19166001179055612af860055560646006553480156200002957600080fd5b50604051620050b7380380620050b78339810160408190526200004c9162000201565b600080546301000000600160b81b031916336301000000021790556001600160a01b0383811660a05282811660c052811660808190526040805163c57981b560e01b81529051620000ef929163c57981b59160048083019260209291908290030181865afa158015620000c3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000e991906200024b565b62000110565b6200010267016345785d8a00006200017c565b505060016010555062000265565b600054630100000090046001600160a01b03163314620001775760405162461bcd60e51b815260206004820152601b60248201527f53706f6e736f723a206f6e6c792061646d696e20616c6c6f776564000000000060448201526064015b60405180910390fd5b600455565b600054630100000090046001600160a01b03163314620001df5760405162461bcd60e51b815260206004820152601b60248201527f53706f6e736f723a206f6e6c792061646d696e20616c6c6f776564000000000060448201526064016200016e565b600e55565b80516001600160a01b0381168114620001fc57600080fd5b919050565b6000806000606084860312156200021757600080fd5b6200022284620001e4565b92506200023260208501620001e4565b91506200024260408501620001e4565b90509250925092565b6000602082840312156200025e57600080fd5b5051919050565b60805160a05160c051614d886200032f6000396000818161057201528181611ae401528181611bb301528181611c7a01528181611d7f01528181611e180152818161218d01528181612257015281816140c6015261415b0152600081816108a1015281816110ad015281816112da015281816118af01528181611a2401528181611b130152818161232701528181612c5e01528181613fd6015281816140490152818161499d0152614a3c0152600081816106910152818161283f01526129c90152614d886000f3fe6080604052600436106102eb5760003560e01c80639206b5f011610184578063db2e21bc116100d6578063e358f15b1161008a578063eddccd7311610064578063eddccd731461090e578063f11b6e431461092e578063f53d0a8e1461094e576102fd565b8063e358f15b146108c3578063e9e6771a146108d9578063ecd4f296146108ee576102fd565b8063df791e50116100bb578063df791e501461085c578063df8089ef1461086f578063e27af3b91461088f576102fd565b8063db2e21bc14610831578063dc7aafba14610846576102fd565b8063a58960c111610138578063bfe7e4e311610112578063bfe7e4e3146107ce578063c42b42a0146107fb578063d2c195a114610811576102fd565b8063a58960c11461076c578063a9f901b61461078c578063ac4bd53a146107a1576102fd565b806397dd535b1161016957806397dd535b146107235780639c32db0b14610743578063a0712d6814610759576102fd565b80639206b5f0146106e0578063952ca92c146106f6576102fd565b8063494c5a3a1161023d5780636765dfe1116101f157806376a4956c116101cb57806376a4956c146105df5780637cff82d31461067f5780637d523aad146106b3576102fd565b80636765dfe11461059457806370740ac9146105b45780637417040e146105c9576102fd565b80634e083278116102225780634e083278146105425780635036e6631461054a57806354389c5e14610560576102fd565b8063494c5a3a146104ff578063496ad91514610515576102fd565b80631fcddb9d1161029f57806337420c411161027957806337420c41146104bf57806339148c53146104d457806346671ba2146104ea576102fd565b80631fcddb9d1461046457806321e04c321461047957806324b937d7146104a9576102fd565b80630a953ec1116102d05780630a953ec1146103e75780631049f1ce146103fc578063146ca5311461044e576102fd565b8063028a3a031461031357806309e69ede14610346576102fd565b366102fd576102fb600034610982565b005b361561030857600080fd5b6102fb600034610982565b34801561031f57600080fd5b5061033361032e366004614aea565b610b01565b6040519081526020015b60405180910390f35b34801561035257600080fd5b506103a9610361366004614aea565b6016602052600090815260409020805460019091015460ff8083169261010081049091169173ffffffffffffffffffffffffffffffffffffffff620100009092048216911684565b604080519415158552921515602085015273ffffffffffffffffffffffffffffffffffffffff9182169284019290925216606082015260800161033d565b3480156103f357600080fd5b50610333600581565b34801561040857600080fd5b506002546104299073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161033d565b34801561045a57600080fd5b5061033360105481565b34801561047057600080fd5b506102fb610b54565b34801561048557600080fd5b50610499610494366004614aea565b610dcb565b604051901515815260200161033d565b3480156104b557600080fd5b50610333600e5481565b3480156104cb57600080fd5b506102fb610e56565b3480156104e057600080fd5b50610333600b5481565b3480156104f657600080fd5b50610333600481565b34801561050b57600080fd5b50610333600d5481565b34801561052157600080fd5b50610333610530366004614aea565b60136020526000908152604090205481565b6102fb610f19565b34801561055657600080fd5b5061033360085481565b34801561056c57600080fd5b506104297f000000000000000000000000000000000000000000000000000000000000000081565b3480156105a057600080fd5b506102fb6105af366004614b05565b610fae565b3480156105c057600080fd5b506102fb611499565b3480156105d557600080fd5b50610333600f5481565b3480156105eb57600080fd5b5061063f6105fa366004614b05565b601560205260009081526040902080546001820154600283015460039093015473ffffffffffffffffffffffffffffffffffffffff9283169391831692918216911684565b6040805173ffffffffffffffffffffffffffffffffffffffff9586168152938516602085015291841691830191909152909116606082015260800161033d565b34801561068b57600080fd5b506104297f000000000000000000000000000000000000000000000000000000000000000081565b3480156106bf57600080fd5b506103336106ce366004614aea565b60146020526000908152604090205481565b3480156106ec57600080fd5b5061033360075481565b34801561070257600080fd5b50610333610711366004614aea565b60126020526000908152604090205481565b34801561072f57600080fd5b506000546104999062010000900460ff1681565b34801561074f57600080fd5b50610333600c5481565b6102fb610767366004614b05565b611702565b34801561077857600080fd5b506102fb610787366004614b05565b611f3c565b34801561079857600080fd5b50610333611fc9565b3480156107ad57600080fd5b506001546104299073ffffffffffffffffffffffffffffffffffffffff1681565b3480156107da57600080fd5b506003546104299073ffffffffffffffffffffffffffffffffffffffff1681565b34801561080757600080fd5b5061033360095481565b34801561081d57600080fd5b506102fb61082c366004614b05565b611fe0565b34801561083d57600080fd5b506102fb61206d565b34801561085257600080fd5b50610333600a5481565b6102fb61086a366004614b1e565b6124a8565b34801561087b57600080fd5b506102fb61088a366004614aea565b612de8565b34801561089b57600080fd5b506104297f000000000000000000000000000000000000000000000000000000000000000081565b3480156108cf57600080fd5b5061033361138881565b3480156108e557600080fd5b50610333612ebe565b3480156108fa57600080fd5b50610333610909366004614aea565b612efb565b34801561091a57600080fd5b506102fb610929366004614b05565b612f4a565b34801561093a57600080fd5b506102fb610949366004614b05565b612fd7565b34801561095a57600080fd5b50600054610429906301000000900473ffffffffffffffffffffffffffffffffffffffff1681565b60003411610a17576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f53706f6e736f723a20706c65617365206465706f73697420736f6d6520616d6f60448201527f756e74000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b60005460ff1615610afd578115610a8f578160076000828254610a3a9190614b89565b9091555050600954600003610a8f576002600754610a589190614bcb565b6009819055600454600554610a8b926127109291610a77919084613064565b600954610a849190614b89565b9190613064565b600b555b8015610afd576000610aa2600283614bcb565b90508160076000828254610ab69190614b89565b925050819055508060086000828254610acf9190614b89565b9091555050600654610ae5908290612710613064565b600a6000828254610af69190614b89565b9091555050505b5050565b6000610b0c82610dcb565b610b17576000610b4e565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260166020908152604080832060105484526002019091529020545b92915050565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff163314610bdc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f53706f6e736f723a206f6e6c792061646d696e20616c6c6f77656400000000006044820152606401610a0e565b6000805260136020527f8fa6efc3be94b5b348b21fea823fe8d100408cee9b7f90524494500445d8ff6c54610c93576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f53706f6e736f723a207468657265206973206e6f207072697a6520746f20636c60448201527f61696d20666f7220746865207a65726f206164647265737300000000000000006064820152608401610a0e565b6000805260136020527f8fa6efc3be94b5b348b21fea823fe8d100408cee9b7f90524494500445d8ff6c54471015610d4d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f53706f6e736f723a207468657265206973206e6f20656e6f75676820616d6f7560448201527f6e7420746f2077697468647261770000000000000000000000000000000000006064820152608401610a0e565b600080805260136020527f8fa6efc3be94b5b348b21fea823fe8d100408cee9b7f90524494500445d8ff6c80549082905581546040519192630100000090910473ffffffffffffffffffffffffffffffffffffffff169183156108fc0291849190818181858888f19350505050158015610afd573d6000803e3d6000fd5b73ffffffffffffffffffffffffffffffffffffffff8116600090815260126020526040812054610dfb9043614bdf565b73ffffffffffffffffffffffffffffffffffffffff831660009081526014602052604090205410801590610b4e57505073ffffffffffffffffffffffffffffffffffffffff1660009081526016602052604090205460ff1690565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff163314610ede576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f53706f6e736f723a206f6e6c792061646d696e20616c6c6f77656400000000006044820152606401610a0e565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff8116620100009182900460ff1615909102179055565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff163314610fa1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f53706f6e736f723a206f6e6c792061646d696e20616c6c6f77656400000000006044820152606401610a0e565b610fac346000610982565b565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016815533815260126020526040902054158015610fef57504315155b80611007575033600090815260146020526040902054155b1561101f573360009081526012602052604090204390555b336000908152601260205260408120546110399043614bdf565b336000908152601460205260409020549091508111801561106957503360009081526016602052604090205460ff165b156110775761107733613160565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815233600482015230602482015282907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063dd62ed3e90604401602060405180830381865afa158015611109573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112d9190614bf2565b10156111e1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604960248201527f53706f6e736f723a20706c6561736520617070726f7665207468652054494d4560448201527f20616d6f756e7420746f20657874656e6420796f75722073706f6e736f72736860648201527f697020706572696f640000000000000000000000000000000000000000000000608482015260a401610a0e565b670de0b6b3a764000082101561129f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604c60248201527f53706f6e736f723a20796f752073686f756c64206465706f736974203120544960448201527f4d45206f72206d6f726520746f20657874656e6420796f75722073706f6e736f60648201527f727368697020706572696f640000000000000000000000000000000000000000608482015260a401610a0e565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd906064016020604051808303816000875af1158015611338573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061135c9190614c0b565b50611371826001670de0b6b3a7640000613064565b3360009081526014602052604081208054909190611390908490614b89565b90915550503360009081526014602052604090205481116113cb57336000908152601460205260409020546113c6908290614bdf565b6113ce565b60005b33600090815260146020818152604080842094855560128252909220439055905254811180159061140d57503360009081526014602052604090205415155b801561142957503360009081526016602052604090205460ff16155b1561143757611437336134ce565b50611440612ebe565b15801561144f57506000600954115b801561145e57506005600f5410155b1561146b5761146b61373e565b50600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b600054610100900460ff1615611531576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f53706f6e736f723a2074686973206f7065726174696f6e206973206c6f636b6560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610a0e565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100178155338152601360205260409020546115f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f53706f6e736f723a207468657265206973206e6f207072697a6520746f20636c60448201527f61696d20666f72207468652063616c6c657220616464726573730000000000006064820152608401610a0e565b33600090815260136020526040902054471015611695576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f53706f6e736f723a207468657265206973206e6f20656e6f75676820616d6f7560448201527f6e7420746f2077697468647261770000000000000000000000000000000000006064820152608401610a0e565b33600081815260136020526040808220805490839055905190929183156108fc02918491818181858888f193505050501580156116d6573d6000803e3d6000fd5b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001681553281526011602052604090205443036117c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f53706f6e736f723a20796f752063616e6e6f7420706572666f726d207468697360448201527f206f7065726174696f6e20616761696e20696e207468697320626c6f636b00006064820152608401610a0e565b32600090815260116020908152604080832043905533835260129091529020541580156117f157504315155b80611809575033600090815260146020526040902054155b15611821573360009081526012602052604090204390555b3360009081526012602052604081205461183b9043614bdf565b336000908152601460205260409020549091508111801561186b57503360009081526016602052604090205460ff165b156118795761187933613160565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815233600482015230602482015282907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063dd62ed3e90604401602060405180830381865afa15801561190b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061192f9190614bf2565b10156119e3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604660248201527f53706f6e736f723a20796f752073686f756c6420616c6c6f772054494d45207460448201527f6f206265207370656e74206265666f72652063616c6c696e672074686520667560648201527f6e6374696f6e0000000000000000000000000000000000000000000000000000608482015260a401610a0e565b8115611b82576040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd906064016020604051808303816000875af1158015611a82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa69190614c0b565b506040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b3906044016020604051808303816000875af1158015611b5c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b809190614c0b565b505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611c0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c339190614bf2565b6040517fa0712d680000000000000000000000000000000000000000000000000000000081526004810185905290915073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063a0712d689034906024016000604051808303818588803b158015611cbf57600080fd5b505af193505050508015611cd1575060015b611d37576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53706f6e736f723a20756e61626c6520746f2072656c6179206d696e740000006044820152606401610a0e565b34600c6000828254611d499190614b89565b90915550506040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611ddb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dff9190614bf2565b905073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001663a9059cbb33611e488585614bdf565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff909216600483015260248201526044016020604051808303816000875af1158015611eb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611edc9190614c0b565b50611ee633610dcb565b8015611ef0575083155b15611f0957611f0133600034613d92565b611f09613f68565b50503360009081526014602052604090205481116113cb57336000908152601460205260409020546113c6908290614bdf565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff163314611fc4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f53706f6e736f723a206f6e6c792061646d696e20616c6c6f77656400000000006044820152606401610a0e565b600455565b6000600854600954611fdb9190614b89565b905090565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff163314612068576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f53706f6e736f723a206f6e6c792061646d696e20616c6c6f77656400000000006044820152606401610a0e565b600655565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff1633146120f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f53706f6e736f723a206f6e6c792061646d696e20616c6c6f77656400000000006044820152606401610a0e565b6120fd6141fe565b6000600781905560088190556009819055600a819055600b819055600c819055600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600d8190556040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156121d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121f89190614bf2565b905080156122e1576000546040517fa9059cbb000000000000000000000000000000000000000000000000000000008152630100000090910473ffffffffffffffffffffffffffffffffffffffff9081166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af19250505080156122da575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526122d791810190614c0b565b60015b156122e157505b6000546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169263a9059cbb9263010000009091049091169083906370a0823190602401602060405180830381865afa158015612383573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123a79190614bf2565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff909216600483015260248201526044016020604051808303816000875af1925050508015612451575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261244e91810190614c0b565b60015b1561245857505b6000805460405173ffffffffffffffffffffffffffffffffffffffff630100000090920491909116914780156108fc02929091818181858888f19350505050158015610afd573d6000803e3d6000fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016815532815260116020526040902054430361256b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f53706f6e736f723a20796f752063616e6e6f7420706572666f726d207468697360448201527f206f7065726174696f6e20616761696e20696e207468697320626c6f636b00006064820152608401610a0e565b326000908152601160209081526040808320439055338352601290915290205415801561259757504315155b806125af575033600090815260146020526040902054155b156125c7573360009081526012602052604090204390555b336000908152601260205260408120546125e19043614bdf565b336000908152601460205260409020549091508111801561261157503360009081526016602052604090205460ff165b1561261f5761261f33613160565b60008073ffffffffffffffffffffffffffffffffffffffff8616156128be576040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523360048201523060248201528690859073ffffffffffffffffffffffffffffffffffffffff83169063dd62ed3e90604401602060405180830381865afa1580156126b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126d69190614bf2565b1015612764576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f53706f6e736f723a20706c6561736520617070726f76652074686520616d6f7560448201527f6e7420746f2073776170000000000000000000000000000000000000000000006064820152608401610a0e565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810186905273ffffffffffffffffffffffffffffffffffffffff8216906323b872dd906064016020604051808303816000875af11580156127dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128019190614c0b565b506040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820187905282169063095ea7b3906044016020604051808303816000875af1158015612897573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128bb9190614c0b565b50505b73ffffffffffffffffffffffffffffffffffffffff851615612972576040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015285925073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015612947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296b9190614bf2565b9050612975565b50475b6040517fdf791e5000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301528681166024830152604482018690527f0000000000000000000000000000000000000000000000000000000000000000169063df791e509034906064016000604051808303818588803b158015612a0e57600080fd5b505af193505050508015612a20575060015b612a86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53706f6e736f723a20756e61626c6520746f2072656c617920737761700000006044820152606401610a0e565b600073ffffffffffffffffffffffffffffffffffffffff861615612bf5576040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa158015612b0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b329190614bf2565b905073ffffffffffffffffffffffffffffffffffffffff831663a9059cbb33612b5b8585614bdf565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff909216600483015260248201526044016020604051808303816000875af1158015612bcb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bef9190614c0b565b50612c2f565b5047336108fc612c058484614bdf565b6040518115909202916000818181858888f19350505050158015612c2d573d6000803e3d6000fd5b505b73ffffffffffffffffffffffffffffffffffffffff8716612cdf57612c5333610dcb565b15612cc757612cbf337f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614612cb6576002612cb9565b60015b34613d92565b612cc7613f68565b34600c6000828254612cd99190614b89565b90915550505b505050336000908152601460205260409020548111612d185733600090815260146020526040902054612d13908290614bdf565b612d1b565b60005b336000908152601460208181526040808420948555601282529092204390559052548111801590612d5a57503360009081526014602052604090205415155b8015612d7657503360009081526016602052604090205460ff16155b15612d8457612d84336134ce565b50612d8d612ebe565b158015612d9c57506000600954115b8015612dab57506005600f5410155b15612db857612db861373e565b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905550565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff163314612e70576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f53706f6e736f723a206f6e6c792061646d696e20616c6c6f77656400000000006044820152606401610a0e565b6000805473ffffffffffffffffffffffffffffffffffffffff9092166301000000027fffffffffffffffffff0000000000000000000000000000000000000000ffffff909216919091179055565b6000600c54600a54612ed09190614b89565b600b5411612ede5750600090565b600c54600a54612eee9190614b89565b600b54611fdb9190614bdf565b6000612f0682610dcb565b612f11576000610b4e565b5073ffffffffffffffffffffffffffffffffffffffff166000908152601660209081526040808320601054845260030190915290205490565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff163314612fd2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f53706f6e736f723a206f6e6c792061646d696e20616c6c6f77656400000000006044820152606401610a0e565b600555565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff16331461305f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f53706f6e736f723a206f6e6c792061646d696e20616c6c6f77656400000000006044820152606401610a0e565b600e55565b6000838302817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870982811083820303915050806000036130b9578382816130af576130af614b9c565b0492505050613159565b8084116130f2576040517f227bc15300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150505b9392505050565b73ffffffffffffffffffffffffffffffffffffffff8116158015906131aa575073ffffffffffffffffffffffffffffffffffffffff811660009081526016602052604090205460ff165b156134cb5773ffffffffffffffffffffffffffffffffffffffff80821660008181526016602052604090208054600190910154600354620100009092048416939081169291160361323657600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84161790555b60025473ffffffffffffffffffffffffffffffffffffffff80851691160361329957600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83161790555b73ffffffffffffffffffffffffffffffffffffffff82161561330c5773ffffffffffffffffffffffffffffffffffffffff828116600090815260166020526040902060010180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169183169190911790555b73ffffffffffffffffffffffffffffffffffffffff8116156133835773ffffffffffffffffffffffffffffffffffffffff8082166000908152601660205260409020805491841662010000027fffffffffffffffffffff0000000000000000000000000000000000000000ffff9092169190911790555b60015473ffffffffffffffffffffffffffffffffffffffff908116908416036133d457600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556000600d555b73ffffffffffffffffffffffffffffffffffffffff8316600090815260166020908152604080832080546001820180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690557fffffffffffffffffffff000000000000000000000000000000000000000000001681556010805485526002820184528285208590555484526003019091528120819055600f80549161347a83614c2d565b909155505060405173ffffffffffffffffffffffffffffffffffffffff841681527f1a5e355a9a34d7eac1e439a6c610ba1fa72aa45f7645724ce5187fa19c3bd3fc9060200160405180910390a150505b50565b73ffffffffffffffffffffffffffffffffffffffff811615801590613519575073ffffffffffffffffffffffffffffffffffffffff811660009081526016602052604090205460ff16155b156134cb5760035473ffffffffffffffffffffffffffffffffffffffff828116600090815260166020526040902080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff169282166201000002929092178255600190910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600254166135ed57600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83161790555b60035473ffffffffffffffffffffffffffffffffffffffff16156136655760035473ffffffffffffffffffffffffffffffffffffffff908116600090815260166020526040902060010180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169183169190911790555b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316908117909155600090815260166020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055600f8054916136ed83614c62565b909155505060405173ffffffffffffffffffffffffffffffffffffffff821681527f31d3ac54da09405b02d1de0ee0de648de637fbdc111123be0d7fc31f2a544c0b9060200160405180910390a150565b600054610100900460ff16156137d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f53706f6e736f723a2074686973206f7065726174696f6e206973206c6f636b6560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610a0e565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010017815561380a611fc9565b9050478111613d66576000613820600a83614bcb565b6001549091506138459073ffffffffffffffffffffffffffffffffffffffff16610dcb565b6138cf5760015461386b9073ffffffffffffffffffffffffffffffffffffffff16613160565b6005600f54101561387d575050613d68565b61388561435a565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055613921565b60015473ffffffffffffffffffffffffffffffffffffffff16600090815260166020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b600061392e826004614c9a565b60015473ffffffffffffffffffffffffffffffffffffffff1660009081526013602052604081208054929350839290919061396a908490614b89565b90915550506010546001546040805192835273ffffffffffffffffffffffffffffffffffffffff909116602083015281018290527fc4e84d5bdf91b848636803e57105825e4031dc6558ea19c80643b5441acfbe1c9060600160405180910390a160006139d561456c565b905060005b8151811015613afb57838183516139f19190614bdf565b6139fb9190614c9a565b92508260136000848481518110613a1457613a14614cb1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254613a659190614b89565b925050819055507fc4e84d5bdf91b848636803e57105825e4031dc6558ea19c80643b5441acfbe1c601054838381518110613aa257613aa2614cb1565b602002602001015185604051613ae19392919092835273ffffffffffffffffffffffffffffffffffffffff919091166020830152604082015260600190565b60405180910390a180613af381614c62565b9150506139da565b50600154601054600090815260156020526040812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909316929092179091558151829190613b6457613b64614cb1565b602002602001015160156000601054815260200190815260200160002060010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600181518110613bd557613bd5614cb1565b602002602001015160156000601054815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600281518110613c4657613c46614cb1565b602002602001015160156000601054815260200190815260200160002060030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508360076000828254613cb69190614bdf565b9091555050600754613cca90600290614bcb565b6009819055613cda576000613cfe565b613cfe612710600454610a776005546127106009546130649092919063ffffffff16565b600b5560006008819055600a819055600c55613d1861496c565b613d206141fe565b6000600d819055600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556010805491613d5d83614c62565b91905055505050505b505b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055565b600e548110158015613db9575073ffffffffffffffffffffffffffffffffffffffff831615155b15613f63576000805462010000900460ff16613df157826002811115613de157613de1614ce0565b613dec906001614b89565b613e19565b826002811115613e0357613e03614ce0565b613e0e906002614bdf565b613e19906001614b89565b73ffffffffffffffffffffffffffffffffffffffff851660009081526016602090815260408083206010548452600201909152812080549293508392909190613e63908490614b89565b90915550613e7390508183614c9a565b73ffffffffffffffffffffffffffffffffffffffff85166000908152601660209081526040808320601054845260030190915281208054909190613eb8908490614b89565b9091555050600d5473ffffffffffffffffffffffffffffffffffffffff8516600090815260166020908152604080832060105484526002019091529020541115613f615773ffffffffffffffffffffffffffffffffffffffff841660008181526016602090815260408083206010548452600201909152902054600d55600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690911790555b505b505050565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011781556040517f901362bd00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063901362bd90602401602060405180830381865afa15801561401d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140419190614bf2565b11156140c2577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663243496716040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156140af57600080fd5b505af19250505080156140c0575060015b505b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16635e7c75456040518163ffffffff1660e01b8152600401602060405180830381865afa15801561412f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141539190614bf2565b11156141d4577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663ccb645966040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156141c157600080fd5b505af19250505080156141d2575060015b505b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b60025473ffffffffffffffffffffffffffffffffffffffff1660005b73ffffffffffffffffffffffffffffffffffffffff8216156142f4575073ffffffffffffffffffffffffffffffffffffffff908116600081815260166020908152604080832060018101805482547fffffffffffffffffffffffff000000000000000000000000000000000000000082169092557fffffffffffffffffffff000000000000000000000000000000000000000000009091168255601080548652600283018552838620869055548552600390910183528184208490559383526014825280832083905560129091529020439055168061421a565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000009081169091556003805490911690556000600f8190556040517f11004f150d9be1b7c9a3de18a09d7fbe5db0be2e4b03861f3b3b1c258a37b9929190a15050565b600060015b73ffffffffffffffffffffffffffffffffffffffff821661456857600254600f5473ffffffffffffffffffffffffffffffffffffffff90911690600090836143a681614c62565b600954600c54600b5460408051602081019690965243908601524260608601524460808601523060a086015260c085019290925260e08401526101008301529450610120016040516020818303038152906040528051906020012060001c61440e9190614d0f565b905060005b73ffffffffffffffffffffffffffffffffffffffff831615614560578181148015614442575061444283610dcb565b1561451f5773ffffffffffffffffffffffffffffffffffffffff8316600090815260166020526040902054610100900460ff16156144c6576001600f546144899190614bdf565b82036144b457505060025473ffffffffffffffffffffffffffffffffffffffff169050600080614413565b816144be81614c62565b925050614413565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260166020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790559193508391614560565b8061452981614c62565b73ffffffffffffffffffffffffffffffffffffffff9485166000908152601660205260409020600101549094169391506144139050565b50505061435f565b5090565b606061457a60016004614bdf565b67ffffffffffffffff81111561459257614592614d23565b6040519080825280602002602001820160405280156145bb578160200160208202803683370190505b5090506000815167ffffffffffffffff8111156145da576145da614d23565b604051908082528060200260200182016040528015614603578160200160208202803683370190505b50905060008060005b6001855161461a9190614bdf565b8110156149045760025473ffffffffffffffffffffffffffffffffffffffff1692505b73ffffffffffffffffffffffffffffffffffffffff8316156147d55773ffffffffffffffffffffffffffffffffffffffff80841660009081526016602052604090206001015485519116925084908290811061469b5761469b614cb1565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff85166000908152601683526040808220601054835260030190935291909120541180156146ed57506146ed83610dcb565b8015614724575073ffffffffffffffffffffffffffffffffffffffff8316600090815260166020526040902054610100900460ff16155b156147cd5773ffffffffffffffffffffffffffffffffffffffff831660009081526016602090815260408083206010548452600301909152902054845185908390811061477357614773614cb1565b6020026020010181815250508285828151811061479257614792614cb1565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b81925061463d565b600073ffffffffffffffffffffffffffffffffffffffff168582815181106147ff576147ff614cb1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16036148775761482a61435a565b85828151811061483c5761483c614cb1565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b60016016600087848151811061488f5761488f614cb1565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000208054911515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909216919091179055806148fc81614c62565b91505061460c565b5061490d61435a565b846001865161491c9190614bdf565b8151811061492c5761492c614cb1565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505050505090565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156149f9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a1d9190614bf2565b905080156134cb5773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166342966c68614a7083611388612710613064565b6040518263ffffffff1660e01b8152600401614a8e91815260200190565b600060405180830381600087803b158015614aa857600080fd5b505af1925050508015614ab9575060015b156134cb5750565b803573ffffffffffffffffffffffffffffffffffffffff81168114614ae557600080fd5b919050565b600060208284031215614afc57600080fd5b61315982614ac1565b600060208284031215614b1757600080fd5b5035919050565b600080600060608486031215614b3357600080fd5b614b3c84614ac1565b9250614b4a60208501614ac1565b9150604084013590509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610b4e57610b4e614b5a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082614bda57614bda614b9c565b500490565b81810381811115610b4e57610b4e614b5a565b600060208284031215614c0457600080fd5b5051919050565b600060208284031215614c1d57600080fd5b8151801515811461315957600080fd5b600081614c3c57614c3c614b5a565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614c9357614c93614b5a565b5060010190565b8082028115828204841417610b4e57610b4e614b5a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600082614d1e57614d1e614b9c565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea26469706673582212206c7dbc03924f0108c9b4e4406c56e78009a6bd10091b412ea2a9d4cf6710710064736f6c634300081500330000000000000000000000000f8f39b92776d9136408280c7209bebe4351123b00000000000000000000000057685ddbc1498f7873963cee5c186c7d95d91688000000000000000000000000b46f8a90492d0d03b8c3ab112179c56f89a6f3e0

Deployed Bytecode

0x6080604052600436106102eb5760003560e01c80639206b5f011610184578063db2e21bc116100d6578063e358f15b1161008a578063eddccd7311610064578063eddccd731461090e578063f11b6e431461092e578063f53d0a8e1461094e576102fd565b8063e358f15b146108c3578063e9e6771a146108d9578063ecd4f296146108ee576102fd565b8063df791e50116100bb578063df791e501461085c578063df8089ef1461086f578063e27af3b91461088f576102fd565b8063db2e21bc14610831578063dc7aafba14610846576102fd565b8063a58960c111610138578063bfe7e4e311610112578063bfe7e4e3146107ce578063c42b42a0146107fb578063d2c195a114610811576102fd565b8063a58960c11461076c578063a9f901b61461078c578063ac4bd53a146107a1576102fd565b806397dd535b1161016957806397dd535b146107235780639c32db0b14610743578063a0712d6814610759576102fd565b80639206b5f0146106e0578063952ca92c146106f6576102fd565b8063494c5a3a1161023d5780636765dfe1116101f157806376a4956c116101cb57806376a4956c146105df5780637cff82d31461067f5780637d523aad146106b3576102fd565b80636765dfe11461059457806370740ac9146105b45780637417040e146105c9576102fd565b80634e083278116102225780634e083278146105425780635036e6631461054a57806354389c5e14610560576102fd565b8063494c5a3a146104ff578063496ad91514610515576102fd565b80631fcddb9d1161029f57806337420c411161027957806337420c41146104bf57806339148c53146104d457806346671ba2146104ea576102fd565b80631fcddb9d1461046457806321e04c321461047957806324b937d7146104a9576102fd565b80630a953ec1116102d05780630a953ec1146103e75780631049f1ce146103fc578063146ca5311461044e576102fd565b8063028a3a031461031357806309e69ede14610346576102fd565b366102fd576102fb600034610982565b005b361561030857600080fd5b6102fb600034610982565b34801561031f57600080fd5b5061033361032e366004614aea565b610b01565b6040519081526020015b60405180910390f35b34801561035257600080fd5b506103a9610361366004614aea565b6016602052600090815260409020805460019091015460ff8083169261010081049091169173ffffffffffffffffffffffffffffffffffffffff620100009092048216911684565b604080519415158552921515602085015273ffffffffffffffffffffffffffffffffffffffff9182169284019290925216606082015260800161033d565b3480156103f357600080fd5b50610333600581565b34801561040857600080fd5b506002546104299073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161033d565b34801561045a57600080fd5b5061033360105481565b34801561047057600080fd5b506102fb610b54565b34801561048557600080fd5b50610499610494366004614aea565b610dcb565b604051901515815260200161033d565b3480156104b557600080fd5b50610333600e5481565b3480156104cb57600080fd5b506102fb610e56565b3480156104e057600080fd5b50610333600b5481565b3480156104f657600080fd5b50610333600481565b34801561050b57600080fd5b50610333600d5481565b34801561052157600080fd5b50610333610530366004614aea565b60136020526000908152604090205481565b6102fb610f19565b34801561055657600080fd5b5061033360085481565b34801561056c57600080fd5b506104297f00000000000000000000000057685ddbc1498f7873963cee5c186c7d95d9168881565b3480156105a057600080fd5b506102fb6105af366004614b05565b610fae565b3480156105c057600080fd5b506102fb611499565b3480156105d557600080fd5b50610333600f5481565b3480156105eb57600080fd5b5061063f6105fa366004614b05565b601560205260009081526040902080546001820154600283015460039093015473ffffffffffffffffffffffffffffffffffffffff9283169391831692918216911684565b6040805173ffffffffffffffffffffffffffffffffffffffff9586168152938516602085015291841691830191909152909116606082015260800161033d565b34801561068b57600080fd5b506104297f000000000000000000000000b46f8a90492d0d03b8c3ab112179c56f89a6f3e081565b3480156106bf57600080fd5b506103336106ce366004614aea565b60146020526000908152604090205481565b3480156106ec57600080fd5b5061033360075481565b34801561070257600080fd5b50610333610711366004614aea565b60126020526000908152604090205481565b34801561072f57600080fd5b506000546104999062010000900460ff1681565b34801561074f57600080fd5b50610333600c5481565b6102fb610767366004614b05565b611702565b34801561077857600080fd5b506102fb610787366004614b05565b611f3c565b34801561079857600080fd5b50610333611fc9565b3480156107ad57600080fd5b506001546104299073ffffffffffffffffffffffffffffffffffffffff1681565b3480156107da57600080fd5b506003546104299073ffffffffffffffffffffffffffffffffffffffff1681565b34801561080757600080fd5b5061033360095481565b34801561081d57600080fd5b506102fb61082c366004614b05565b611fe0565b34801561083d57600080fd5b506102fb61206d565b34801561085257600080fd5b50610333600a5481565b6102fb61086a366004614b1e565b6124a8565b34801561087b57600080fd5b506102fb61088a366004614aea565b612de8565b34801561089b57600080fd5b506104297f0000000000000000000000000f8f39b92776d9136408280c7209bebe4351123b81565b3480156108cf57600080fd5b5061033361138881565b3480156108e557600080fd5b50610333612ebe565b3480156108fa57600080fd5b50610333610909366004614aea565b612efb565b34801561091a57600080fd5b506102fb610929366004614b05565b612f4a565b34801561093a57600080fd5b506102fb610949366004614b05565b612fd7565b34801561095a57600080fd5b50600054610429906301000000900473ffffffffffffffffffffffffffffffffffffffff1681565b60003411610a17576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f53706f6e736f723a20706c65617365206465706f73697420736f6d6520616d6f60448201527f756e74000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b60005460ff1615610afd578115610a8f578160076000828254610a3a9190614b89565b9091555050600954600003610a8f576002600754610a589190614bcb565b6009819055600454600554610a8b926127109291610a77919084613064565b600954610a849190614b89565b9190613064565b600b555b8015610afd576000610aa2600283614bcb565b90508160076000828254610ab69190614b89565b925050819055508060086000828254610acf9190614b89565b9091555050600654610ae5908290612710613064565b600a6000828254610af69190614b89565b9091555050505b5050565b6000610b0c82610dcb565b610b17576000610b4e565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260166020908152604080832060105484526002019091529020545b92915050565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff163314610bdc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f53706f6e736f723a206f6e6c792061646d696e20616c6c6f77656400000000006044820152606401610a0e565b6000805260136020527f8fa6efc3be94b5b348b21fea823fe8d100408cee9b7f90524494500445d8ff6c54610c93576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f53706f6e736f723a207468657265206973206e6f207072697a6520746f20636c60448201527f61696d20666f7220746865207a65726f206164647265737300000000000000006064820152608401610a0e565b6000805260136020527f8fa6efc3be94b5b348b21fea823fe8d100408cee9b7f90524494500445d8ff6c54471015610d4d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f53706f6e736f723a207468657265206973206e6f20656e6f75676820616d6f7560448201527f6e7420746f2077697468647261770000000000000000000000000000000000006064820152608401610a0e565b600080805260136020527f8fa6efc3be94b5b348b21fea823fe8d100408cee9b7f90524494500445d8ff6c80549082905581546040519192630100000090910473ffffffffffffffffffffffffffffffffffffffff169183156108fc0291849190818181858888f19350505050158015610afd573d6000803e3d6000fd5b73ffffffffffffffffffffffffffffffffffffffff8116600090815260126020526040812054610dfb9043614bdf565b73ffffffffffffffffffffffffffffffffffffffff831660009081526014602052604090205410801590610b4e57505073ffffffffffffffffffffffffffffffffffffffff1660009081526016602052604090205460ff1690565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff163314610ede576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f53706f6e736f723a206f6e6c792061646d696e20616c6c6f77656400000000006044820152606401610a0e565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff8116620100009182900460ff1615909102179055565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff163314610fa1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f53706f6e736f723a206f6e6c792061646d696e20616c6c6f77656400000000006044820152606401610a0e565b610fac346000610982565b565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016815533815260126020526040902054158015610fef57504315155b80611007575033600090815260146020526040902054155b1561101f573360009081526012602052604090204390555b336000908152601260205260408120546110399043614bdf565b336000908152601460205260409020549091508111801561106957503360009081526016602052604090205460ff165b156110775761107733613160565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815233600482015230602482015282907f0000000000000000000000000f8f39b92776d9136408280c7209bebe4351123b73ffffffffffffffffffffffffffffffffffffffff169063dd62ed3e90604401602060405180830381865afa158015611109573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112d9190614bf2565b10156111e1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604960248201527f53706f6e736f723a20706c6561736520617070726f7665207468652054494d4560448201527f20616d6f756e7420746f20657874656e6420796f75722073706f6e736f72736860648201527f697020706572696f640000000000000000000000000000000000000000000000608482015260a401610a0e565b670de0b6b3a764000082101561129f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604c60248201527f53706f6e736f723a20796f752073686f756c64206465706f736974203120544960448201527f4d45206f72206d6f726520746f20657874656e6420796f75722073706f6e736f60648201527f727368697020706572696f640000000000000000000000000000000000000000608482015260a401610a0e565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018390527f0000000000000000000000000f8f39b92776d9136408280c7209bebe4351123b73ffffffffffffffffffffffffffffffffffffffff16906323b872dd906064016020604051808303816000875af1158015611338573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061135c9190614c0b565b50611371826001670de0b6b3a7640000613064565b3360009081526014602052604081208054909190611390908490614b89565b90915550503360009081526014602052604090205481116113cb57336000908152601460205260409020546113c6908290614bdf565b6113ce565b60005b33600090815260146020818152604080842094855560128252909220439055905254811180159061140d57503360009081526014602052604090205415155b801561142957503360009081526016602052604090205460ff16155b1561143757611437336134ce565b50611440612ebe565b15801561144f57506000600954115b801561145e57506005600f5410155b1561146b5761146b61373e565b50600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b600054610100900460ff1615611531576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f53706f6e736f723a2074686973206f7065726174696f6e206973206c6f636b6560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610a0e565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100178155338152601360205260409020546115f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f53706f6e736f723a207468657265206973206e6f207072697a6520746f20636c60448201527f61696d20666f72207468652063616c6c657220616464726573730000000000006064820152608401610a0e565b33600090815260136020526040902054471015611695576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f53706f6e736f723a207468657265206973206e6f20656e6f75676820616d6f7560448201527f6e7420746f2077697468647261770000000000000000000000000000000000006064820152608401610a0e565b33600081815260136020526040808220805490839055905190929183156108fc02918491818181858888f193505050501580156116d6573d6000803e3d6000fd5b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001681553281526011602052604090205443036117c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f53706f6e736f723a20796f752063616e6e6f7420706572666f726d207468697360448201527f206f7065726174696f6e20616761696e20696e207468697320626c6f636b00006064820152608401610a0e565b32600090815260116020908152604080832043905533835260129091529020541580156117f157504315155b80611809575033600090815260146020526040902054155b15611821573360009081526012602052604090204390555b3360009081526012602052604081205461183b9043614bdf565b336000908152601460205260409020549091508111801561186b57503360009081526016602052604090205460ff165b156118795761187933613160565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815233600482015230602482015282907f0000000000000000000000000f8f39b92776d9136408280c7209bebe4351123b73ffffffffffffffffffffffffffffffffffffffff169063dd62ed3e90604401602060405180830381865afa15801561190b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061192f9190614bf2565b10156119e3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604660248201527f53706f6e736f723a20796f752073686f756c6420616c6c6f772054494d45207460448201527f6f206265207370656e74206265666f72652063616c6c696e672074686520667560648201527f6e6374696f6e0000000000000000000000000000000000000000000000000000608482015260a401610a0e565b8115611b82576040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018390527f0000000000000000000000000f8f39b92776d9136408280c7209bebe4351123b73ffffffffffffffffffffffffffffffffffffffff16906323b872dd906064016020604051808303816000875af1158015611a82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa69190614c0b565b506040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000057685ddbc1498f7873963cee5c186c7d95d9168881166004830152602482018490527f0000000000000000000000000f8f39b92776d9136408280c7209bebe4351123b169063095ea7b3906044016020604051808303816000875af1158015611b5c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b809190614c0b565b505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f00000000000000000000000057685ddbc1498f7873963cee5c186c7d95d9168873ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611c0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c339190614bf2565b6040517fa0712d680000000000000000000000000000000000000000000000000000000081526004810185905290915073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000057685ddbc1498f7873963cee5c186c7d95d91688169063a0712d689034906024016000604051808303818588803b158015611cbf57600080fd5b505af193505050508015611cd1575060015b611d37576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53706f6e736f723a20756e61626c6520746f2072656c6179206d696e740000006044820152606401610a0e565b34600c6000828254611d499190614b89565b90915550506040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f00000000000000000000000057685ddbc1498f7873963cee5c186c7d95d9168873ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611ddb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dff9190614bf2565b905073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000057685ddbc1498f7873963cee5c186c7d95d916881663a9059cbb33611e488585614bdf565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff909216600483015260248201526044016020604051808303816000875af1158015611eb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611edc9190614c0b565b50611ee633610dcb565b8015611ef0575083155b15611f0957611f0133600034613d92565b611f09613f68565b50503360009081526014602052604090205481116113cb57336000908152601460205260409020546113c6908290614bdf565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff163314611fc4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f53706f6e736f723a206f6e6c792061646d696e20616c6c6f77656400000000006044820152606401610a0e565b600455565b6000600854600954611fdb9190614b89565b905090565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff163314612068576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f53706f6e736f723a206f6e6c792061646d696e20616c6c6f77656400000000006044820152606401610a0e565b600655565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff1633146120f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f53706f6e736f723a206f6e6c792061646d696e20616c6c6f77656400000000006044820152606401610a0e565b6120fd6141fe565b6000600781905560088190556009819055600a819055600b819055600c819055600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600d8190556040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000057685ddbc1498f7873963cee5c186c7d95d9168816906370a0823190602401602060405180830381865afa1580156121d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121f89190614bf2565b905080156122e1576000546040517fa9059cbb000000000000000000000000000000000000000000000000000000008152630100000090910473ffffffffffffffffffffffffffffffffffffffff9081166004830152602482018390527f00000000000000000000000057685ddbc1498f7873963cee5c186c7d95d91688169063a9059cbb906044016020604051808303816000875af19250505080156122da575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526122d791810190614c0b565b60015b156122e157505b6000546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000f8f39b92776d9136408280c7209bebe4351123b81169263a9059cbb9263010000009091049091169083906370a0823190602401602060405180830381865afa158015612383573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123a79190614bf2565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff909216600483015260248201526044016020604051808303816000875af1925050508015612451575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261244e91810190614c0b565b60015b1561245857505b6000805460405173ffffffffffffffffffffffffffffffffffffffff630100000090920491909116914780156108fc02929091818181858888f19350505050158015610afd573d6000803e3d6000fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016815532815260116020526040902054430361256b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f53706f6e736f723a20796f752063616e6e6f7420706572666f726d207468697360448201527f206f7065726174696f6e20616761696e20696e207468697320626c6f636b00006064820152608401610a0e565b326000908152601160209081526040808320439055338352601290915290205415801561259757504315155b806125af575033600090815260146020526040902054155b156125c7573360009081526012602052604090204390555b336000908152601260205260408120546125e19043614bdf565b336000908152601460205260409020549091508111801561261157503360009081526016602052604090205460ff165b1561261f5761261f33613160565b60008073ffffffffffffffffffffffffffffffffffffffff8616156128be576040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523360048201523060248201528690859073ffffffffffffffffffffffffffffffffffffffff83169063dd62ed3e90604401602060405180830381865afa1580156126b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126d69190614bf2565b1015612764576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f53706f6e736f723a20706c6561736520617070726f76652074686520616d6f7560448201527f6e7420746f2073776170000000000000000000000000000000000000000000006064820152608401610a0e565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810186905273ffffffffffffffffffffffffffffffffffffffff8216906323b872dd906064016020604051808303816000875af11580156127dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128019190614c0b565b506040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000b46f8a90492d0d03b8c3ab112179c56f89a6f3e0811660048301526024820187905282169063095ea7b3906044016020604051808303816000875af1158015612897573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128bb9190614c0b565b50505b73ffffffffffffffffffffffffffffffffffffffff851615612972576040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015285925073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015612947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296b9190614bf2565b9050612975565b50475b6040517fdf791e5000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301528681166024830152604482018690527f000000000000000000000000b46f8a90492d0d03b8c3ab112179c56f89a6f3e0169063df791e509034906064016000604051808303818588803b158015612a0e57600080fd5b505af193505050508015612a20575060015b612a86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53706f6e736f723a20756e61626c6520746f2072656c617920737761700000006044820152606401610a0e565b600073ffffffffffffffffffffffffffffffffffffffff861615612bf5576040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa158015612b0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b329190614bf2565b905073ffffffffffffffffffffffffffffffffffffffff831663a9059cbb33612b5b8585614bdf565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff909216600483015260248201526044016020604051808303816000875af1158015612bcb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bef9190614c0b565b50612c2f565b5047336108fc612c058484614bdf565b6040518115909202916000818181858888f19350505050158015612c2d573d6000803e3d6000fd5b505b73ffffffffffffffffffffffffffffffffffffffff8716612cdf57612c5333610dcb565b15612cc757612cbf337f0000000000000000000000000f8f39b92776d9136408280c7209bebe4351123b73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614612cb6576002612cb9565b60015b34613d92565b612cc7613f68565b34600c6000828254612cd99190614b89565b90915550505b505050336000908152601460205260409020548111612d185733600090815260146020526040902054612d13908290614bdf565b612d1b565b60005b336000908152601460208181526040808420948555601282529092204390559052548111801590612d5a57503360009081526014602052604090205415155b8015612d7657503360009081526016602052604090205460ff16155b15612d8457612d84336134ce565b50612d8d612ebe565b158015612d9c57506000600954115b8015612dab57506005600f5410155b15612db857612db861373e565b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905550565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff163314612e70576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f53706f6e736f723a206f6e6c792061646d696e20616c6c6f77656400000000006044820152606401610a0e565b6000805473ffffffffffffffffffffffffffffffffffffffff9092166301000000027fffffffffffffffffff0000000000000000000000000000000000000000ffffff909216919091179055565b6000600c54600a54612ed09190614b89565b600b5411612ede5750600090565b600c54600a54612eee9190614b89565b600b54611fdb9190614bdf565b6000612f0682610dcb565b612f11576000610b4e565b5073ffffffffffffffffffffffffffffffffffffffff166000908152601660209081526040808320601054845260030190915290205490565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff163314612fd2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f53706f6e736f723a206f6e6c792061646d696e20616c6c6f77656400000000006044820152606401610a0e565b600555565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff16331461305f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f53706f6e736f723a206f6e6c792061646d696e20616c6c6f77656400000000006044820152606401610a0e565b600e55565b6000838302817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870982811083820303915050806000036130b9578382816130af576130af614b9c565b0492505050613159565b8084116130f2576040517f227bc15300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150505b9392505050565b73ffffffffffffffffffffffffffffffffffffffff8116158015906131aa575073ffffffffffffffffffffffffffffffffffffffff811660009081526016602052604090205460ff165b156134cb5773ffffffffffffffffffffffffffffffffffffffff80821660008181526016602052604090208054600190910154600354620100009092048416939081169291160361323657600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84161790555b60025473ffffffffffffffffffffffffffffffffffffffff80851691160361329957600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83161790555b73ffffffffffffffffffffffffffffffffffffffff82161561330c5773ffffffffffffffffffffffffffffffffffffffff828116600090815260166020526040902060010180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169183169190911790555b73ffffffffffffffffffffffffffffffffffffffff8116156133835773ffffffffffffffffffffffffffffffffffffffff8082166000908152601660205260409020805491841662010000027fffffffffffffffffffff0000000000000000000000000000000000000000ffff9092169190911790555b60015473ffffffffffffffffffffffffffffffffffffffff908116908416036133d457600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556000600d555b73ffffffffffffffffffffffffffffffffffffffff8316600090815260166020908152604080832080546001820180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690557fffffffffffffffffffff000000000000000000000000000000000000000000001681556010805485526002820184528285208590555484526003019091528120819055600f80549161347a83614c2d565b909155505060405173ffffffffffffffffffffffffffffffffffffffff841681527f1a5e355a9a34d7eac1e439a6c610ba1fa72aa45f7645724ce5187fa19c3bd3fc9060200160405180910390a150505b50565b73ffffffffffffffffffffffffffffffffffffffff811615801590613519575073ffffffffffffffffffffffffffffffffffffffff811660009081526016602052604090205460ff16155b156134cb5760035473ffffffffffffffffffffffffffffffffffffffff828116600090815260166020526040902080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff169282166201000002929092178255600190910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600254166135ed57600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83161790555b60035473ffffffffffffffffffffffffffffffffffffffff16156136655760035473ffffffffffffffffffffffffffffffffffffffff908116600090815260166020526040902060010180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169183169190911790555b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316908117909155600090815260166020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055600f8054916136ed83614c62565b909155505060405173ffffffffffffffffffffffffffffffffffffffff821681527f31d3ac54da09405b02d1de0ee0de648de637fbdc111123be0d7fc31f2a544c0b9060200160405180910390a150565b600054610100900460ff16156137d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f53706f6e736f723a2074686973206f7065726174696f6e206973206c6f636b6560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610a0e565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010017815561380a611fc9565b9050478111613d66576000613820600a83614bcb565b6001549091506138459073ffffffffffffffffffffffffffffffffffffffff16610dcb565b6138cf5760015461386b9073ffffffffffffffffffffffffffffffffffffffff16613160565b6005600f54101561387d575050613d68565b61388561435a565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055613921565b60015473ffffffffffffffffffffffffffffffffffffffff16600090815260166020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b600061392e826004614c9a565b60015473ffffffffffffffffffffffffffffffffffffffff1660009081526013602052604081208054929350839290919061396a908490614b89565b90915550506010546001546040805192835273ffffffffffffffffffffffffffffffffffffffff909116602083015281018290527fc4e84d5bdf91b848636803e57105825e4031dc6558ea19c80643b5441acfbe1c9060600160405180910390a160006139d561456c565b905060005b8151811015613afb57838183516139f19190614bdf565b6139fb9190614c9a565b92508260136000848481518110613a1457613a14614cb1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254613a659190614b89565b925050819055507fc4e84d5bdf91b848636803e57105825e4031dc6558ea19c80643b5441acfbe1c601054838381518110613aa257613aa2614cb1565b602002602001015185604051613ae19392919092835273ffffffffffffffffffffffffffffffffffffffff919091166020830152604082015260600190565b60405180910390a180613af381614c62565b9150506139da565b50600154601054600090815260156020526040812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909316929092179091558151829190613b6457613b64614cb1565b602002602001015160156000601054815260200190815260200160002060010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600181518110613bd557613bd5614cb1565b602002602001015160156000601054815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600281518110613c4657613c46614cb1565b602002602001015160156000601054815260200190815260200160002060030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508360076000828254613cb69190614bdf565b9091555050600754613cca90600290614bcb565b6009819055613cda576000613cfe565b613cfe612710600454610a776005546127106009546130649092919063ffffffff16565b600b5560006008819055600a819055600c55613d1861496c565b613d206141fe565b6000600d819055600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556010805491613d5d83614c62565b91905055505050505b505b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055565b600e548110158015613db9575073ffffffffffffffffffffffffffffffffffffffff831615155b15613f63576000805462010000900460ff16613df157826002811115613de157613de1614ce0565b613dec906001614b89565b613e19565b826002811115613e0357613e03614ce0565b613e0e906002614bdf565b613e19906001614b89565b73ffffffffffffffffffffffffffffffffffffffff851660009081526016602090815260408083206010548452600201909152812080549293508392909190613e63908490614b89565b90915550613e7390508183614c9a565b73ffffffffffffffffffffffffffffffffffffffff85166000908152601660209081526040808320601054845260030190915281208054909190613eb8908490614b89565b9091555050600d5473ffffffffffffffffffffffffffffffffffffffff8516600090815260166020908152604080832060105484526002019091529020541115613f615773ffffffffffffffffffffffffffffffffffffffff841660008181526016602090815260408083206010548452600201909152902054600d55600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690911790555b505b505050565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011781556040517f901362bd00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000f8f39b92776d9136408280c7209bebe4351123b169063901362bd90602401602060405180830381865afa15801561401d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140419190614bf2565b11156140c2577f0000000000000000000000000f8f39b92776d9136408280c7209bebe4351123b73ffffffffffffffffffffffffffffffffffffffff1663243496716040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156140af57600080fd5b505af19250505080156140c0575060015b505b60007f00000000000000000000000057685ddbc1498f7873963cee5c186c7d95d9168873ffffffffffffffffffffffffffffffffffffffff16635e7c75456040518163ffffffff1660e01b8152600401602060405180830381865afa15801561412f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141539190614bf2565b11156141d4577f00000000000000000000000057685ddbc1498f7873963cee5c186c7d95d9168873ffffffffffffffffffffffffffffffffffffffff1663ccb645966040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156141c157600080fd5b505af19250505080156141d2575060015b505b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b60025473ffffffffffffffffffffffffffffffffffffffff1660005b73ffffffffffffffffffffffffffffffffffffffff8216156142f4575073ffffffffffffffffffffffffffffffffffffffff908116600081815260166020908152604080832060018101805482547fffffffffffffffffffffffff000000000000000000000000000000000000000082169092557fffffffffffffffffffff000000000000000000000000000000000000000000009091168255601080548652600283018552838620869055548552600390910183528184208490559383526014825280832083905560129091529020439055168061421a565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000009081169091556003805490911690556000600f8190556040517f11004f150d9be1b7c9a3de18a09d7fbe5db0be2e4b03861f3b3b1c258a37b9929190a15050565b600060015b73ffffffffffffffffffffffffffffffffffffffff821661456857600254600f5473ffffffffffffffffffffffffffffffffffffffff90911690600090836143a681614c62565b600954600c54600b5460408051602081019690965243908601524260608601524460808601523060a086015260c085019290925260e08401526101008301529450610120016040516020818303038152906040528051906020012060001c61440e9190614d0f565b905060005b73ffffffffffffffffffffffffffffffffffffffff831615614560578181148015614442575061444283610dcb565b1561451f5773ffffffffffffffffffffffffffffffffffffffff8316600090815260166020526040902054610100900460ff16156144c6576001600f546144899190614bdf565b82036144b457505060025473ffffffffffffffffffffffffffffffffffffffff169050600080614413565b816144be81614c62565b925050614413565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260166020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790559193508391614560565b8061452981614c62565b73ffffffffffffffffffffffffffffffffffffffff9485166000908152601660205260409020600101549094169391506144139050565b50505061435f565b5090565b606061457a60016004614bdf565b67ffffffffffffffff81111561459257614592614d23565b6040519080825280602002602001820160405280156145bb578160200160208202803683370190505b5090506000815167ffffffffffffffff8111156145da576145da614d23565b604051908082528060200260200182016040528015614603578160200160208202803683370190505b50905060008060005b6001855161461a9190614bdf565b8110156149045760025473ffffffffffffffffffffffffffffffffffffffff1692505b73ffffffffffffffffffffffffffffffffffffffff8316156147d55773ffffffffffffffffffffffffffffffffffffffff80841660009081526016602052604090206001015485519116925084908290811061469b5761469b614cb1565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff85166000908152601683526040808220601054835260030190935291909120541180156146ed57506146ed83610dcb565b8015614724575073ffffffffffffffffffffffffffffffffffffffff8316600090815260166020526040902054610100900460ff16155b156147cd5773ffffffffffffffffffffffffffffffffffffffff831660009081526016602090815260408083206010548452600301909152902054845185908390811061477357614773614cb1565b6020026020010181815250508285828151811061479257614792614cb1565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b81925061463d565b600073ffffffffffffffffffffffffffffffffffffffff168582815181106147ff576147ff614cb1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16036148775761482a61435a565b85828151811061483c5761483c614cb1565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b60016016600087848151811061488f5761488f614cb1565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000208054911515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909216919091179055806148fc81614c62565b91505061460c565b5061490d61435a565b846001865161491c9190614bdf565b8151811061492c5761492c614cb1565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505050505090565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f0000000000000000000000000f8f39b92776d9136408280c7209bebe4351123b73ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156149f9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a1d9190614bf2565b905080156134cb5773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000f8f39b92776d9136408280c7209bebe4351123b166342966c68614a7083611388612710613064565b6040518263ffffffff1660e01b8152600401614a8e91815260200190565b600060405180830381600087803b158015614aa857600080fd5b505af1925050508015614ab9575060015b156134cb5750565b803573ffffffffffffffffffffffffffffffffffffffff81168114614ae557600080fd5b919050565b600060208284031215614afc57600080fd5b61315982614ac1565b600060208284031215614b1757600080fd5b5035919050565b600080600060608486031215614b3357600080fd5b614b3c84614ac1565b9250614b4a60208501614ac1565b9150604084013590509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610b4e57610b4e614b5a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082614bda57614bda614b9c565b500490565b81810381811115610b4e57610b4e614b5a565b600060208284031215614c0457600080fd5b5051919050565b600060208284031215614c1d57600080fd5b8151801515811461315957600080fd5b600081614c3c57614c3c614b5a565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614c9357614c93614b5a565b5060010190565b8082028115828204841417610b4e57610b4e614b5a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600082614d1e57614d1e614b9c565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea26469706673582212206c7dbc03924f0108c9b4e4406c56e78009a6bd10091b412ea2a9d4cf6710710064736f6c63430008150033

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

0000000000000000000000000f8f39b92776d9136408280c7209bebe4351123b00000000000000000000000057685ddbc1498f7873963cee5c186c7d95d91688000000000000000000000000b46f8a90492d0d03b8c3ab112179c56f89a6f3e0

-----Decoded View---------------
Arg [0] : timeTokenAddress (address): 0x0f8F39B92776D9136408280C7209BeBE4351123B
Arg [1] : tupTokenAddress (address): 0x57685Ddbc1498f7873963CEE5C186C7D95D91688
Arg [2] : timeExchangeAddress (address): 0xb46F8A90492D0d03b8c3ab112179c56F89A6f3e0

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000000f8f39b92776d9136408280c7209bebe4351123b
Arg [1] : 00000000000000000000000057685ddbc1498f7873963cee5c186c7d95d91688
Arg [2] : 000000000000000000000000b46f8a90492d0d03b8c3ab112179c56f89a6f3e0


Block Transaction Gas Used Reward
view all blocks produced
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
View All Validatorset

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.