Contract 0x63a53122e840d0cb972364d840d4cd15a2c436d7

 
 
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x27c45424350e1f0024d514ae3d27f85d96a29ab925dccf0cb7736215e7d444bfWithdraw Link262346802022-03-22 17:05:13260 days 10 hrs ago0x58ee0e715b6ff9e8c9267517a46ff7060e528858 IN  0x63a53122e840d0cb972364d840d4cd15a2c436d70 MATIC0.001338198014 35.003871677
0x76f8c7de4213c2f754934a4f52415ea16824a117ffac0be359d36f0d2c302cfeDistribute Winne...261894002022-03-21 13:22:46261 days 14 hrs ago0x6085fbb553f125c0234b28de7d4228f2873b3429 IN  0x63a53122e840d0cb972364d840d4cd15a2c436d70 MATIC0.015953815266 32.802145028
0x9bcc38ed5758a10cfc0ff778860cb76e7d931139fb5aa5598a013f3fda97ef26Get Winners261870572022-03-21 12:00:04261 days 15 hrs ago0x58ee0e715b6ff9e8c9267517a46ff7060e528858 IN  0x63a53122e840d0cb972364d840d4cd15a2c436d70 MATIC0.0228917550
0x64a6c0229c5074c7e1bd655e35dd65133419200f93d5737af35797ed8d733529Distribute Winne...261503012022-03-20 13:25:42262 days 14 hrs ago0x58ee0e715b6ff9e8c9267517a46ff7060e528858 IN  0x63a53122e840d0cb972364d840d4cd15a2c436d70 MATIC0.022236598866 43.31006269
0x6487d854701a5f6b34c8f7b601622b7a98c9c1a07242ee67b390fab59b762c16Get Winners261494102022-03-20 12:50:55262 days 14 hrs ago0x58ee0e715b6ff9e8c9267517a46ff7060e528858 IN  0x63a53122e840d0cb972364d840d4cd15a2c436d70 MATIC0.014851555956 32.43313895
0x8c104c6a09141777055c756c13220ccf5f47e8b4ea8658739714b0e71659a352Get Winners261480242022-03-20 12:01:07262 days 15 hrs ago0x58ee0e715b6ff9e8c9267517a46ff7060e528858 IN  0x63a53122e840d0cb972364d840d4cd15a2c436d70 MATIC0.049539350
0xb450cdd71724f22e0a2f54b77a7d87502f69c3ed23d6887b48af4101f3c53ef3Add Games261151752022-03-19 15:12:11263 days 12 hrs ago0x58ee0e715b6ff9e8c9267517a46ff7060e528858 IN  0x63a53122e840d0cb972364d840d4cd15a2c436d70 MATIC0.203053150
0x1a5c452b65ebc92958af650d1d902a68fe084d0a38b80f54e92d7c082dd51eaaDistribute Winne...261118282022-03-19 13:00:05263 days 14 hrs ago0x58ee0e715b6ff9e8c9267517a46ff7060e528858 IN  0x63a53122e840d0cb972364d840d4cd15a2c436d70 MATIC0.0458162550
0x419cadf4d7e20fadcd41b1667e03f03939102b82f4d2edc8daaa64f70c19af7bGet Winners261109692022-03-19 12:21:47263 days 15 hrs ago0x58ee0e715b6ff9e8c9267517a46ff7060e528858 IN  0x63a53122e840d0cb972364d840d4cd15a2c436d70 MATIC0.02257742576 32.380210768
0x8f4b233499d644fbe8138ab5d7a23bd2a732daf65ce5501c31a3173530dda73aGet Winners261103942022-03-19 12:00:05263 days 15 hrs ago0x58ee0e715b6ff9e8c9267517a46ff7060e528858 IN  0x63a53122e840d0cb972364d840d4cd15a2c436d70 MATIC0.019929550
0xa8b17bbde5b77904c23419148e74ba4517f9c01cdbc8ab54fa1749e8a28f03b5Add Games260776032022-03-18 14:21:55264 days 13 hrs ago0x58ee0e715b6ff9e8c9267517a46ff7060e528858 IN  0x63a53122e840d0cb972364d840d4cd15a2c436d70 MATIC0.166026550
0x779dfb4ec6fc61694dff13a0a1542e010f2f3c10f3070246132cf7e06882930aAdd Games260765152022-03-18 13:40:15264 days 13 hrs ago0x58ee0e715b6ff9e8c9267517a46ff7060e528858 IN  0x63a53122e840d0cb972364d840d4cd15a2c436d70 MATIC0.3951923550
0xf5e8c7f5e01ddf428755e634148a246005cc9f97788404b196d6dde2764a01b8Deploy To Group260761922022-03-18 13:29:09264 days 13 hrs ago0x58ee0e715b6ff9e8c9267517a46ff7060e528858 IN  0x63a53122e840d0cb972364d840d4cd15a2c436d70 MATIC0.0070754550
0x6930aa2ee81d7e146ec776cce26c3c799ed8cca5c9b53bcb48b6799be9b6889dDeploy To Group260761762022-03-18 13:28:37264 days 13 hrs ago0x58ee0e715b6ff9e8c9267517a46ff7060e528858 IN  0x63a53122e840d0cb972364d840d4cd15a2c436d70 MATIC0.0070738550
0xb375288222310e02075c45de8556dc7a8662201ee4243ab97c5bc26532bcd904Deploy To Group260761602022-03-18 13:28:05264 days 14 hrs ago0x58ee0e715b6ff9e8c9267517a46ff7060e528858 IN  0x63a53122e840d0cb972364d840d4cd15a2c436d70 MATIC0.0070716550
0xb8a3d066c9ddb6a3368afcd5de8b9b188d750389624e5c7272c4bdee466b622f0x60806040260760892022-03-18 13:25:35264 days 14 hrs ago0x58ee0e715b6ff9e8c9267517a46ff7060e528858 IN  Create: GrandFantasyManager0 MATIC0.269451550
[ Download CSV Export 
Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
GrandFantasyManager

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 1500 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 14 : grandfantasymanager.sol
pragma solidity >=0.8.0 <0.9.0;

import "@openzeppelin/contracts/utils/Counters.sol";
import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";
import "./nftpickem.sol";

// Status 1 is loss, 2 is win, 0 is refund
struct ContestPerformance {
  bytes32 contestName;
  uint256 entryFee;
  uint256 payout;
  uint8 status;
  uint8 picksCorrect;
  uint8 totalPicks;
  address player;
}

contract GrandFantasyManager is ChainlinkClient {
  using Counters for Counters.Counter;
  using Chainlink for Chainlink.Request;

  // Variables to hold contest history for participants
  mapping (uint => ContestPerformance) public performances;
  mapping (address => uint[]) public playerPerformances;
  Counters.Counter private currentPerformanceId;

  // Gets current oracle address for The Rundown
  function getOracleAddress() external view returns (address) {
    return chainlinkOracleAddress();
  }

  // Sets oracle address for The Rundown
  function setOracle(address _oracle) external {
    require(msg.sender == administrator);
    setChainlinkOracle(_oracle);
  }

  // Sends all link in contract back to administrator
  function withdrawLink() public {
    require(msg.sender == administrator);
    LinkTokenInterface linkToken = LinkTokenInterface(chainlinkTokenAddress());
    require(linkToken.transfer(administrator, linkToken.balanceOf(address(this))), "Unable to transfer");
  }

  // Sets the JobId for The Rundown get resolved games job
  function setSpecId(bytes32 jobId) public {
    require(msg.sender == administrator);
    specId = jobId;
  }

  // Resolved game response that will be received from The Rundown oracle
  struct GameResolve {
    bytes32 gameId;
    uint8 homeScore;
    uint8 awayScore;
    uint8 statusId;
  }
  // Game data received from fulfill
  bytes[] public gamesFromOracle;

  function bytes32ToStr(bytes32 _bytes32) public pure returns (string memory) {
    bytes memory bytesArray = new bytes(32);
    for (uint256 i; i < 32; i++) {
        bytesArray[i] = _bytes32[i];
        }
    return string(bytesArray);
  }


  // Calls the rundown api to receive game results for the contest group with the
  // highest priority
  function requestGameResults(uint32 date, uint256 payment, uint contractGroup, uint gamesLength) private {
    Chainlink.Request memory request = buildChainlinkRequest(specId, address(this), this.fulfill.selector);
    uint i;
    string[] memory gameIds = new string[](gamesLength);
    if(contractGroup == 1) {
      for(i = 0; i<ncaabGames1.length; i++) {
        gameIds[i] = string(bytes32ToStr(ncaabGames1[i].rundownId));
      }
    } else if(contractGroup == 2) {
      for(i = 0; i<ncaabGames2.length; i++) {
        gameIds[i] = string(bytes32ToStr(ncaabGames2[i].rundownId));
      }
    } else if(contractGroup == 3) {
      for(i = 0; i<ncaabGames3.length; i++) {
        gameIds[i] = string(bytes32ToStr(ncaabGames3[i].rundownId));
      }
    }

    request.addUint("sportId", 5);
    request.add("market", "resolve");
    request.addUint("date", uint256(date));
    request.addStringArray("gameIds", gameIds);

    sendChainlinkRequest(request, payment);
  }

  // Callback function from request game results
  function fulfill(bytes32 _requestId, bytes[] memory _games) public recordChainlinkFulfillment(_requestId) {
    //Games come back here
    uint i;
    for(i=0; i<_games.length; i++) {
      gamesFromOracle.push(_games[i]);
    }
  }

  // Receives a group of contest performancs from a child contract
  // these contest performances are used to hold contest history
  function receivePerformance(ContestPerformance[] memory newPerformances) public {
    address sender = msg.sender;
    bool senderValid = false;

    uint i;
    for(i = 0; i<activeContracts1.current() + 1; i++) {
      if(ncaabContracts1[i] == sender) {
        senderValid = true;
      }
    }
    for(i = 0; i<activeContracts2.current(); i++) {
      if(ncaabContracts2[i] == sender) {
        senderValid = true;
      }
    }
    for(i = 0; i<activeContracts3.current(); i++) {
      if(ncaabContracts3[i] == sender) {
        senderValid = true;
      }
    }

    require(senderValid);

    for(i = 0; i<newPerformances.length; i++) {
      performances[uint(currentPerformanceId.current())] = newPerformances[i];
      playerPerformances[newPerformances[i].player].push(uint(currentPerformanceId.current()));
      currentPerformanceId.increment();
    }
  }

  function getPerformanceForPlayer(address playerWallet) public view returns(ContestPerformance[] memory) {
    uint[] memory performanceIds = playerPerformances[playerWallet];
    ContestPerformance[] memory returnPerformances = new ContestPerformance[](performanceIds.length);
    uint i;
    for(i = 0; i<performanceIds.length; i++) {
      returnPerformances[i] = performances[performanceIds[i]];
    }
    return returnPerformances;
  }


  // Queue for contest resolution
  mapping(uint256 => uint) queue;
  uint256 first = 1;
  uint256 last = 0;
  function enqueue(uint data) private {
      last += 1;
      queue[last] = data;
  }
  function dequeue() private returns (uint data) {
      require(last >= first);  // non-empty queue

      data = queue[first];

      delete queue[first];
      first += 1;
  }
  function peek() private view returns (uint data) {
    require(last >= first);
    data = queue[first];
  }

  // Holds all reusable ncaab contest smart contracts
  // and the games areas that will be populated for ongoing contest group
  address[] public ncaabContracts1;
  Game[] public ncaabGames1;
  bytes32[] public ncaabGameIds1;
  Counters.Counter private activeContracts1;
  address[] public ncaabContracts2;
  Game[] public ncaabGames2;
  bytes32[] public ncaabGameIds2;
  Counters.Counter private activeContracts2;
  address[] public ncaabContracts3;
  Game[] public ncaabGames3;
  bytes32[] public ncaabGameIds3;
  Counters.Counter private activeContracts3;
  bool ongoingContracts1;
  bool ongoingContracts2;
  bool ongoingContracts3;
  uint public maxChildContracts;
  // Address of the Grand Fantasy managed wallet that will perform administrative actions for the manager
  address public administrator;

  bytes32 specId;

  constructor(address _link, address _oracle, bytes32 jobId) {
    // Set chainlink token address and The Rundown oracle address
    setChainlinkToken(_link);
    setChainlinkOracle(_oracle);
    specId = jobId;


    // Set the administrator to be the contract owner initially
    administrator = msg.sender;

    ongoingContracts1 = false;
    ongoingContracts2 = false;
    ongoingContracts3 = false;

    // multiple of 4 since 4 contracts are deployed at a time for each group
    maxChildContracts = 32;

    currentPerformanceId.increment();
  }

  function setMaxChildContracts(uint max) public {
    require(msg.sender == administrator);
    maxChildContracts = max;
  }

  // Returns a list of contracts that the player is entered in
  // All remaining spaces in array filled with 0x0
  function getOngoingContractsForPlayer(address player) public view returns(address[] memory) {
    // Nearly all of these slots are not going to be filled, but this is technically the max
    address[] memory ongoingContracts = new address[](maxChildContracts * 3);
    uint numberOfOngoing = 0;

    uint i;
    for(i = 0; i<ncaabContracts1.length; i++) {
      GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(ncaabContracts1[i]);
      if(pickEm.getEnteredToday(player)) {
        ongoingContracts[numberOfOngoing] = ncaabContracts1[i];
        numberOfOngoing++;
      }
    }
    for(i = 0; i<ncaabContracts2.length; i++) {
      GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(ncaabContracts2[i]);
      if(pickEm.getEnteredToday(player)) {
        ongoingContracts[numberOfOngoing] = ncaabContracts2[i];
        numberOfOngoing++;
      }
    }
    for(i = 0; i<ncaabContracts3.length; i++) {
      GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(ncaabContracts3[i]);
      if(pickEm.getEnteredToday(player)) {
        ongoingContracts[numberOfOngoing] = ncaabContracts3[i];
        numberOfOngoing++;
      }
    }

    return ongoingContracts;
  }

  // Returns a list of contracts that owe a player wei
  // all remaining spaces in array filled with 0x0
  function getContractsThatOwePlayer(address player) public view returns(address[] memory) {
    // Nearly all of these slots are not going to be filled, but this is technically the max
    address[] memory contractsThatOwe = new address[](maxChildContracts * 3);
    uint numberThatOwe = 0;

    uint i;
    for(i = 0; i<ncaabContracts1.length; i++) {
      GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(ncaabContracts1[i]);
      if(pickEm.getWinningsOwed(player) > 0) {
        contractsThatOwe[numberThatOwe] = ncaabContracts1[i];
        numberThatOwe++;
      }
    }
    for(i = 0; i<ncaabContracts2.length; i++) {
      GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(ncaabContracts2[i]);
      if(pickEm.getWinningsOwed(player) > 0) {
        contractsThatOwe[numberThatOwe] = ncaabContracts2[i];
        numberThatOwe++;
      }
    }
    for(i = 0; i<ncaabContracts3.length; i++) {
      GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(ncaabContracts3[i]);
      if(pickEm.getWinningsOwed(player) > 0) {
        contractsThatOwe[numberThatOwe] = ncaabContracts3[i];
        numberThatOwe++;
      }
    }

    return contractsThatOwe;
  }

  // Checks whether or not new contest contracts are needed
  function needsDeployment() public view returns(bool[] memory) {
    bool[] memory needsDeploy = new bool[](3);

    // Cap the number of child contracts at 32 until we know exactly how this scales
    if(ncaabContracts1.length < maxChildContracts) {
      GrandFantasyNFTPickEm group1 = GrandFantasyNFTPickEm(ncaabContracts1[activeContracts1.current()]);
      if(group1.getContestOpen() && (group1.getCurrentEntrants() >= group1.getMaxEntrants()) && (ncaabContracts1.length < activeContracts1.current() + 2)) {
        needsDeploy[0] = true;
      }
    }

    if(ncaabContracts2.length <maxChildContracts) {
      GrandFantasyNFTPickEm group2 = GrandFantasyNFTPickEm(ncaabContracts2[activeContracts2.current()]);
      if(group2.getContestOpen() && (group2.getCurrentEntrants() >= group2.getMaxEntrants()) && (ncaabContracts2.length < activeContracts2.current() + 2)) {
        needsDeploy[1] = true;
      }
    }

    if(ncaabContracts3.length < maxChildContracts) {
      GrandFantasyNFTPickEm group3 = GrandFantasyNFTPickEm(ncaabContracts3[activeContracts3.current()]);
      if(group3.getContestOpen() && (group3.getCurrentEntrants() >= group3.getMaxEntrants()) && (ncaabContracts3.length < activeContracts3.current() + 2)) {
        needsDeploy[2] = true;
      }
    }

    return needsDeploy;
  }

  function needsScaling() public view returns(bool[] memory) {
    bool[] memory shouldScale = new bool[](3);
    GrandFantasyNFTPickEm group1 = GrandFantasyNFTPickEm(ncaabContracts1[activeContracts1.current()]);
    if(group1.getContestOpen() && (group1.getCurrentEntrants() >= group1.getMaxEntrants()) && (ncaabContracts1.length >= activeContracts1.current() + 2)) {
      shouldScale[0] = true;
    }

    GrandFantasyNFTPickEm group2 = GrandFantasyNFTPickEm(ncaabContracts2[activeContracts2.current()]);
    if(group2.getContestOpen() && (group2.getCurrentEntrants() >= group2.getMaxEntrants()) && (ncaabContracts2.length >= activeContracts2.current() + 2)) {
      shouldScale[1] = true;
    }

    GrandFantasyNFTPickEm group3 = GrandFantasyNFTPickEm(ncaabContracts3[activeContracts3.current()]);
    if(group3.getContestOpen() && (group3.getCurrentEntrants() >= group3.getMaxEntrants()) && (ncaabContracts3.length >= activeContracts3.current() + 2)) {
      shouldScale[2] = true;
    }

    return shouldScale;
  }

  function scaleGroup(uint8 group) public {
    require(msg.sender == administrator);

    uint i;
    if(group == 1) {
      for(i = 0; i<4; i++) {
        GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(ncaabContracts1[i]);
        pickEm.addGames(ncaabGames1);
        pickEm.performUpkeep();
      }
    } else if(group == 2) {
      for(i = 0; i<4; i++) {
        GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(ncaabContracts2[i]);
        pickEm.addGames(ncaabGames2);
        pickEm.performUpkeep();
      }
    } else if(group == 3) {
      for(i = 0; i<4; i++) {
        activeContracts3.increment();
        GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(ncaabContracts3[i]);
        pickEm.addGames(ncaabGames3);
        pickEm.performUpkeep();
      }
    }
  }


  function deployToGroup(address[] memory contractsToAdd, uint8 group) public {
    require(msg.sender == administrator);
    require(contractsToAdd.length == 4);

    if(group == 1) {
      uint i;
      for(i = 0; i<4; i++) {
        ncaabContracts1.push(contractsToAdd[i]);
        if(ncaabGames1.length > 0) {
          GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(contractsToAdd[i]);
          pickEm.addGames(ncaabGames1);
          pickEm.performUpkeep();
        }
      }
    } else if(group == 2) {
      uint i;
      for(i = 0; i<4; i++) {
        ncaabContracts2.push(contractsToAdd[i]);
        if(ncaabGames2.length > 0) {
          GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(contractsToAdd[i]);
          pickEm.addGames(ncaabGames2);
          pickEm.performUpkeep();
        }
      }
    } else if(group == 3) {
      uint i;
      for(i = 0; i<4; i++) {
        ncaabContracts3.push(contractsToAdd[i]);
        if(ncaabGames3.length > 0) {
          GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(contractsToAdd[i]);
          pickEm.addGames(ncaabGames3);
          pickEm.performUpkeep();
        }
      }
    }
  }

  function pullContractsForContests() public view returns(address[] memory) {
    uint totalContractAddresses = activeContracts1.current() + 1;
    totalContractAddresses = totalContractAddresses + activeContracts2.current() + 1;
    totalContractAddresses = totalContractAddresses + activeContracts3.current() + 1;

    address[] memory contracts = new address[](totalContractAddresses);
    uint i;
    for(i = 0; i<activeContracts1.current() + 1; i++) {
      contracts[i] = ncaabContracts1[i];
    }
    for(i = 0; i<activeContracts2.current() + 1; i++) {
      contracts[i + activeContracts1.current() + 1] = ncaabContracts2[i];
    }
    for(i = 0; i<activeContracts3.current() + 1; i++) {
      contracts[i + activeContracts1.current() + 1 + activeContracts2.current() + 1] = ncaabContracts3[i];
    }

    return contracts;
  }

  function addGames(Game[] memory newGames) public {
    require(msg.sender == administrator);
    require(newGames.length <= 16);
    // There must be contracts available to run the contests on
    require(ongoingContracts1 == false || ongoingContracts2 == false || ongoingContracts3 == false);
    uint i;

    // There are not currently contests running on the contracts group 1
    if(ongoingContracts1 == false) {
      activeContracts1.reset();

      // Add games to first four contracts
      uint lengthToAdd = ncaabContracts1.length >= 4 ? 4 : 0;
      for(i = 0; i<lengthToAdd; i++) {
        GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(ncaabContracts1[i]);
        pickEm.addGames(newGames);

        if(i != lengthToAdd - 1) {
          activeContracts1.increment();
        }
      }
      for(i = 0; i<newGames.length; i++) {
        ncaabGameIds1.push(newGames[i].rundownId);
        ncaabGames1.push(newGames[i]);
      }

      // There are now contests ongoing on the contracts group 1
      ongoingContracts1 = true;
      enqueue(1);
    } else if(ongoingContracts2 == false) {
      activeContracts2.reset();

      // Add games to first four contracts
      uint lengthToAdd = ncaabContracts2.length >= 4 ? 3 : 0;
      for(i = 0; i<lengthToAdd; i++) {
        GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(ncaabContracts2[i]);
        pickEm.addGames(newGames);

        if(i != lengthToAdd - 1) {
          activeContracts2.increment();
        }
      }
      for(i = 0; i<newGames.length; i++) {
        ncaabGameIds2.push(newGames[i].rundownId);
        ncaabGames2.push(newGames[i]);
      }

      ongoingContracts2 = true;
      enqueue(2);
    } else if(ongoingContracts3 == false) {
        activeContracts3.reset();

        // Add game to first four contracts
        uint lengthToAdd = ncaabContracts3.length >= 4 ? 3 : 0;
        for(i = 0; i<lengthToAdd; i++) {
          GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(ncaabContracts3[i]);
          pickEm.addGames(newGames);

          if(i != lengthToAdd - 1) {
            activeContracts3.increment();
          }
        }
        for(i = 0; i<newGames.length; i++) {
          ncaabGameIds3.push(newGames[i].rundownId);
          ncaabGames3.push(newGames[i]);
        }

        // There are now contests ongoing on the contracts group 3
        ongoingContracts3 = true;
        enqueue(3);
    }
  }

  // Makes request to oracle to get results for the highest priority games
  // that have ended.
  // Param apiKey is a valid key for the Rundown API
  function getWinners() public {
    require(msg.sender == administrator);

    // Peek which contest group is up next for resolution
    uint contractsToResolve = peek();
    uint gamesLength = 0;

    // Grab the start time of the last game to check alongside the current timestamp
    // Also populate a list of game ids to resolve
    uint i;
    uint32 lastGameStartTime = 0;
    uint256 firstStartTime = 2**256 - 1;
    if(contractsToResolve == 1) {
      gamesLength = ncaabGameIds1.length;
      for(i = 0; i<ncaabGames1.length; i++) {
        if(ncaabGames1[i].startTime > lastGameStartTime) {
          lastGameStartTime = ncaabGames1[i].startTime;
        }
        if(uint256(ncaabGames1[i].startTime) < firstStartTime) {
          firstStartTime = uint256(ncaabGames1[i].startTime);
        }
      }
    } else if(contractsToResolve == 2) {
      gamesLength = ncaabGameIds2.length;
      for(i = 0; i<ncaabGames2.length; i++) {
        if(ncaabGames2[i].startTime > lastGameStartTime) {
          lastGameStartTime = ncaabGames2[i].startTime;
        }
        if(uint256(ncaabGames2[i].startTime) < firstStartTime) {
          firstStartTime = uint256(ncaabGames2[i].startTime);
        }
      }
    } else if (contractsToResolve == 3) {
      gamesLength = ncaabGameIds3.length;
      for(i = 0; i<ncaabGames3.length; i++) {
        if(ncaabGames3[i].startTime > lastGameStartTime) {
          lastGameStartTime = ncaabGames3[i].startTime;
        }
        if(uint256(ncaabGames3[i].startTime) < firstStartTime) {
          firstStartTime = uint256(ncaabGames3[i].startTime);
        }
      }
    }


    // Only make the oracle request for the winners when the games are  over
    // Making the request before the games end will not be useful
    uint256 comparisonTimestamp = lastGameStartTime + 28800;
    if(block.timestamp > comparisonTimestamp) {
      uint256 payment = 0.1 * 10 ** 18;
      requestGameResults(lastGameStartTime, payment, contractsToResolve, gamesLength);
    }

    // For the case where games are on two different UTC days, we want to make sure we are pulling all games
    if(lastGameStartTime > uint32(firstStartTime)) {
      if(lastGameStartTime - uint32(firstStartTime) > 18000) {
        uint256 payment = 0.1 * 10 ** 18;
        requestGameResults(uint32(firstStartTime), payment, contractsToResolve, gamesLength);
      }
    }
  }

  // When called, takes scores received through oracle and distributes
  // to the correct child contract
  function distributeWinnersToContests() public {
    uint i;
    uint x;
    uint contractsToResolve = peek();

    // First, grab the games that have been received from the oracle
    // Assign winners to the existing games
    require(gamesFromOracle.length > 0);
    if(contractsToResolve == 1) {
      for(i = 0; i<gamesFromOracle.length; i++) {
        GameResolve memory game = abi.decode(gamesFromOracle[i], (GameResolve));
        for(x = 0; x<ncaabGames1.length; x++) {
          if(ncaabGames1[x].rundownId == game.gameId) {
            ncaabGames1[x].winner = game.homeScore > game.awayScore ? 1 : 2;
            break;
          }
        }
      }
    } else if(contractsToResolve == 2) {
      for(i = 0; i<gamesFromOracle.length; i++) {
        GameResolve memory game = abi.decode(gamesFromOracle[i], (GameResolve));
        for(x = 0; x<ncaabGames2.length; x++) {
          if(ncaabGames2[x].rundownId == game.gameId) {
            ncaabGames2[x].winner = game.homeScore > game.awayScore ? 1 : 2;
            break;
          }
        }
      }
    } else if(contractsToResolve == 3) {
      for(i = 0; i<gamesFromOracle.length; i++) {
        GameResolve memory game = abi.decode(gamesFromOracle[i], (GameResolve));
        for(x = 0; x<ncaabGames3.length; x++) {
          if(ncaabGames3[x].rundownId == game.gameId) {
            ncaabGames3[x].winner = game.homeScore > game.awayScore ? 1 : 2;
            break;
          }
        }
      }
    }

    // Next, make sure that we have the winner for every single
    // game
    if(contractsToResolve == 1) {
      for(i = 0; i<ncaabGames1.length; i++) {
        require(ncaabGames1[i].winner > 0);
      }
    } else if(contractsToResolve == 2) {
      for(i = 0; i<ncaabGames2.length; i++) {
        require(ncaabGames2[i].winner > 0);
      }
    } else {
      for(i = 0; i<ncaabGames3.length; i++) {
        require(ncaabGames3[i].winner > 0);
      }
    }

    // If we've made it here, we have all necessary winners to proceed
    // we can dequeue and resolve the contests
    contractsToResolve = dequeue();
    if(contractsToResolve == 1) {
      uint8[] memory finalGameWinners = new uint8[](ncaabGameIds1.length);
      for(x = 0; x<ncaabGames1.length; x++) {
        finalGameWinners[x] = ncaabGames1[x].winner;
      }

      for(i = 0; i<activeContracts1.current() + 1; i++) {
        GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(ncaabContracts1[i]);
        pickEm.receiveWinners(finalGameWinners);
      }

      ongoingContracts1 = false;
      delete ncaabGameIds1;
      delete ncaabGames1;
      delete gamesFromOracle;
    } else if(contractsToResolve == 2) {
      uint8[] memory finalGameWinners = new uint8[](ncaabGameIds2.length);
      for(x = 0; x<ncaabGames2.length; x++) {
        finalGameWinners[x] = ncaabGames2[x].winner;
      }

      for(i = 0; i<activeContracts2.current() + 1; i++) {
        GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(ncaabContracts2[i]);
        pickEm.receiveWinners(finalGameWinners);
      }

      ongoingContracts2 = false;
      delete ncaabGameIds2;
      delete ncaabGames2;
      delete gamesFromOracle;
    } else if(contractsToResolve == 3) {
      uint8[] memory finalGameWinners = new uint8[](ncaabGameIds3.length);
      for(x = 0; x<ncaabGames3.length; x++) {
        finalGameWinners[x] = ncaabGames3[x].winner;
      }

      for(i = 0; i<activeContracts3.current() + 1; i++) {
        GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(ncaabContracts3[i]);
        pickEm.receiveWinners(finalGameWinners);
      }

      ongoingContracts3 = false;
      delete ncaabGameIds3;
      delete ncaabGames3;
      delete gamesFromOracle;
    }
  }

  // This function is an emergency alternative to resolving contests
  // with chainlink oracles
  // If the oracle service is down or data is problematic, any contest can be
  // refunded
  function refundContest() public {
    require(msg.sender == administrator);

    uint contractsToRefund = dequeue();
    uint i;
    if(contractsToRefund == 1) {
      for(i = 0; i<activeContracts1.current() + 1; i++) {
        GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(ncaabContracts1[i]);
        pickEm.refundContest();
      }

      delete ncaabGameIds1;
      delete ncaabGames1;
      delete gamesFromOracle;
    } else if(contractsToRefund == 2) {
      for(i = 0; i<activeContracts2.current() + 1; i++) {
        GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(ncaabContracts2[i]);
        pickEm.refundContest();
      }

      delete ncaabGameIds2;
      delete ncaabGames2;
      delete gamesFromOracle;
    } else if(contractsToRefund == 3) {
      for(i = 0; i<activeContracts3.current() + 1; i++) {
        GrandFantasyNFTPickEm pickEm = GrandFantasyNFTPickEm(ncaabContracts3[i]);
        pickEm.refundContest();
      }

      delete ncaabGameIds3;
      delete ncaabGames3;
      delete gamesFromOracle;
    }
  }
}

File 2 of 14 : nftpickem.sol
pragma solidity >=0.8.0 <0.9.0;

import "@openzeppelin/contracts/utils/Counters.sol";
import "./grandfantasymanager.sol";

// Struct that represents a game for the PickEm
// Team1Name and Team2Name up to 32 characters
// startTime is unix timestamp
// winner will be set to 1 or 2 after the game concludes, depending on which team won
struct Game {
  bytes32 team1Name;
  bytes32 team2Name;
  uint32 startTime;
  uint16 id;
  uint8 winner;
  bytes32 rundownId;
}

contract GrandFantasyNFTPickEm {
  using Counters for Counters.Counter;

  // Whether or not players can place picks, this will be set to false before game begin
  bool public contestOpen;

  // Address of the Grand Fantasy managed wallet that will perform administrative actions for the contest
  address public administrator;

  // Address of Grand Fantasy contest manager smart contract that handles deployment of contests
  address public managerAddress;

  // UNIX timestamp of what time the next PickEm competition will open for entries...0 for not scheduled
  uint32 public nextContestStartTime;

  // UNIX timestamp of the start time of the earliest game added to the contest
  uint32 public firstGameStartTime;

  // UNIX timestamp of the start time of the latest game added to the contest
  uint32 public lastGameStartTime;

  // Boolean indicating whether or not the winners for the games have been sent in
  bool public gameWinnersReceived;

  // Boolean indicating whether or not all past contests on this contract have been resolved
  bool public contestResolved;

  // The number of correct picks a user needs to be deemed a winner of the current contest
  uint8 public requirementToWin;

  // The number of total picks a user needs to submit to be entered in to a contest
  // This is calculated when adding games to the contest
  uint8 public totalPicksRequired;

  // In wei, the prize pool of the current contest
  // Prize pool goes up with each entry
  uint256 public prizePool;

  // Name of the contest for display in the client side UI
  bytes32 public contestName;

  // Entry fee, in wei, for the contest
  uint256 public weiEntryFee;

  // Counter to keep track of how many entrants there are in the current contest
  Counters.Counter private currentEntrants;

  // Maximum number of entrants for the contest
  uint32 public maxEntrants;

  // Counter to apply an id to user pick selections
  Counters.Counter private currentPickId;

  // Array of addresses that will hold the winners of the current contest
  // Array will be populated from the end of one contest until the next is set up
  address[] public winners;

  // Chainlink upkeep variables used in order to update contests automatically
  // and without direct administrator intervention
  uint public immutable interval;
  uint public lastTimeStamp;

  // Maps GameIds to game struct
  mapping (uint16 => Game) public games;

  constructor(uint updateInterval, bytes32 name, uint256 entryFee, address manager) {
    // Set the administrator to be the contract owner initially
    administrator = msg.sender;

    // Set metadata for the contest contract
    contestName = name;
    weiEntryFee = entryFee;

    // Set the contest manager contract
    managerAddress = manager;

    // Increment the currentPickId so it starts at 1
    currentPickId.increment();

    // Make is so the admin is able to create a new contest by default
    contestResolved = true;

    // Set chainlink upkeep variables
    interval = updateInterval;
    lastTimeStamp = 0;
  }

  // Determines whether or not upkeep is needed on the contract
  function checkUpkeep() external view returns (bool upkeepNeeded) {
    if((block.timestamp - lastTimeStamp) > interval) {
      // If there have been no games added or contest details have not been added, there is no upkeep to perform
      if(totalPicksRequired > 0 && requirementToWin > 0) {
        upkeepNeeded = true;
      } else {
        upkeepNeeded = false;
      }
    } else {
      upkeepNeeded = false;
    }
  }

  function performUpkeep() external {
    require(msg.sender == administrator || msg.sender == managerAddress);
    lastTimeStamp = block.timestamp;

    // If the contest is closed for entries, but the next contest has been scheduled
    if(!contestOpen && nextContestStartTime > 0) {
      // Open the contest for entries if the current date is an hour or less before
      // the scheduled time to open entries
      if(block.timestamp > nextContestStartTime) {
        contestOpen = true;
        nextContestStartTime = 0;
        contestResolved = false;
      } else if(nextContestStartTime - block.timestamp <= 3600) {
        contestOpen = true;
        nextContestStartTime = 0;
        contestResolved = false;
      }
    }
    // If the contest is closed for entries and a contest is ongoing
    else if(!contestOpen && nextContestStartTime == 0 && gameWinnersReceived) {
      // Resolve contest and pay out winners if it has been at least 8 hours since the start
      // time of the lastest game
      // This also requires knowing the outcome of the games
      if(block.timestamp > lastGameStartTime && block.timestamp - lastGameStartTime >= 28800) {
        markForPayout();
      }
    }
    // If entries for the contest are currently open
    else if(contestOpen) {
      // Close contest entries if upkeep is happening within an hour and a half of the
      // earliest game
      if(block.timestamp > firstGameStartTime) {
        contestOpen = false;
        if(currentEntrants.current() < 3) {
          refundContest();
        }
      } else if(firstGameStartTime - block.timestamp <= 5400) {
        contestOpen = false;
        if(currentEntrants.current() < 3) {
          refundContest();
        }
      }
    }
}


  // Returns the number of current entrants into the contest
  function getCurrentEntrants() public view returns (uint) {
    return currentEntrants.current();
  }

  // Returns the number of maximum entrants into the contest
  function getMaxEntrants() public view returns (uint) {
    return maxEntrants;
  }

  function getContestOpen() public view returns (bool) {
    return contestOpen;
  }

  // Passes administration privleges to a new address
  // ADMINISTRATOR ONLY
  function passAdministrationPrivleges(address newAdministrator) public {
    require(msg.sender == administrator);
    administrator = newAdministrator;
  }

  // Function that sets the start time, number of picks required to win, and
  // maximum entrants of a new contest
  // ADMINISTRATOR ONLY
  // Param startTime - unix timestamp for start time
  // Param requirement - # of correct picks required to win the PickEm contest
  // Param max - maximum entrants into this contest
  function setContestDetails(uint32 startTime) private {
    require(contestResolved);

    // Winners could still be populated from a previous contest, clear the array
    delete winners;

    nextContestStartTime = startTime;

    uint8 requirement = totalPicksRequired - (totalPicksRequired / 3);
    requirementToWin = requirement;
    maxEntrants = 20;
  }

  // Returns an array of all games that have been added to the contest
  function getGames() public view returns(Game[] memory) {
    Game[] memory allGames = new Game[](totalPicksRequired);
    uint i;
    for(i = 0; i < totalPicksRequired; i++) {
      allGames[i] = games[uint16(i)];
    }
    return allGames;
  }

  // Struct that represents a single user pick for the PickEm
  // Pick is a value 1 to pick team1 or 2 to pick team2
  struct Pick {
    uint16 gameId;
    uint8 pick;
    uint24 pickId;
  }
  mapping (uint24 => Pick) public picks;

  // Struct that represents a player in a PickEm contest
  // playerAddress, weiOwed will be persistent accross contests
  struct Player {
    address playerAddress;
    uint24[] pickIds;
    uint256 weiOwed;
    bool enteredToday;
  }
  mapping (address => Player) public playerStructs;

  // Holds the players that have entered into the current contest
  address[] public playersToday;

  // Adds [games] for use in the PickEm contest. Winner value of these games will be set to 0.
  // ADMINISTRATOR ONLY - this will be called each day at
  // Param newGames are the games to add to the games mapping
  function addGames(Game[] memory newGames) public {
    require(msg.sender == managerAddress);
    require(contestResolved);

    if(newGames.length > 0) {
      totalPicksRequired = uint8(newGames.length);

      // Only the administrator can send in games and
      // will not send more than how many PickEm games are in a day. Likely ~10
      uint i;

      // Use max int for comparison
      uint256 firstStartTime = 2**256 - 1;
      uint32 lastStartTime;
      for (i = 0; i < newGames.length; i++) {
        // Record the start time of the earliest game and the start time of the
        // lastest game
        if(uint256(newGames[i].startTime) < firstStartTime) {
          firstStartTime = uint256(newGames[i].startTime);
        }
        if(newGames[i].startTime > lastStartTime) {
          lastStartTime = newGames[i].startTime;
        }

        games[newGames[i].id] = newGames[i];
      }

      // Save earliest and latest start time to storage
      firstGameStartTime = uint32(firstStartTime);
      lastGameStartTime = lastStartTime;

      // Open contest for entries 24 hours before games
      uint256 contestStartTime = firstStartTime - 86400;
      setContestDetails(uint32(contestStartTime));
    }
  }

  // Function to make picks here
  function submitPicksForContest(uint8[] memory playerPicks) public payable {
    // Require contest to be open to place picks
    require(contestOpen);

    // Require the entrants to not be over the max
    require(currentEntrants.current() < maxEntrants);

    // Require the value of the transaction to be over the wei entry fee
    require(msg.value >= weiEntryFee);

    address player = msg.sender;
    // Only one entry allowed per player
    require(playerStructs[player].enteredToday == false);
    // # of picks submitted must exactly equal the number of games
    require(playerPicks.length == totalPicksRequired);

    uint i;
    for(i = 0; i<playerPicks.length; i++) {
      // Picks must either be for team 1 or team 2, no other values
      require(playerPicks[i] == 1 || playerPicks[i] == 2);

      // Create data for each pick
      Pick memory newPick;
      newPick.gameId = uint16(i);
      newPick.pick = playerPicks[i];
      uint24 newPickId = uint24(currentPickId.current());
      newPick.pickId = newPickId;

      // This is a new player, initialize them in the struct
      if(i == 0 && playerStructs[player].playerAddress == address(0x0)) {
        Player memory newPlayer;
        newPlayer.playerAddress = player;
        playerStructs[player] = newPlayer;
        playerStructs[player].pickIds.push(newPickId);
      } else {
        playerStructs[player].pickIds.push(newPickId);
      }

      // Reflect the new pick in the picks struct
      picks[newPickId] = newPick;

      // Increment the counter so each pick has a unique id
      currentPickId.increment();
    }

    // Player has been successfully entered in the current contest
    playerStructs[player].enteredToday = true;
    playersToday.push(player);
    currentEntrants.increment();
    prizePool = prizePool + weiEntryFee;
  }

  function getPicksForPlayer(address player) public view returns(Pick[] memory) {
    uint24[] memory playerPickIds = playerStructs[player].pickIds;
    Pick[] memory playerPicks = new Pick[](playerPickIds.length);
    uint i;
    for(i = 0; i<playerPickIds.length; i++) {
      playerPicks[i] = picks[playerPickIds[i]];
    }
    return playerPicks;
  }

  function receiveWinners(uint8[] memory finalGames) public {
    require(msg.sender == managerAddress);

    // If the contest has been refunded, we don't want to do any of this
    if(contestResolved == false) {
      uint i;
      // Update all game structs to contain the winners using administrator data
      for(i = 0; i < finalGames.length; i++) {
        games[uint16(i)].winner = finalGames[i];
      }

      gameWinnersReceived = true;
    }
  }

  function markForPayout() private {
    uint i;
    uint8 correctPicks;
    uint x;
    ContestPerformance[] memory contestPerformances = new ContestPerformance[](currentEntrants.current());

    // At this point, the winner portion of the games structs are set
    // Go through all players today
    for(i = 0; i < playersToday.length; i++) {
      Player memory player = playerStructs[playersToday[i]];

      correctPicks = 0;

      // For each player today, go through each of their picks
      // Number of pickIds is bounded by the number of games added for the contest, usually ~10
      for(x = 0; x < player.pickIds.length; x++) {
        Pick memory pick = picks[player.pickIds[x]];
        Game memory game = games[pick.gameId];

        // If the pick aligns with the winner, it was correct
        if(game.winner == pick.pick) {
          correctPicks++;
        }
      }

      // Clear the pick ids, they will never be needed again but we may need this field again
      delete player.pickIds;

      // Remove entered today so that players will be able to enter the next contest
      player.enteredToday = false;

      // If the player has enough correct picks, they are officially a winner
      ContestPerformance memory newPerformance;
      if(correctPicks >= requirementToWin) {
        newPerformance.contestName = contestName;
        newPerformance.entryFee = weiEntryFee;
        newPerformance.payout = 0;
        newPerformance.status = 2;
        newPerformance.picksCorrect = correctPicks;
        newPerformance.totalPicks = totalPicksRequired;
        newPerformance.player = playersToday[i];
        contestPerformances[i] = newPerformance;

        winners.push(player.playerAddress);
      } else {
        newPerformance.contestName = contestName;
        newPerformance.entryFee = weiEntryFee;
        newPerformance.payout = 0;
        newPerformance.status = 1;
        newPerformance.picksCorrect = correctPicks;
        newPerformance.totalPicks = totalPicksRequired;
        newPerformance.player = playersToday[i];
        contestPerformances[i] = newPerformance;
      }

      // Set memory variable back to storage so that changes persist
      playerStructs[playersToday[i]] = player;
    }

    // Calculate payout by dividing prize pool by # of winners
    // Take a 10% rake here
    uint256 payout;
    if(winners.length > 0) {
      payout = (prizePool / 10 * 9) / winners.length;
    } else {
      playerStructs[administrator].weiOwed = playerStructs[administrator].weiOwed + prizePool;
    }

    bool takeRake = false;

    for(i = 0; i < winners.length; i++) {
      if(payout < weiEntryFee) {
        playerStructs[winners[i]].weiOwed = playerStructs[winners[i]].weiOwed + weiEntryFee;
      } else {
        playerStructs[winners[i]].weiOwed = playerStructs[winners[i]].weiOwed + payout;
        takeRake = true;
      }
    }

    for(i = 0; i<contestPerformances.length; i++) {
      if(payout < weiEntryFee &&  (contestPerformances[i].picksCorrect >= requirementToWin)) {
        contestPerformances[i].payout = contestPerformances[i].payout + weiEntryFee;
      } else if(contestPerformances[i].picksCorrect >= requirementToWin) {
        contestPerformances[i].payout = contestPerformances[i].payout + payout;
      }
    }

    GrandFantasyManager manager = GrandFantasyManager(managerAddress);
    manager.receivePerformance(contestPerformances);

    if(takeRake) {
      // The administrator wallet is able to withdraw the rake
      uint256 rake = prizePool / 10;
      playerStructs[administrator].weiOwed = playerStructs[administrator].weiOwed + rake;
    }

    // Delete all games from the games mapping
    for(i = 0; i < totalPicksRequired; i++) {
      delete games[uint16(i)];
    }

    // Do some housekeeping to get ready for any future contests
    requirementToWin = 0;
    totalPicksRequired = 0;
    prizePool = 0;
    maxEntrants = 0;
    firstGameStartTime = 0;
    lastGameStartTime = 0;
    gameWinnersReceived = false;
    contestResolved = true;

    delete playersToday;
    currentEntrants.reset();
  }

  //Function to refund contest
  function refundContest() public {
    require(msg.sender == administrator || msg.sender == managerAddress);
    uint i;
    ContestPerformance[] memory refundPerformances = new ContestPerformance[](playersToday.length);
    for(i = 0; i < playersToday.length; i++) {
      Player memory player = playerStructs[playersToday[i]];

      // Clear the pick ids, they will never be needed again but we may need this field again
      delete player.pickIds;

      // Remove entered today so that players will be able to enter the next contest
      player.enteredToday = false;

      // Refund the entry fee to the contest
      player.weiOwed = player.weiOwed + weiEntryFee;


      // Set memory variable back to storage so that changes persist
      playerStructs[playersToday[i]] = player;

      ContestPerformance memory newPerformance;
      newPerformance.contestName = contestName;
      newPerformance.entryFee = weiEntryFee;
      newPerformance.payout = weiEntryFee;
      newPerformance.status = 0;
      newPerformance.picksCorrect = 0;
      newPerformance.totalPicks = 0;
      newPerformance.player = playersToday[i];
      refundPerformances[i] = newPerformance;
    }

    GrandFantasyManager manager = GrandFantasyManager(managerAddress);
    manager.receivePerformance(refundPerformances);

    // Delete all games from the games mapping
    for(i = 0; i < totalPicksRequired; i++) {
      delete games[uint16(i)];
    }

    // Do some housekeeping to get ready for any future contests
    requirementToWin = 0;
    totalPicksRequired = 0;
    prizePool = 0;
    maxEntrants = 0;
    firstGameStartTime = 0;
    lastGameStartTime = 0;
    gameWinnersReceived = false;
    contestResolved = true;

    delete playersToday;
    currentEntrants.reset();
  }

  // If a wallet is owed wei from contests, they can call upon this function
  // to withdraw this money
  function withdrawWinnings() public {
    if(playerStructs[msg.sender].weiOwed > 0) {
      uint maticToSend = playerStructs[msg.sender].weiOwed;
      playerStructs[msg.sender].weiOwed = 0;
      payable(msg.sender).transfer(maticToSend);
    }
  }

  function getWinningsOwed(address player) public view returns(uint) {
    return playerStructs[player].weiOwed;
  }

  function getEnteredToday(address player) public view returns(bool) {
    return playerStructs[player].enteredToday;
  }
}

File 3 of 14 : Counters.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)

pragma solidity ^0.8.0;

/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 */
library Counters {
    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        unchecked {
            counter._value += 1;
        }
    }

    function decrement(Counter storage counter) internal {
        uint256 value = counter._value;
        require(value > 0, "Counter: decrement overflow");
        unchecked {
            counter._value = value - 1;
        }
    }

    function reset(Counter storage counter) internal {
        counter._value = 0;
    }
}

File 4 of 14 : ENSResolver.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

abstract contract ENSResolver {
  function addr(bytes32 node) public view virtual returns (address);
}

File 5 of 14 : CBORChainlink.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.19;

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

library CBORChainlink {
  using BufferChainlink for BufferChainlink.buffer;

  uint8 private constant MAJOR_TYPE_INT = 0;
  uint8 private constant MAJOR_TYPE_NEGATIVE_INT = 1;
  uint8 private constant MAJOR_TYPE_BYTES = 2;
  uint8 private constant MAJOR_TYPE_STRING = 3;
  uint8 private constant MAJOR_TYPE_ARRAY = 4;
  uint8 private constant MAJOR_TYPE_MAP = 5;
  uint8 private constant MAJOR_TYPE_TAG = 6;
  uint8 private constant MAJOR_TYPE_CONTENT_FREE = 7;

  uint8 private constant TAG_TYPE_BIGNUM = 2;
  uint8 private constant TAG_TYPE_NEGATIVE_BIGNUM = 3;

  function encodeFixedNumeric(BufferChainlink.buffer memory buf, uint8 major, uint64 value) private pure {
    if(value <= 23) {
      buf.appendUint8(uint8((major << 5) | value));
    } else if (value <= 0xFF) {
      buf.appendUint8(uint8((major << 5) | 24));
      buf.appendInt(value, 1);
    } else if (value <= 0xFFFF) {
      buf.appendUint8(uint8((major << 5) | 25));
      buf.appendInt(value, 2);
    } else if (value <= 0xFFFFFFFF) {
      buf.appendUint8(uint8((major << 5) | 26));
      buf.appendInt(value, 4);
    } else {
      buf.appendUint8(uint8((major << 5) | 27));
      buf.appendInt(value, 8);
    }
  }

  function encodeIndefiniteLengthType(BufferChainlink.buffer memory buf, uint8 major) private pure {
    buf.appendUint8(uint8((major << 5) | 31));
  }

  function encodeUInt(BufferChainlink.buffer memory buf, uint value) internal pure {
    if(value > 0xFFFFFFFFFFFFFFFF) {
      encodeBigNum(buf, value);
    } else {
      encodeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(value));
    }
  }

  function encodeInt(BufferChainlink.buffer memory buf, int value) internal pure {
    if(value < -0x10000000000000000) {
      encodeSignedBigNum(buf, value);
    } else if(value > 0xFFFFFFFFFFFFFFFF) {
      encodeBigNum(buf, uint(value));
    } else if(value >= 0) {
      encodeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(uint256(value)));
    } else {
      encodeFixedNumeric(buf, MAJOR_TYPE_NEGATIVE_INT, uint64(uint256(-1 - value)));
    }
  }

  function encodeBytes(BufferChainlink.buffer memory buf, bytes memory value) internal pure {
    encodeFixedNumeric(buf, MAJOR_TYPE_BYTES, uint64(value.length));
    buf.append(value);
  }

  function encodeBigNum(BufferChainlink.buffer memory buf, uint value) internal pure {
    buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_BIGNUM));
    encodeBytes(buf, abi.encode(value));
  }

  function encodeSignedBigNum(BufferChainlink.buffer memory buf, int input) internal pure {
    buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_NEGATIVE_BIGNUM));
    encodeBytes(buf, abi.encode(uint256(-1 - input)));
  }

  function encodeString(BufferChainlink.buffer memory buf, string memory value) internal pure {
    encodeFixedNumeric(buf, MAJOR_TYPE_STRING, uint64(bytes(value).length));
    buf.append(bytes(value));
  }

  function startArray(BufferChainlink.buffer memory buf) internal pure {
    encodeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY);
  }

  function startMap(BufferChainlink.buffer memory buf) internal pure {
    encodeIndefiniteLengthType(buf, MAJOR_TYPE_MAP);
  }

  function endSequence(BufferChainlink.buffer memory buf) internal pure {
    encodeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE);
  }
}

File 6 of 14 : BufferChainlink.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @dev A library for working with mutable byte buffers in Solidity.
 *
 * Byte buffers are mutable and expandable, and provide a variety of primitives
 * for writing to them. At any time you can fetch a bytes object containing the
 * current contents of the buffer. The bytes object should not be stored between
 * operations, as it may change due to resizing of the buffer.
 */
library BufferChainlink {
  /**
   * @dev Represents a mutable buffer. Buffers have a current value (buf) and
   *      a capacity. The capacity may be longer than the current value, in
   *      which case it can be extended without the need to allocate more memory.
   */
  struct buffer {
    bytes buf;
    uint256 capacity;
  }

  /**
   * @dev Initializes a buffer with an initial capacity.
   * @param buf The buffer to initialize.
   * @param capacity The number of bytes of space to allocate the buffer.
   * @return The buffer, for chaining.
   */
  function init(buffer memory buf, uint256 capacity) internal pure returns (buffer memory) {
    if (capacity % 32 != 0) {
      capacity += 32 - (capacity % 32);
    }
    // Allocate space for the buffer data
    buf.capacity = capacity;
    assembly {
      let ptr := mload(0x40)
      mstore(buf, ptr)
      mstore(ptr, 0)
      mstore(0x40, add(32, add(ptr, capacity)))
    }
    return buf;
  }

  /**
   * @dev Initializes a new buffer from an existing bytes object.
   *      Changes to the buffer may mutate the original value.
   * @param b The bytes object to initialize the buffer with.
   * @return A new buffer.
   */
  function fromBytes(bytes memory b) internal pure returns (buffer memory) {
    buffer memory buf;
    buf.buf = b;
    buf.capacity = b.length;
    return buf;
  }

  function resize(buffer memory buf, uint256 capacity) private pure {
    bytes memory oldbuf = buf.buf;
    init(buf, capacity);
    append(buf, oldbuf);
  }

  function max(uint256 a, uint256 b) private pure returns (uint256) {
    if (a > b) {
      return a;
    }
    return b;
  }

  /**
   * @dev Sets buffer length to 0.
   * @param buf The buffer to truncate.
   * @return The original buffer, for chaining..
   */
  function truncate(buffer memory buf) internal pure returns (buffer memory) {
    assembly {
      let bufptr := mload(buf)
      mstore(bufptr, 0)
    }
    return buf;
  }

  /**
   * @dev Writes a byte string to a buffer. Resizes if doing so would exceed
   *      the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param off The start offset to write to.
   * @param data The data to append.
   * @param len The number of bytes to copy.
   * @return The original buffer, for chaining.
   */
  function write(
    buffer memory buf,
    uint256 off,
    bytes memory data,
    uint256 len
  ) internal pure returns (buffer memory) {
    require(len <= data.length);

    if (off + len > buf.capacity) {
      resize(buf, max(buf.capacity, len + off) * 2);
    }

    uint256 dest;
    uint256 src;
    assembly {
      // Memory address of the buffer data
      let bufptr := mload(buf)
      // Length of existing buffer data
      let buflen := mload(bufptr)
      // Start address = buffer address + offset + sizeof(buffer length)
      dest := add(add(bufptr, 32), off)
      // Update buffer length if we're extending it
      if gt(add(len, off), buflen) {
        mstore(bufptr, add(len, off))
      }
      src := add(data, 32)
    }

    // Copy word-length chunks while possible
    for (; len >= 32; len -= 32) {
      assembly {
        mstore(dest, mload(src))
      }
      dest += 32;
      src += 32;
    }

    // Copy remaining bytes
    unchecked {
      uint256 mask = (256**(32 - len)) - 1;
      assembly {
        let srcpart := and(mload(src), not(mask))
        let destpart := and(mload(dest), mask)
        mstore(dest, or(destpart, srcpart))
      }
    }

    return buf;
  }

  /**
   * @dev Appends a byte string to a buffer. Resizes if doing so would exceed
   *      the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param data The data to append.
   * @param len The number of bytes to copy.
   * @return The original buffer, for chaining.
   */
  function append(
    buffer memory buf,
    bytes memory data,
    uint256 len
  ) internal pure returns (buffer memory) {
    return write(buf, buf.buf.length, data, len);
  }

  /**
   * @dev Appends a byte string to a buffer. Resizes if doing so would exceed
   *      the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param data The data to append.
   * @return The original buffer, for chaining.
   */
  function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) {
    return write(buf, buf.buf.length, data, data.length);
  }

  /**
   * @dev Writes a byte to the buffer. Resizes if doing so would exceed the
   *      capacity of the buffer.
   * @param buf The buffer to append to.
   * @param off The offset to write the byte at.
   * @param data The data to append.
   * @return The original buffer, for chaining.
   */
  function writeUint8(
    buffer memory buf,
    uint256 off,
    uint8 data
  ) internal pure returns (buffer memory) {
    if (off >= buf.capacity) {
      resize(buf, buf.capacity * 2);
    }

    assembly {
      // Memory address of the buffer data
      let bufptr := mload(buf)
      // Length of existing buffer data
      let buflen := mload(bufptr)
      // Address = buffer address + sizeof(buffer length) + off
      let dest := add(add(bufptr, off), 32)
      mstore8(dest, data)
      // Update buffer length if we extended it
      if eq(off, buflen) {
        mstore(bufptr, add(buflen, 1))
      }
    }
    return buf;
  }

  /**
   * @dev Appends a byte to the buffer. Resizes if doing so would exceed the
   *      capacity of the buffer.
   * @param buf The buffer to append to.
   * @param data The data to append.
   * @return The original buffer, for chaining.
   */
  function appendUint8(buffer memory buf, uint8 data) internal pure returns (buffer memory) {
    return writeUint8(buf, buf.buf.length, data);
  }

  /**
   * @dev Writes up to 32 bytes to the buffer. Resizes if doing so would
   *      exceed the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param off The offset to write at.
   * @param data The data to append.
   * @param len The number of bytes to write (left-aligned).
   * @return The original buffer, for chaining.
   */
  function write(
    buffer memory buf,
    uint256 off,
    bytes32 data,
    uint256 len
  ) private pure returns (buffer memory) {
    if (len + off > buf.capacity) {
      resize(buf, (len + off) * 2);
    }

    unchecked {
      uint256 mask = (256**len) - 1;
      // Right-align data
      data = data >> (8 * (32 - len));
      assembly {
        // Memory address of the buffer data
        let bufptr := mload(buf)
        // Address = buffer address + sizeof(buffer length) + off + len
        let dest := add(add(bufptr, off), len)
        mstore(dest, or(and(mload(dest), not(mask)), data))
        // Update buffer length if we extended it
        if gt(add(off, len), mload(bufptr)) {
          mstore(bufptr, add(off, len))
        }
      }
    }
    return buf;
  }

  /**
   * @dev Writes a bytes20 to the buffer. Resizes if doing so would exceed the
   *      capacity of the buffer.
   * @param buf The buffer to append to.
   * @param off The offset to write at.
   * @param data The data to append.
   * @return The original buffer, for chaining.
   */
  function writeBytes20(
    buffer memory buf,
    uint256 off,
    bytes20 data
  ) internal pure returns (buffer memory) {
    return write(buf, off, bytes32(data), 20);
  }

  /**
   * @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed
   *      the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param data The data to append.
   * @return The original buffer, for chhaining.
   */
  function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) {
    return write(buf, buf.buf.length, bytes32(data), 20);
  }

  /**
   * @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed
   *      the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param data The data to append.
   * @return The original buffer, for chaining.
   */
  function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) {
    return write(buf, buf.buf.length, data, 32);
  }

  /**
   * @dev Writes an integer to the buffer. Resizes if doing so would exceed
   *      the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param off The offset to write at.
   * @param data The data to append.
   * @param len The number of bytes to write (right-aligned).
   * @return The original buffer, for chaining.
   */
  function writeInt(
    buffer memory buf,
    uint256 off,
    uint256 data,
    uint256 len
  ) private pure returns (buffer memory) {
    if (len + off > buf.capacity) {
      resize(buf, (len + off) * 2);
    }

    uint256 mask = (256**len) - 1;
    assembly {
      // Memory address of the buffer data
      let bufptr := mload(buf)
      // Address = buffer address + off + sizeof(buffer length) + len
      let dest := add(add(bufptr, off), len)
      mstore(dest, or(and(mload(dest), not(mask)), data))
      // Update buffer length if we extended it
      if gt(add(off, len), mload(bufptr)) {
        mstore(bufptr, add(off, len))
      }
    }
    return buf;
  }

  /**
   * @dev Appends a byte to the end of the buffer. Resizes if doing so would
   * exceed the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param data The data to append.
   * @return The original buffer.
   */
  function appendInt(
    buffer memory buf,
    uint256 data,
    uint256 len
  ) internal pure returns (buffer memory) {
    return writeInt(buf, buf.buf.length, data, len);
  }
}

File 7 of 14 : PointerInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface PointerInterface {
  function getAddress() external view returns (address);
}

File 8 of 14 : OracleInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface OracleInterface {
  function fulfillOracleRequest(
    bytes32 requestId,
    uint256 payment,
    address callbackAddress,
    bytes4 callbackFunctionId,
    uint256 expiration,
    bytes32 data
  ) external returns (bool);

  function isAuthorizedSender(address node) external view returns (bool);

  function withdraw(address recipient, uint256 amount) external;

  function withdrawable() external view returns (uint256);
}

File 9 of 14 : OperatorInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./OracleInterface.sol";
import "./ChainlinkRequestInterface.sol";

interface OperatorInterface is OracleInterface, ChainlinkRequestInterface {
  function operatorRequest(
    address sender,
    uint256 payment,
    bytes32 specId,
    bytes4 callbackFunctionId,
    uint256 nonce,
    uint256 dataVersion,
    bytes calldata data
  ) external;

  function fulfillOracleRequest2(
    bytes32 requestId,
    uint256 payment,
    address callbackAddress,
    bytes4 callbackFunctionId,
    uint256 expiration,
    bytes calldata data
  ) external returns (bool);

  function ownerTransferAndCall(
    address to,
    uint256 value,
    bytes calldata data
  ) external returns (bool success);

  function distributeFunds(address payable[] calldata receivers, uint256[] calldata amounts) external payable;

  function getAuthorizedSenders() external returns (address[] memory);

  function setAuthorizedSenders(address[] calldata senders) external;

  function getForwarder() external returns (address);
}

File 10 of 14 : LinkTokenInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface LinkTokenInterface {
  function allowance(address owner, address spender) external view returns (uint256 remaining);

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

  function balanceOf(address owner) external view returns (uint256 balance);

  function decimals() external view returns (uint8 decimalPlaces);

  function decreaseApproval(address spender, uint256 addedValue) external returns (bool success);

  function increaseApproval(address spender, uint256 subtractedValue) external;

  function name() external view returns (string memory tokenName);

  function symbol() external view returns (string memory tokenSymbol);

  function totalSupply() external view returns (uint256 totalTokensIssued);

  function transfer(address to, uint256 value) external returns (bool success);

  function transferAndCall(
    address to,
    uint256 value,
    bytes calldata data
  ) external returns (bool success);

  function transferFrom(
    address from,
    address to,
    uint256 value
  ) external returns (bool success);
}

File 11 of 14 : ENSInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface ENSInterface {
  // Logged when the owner of a node assigns a new owner to a subnode.
  event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);

  // Logged when the owner of a node transfers ownership to a new account.
  event Transfer(bytes32 indexed node, address owner);

  // Logged when the resolver for a node changes.
  event NewResolver(bytes32 indexed node, address resolver);

  // Logged when the TTL of a node changes
  event NewTTL(bytes32 indexed node, uint64 ttl);

  function setSubnodeOwner(
    bytes32 node,
    bytes32 label,
    address owner
  ) external;

  function setResolver(bytes32 node, address resolver) external;

  function setOwner(bytes32 node, address owner) external;

  function setTTL(bytes32 node, uint64 ttl) external;

  function owner(bytes32 node) external view returns (address);

  function resolver(bytes32 node) external view returns (address);

  function ttl(bytes32 node) external view returns (uint64);
}

File 12 of 14 : ChainlinkRequestInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface ChainlinkRequestInterface {
  function oracleRequest(
    address sender,
    uint256 requestPrice,
    bytes32 serviceAgreementID,
    address callbackAddress,
    bytes4 callbackFunctionId,
    uint256 nonce,
    uint256 dataVersion,
    bytes calldata data
  ) external;

  function cancelOracleRequest(
    bytes32 requestId,
    uint256 payment,
    bytes4 callbackFunctionId,
    uint256 expiration
  ) external;
}

File 13 of 14 : ChainlinkClient.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./Chainlink.sol";
import "./interfaces/ENSInterface.sol";
import "./interfaces/LinkTokenInterface.sol";
import "./interfaces/ChainlinkRequestInterface.sol";
import "./interfaces/OperatorInterface.sol";
import "./interfaces/PointerInterface.sol";
import {ENSResolver as ENSResolver_Chainlink} from "./vendor/ENSResolver.sol";

/**
 * @title The ChainlinkClient contract
 * @notice Contract writers can inherit this contract in order to create requests for the
 * Chainlink network
 */
abstract contract ChainlinkClient {
  using Chainlink for Chainlink.Request;

  uint256 internal constant LINK_DIVISIBILITY = 10**18;
  uint256 private constant AMOUNT_OVERRIDE = 0;
  address private constant SENDER_OVERRIDE = address(0);
  uint256 private constant ORACLE_ARGS_VERSION = 1;
  uint256 private constant OPERATOR_ARGS_VERSION = 2;
  bytes32 private constant ENS_TOKEN_SUBNAME = keccak256("link");
  bytes32 private constant ENS_ORACLE_SUBNAME = keccak256("oracle");
  address private constant LINK_TOKEN_POINTER = 0xC89bD4E1632D3A43CB03AAAd5262cbe4038Bc571;

  ENSInterface private s_ens;
  bytes32 private s_ensNode;
  LinkTokenInterface private s_link;
  OperatorInterface private s_oracle;
  uint256 private s_requestCount = 1;
  mapping(bytes32 => address) private s_pendingRequests;

  event ChainlinkRequested(bytes32 indexed id);
  event ChainlinkFulfilled(bytes32 indexed id);
  event ChainlinkCancelled(bytes32 indexed id);

  /**
   * @notice Creates a request that can hold additional parameters
   * @param specId The Job Specification ID that the request will be created for
   * @param callbackAddr address to operate the callback on
   * @param callbackFunctionSignature function signature to use for the callback
   * @return A Chainlink Request struct in memory
   */
  function buildChainlinkRequest(
    bytes32 specId,
    address callbackAddr,
    bytes4 callbackFunctionSignature
  ) internal pure returns (Chainlink.Request memory) {
    Chainlink.Request memory req;
    return req.initialize(specId, callbackAddr, callbackFunctionSignature);
  }

  /**
   * @notice Creates a request that can hold additional parameters
   * @param specId The Job Specification ID that the request will be created for
   * @param callbackFunctionSignature function signature to use for the callback
   * @return A Chainlink Request struct in memory
   */
  function buildOperatorRequest(bytes32 specId, bytes4 callbackFunctionSignature)
    internal
    view
    returns (Chainlink.Request memory)
  {
    Chainlink.Request memory req;
    return req.initialize(specId, address(this), callbackFunctionSignature);
  }

  /**
   * @notice Creates a Chainlink request to the stored oracle address
   * @dev Calls `chainlinkRequestTo` with the stored oracle address
   * @param req The initialized Chainlink Request
   * @param payment The amount of LINK to send for the request
   * @return requestId The request ID
   */
  function sendChainlinkRequest(Chainlink.Request memory req, uint256 payment) internal returns (bytes32) {
    return sendChainlinkRequestTo(address(s_oracle), req, payment);
  }

  /**
   * @notice Creates a Chainlink request to the specified oracle address
   * @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to
   * send LINK which creates a request on the target oracle contract.
   * Emits ChainlinkRequested event.
   * @param oracleAddress The address of the oracle for the request
   * @param req The initialized Chainlink Request
   * @param payment The amount of LINK to send for the request
   * @return requestId The request ID
   */
  function sendChainlinkRequestTo(
    address oracleAddress,
    Chainlink.Request memory req,
    uint256 payment
  ) internal returns (bytes32 requestId) {
    uint256 nonce = s_requestCount;
    s_requestCount = nonce + 1;
    bytes memory encodedRequest = abi.encodeWithSelector(
      ChainlinkRequestInterface.oracleRequest.selector,
      SENDER_OVERRIDE, // Sender value - overridden by onTokenTransfer by the requesting contract's address
      AMOUNT_OVERRIDE, // Amount value - overridden by onTokenTransfer by the actual amount of LINK sent
      req.id,
      address(this),
      req.callbackFunctionId,
      nonce,
      ORACLE_ARGS_VERSION,
      req.buf.buf
    );
    return _rawRequest(oracleAddress, nonce, payment, encodedRequest);
  }

  /**
   * @notice Creates a Chainlink request to the stored oracle address
   * @dev This function supports multi-word response
   * @dev Calls `sendOperatorRequestTo` with the stored oracle address
   * @param req The initialized Chainlink Request
   * @param payment The amount of LINK to send for the request
   * @return requestId The request ID
   */
  function sendOperatorRequest(Chainlink.Request memory req, uint256 payment) internal returns (bytes32) {
    return sendOperatorRequestTo(address(s_oracle), req, payment);
  }

  /**
   * @notice Creates a Chainlink request to the specified oracle address
   * @dev This function supports multi-word response
   * @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to
   * send LINK which creates a request on the target oracle contract.
   * Emits ChainlinkRequested event.
   * @param oracleAddress The address of the oracle for the request
   * @param req The initialized Chainlink Request
   * @param payment The amount of LINK to send for the request
   * @return requestId The request ID
   */
  function sendOperatorRequestTo(
    address oracleAddress,
    Chainlink.Request memory req,
    uint256 payment
  ) internal returns (bytes32 requestId) {
    uint256 nonce = s_requestCount;
    s_requestCount = nonce + 1;
    bytes memory encodedRequest = abi.encodeWithSelector(
      OperatorInterface.operatorRequest.selector,
      SENDER_OVERRIDE, // Sender value - overridden by onTokenTransfer by the requesting contract's address
      AMOUNT_OVERRIDE, // Amount value - overridden by onTokenTransfer by the actual amount of LINK sent
      req.id,
      req.callbackFunctionId,
      nonce,
      OPERATOR_ARGS_VERSION,
      req.buf.buf
    );
    return _rawRequest(oracleAddress, nonce, payment, encodedRequest);
  }

  /**
   * @notice Make a request to an oracle
   * @param oracleAddress The address of the oracle for the request
   * @param nonce used to generate the request ID
   * @param payment The amount of LINK to send for the request
   * @param encodedRequest data encoded for request type specific format
   * @return requestId The request ID
   */
  function _rawRequest(
    address oracleAddress,
    uint256 nonce,
    uint256 payment,
    bytes memory encodedRequest
  ) private returns (bytes32 requestId) {
    requestId = keccak256(abi.encodePacked(this, nonce));
    s_pendingRequests[requestId] = oracleAddress;
    emit ChainlinkRequested(requestId);
    require(s_link.transferAndCall(oracleAddress, payment, encodedRequest), "unable to transferAndCall to oracle");
  }

  /**
   * @notice Allows a request to be cancelled if it has not been fulfilled
   * @dev Requires keeping track of the expiration value emitted from the oracle contract.
   * Deletes the request from the `pendingRequests` mapping.
   * Emits ChainlinkCancelled event.
   * @param requestId The request ID
   * @param payment The amount of LINK sent for the request
   * @param callbackFunc The callback function specified for the request
   * @param expiration The time of the expiration for the request
   */
  function cancelChainlinkRequest(
    bytes32 requestId,
    uint256 payment,
    bytes4 callbackFunc,
    uint256 expiration
  ) internal {
    OperatorInterface requested = OperatorInterface(s_pendingRequests[requestId]);
    delete s_pendingRequests[requestId];
    emit ChainlinkCancelled(requestId);
    requested.cancelOracleRequest(requestId, payment, callbackFunc, expiration);
  }

  /**
   * @notice the next request count to be used in generating a nonce
   * @dev starts at 1 in order to ensure consistent gas cost
   * @return returns the next request count to be used in a nonce
   */
  function getNextRequestCount() internal view returns (uint256) {
    return s_requestCount;
  }

  /**
   * @notice Sets the stored oracle address
   * @param oracleAddress The address of the oracle contract
   */
  function setChainlinkOracle(address oracleAddress) internal {
    s_oracle = OperatorInterface(oracleAddress);
  }

  /**
   * @notice Sets the LINK token address
   * @param linkAddress The address of the LINK token contract
   */
  function setChainlinkToken(address linkAddress) internal {
    s_link = LinkTokenInterface(linkAddress);
  }

  /**
   * @notice Sets the Chainlink token address for the public
   * network as given by the Pointer contract
   */
  function setPublicChainlinkToken() internal {
    setChainlinkToken(PointerInterface(LINK_TOKEN_POINTER).getAddress());
  }

  /**
   * @notice Retrieves the stored address of the LINK token
   * @return The address of the LINK token
   */
  function chainlinkTokenAddress() internal view returns (address) {
    return address(s_link);
  }

  /**
   * @notice Retrieves the stored address of the oracle contract
   * @return The address of the oracle contract
   */
  function chainlinkOracleAddress() internal view returns (address) {
    return address(s_oracle);
  }

  /**
   * @notice Allows for a request which was created on another contract to be fulfilled
   * on this contract
   * @param oracleAddress The address of the oracle contract that will fulfill the request
   * @param requestId The request ID used for the response
   */
  function addChainlinkExternalRequest(address oracleAddress, bytes32 requestId) internal notPendingRequest(requestId) {
    s_pendingRequests[requestId] = oracleAddress;
  }

  /**
   * @notice Sets the stored oracle and LINK token contracts with the addresses resolved by ENS
   * @dev Accounts for subnodes having different resolvers
   * @param ensAddress The address of the ENS contract
   * @param node The ENS node hash
   */
  function useChainlinkWithENS(address ensAddress, bytes32 node) internal {
    s_ens = ENSInterface(ensAddress);
    s_ensNode = node;
    bytes32 linkSubnode = keccak256(abi.encodePacked(s_ensNode, ENS_TOKEN_SUBNAME));
    ENSResolver_Chainlink resolver = ENSResolver_Chainlink(s_ens.resolver(linkSubnode));
    setChainlinkToken(resolver.addr(linkSubnode));
    updateChainlinkOracleWithENS();
  }

  /**
   * @notice Sets the stored oracle contract with the address resolved by ENS
   * @dev This may be called on its own as long as `useChainlinkWithENS` has been called previously
   */
  function updateChainlinkOracleWithENS() internal {
    bytes32 oracleSubnode = keccak256(abi.encodePacked(s_ensNode, ENS_ORACLE_SUBNAME));
    ENSResolver_Chainlink resolver = ENSResolver_Chainlink(s_ens.resolver(oracleSubnode));
    setChainlinkOracle(resolver.addr(oracleSubnode));
  }

  /**
   * @notice Ensures that the fulfillment is valid for this contract
   * @dev Use if the contract developer prefers methods instead of modifiers for validation
   * @param requestId The request ID for fulfillment
   */
  function validateChainlinkCallback(bytes32 requestId)
    internal
    recordChainlinkFulfillment(requestId)
  // solhint-disable-next-line no-empty-blocks
  {

  }

  /**
   * @dev Reverts if the sender is not the oracle of the request.
   * Emits ChainlinkFulfilled event.
   * @param requestId The request ID for fulfillment
   */
  modifier recordChainlinkFulfillment(bytes32 requestId) {
    require(msg.sender == s_pendingRequests[requestId], "Source must be the oracle of the request");
    delete s_pendingRequests[requestId];
    emit ChainlinkFulfilled(requestId);
    _;
  }

  /**
   * @dev Reverts if the request is already pending
   * @param requestId The request ID for fulfillment
   */
  modifier notPendingRequest(bytes32 requestId) {
    require(s_pendingRequests[requestId] == address(0), "Request is already pending");
    _;
  }
}

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

import {CBORChainlink} from "./vendor/CBORChainlink.sol";
import {BufferChainlink} from "./vendor/BufferChainlink.sol";

/**
 * @title Library for common Chainlink functions
 * @dev Uses imported CBOR library for encoding to buffer
 */
library Chainlink {
  uint256 internal constant defaultBufferSize = 256; // solhint-disable-line const-name-snakecase

  using CBORChainlink for BufferChainlink.buffer;

  struct Request {
    bytes32 id;
    address callbackAddress;
    bytes4 callbackFunctionId;
    uint256 nonce;
    BufferChainlink.buffer buf;
  }

  /**
   * @notice Initializes a Chainlink request
   * @dev Sets the ID, callback address, and callback function signature on the request
   * @param self The uninitialized request
   * @param jobId The Job Specification ID
   * @param callbackAddr The callback address
   * @param callbackFunc The callback function signature
   * @return The initialized request
   */
  function initialize(
    Request memory self,
    bytes32 jobId,
    address callbackAddr,
    bytes4 callbackFunc
  ) internal pure returns (Chainlink.Request memory) {
    BufferChainlink.init(self.buf, defaultBufferSize);
    self.id = jobId;
    self.callbackAddress = callbackAddr;
    self.callbackFunctionId = callbackFunc;
    return self;
  }

  /**
   * @notice Sets the data for the buffer without encoding CBOR on-chain
   * @dev CBOR can be closed with curly-brackets {} or they can be left off
   * @param self The initialized request
   * @param data The CBOR data
   */
  function setBuffer(Request memory self, bytes memory data) internal pure {
    BufferChainlink.init(self.buf, data.length);
    BufferChainlink.append(self.buf, data);
  }

  /**
   * @notice Adds a string value to the request with a given key name
   * @param self The initialized request
   * @param key The name of the key
   * @param value The string value to add
   */
  function add(
    Request memory self,
    string memory key,
    string memory value
  ) internal pure {
    self.buf.encodeString(key);
    self.buf.encodeString(value);
  }

  /**
   * @notice Adds a bytes value to the request with a given key name
   * @param self The initialized request
   * @param key The name of the key
   * @param value The bytes value to add
   */
  function addBytes(
    Request memory self,
    string memory key,
    bytes memory value
  ) internal pure {
    self.buf.encodeString(key);
    self.buf.encodeBytes(value);
  }

  /**
   * @notice Adds a int256 value to the request with a given key name
   * @param self The initialized request
   * @param key The name of the key
   * @param value The int256 value to add
   */
  function addInt(
    Request memory self,
    string memory key,
    int256 value
  ) internal pure {
    self.buf.encodeString(key);
    self.buf.encodeInt(value);
  }

  /**
   * @notice Adds a uint256 value to the request with a given key name
   * @param self The initialized request
   * @param key The name of the key
   * @param value The uint256 value to add
   */
  function addUint(
    Request memory self,
    string memory key,
    uint256 value
  ) internal pure {
    self.buf.encodeString(key);
    self.buf.encodeUInt(value);
  }

  /**
   * @notice Adds an array of strings to the request with a given key name
   * @param self The initialized request
   * @param key The name of the key
   * @param values The array of string values to add
   */
  function addStringArray(
    Request memory self,
    string memory key,
    string[] memory values
  ) internal pure {
    self.buf.encodeString(key);
    self.buf.startArray();
    for (uint256 i = 0; i < values.length; i++) {
      self.buf.encodeString(values[i]);
    }
    self.buf.endSequence();
  }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_link","type":"address"},{"internalType":"address","name":"_oracle","type":"address"},{"internalType":"bytes32","name":"jobId","type":"bytes32"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"ChainlinkCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"ChainlinkFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"ChainlinkRequested","type":"event"},{"inputs":[{"components":[{"internalType":"bytes32","name":"team1Name","type":"bytes32"},{"internalType":"bytes32","name":"team2Name","type":"bytes32"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint16","name":"id","type":"uint16"},{"internalType":"uint8","name":"winner","type":"uint8"},{"internalType":"bytes32","name":"rundownId","type":"bytes32"}],"internalType":"struct Game[]","name":"newGames","type":"tuple[]"}],"name":"addGames","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"administrator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_bytes32","type":"bytes32"}],"name":"bytes32ToStr","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address[]","name":"contractsToAdd","type":"address[]"},{"internalType":"uint8","name":"group","type":"uint8"}],"name":"deployToGroup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"distributeWinnersToContests","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_requestId","type":"bytes32"},{"internalType":"bytes[]","name":"_games","type":"bytes[]"}],"name":"fulfill","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"gamesFromOracle","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"player","type":"address"}],"name":"getContractsThatOwePlayer","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"player","type":"address"}],"name":"getOngoingContractsForPlayer","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOracleAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"playerWallet","type":"address"}],"name":"getPerformanceForPlayer","outputs":[{"components":[{"internalType":"bytes32","name":"contestName","type":"bytes32"},{"internalType":"uint256","name":"entryFee","type":"uint256"},{"internalType":"uint256","name":"payout","type":"uint256"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"uint8","name":"picksCorrect","type":"uint8"},{"internalType":"uint8","name":"totalPicks","type":"uint8"},{"internalType":"address","name":"player","type":"address"}],"internalType":"struct ContestPerformance[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWinners","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxChildContracts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ncaabContracts1","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ncaabContracts2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ncaabContracts3","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ncaabGameIds1","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ncaabGameIds2","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ncaabGameIds3","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ncaabGames1","outputs":[{"internalType":"bytes32","name":"team1Name","type":"bytes32"},{"internalType":"bytes32","name":"team2Name","type":"bytes32"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint16","name":"id","type":"uint16"},{"internalType":"uint8","name":"winner","type":"uint8"},{"internalType":"bytes32","name":"rundownId","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ncaabGames2","outputs":[{"internalType":"bytes32","name":"team1Name","type":"bytes32"},{"internalType":"bytes32","name":"team2Name","type":"bytes32"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint16","name":"id","type":"uint16"},{"internalType":"uint8","name":"winner","type":"uint8"},{"internalType":"bytes32","name":"rundownId","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ncaabGames3","outputs":[{"internalType":"bytes32","name":"team1Name","type":"bytes32"},{"internalType":"bytes32","name":"team2Name","type":"bytes32"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint16","name":"id","type":"uint16"},{"internalType":"uint8","name":"winner","type":"uint8"},{"internalType":"bytes32","name":"rundownId","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"needsDeployment","outputs":[{"internalType":"bool[]","name":"","type":"bool[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"needsScaling","outputs":[{"internalType":"bool[]","name":"","type":"bool[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"performances","outputs":[{"internalType":"bytes32","name":"contestName","type":"bytes32"},{"internalType":"uint256","name":"entryFee","type":"uint256"},{"internalType":"uint256","name":"payout","type":"uint256"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"uint8","name":"picksCorrect","type":"uint8"},{"internalType":"uint8","name":"totalPicks","type":"uint8"},{"internalType":"address","name":"player","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"playerPerformances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pullContractsForContests","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"contestName","type":"bytes32"},{"internalType":"uint256","name":"entryFee","type":"uint256"},{"internalType":"uint256","name":"payout","type":"uint256"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"uint8","name":"picksCorrect","type":"uint8"},{"internalType":"uint8","name":"totalPicks","type":"uint8"},{"internalType":"address","name":"player","type":"address"}],"internalType":"struct ContestPerformance[]","name":"newPerformances","type":"tuple[]"}],"name":"receivePerformance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"refundContest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"group","type":"uint8"}],"name":"scaleGroup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"max","type":"uint256"}],"name":"setMaxChildContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_oracle","type":"address"}],"name":"setOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"jobId","type":"bytes32"}],"name":"setSpecId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawLink","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405260016004556001600b556000600c553480156200002057600080fd5b5060405162005e7e38038062005e7e8339810160408190526200004391620000e9565b600280546001600160a01b0319166001600160a01b038516179055600380546001600160a01b0319166001600160a01b038416179055601c819055601b80546001600160a01b031916331790556019805462ffffff191690556020601a819055620000ba9060089062004380620000c3821b17901c565b5050506200012a565b80546001019055565b80516001600160a01b0381168114620000e457600080fd5b919050565b600080600060608486031215620000ff57600080fd5b6200010a84620000cc565b92506200011a60208501620000cc565b9150604084015190509250925092565b615d44806200013a6000396000f3fe608060405234801561001057600080fd5b50600436106102265760003560e01c80639120326f1161012a578063caac339e116100bd578063df15c37e1161008c578063ef0b236811610071578063ef0b23681461054b578063f53d0a8e1461055e578063ff533d7f1461057157600080fd5b8063df15c37e14610530578063e3221baa1461053857600080fd5b8063caac339e14610459578063cec286751461046c578063d443d8c91461047f578063dcbc3bb31461049257600080fd5b8063c02ba6a3116100f9578063c02ba6a314610417578063c499803c1461042a578063c52e899c14610433578063c8ae3e581461044657600080fd5b80639120326f146103ec5780639ddfe98b146103ff578063aa4db99e14610407578063b18b78dd1461040f57600080fd5b80633780b254116101bd5780636ab165b11161018c5780637adbf973116101715780637adbf973146103b157806386d183b3146103c45780638dc654a2146103e457600080fd5b80636ab165b1146103705780636c7dc9901461039157600080fd5b80633780b254146103225780633e7cde391461033757806354202aff1461034a57806355f9e9591461035d57600080fd5b80631d48390d116101f95780631d48390d146102a3578063294acf3f146102b6578063296c4201146102be578063358289ee1461030f57600080fd5b8063099f2fd01461022b5780630a4b417f1461025b578063153b183a1461027b5780631549b40b14610290575b600080fd5b61023e6102393660046151ad565b610579565b6040516001600160a01b0390911681526020015b60405180910390f35b61026e6102693660046151ad565b6105a3565b6040516102529190615213565b61028e61028936600461530e565b61064f565b005b61028e61029e36600461541b565b610901565b61028e6102b13660046151ad565b610a49565b61028e610a65565b6102d16102cc3660046151ad565b610cec565b60408051968752602087019590955263ffffffff9093169385019390935261ffff16606084015260ff909116608083015260a082015260c001610252565b61028e61031d36600461552d565b610d48565b61032a6113ea565b6040516102529190615628565b61028e6103453660046151ad565b61190b565b6102d16103583660046151ad565b611927565b61023e61036b3660046151ad565b611937565b61038361037e3660046151ad565b611947565b604051908152602001610252565b6103a461039f36600461566e565b611968565b6040516102529190615689565b61028e6103bf36600461566e565b611d22565b6103d76103d236600461566e565b611d67565b60405161025291906156ca565b61028e611f2b565b6103836103fa366004615762565b6120be565b6103a46120ef565b61032a612368565b61023e6128ad565b6102d16104253660046151ad565b6128c6565b610383601a5481565b6103a461044136600461566e565b6128d6565b61023e6104543660046151ad565b612c87565b6103836104673660046151ad565b612c97565b61038361047a3660046151ad565b612ca7565b61028e61048d36600461578c565b612cb7565b6104ed6104a03660046151ad565b60066020526000908152604090208054600182015460028301546003909301549192909160ff8082169161010081048216916201000082041690630100000090046001600160a01b031687565b6040805197885260208801969096529486019390935260ff9182166060860152811660808501521660a08301526001600160a01b031660c082015260e001610252565b61028e612fea565b61028e6105463660046157b0565b613391565b61026e6105593660046151ad565b6137d6565b601b5461023e906001600160a01b031681565b61028e613870565b6015818154811061058957600080fd5b6000918252602090912001546001600160a01b0316905081565b600981815481106105b357600080fd5b9060005260206000200160009150905080546105ce9061585a565b80601f01602080910402602001604051908101604052809291908181526020018280546105fa9061585a565b80156106475780601f1061061c57610100808354040283529160200191610647565b820191906000526020600020905b81548152906001019060200180831161062a57829003601f168201915b505050505081565b336000805b6010546106629060016158a5565b8110156106b857826001600160a01b0316600d8281548110610686576106866158bd565b6000918252602090912001546001600160a01b031614156106a657600191505b806106b0816158d3565b915050610654565b5060005b60145481101561071557826001600160a01b0316601182815481106106e3576106e36158bd565b6000918252602090912001546001600160a01b0316141561070357600191505b8061070d816158d3565b9150506106bc565b5060005b60185481101561077257826001600160a01b031660158281548110610740576107406158bd565b6000918252602090912001546001600160a01b0316141561076057600191505b8061076a816158d3565b915050610719565b8161077c57600080fd5b5060005b83518110156108fb5783818151811061079b5761079b6158bd565b6020026020010151600660006107b060085490565b81526020808201929092526040908101600090812084518155928401516001840155908301516002830155606083015160039092018054608085015160a086015160c0909601516001600160a01b03166301000000027fffffffffffffffffff0000000000000000000000000000000000000000ffffff60ff9788166201000002167fffffffffffffffffff000000000000000000000000000000000000000000ffff9288166101000261ffff199094169790961696909617919091171692909217929092179055845160079190869084908110610890576108906158bd565b602002602001015160c001516001600160a01b03166001600160a01b031681526020019081526020016000206108c560085490565b815460018101835560009283526020909220909101556108e9600880546001019055565b806108f3816158d3565b915050610780565b50505050565b60008281526005602052604090205482906001600160a01b031633146109945760405162461bcd60e51b815260206004820152602860248201527f536f75726365206d75737420626520746865206f7261636c65206f662074686560448201527f207265717565737400000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b600081815260056020526040808220805473ffffffffffffffffffffffffffffffffffffffff191690555182917f7cc135e0cebb02c3480ae5d74d377283180a2601f8f644edf7987b009316c63a91a260005b82518110156108fb576009838281518110610a0457610a046158bd565b60209081029190910181015182546001810184556000938452928290208151610a36949190910192919091019061502c565b5080610a41816158d3565b9150506109e7565b601b546001600160a01b03163314610a6057600080fd5b601c55565b601b546001600160a01b03163314610a7c57600080fd5b6000610a86614389565b905060008160011415610b60575060005b601054610aa59060016158a5565b811015610b38576000600d8281548110610ac157610ac16158bd565b60009182526020822001546040805163294acf3f60e01b815290516001600160a01b039092169350839263294acf3f9260048084019382900301818387803b158015610b0c57600080fd5b505af1158015610b20573d6000803e3d6000fd5b50505050508080610b30906158d3565b915050610a97565b610b44600f60006150b0565b610b50600e60006150ce565b610b5c600960006150ef565b5050565b8160021415610c26575060005b601454610b7b9060016158a5565b811015610c0e57600060118281548110610b9757610b976158bd565b60009182526020822001546040805163294acf3f60e01b815290516001600160a01b039092169350839263294acf3f9260048084019382900301818387803b158015610be257600080fd5b505af1158015610bf6573d6000803e3d6000fd5b50505050508080610c06906158d3565b915050610b6d565b610c1a601360006150b0565b610b50601260006150ce565b8160031415610b5c575060005b601854610c419060016158a5565b811015610cd457600060158281548110610c5d57610c5d6158bd565b60009182526020822001546040805163294acf3f60e01b815290516001600160a01b039092169350839263294acf3f9260048084019382900301818387803b158015610ca857600080fd5b505af1158015610cbc573d6000803e3d6000fd5b50505050508080610ccc906158d3565b915050610c33565b610ce0601760006150b0565b610b50601660006150ce565b600e8181548110610cfc57600080fd5b600091825260209091206004909102018054600182015460028301546003909301549193509163ffffffff811691640100000000820461ffff16916601000000000000900460ff169086565b601b546001600160a01b03163314610d5f57600080fd5b601081511115610d6e57600080fd5b60195460ff161580610d885750601954610100900460ff16155b80610d9c575060195462010000900460ff16155b610da557600080fd5b60195460009060ff16610fbd576000601055600d5460009060041115610dcc576000610dcf565b60045b60ff169050600091505b80821015610e98576000600d8381548110610df657610df66158bd565b600091825260209091200154604051631ac144f760e11b81526001600160a01b039091169150819063358289ee90610e329087906004016158ee565b600060405180830381600087803b158015610e4c57600080fd5b505af1158015610e60573d6000803e3d6000fd5b50505050600182610e719190615966565b8314610e8557610e85601080546001019055565b5081610e90816158d3565b925050610dd9565b600091505b8251821015610f9f57600f838381518110610eba57610eba6158bd565b60209081029190910181015160a00151825460018101845560009384529190922001558251600e90849084908110610ef457610ef46158bd565b6020908102919091018101518254600181810185556000948552938390208251600490920201908155918101519282019290925560408201516002820180546060850151608086015160ff1666010000000000000266ff0000000000001961ffff9092166401000000000265ffffffffffff1990931663ffffffff90951694909417919091171691909117905560a09091015160039091015581610f97816158d3565b925050610e9d565b6019805460ff19166001908117909155610fb8906143d3565b505050565b601954610100900460ff166111d257600060145560115460009060041115610fe6576000610fe9565b60035b60ff169050600091505b808210156110b257600060118381548110611010576110106158bd565b600091825260209091200154604051631ac144f760e11b81526001600160a01b039091169150819063358289ee9061104c9087906004016158ee565b600060405180830381600087803b15801561106657600080fd5b505af115801561107a573d6000803e3d6000fd5b5050505060018261108b9190615966565b831461109f5761109f601480546001019055565b50816110aa816158d3565b925050610ff3565b600091505b82518210156111b95760138383815181106110d4576110d46158bd565b60209081029190910181015160a0015182546001810184556000938452919092200155825160129084908490811061110e5761110e6158bd565b6020908102919091018101518254600181810185556000948552938390208251600490920201908155918101519282019290925560408201516002820180546060850151608086015160ff1666010000000000000266ff0000000000001961ffff9092166401000000000265ffffffffffff1990931663ffffffff90951694909417919091171691909117905560a090910151600390910155816111b1816158d3565b9250506110b7565b6019805461ff001916610100179055610fb860026143d3565b60195462010000900460ff16610b5c576000601855601554600090600411156111fc5760006111ff565b60035b60ff169050600091505b808210156112c857600060158381548110611226576112266158bd565b600091825260209091200154604051631ac144f760e11b81526001600160a01b039091169150819063358289ee906112629087906004016158ee565b600060405180830381600087803b15801561127c57600080fd5b505af1158015611290573d6000803e3d6000fd5b505050506001826112a19190615966565b83146112b5576112b5601880546001019055565b50816112c0816158d3565b925050611209565b600091505b82518210156113cf5760178383815181106112ea576112ea6158bd565b60209081029190910181015160a00151825460018101845560009384529190922001558251601690849084908110611324576113246158bd565b6020908102919091018101518254600181810185556000948552938390208251600490920201908155918101519282019290925560408201516002820180546060850151608086015160ff1666010000000000000266ff0000000000001961ffff9092166401000000000265ffffffffffff1990931663ffffffff90951694909417919091171691909117905560a090910151600390910155816113c7816158d3565b9250506112cd565b6019805462ff0000191662010000179055610fb860036143d3565b60408051600380825260808201909252606091600091906020820184803683370190505090506000600d61141d60105490565b8154811061142d5761142d6158bd565b6000918252602091829020015460408051630a00d38360e01b815290516001600160a01b0390921693508392630a00d383926004808401938290030181865afa15801561147e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114a2919061597d565b80156115705750806001600160a01b03166306d4591c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061150b919061599f565b816001600160a01b031663539ba05a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611549573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156d919061599f565b10155b801561158b57506010546115859060026158a5565b600d5410155b156115b6576001826000815181106115a5576115a56158bd565b911515602092830291909101909101525b600060116115c360145490565b815481106115d3576115d36158bd565b6000918252602091829020015460408051630a00d38360e01b815290516001600160a01b0390921693508392630a00d383926004808401938290030181865afa158015611624573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611648919061597d565b80156117165750806001600160a01b03166306d4591c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561168d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b1919061599f565b816001600160a01b031663539ba05a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116ef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611713919061599f565b10155b8015611731575060145461172b9060026158a5565b60115410155b1561175c5760018360018151811061174b5761174b6158bd565b911515602092830291909101909101525b6000601561176960185490565b81548110611779576117796158bd565b6000918252602091829020015460408051630a00d38360e01b815290516001600160a01b0390921693508392630a00d383926004808401938290030181865afa1580156117ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ee919061597d565b80156118bc5750806001600160a01b03166306d4591c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611833573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611857919061599f565b816001600160a01b031663539ba05a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611895573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b9919061599f565b10155b80156118d757506018546118d19060026158a5565b60155410155b15611902576001846002815181106118f1576118f16158bd565b911515602092830291909101909101525b50919392505050565b601b546001600160a01b0316331461192257600080fd5b601a55565b60128181548110610cfc57600080fd5b6011818154811061058957600080fd5b6017818154811061195757600080fd5b600091825260209091200154905081565b60606000601a54600361197b91906159b8565b67ffffffffffffffff81111561199357611993615226565b6040519080825280602002602001820160405280156119bc578160200160208202803683370190505b5090506000805b600d54811015611add576000600d82815481106119e2576119e26158bd565b600091825260208220015460405163596ffb1960e11b81526001600160a01b0389811660048301529091169250829063b2dff63290602401602060405180830381865afa158015611a37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a5b919061599f565b1115611aca57600d8281548110611a7457611a746158bd565b9060005260206000200160009054906101000a90046001600160a01b0316848481518110611aa457611aa46158bd565b6001600160a01b039092166020928302919091019091015282611ac6816158d3565b9350505b5080611ad5816158d3565b9150506119c3565b5060005b601154811015611bfb57600060118281548110611b0057611b006158bd565b600091825260208220015460405163596ffb1960e11b81526001600160a01b0389811660048301529091169250829063b2dff63290602401602060405180830381865afa158015611b55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b79919061599f565b1115611be85760118281548110611b9257611b926158bd565b9060005260206000200160009054906101000a90046001600160a01b0316848481518110611bc257611bc26158bd565b6001600160a01b039092166020928302919091019091015282611be4816158d3565b9350505b5080611bf3816158d3565b915050611ae1565b5060005b601554811015611d1957600060158281548110611c1e57611c1e6158bd565b600091825260208220015460405163596ffb1960e11b81526001600160a01b0389811660048301529091169250829063b2dff63290602401602060405180830381865afa158015611c73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c97919061599f565b1115611d065760158281548110611cb057611cb06158bd565b9060005260206000200160009054906101000a90046001600160a01b0316848481518110611ce057611ce06158bd565b6001600160a01b039092166020928302919091019091015282611d02816158d3565b9350505b5080611d11816158d3565b915050611bff565b50909392505050565b601b546001600160a01b03163314611d3957600080fd5b6003805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03831617905550565b50565b6001600160a01b0381166000908152600760209081526040808320805482518185028101850190935280835260609493830182828015611dc657602002820191906000526020600020905b815481526020019060010190808311611db2575b505050505090506000815167ffffffffffffffff811115611de957611de9615226565b604051908082528060200260200182016040528015611e5057816020015b6040805160e08101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c08201528252600019909201910181611e075790505b50905060005b8251811015611f235760066000848381518110611e7557611e756158bd565b6020908102919091018101518252818101929092526040908101600020815160e081018352815481526001820154938101939093526002810154918301919091526003015460ff80821660608401526101008204811660808401526201000082041660a0830152630100000090046001600160a01b031660c08201528251839083908110611f0557611f056158bd565b60200260200101819052508080611f1b906158d3565b915050611e56565b509392505050565b601b546001600160a01b03163314611f4257600080fd5b6000611f566002546001600160a01b031690565b601b546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529192506001600160a01b038084169263a9059cbb92919091169083906370a0823190602401602060405180830381865afa158015611fc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611feb919061599f565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af115801561204e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612072919061597d565b611d645760405162461bcd60e51b815260206004820152601260248201527f556e61626c6520746f207472616e736665720000000000000000000000000000604482015260640161098b565b600760205281600052604060002081815481106120da57600080fd5b90600052602060002001600091509150505481565b606060006120fc60105490565b6121079060016158a5565b905061211260145490565b61211c90826158a5565b6121279060016158a5565b905061213260185490565b61213c90826158a5565b6121479060016158a5565b905060008167ffffffffffffffff81111561216457612164615226565b60405190808252806020026020018201604052801561218d578160200160208202803683370190505b50905060005b6010546121a19060016158a5565b81101561221557600d81815481106121bb576121bb6158bd565b9060005260206000200160009054906101000a90046001600160a01b03168282815181106121eb576121eb6158bd565b6001600160a01b03909216602092830291909101909101528061220d816158d3565b915050612193565b5060005b6014546122279060016158a5565b8110156122af5760118181548110612241576122416158bd565b6000918252602090912001546001600160a01b03168261226060105490565b61226a90846158a5565b6122759060016158a5565b81518110612285576122856158bd565b6001600160a01b0390921660209283029190910190910152806122a7816158d3565b915050612219565b5060005b6018546122c19060016158a5565b81101561236157601581815481106122db576122db6158bd565b6000918252602090912001546001600160a01b0316826122fa60145490565b60105461230790856158a5565b6123129060016158a5565b61231c91906158a5565b6123279060016158a5565b81518110612337576123376158bd565b6001600160a01b039092166020928302919091019091015280612359816158d3565b9150506122b3565b5092915050565b604080516003808252608082019092526060916000919060208201848036833701905050601a54600d549192501115612542576000600d6123a860105490565b815481106123b8576123b86158bd565b6000918252602091829020015460408051630a00d38360e01b815290516001600160a01b0390921693508392630a00d383926004808401938290030181865afa158015612409573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061242d919061597d565b80156124fb5750806001600160a01b03166306d4591c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612472573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612496919061599f565b816001600160a01b031663539ba05a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124f8919061599f565b10155b801561251557506010546125109060026158a5565b600d54105b156125405760018260008151811061252f5761252f6158bd565b911515602092830291909101909101525b505b601a5460115410156126f5576000601161255b60145490565b8154811061256b5761256b6158bd565b6000918252602091829020015460408051630a00d38360e01b815290516001600160a01b0390921693508392630a00d383926004808401938290030181865afa1580156125bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125e0919061597d565b80156126ae5750806001600160a01b03166306d4591c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612625573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612649919061599f565b816001600160a01b031663539ba05a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612687573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126ab919061599f565b10155b80156126c857506014546126c39060026158a5565b601154105b156126f3576001826001815181106126e2576126e26158bd565b911515602092830291909101909101525b505b601a5460155410156128a8576000601561270e60185490565b8154811061271e5761271e6158bd565b6000918252602091829020015460408051630a00d38360e01b815290516001600160a01b0390921693508392630a00d383926004808401938290030181865afa15801561276f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612793919061597d565b80156128615750806001600160a01b03166306d4591c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156127d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127fc919061599f565b816001600160a01b031663539ba05a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561283a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061285e919061599f565b10155b801561287b57506018546128769060026158a5565b601554105b156128a657600182600281518110612895576128956158bd565b911515602092830291909101909101525b505b919050565b60006128c16003546001600160a01b031690565b905090565b60168181548110610cfc57600080fd5b60606000601a5460036128e991906159b8565b67ffffffffffffffff81111561290157612901615226565b60405190808252806020026020018201604052801561292a578160200160208202803683370190505b5090506000805b600d54811015612a4b576000600d8281548110612950576129506158bd565b60009182526020909120015460405163a7dc5fb960e01b81526001600160a01b0388811660048301529091169150819063a7dc5fb990602401602060405180830381865afa1580156129a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ca919061597d565b15612a3857600d82815481106129e2576129e26158bd565b9060005260206000200160009054906101000a90046001600160a01b0316848481518110612a1257612a126158bd565b6001600160a01b039092166020928302919091019091015282612a34816158d3565b9350505b5080612a43816158d3565b915050612931565b5060005b601154811015612b6957600060118281548110612a6e57612a6e6158bd565b60009182526020909120015460405163a7dc5fb960e01b81526001600160a01b0388811660048301529091169150819063a7dc5fb990602401602060405180830381865afa158015612ac4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ae8919061597d565b15612b565760118281548110612b0057612b006158bd565b9060005260206000200160009054906101000a90046001600160a01b0316848481518110612b3057612b306158bd565b6001600160a01b039092166020928302919091019091015282612b52816158d3565b9350505b5080612b61816158d3565b915050612a4f565b5060005b601554811015611d1957600060158281548110612b8c57612b8c6158bd565b60009182526020909120015460405163a7dc5fb960e01b81526001600160a01b0388811660048301529091169150819063a7dc5fb990602401602060405180830381865afa158015612be2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c06919061597d565b15612c745760158281548110612c1e57612c1e6158bd565b9060005260206000200160009054906101000a90046001600160a01b0316848481518110612c4e57612c4e6158bd565b6001600160a01b039092166020928302919091019091015282612c70816158d3565b9350505b5080612c7f816158d3565b915050612b6d565b600d818154811061058957600080fd5b6013818154811061195757600080fd5b600f818154811061195757600080fd5b601b546001600160a01b03163314612cce57600080fd5b60008160ff1660011415612dd4575060005b6004811015610b5c576000600d8281548110612cfe57612cfe6158bd565b600091825260209091200154604051631ac144f760e11b81526001600160a01b039091169150819063358289ee90612d3b90600e906004016159d7565b600060405180830381600087803b158015612d5557600080fd5b505af1158015612d69573d6000803e3d6000fd5b50505050806001600160a01b0316636e4d243a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612da857600080fd5b505af1158015612dbc573d6000803e3d6000fd5b50505050508080612dcc906158d3565b915050612ce0565b8160ff1660021415612ed8575060005b6004811015610b5c57600060118281548110612e0257612e026158bd565b600091825260209091200154604051631ac144f760e11b81526001600160a01b039091169150819063358289ee90612e3f906012906004016159d7565b600060405180830381600087803b158015612e5957600080fd5b505af1158015612e6d573d6000803e3d6000fd5b50505050806001600160a01b0316636e4d243a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612eac57600080fd5b505af1158015612ec0573d6000803e3d6000fd5b50505050508080612ed0906158d3565b915050612de4565b8160ff1660031415610b5c575060005b6004811015610b5c57612eff601880546001019055565b600060158281548110612f1457612f146158bd565b600091825260209091200154604051631ac144f760e11b81526001600160a01b039091169150819063358289ee90612f51906016906004016159d7565b600060405180830381600087803b158015612f6b57600080fd5b505af1158015612f7f573d6000803e3d6000fd5b50505050806001600160a01b0316636e4d243a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612fbe57600080fd5b505af1158015612fd2573d6000803e3d6000fd5b50505050508080612fe2906158d3565b915050612ee8565b601b546001600160a01b0316331461300157600080fd5b600061300b6143ff565b905060008080600019600185141561311657600f549350600092505b600e54831015613111578163ffffffff16600e848154811061304b5761304b6158bd565b600091825260209091206002600490920201015463ffffffff16111561309b57600e838154811061307e5761307e6158bd565b600091825260209091206002600490920201015463ffffffff1691505b80600e84815481106130af576130af6158bd565b600091825260209091206002600490920201015463ffffffff1610156130ff57600e83815481106130e2576130e26158bd565b600091825260209091206002600490920201015463ffffffff1690505b82613109816158d3565b935050613027565b613310565b8460021415613213576013549350600092505b601254831015613111578163ffffffff166012848154811061314d5761314d6158bd565b600091825260209091206002600490920201015463ffffffff16111561319d5760128381548110613180576131806158bd565b600091825260209091206002600490920201015463ffffffff1691505b80601284815481106131b1576131b16158bd565b600091825260209091206002600490920201015463ffffffff16101561320157601283815481106131e4576131e46158bd565b600091825260209091206002600490920201015463ffffffff1690505b8261320b816158d3565b935050613129565b8460031415613310576017549350600092505b601654831015613310578163ffffffff166016848154811061324a5761324a6158bd565b600091825260209091206002600490920201015463ffffffff16111561329a576016838154811061327d5761327d6158bd565b600091825260209091206002600490920201015463ffffffff1691505b80601684815481106132ae576132ae6158bd565b600091825260209091206002600490920201015463ffffffff1610156132fe57601683815481106132e1576132e16158bd565b600091825260209091206002600490920201015463ffffffff1690505b82613308816158d3565b935050613226565b600061331e83617080615a54565b63ffffffff169050804211156133455767016345785d8a000061334384828989614428565b505b8163ffffffff168363ffffffff161115613389576146506133668385615a7c565b63ffffffff1611156133895767016345785d8a000061338783828989614428565b505b505050505050565b601b546001600160a01b031633146133a857600080fd5b81516004146133b657600080fd5b8060ff16600114156135165760005b6004811015610fb857600d8382815181106133e2576133e26158bd565b602090810291909101810151825460018101845560009384529190922001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03909216919091179055600e5415613504576000838281518110613446576134466158bd565b60200260200101519050806001600160a01b031663358289ee600e6040518263ffffffff1660e01b815260040161347d91906159d7565b600060405180830381600087803b15801561349757600080fd5b505af11580156134ab573d6000803e3d6000fd5b50505050806001600160a01b0316636e4d243a6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156134ea57600080fd5b505af11580156134fe573d6000803e3d6000fd5b50505050505b8061350e816158d3565b9150506133c5565b8060ff16600214156136765760005b6004811015610fb8576011838281518110613542576135426158bd565b602090810291909101810151825460018101845560009384529190922001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03909216919091179055601254156136645760008382815181106135a6576135a66158bd565b60200260200101519050806001600160a01b031663358289ee60126040518263ffffffff1660e01b81526004016135dd91906159d7565b600060405180830381600087803b1580156135f757600080fd5b505af115801561360b573d6000803e3d6000fd5b50505050806001600160a01b0316636e4d243a6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561364a57600080fd5b505af115801561365e573d6000803e3d6000fd5b50505050505b8061366e816158d3565b915050613525565b8060ff1660031415610b5c5760005b6004811015610fb85760158382815181106136a2576136a26158bd565b602090810291909101810151825460018101845560009384529190922001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03909216919091179055601654156137c4576000838281518110613706576137066158bd565b60200260200101519050806001600160a01b031663358289ee60166040518263ffffffff1660e01b815260040161373d91906159d7565b600060405180830381600087803b15801561375757600080fd5b505af115801561376b573d6000803e3d6000fd5b50505050806001600160a01b0316636e4d243a6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156137aa57600080fd5b505af11580156137be573d6000803e3d6000fd5b50505050505b806137ce816158d3565b915050613685565b6040805160208082528183019092526060916000919060208201818036833701905050905060005b602081101561236157838160208110613819576138196158bd565b1a60f81b82828151811061382f5761382f6158bd565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535080613868816158d3565b9150506137fe565b600080600061387d6143ff565b60095490915061388c57600080fd5b8060011415613a2857600092505b600954831015613a23576000600984815481106138b9576138b96158bd565b9060005260206000200180546138ce9061585a565b80601f01602080910402602001604051908101604052809291908181526020018280546138fa9061585a565b80156139475780601f1061391c57610100808354040283529160200191613947565b820191906000526020600020905b81548152906001019060200180831161392a57829003601f168201915b505050505080602001905181019061395f9190615aa1565b9050600092505b600e54831015613a10578051600e805485908110613986576139866158bd565b90600052602060002090600402016003015414156139fe57806040015160ff16816020015160ff16116139ba5760026139bd565b60015b600e84815481106139d0576139d06158bd565b906000526020600020906004020160020160066101000a81548160ff021916908360ff160217905550613a10565b82613a08816158d3565b935050613966565b5082613a1b816158d3565b93505061389a565b613d56565b8060021415613bbf57600092505b600954831015613a2357600060098481548110613a5557613a556158bd565b906000526020600020018054613a6a9061585a565b80601f0160208091040260200160405190810160405280929190818152602001828054613a969061585a565b8015613ae35780601f10613ab857610100808354040283529160200191613ae3565b820191906000526020600020905b815481529060010190602001808311613ac657829003601f168201915b5050505050806020019051810190613afb9190615aa1565b9050600092505b601254831015613bac5780516012805485908110613b2257613b226158bd565b9060005260206000209060040201600301541415613b9a57806040015160ff16816020015160ff1611613b56576002613b59565b60015b60128481548110613b6c57613b6c6158bd565b906000526020600020906004020160020160066101000a81548160ff021916908360ff160217905550613bac565b82613ba4816158d3565b935050613b02565b5082613bb7816158d3565b935050613a36565b8060031415613d5657600092505b600954831015613d5657600060098481548110613bec57613bec6158bd565b906000526020600020018054613c019061585a565b80601f0160208091040260200160405190810160405280929190818152602001828054613c2d9061585a565b8015613c7a5780601f10613c4f57610100808354040283529160200191613c7a565b820191906000526020600020905b815481529060010190602001808311613c5d57829003601f168201915b5050505050806020019051810190613c929190615aa1565b9050600092505b601654831015613d435780516016805485908110613cb957613cb96158bd565b9060005260206000209060040201600301541415613d3157806040015160ff16816020015160ff1611613ced576002613cf0565b60015b60168481548110613d0357613d036158bd565b906000526020600020906004020160020160066101000a81548160ff021916908360ff160217905550613d43565b82613d3b816158d3565b935050613c99565b5082613d4e816158d3565b935050613bcd565b8060011415613dc557600092505b600e54831015613dc0576000600e8481548110613d8357613d836158bd565b60009182526020909120600490910201600201546601000000000000900460ff1611613dae57600080fd5b82613db8816158d3565b935050613d64565b613e90565b8060021415613e2f57600092505b601254831015613dc057600060128481548110613df257613df26158bd565b60009182526020909120600490910201600201546601000000000000900460ff1611613e1d57600080fd5b82613e27816158d3565b935050613dd3565b600092505b601654831015613e9057600060168481548110613e5357613e536158bd565b60009182526020909120600490910201600201546601000000000000900460ff1611613e7e57600080fd5b82613e88816158d3565b935050613e34565b613e98614389565b9050806001141561404357600f5460009067ffffffffffffffff811115613ec157613ec1615226565b604051908082528060200260200182016040528015613eea578160200160208202803683370190505b509050600092505b600e54831015613f6457600e8381548110613f0f57613f0f6158bd565b906000526020600020906004020160020160069054906101000a900460ff16818481518110613f4057613f406158bd565b60ff9092166020928302919091019091015282613f5c816158d3565b935050613ef2565b600093505b601054613f779060016158a5565b841015614015576000600d8581548110613f9357613f936158bd565b6000918252602090912001546040516320bd0e3b60e11b81526001600160a01b039091169150819063417a1c7690613fcf908590600401615b1d565b600060405180830381600087803b158015613fe957600080fd5b505af1158015613ffd573d6000803e3d6000fd5b5050505050838061400d906158d3565b945050613f69565b6019805460ff1916905561402b600f60006150b0565b614037600e60006150ce565b6108fb600960006150ef565b80600214156141e15760135460009067ffffffffffffffff81111561406a5761406a615226565b604051908082528060200260200182016040528015614093578160200160208202803683370190505b509050600092505b60125483101561410d57601283815481106140b8576140b86158bd565b906000526020600020906004020160020160069054906101000a900460ff168184815181106140e9576140e96158bd565b60ff9092166020928302919091019091015282614105816158d3565b93505061409b565b600093505b6014546141209060016158a5565b8410156141be5760006011858154811061413c5761413c6158bd565b6000918252602090912001546040516320bd0e3b60e11b81526001600160a01b039091169150819063417a1c7690614178908590600401615b1d565b600060405180830381600087803b15801561419257600080fd5b505af11580156141a6573d6000803e3d6000fd5b505050505083806141b6906158d3565b945050614112565b6019805461ff00191690556141d5601360006150b0565b614037601260006150ce565b8060031415610fb85760175460009067ffffffffffffffff81111561420857614208615226565b604051908082528060200260200182016040528015614231578160200160208202803683370190505b509050600092505b6016548310156142ab5760168381548110614256576142566158bd565b906000526020600020906004020160020160069054906101000a900460ff16818481518110614287576142876158bd565b60ff90921660209283029190910190910152826142a3816158d3565b935050614239565b600093505b6018546142be9060016158a5565b84101561435c576000601585815481106142da576142da6158bd565b6000918252602090912001546040516320bd0e3b60e11b81526001600160a01b039091169150819063417a1c7690614316908590600401615b1d565b600060405180830381600087803b15801561433057600080fd5b505af1158015614344573d6000803e3d6000fd5b50505050508380614354906158d3565b9450506142b0565b6019805462ff000019169055614374601760006150b0565b614037601660006150ce565b80546001019055565b6000600b54600c54101561439c57600080fd5b50600b80546000908152600a602052604081208054908290558254909260019290916143c99084906158a5565b9250508190555090565b6001600c60008282546143e691906158a5565b9091555050600c546000908152600a6020526040902055565b6000600b54600c54101561441257600080fd5b50600b546000908152600a602052604090205490565b600061443e601c5430631549b40b60e01b614725565b90506000808367ffffffffffffffff81111561445c5761445c615226565b60405190808252806020026020018201604052801561448f57816020015b606081526020019060019003908161447a5790505b509050846001141561450c57600091505b600e54821015614507576144d7600e83815481106144c0576144c06158bd565b9060005260206000209060040201600301546137d6565b8183815181106144e9576144e96158bd565b602002602001018190525081806144ff906158d3565b9250506144a0565b6145c8565b846002141561456a57600091505b6012548210156145075761453a601283815481106144c0576144c06158bd565b81838151811061454c5761454c6158bd565b60200260200101819052508180614562906158d3565b92505061451a565b84600314156145c857600091505b6016548210156145c857614598601683815481106144c0576144c06158bd565b8183815181106145aa576145aa6158bd565b602002602001018190525081806145c0906158d3565b925050614578565b60408051808201909152600781527f73706f7274496400000000000000000000000000000000000000000000000000602082015261460990849060056147b6565b6146886040518060400160405280600681526020017f6d61726b657400000000000000000000000000000000000000000000000000008152506040518060400160405280600781526020017f7265736f6c766500000000000000000000000000000000000000000000000000815250856147d49092919063ffffffff16565b60408051808201909152600481527f646174650000000000000000000000000000000000000000000000000000000060208201526146d190849063ffffffff808b16906147b616565b60408051808201909152600781527f67616d65496473000000000000000000000000000000000000000000000000006020820152614711908490836147f2565b61471b838761486a565b5050505050505050565b6147636040805160a0810182526000808252602080830182905282840182905260608084018390528451808601909552845283015290608082015290565b6147a16040805160a0810182526000808252602080830182905282840182905260608084018390528451808601909552845283015290608082015290565b6147ad8186868661488d565b95945050505050565b60808301516147c59083614921565b6080830151610fb89082614938565b60808301516147e39083614921565b6080830151610fb89082614921565b60808301516148019083614921565b61480e836080015161495e565b60005b815181101561485c5761484a82828151811061482f5761482f6158bd565b6020026020010151856080015161492190919063ffffffff16565b80614854816158d3565b915050614811565b50610fb88360800151614969565b600354600090614884906001600160a01b03168484614974565b90505b92915050565b6148cb6040805160a0810182526000808252602080830182905282840182905260608084018390528451808601909552845283015290608082015290565b6148db8560800151610100614a4d565b50508284526001600160a01b03821660208501527fffffffff0000000000000000000000000000000000000000000000000000000081166040850152835b949350505050565b61492e8260038351614ab2565b610fb88282614bc1565b67ffffffffffffffff81111561495257610b5c8282614be8565b610b5c82600083614ab2565b611d64816004614c1f565b611d64816007614c1f565b6004546000906149858160016158a5565b600455835160408086015160808701515191516000937f4042994600000000000000000000000000000000000000000000000000000000936149d69386938493923092918a91600191602401615b58565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050614a4386838684614c34565b9695505050505050565b604080518082019091526060815260006020820152614a6d602083615bd4565b15614a9557614a7d602083615bd4565b614a88906020615966565b614a9290836158a5565b91505b506020828101829052604080518085526000815290920101905290565b60178167ffffffffffffffff1611614ad7576108fb8360e0600585901b168317614de5565b60ff8167ffffffffffffffff1611614b1557614afe836018611fe0600586901b1617614de5565b506108fb8367ffffffffffffffff83166001614e0a565b61ffff8167ffffffffffffffff1611614b5457614b3d836019611fe0600586901b1617614de5565b506108fb8367ffffffffffffffff83166002614e0a565b63ffffffff8167ffffffffffffffff1611614b9557614b7e83601a611fe0600586901b1617614de5565b506108fb8367ffffffffffffffff83166004614e0a565b614baa83601b611fe0600586901b1617614de5565b506108fb8367ffffffffffffffff83166008614e0a565b60408051808201909152606081526000602082015261488483846000015151848551614e30565b614bf38260c2614de5565b50610b5c8282604051602001614c0b91815260200190565b604051602081830303815290604052614f1a565b610fb882601f611fe0600585901b1617614de5565b6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003060601b1660208201526034810184905260009060540160408051808303601f19018152828252805160209182012060008181526005909252918120805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038a1617905590925082917fb5e6e01e79f91267dc17b4e6314d5d4d03593d2ceee0fbb452b750bd70ea5af99190a26002546040517f4000aea00000000000000000000000000000000000000000000000000000000081526001600160a01b0390911690634000aea090614d3090889087908790600401615bf6565b6020604051808303816000875af1158015614d4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614d73919061597d565b6149195760405162461bcd60e51b815260206004820152602360248201527f756e61626c6520746f207472616e73666572416e6443616c6c20746f206f726160448201527f636c650000000000000000000000000000000000000000000000000000000000606482015260840161098b565b6040805180820190915260608152600060208201526148848384600001515184614f27565b604080518082019091526060815260006020820152614919848560000151518585614f83565b6040805180820190915260608152600060208201528251821115614e5357600080fd5b6020850151614e6283866158a5565b1115614e9557614e9585614e8587602001518786614e8091906158a5565b615004565b614e909060026159b8565b615015565b600080865180518760208301019350808887011115614eb45787860182525b505050602084015b60208410614ef45780518252614ed36020836158a5565b9150614ee06020826158a5565b9050614eed602085615966565b9350614ebc565b51815160001960208690036101000a019081169019919091161790525083949350505050565b61492e8260028351614ab2565b60408051808201909152606081526000602082015283602001518310614f5c57614f5c8485602001516002614e9091906159b8565b835180516020858301018481535080851415614f79576001810182525b5093949350505050565b6040805180820190915260608152600060208201526020850151614fa785846158a5565b1115614fbb57614fbb85614e8586856158a5565b60006001614fcb84610100615d02565b614fd59190615966565b9050855183868201018583198251161781525080518487011115614ff95783860181525b509495945050505050565b6000818311156128a6575081614887565b81516150218383614a4d565b506108fb8382614bc1565b8280546150389061585a565b90600052602060002090601f01602090048101928261505a57600085556150a0565b82601f1061507357805160ff19168380011785556150a0565b828001600101855582156150a0579182015b828111156150a0578251825591602001919060010190615085565b506150ac92915061510d565b5090565b5080546000825590600052602060002090810190611d64919061510d565b5080546000825560040290600052602060002090810190611d649190615122565b5080546000825590600052602060002090810190611d649190615156565b5b808211156150ac576000815560010161510e565b5b808211156150ac5760008082556001820181905560028201805466ffffffffffffff191690556003820155600401615123565b808211156150ac57600061516a8282615173565b50600101615156565b50805461517f9061585a565b6000825580601f1061518f575050565b601f016020900490600052602060002090810190611d64919061510d565b6000602082840312156151bf57600080fd5b5035919050565b6000815180845260005b818110156151ec576020818501810151868301820152016151d0565b818111156151fe576000602083870101525b50601f01601f19169290920160200192915050565b60208152600061488460208301846151c6565b634e487b7160e01b600052604160045260246000fd5b60405160e0810167ffffffffffffffff8111828210171561525f5761525f615226565b60405290565b60405160c0810167ffffffffffffffff8111828210171561525f5761525f615226565b604051601f8201601f1916810167ffffffffffffffff811182821017156152b1576152b1615226565b604052919050565b600067ffffffffffffffff8211156152d3576152d3615226565b5060051b60200190565b60ff81168114611d6457600080fd5b80356128a8816152dd565b80356001600160a01b03811681146128a857600080fd5b6000602080838503121561532157600080fd5b823567ffffffffffffffff81111561533857600080fd5b8301601f8101851361534957600080fd5b803561535c615357826152b9565b615288565b81815260e0918202830184019184820191908884111561537b57600080fd5b938501935b8385101561540f5780858a0312156153985760008081fd5b6153a061523c565b853581528686013587820152604080870135908201526060808701356153c5816152dd565b908201526080868101356153d8816152dd565b9082015260a0868101356153eb816152dd565b9082015260c06153fc8782016152f7565b9082015283529384019391850191615380565b50979650505050505050565b600080604080848603121561542f57600080fd5b8335925060208085013567ffffffffffffffff8082111561544f57600080fd5b8187019150601f888184011261546457600080fd5b8235615472615357826152b9565b81815260059190911b8401850190858101908b83111561549157600080fd5b8686015b8381101561551a578035868111156154ad5760008081fd5b8701603f81018e136154bf5760008081fd5b88810135878111156154d3576154d3615226565b6154e4818801601f19168b01615288565b8181528f8c8385010111156154f95760008081fd5b818c84018c83013760009181018b0191909152845250918701918701615495565b5080985050505050505050509250929050565b6000602080838503121561554057600080fd5b823567ffffffffffffffff81111561555757600080fd5b8301601f8101851361556857600080fd5b8035615576615357826152b9565b81815260c0918202830184019184820191908884111561559557600080fd5b938501935b8385101561540f5780858a0312156155b25760008081fd5b6155ba615265565b85358152868601358782015260408087013563ffffffff811681146155df5760008081fd5b9082015260608681013561ffff811681146155fa5760008081fd5b90820152608061560b8782016152ec565b9082015260a086810135908201528352938401939185019161559a565b6020808252825182820181905260009190848201906040850190845b81811015615662578351151583529284019291840191600101615644565b50909695505050505050565b60006020828403121561568057600080fd5b614884826152f7565b6020808252825182820181905260009190848201906040850190845b818110156156625783516001600160a01b0316835292840192918401916001016156a5565b602080825282518282018190526000919060409081850190868401855b82811015615755578151805185528681015187860152858101518686015260608082015160ff9081169187019190915260808083015182169087015260a0808301519091169086015260c0908101516001600160a01b03169085015260e090930192908501906001016156e7565b5091979650505050505050565b6000806040838503121561577557600080fd5b61577e836152f7565b946020939093013593505050565b60006020828403121561579e57600080fd5b81356157a9816152dd565b9392505050565b600080604083850312156157c357600080fd5b823567ffffffffffffffff8111156157da57600080fd5b8301601f810185136157eb57600080fd5b803560206157fb615357836152b9565b82815260059290921b8301810191818101908884111561581a57600080fd5b938201935b8385101561583f57615830856152f7565b8252938201939082019061581f565b955061584e90508682016152ec565b93505050509250929050565b600181811c9082168061586e57607f821691505b602082108114156128a657634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082198211156158b8576158b861588f565b500190565b634e487b7160e01b600052603260045260246000fd5b60006000198214156158e7576158e761588f565b5060010190565b602080825282518282018190526000919060409081850190868401855b828110156157555781518051855286810151878601528581015163ffffffff168686015260608082015161ffff169086015260808082015160ff169086015260a0908101519085015260c0909301929085019060010161590b565b6000828210156159785761597861588f565b500390565b60006020828403121561598f57600080fd5b815180151581146157a957600080fd5b6000602082840312156159b157600080fd5b5051919050565b60008160001904831182151516156159d2576159d261588f565b500290565b60006020808301818452808554808352604092508286019150866000528360002060005b82811015615755578154845260018083015487860152600283015463ffffffff81168787015280881c61ffff16606087015260301c60ff166080860152600383015460a086015260c090940193600490920191016159fb565b600063ffffffff808316818516808303821115615a7357615a7361588f565b01949350505050565b600063ffffffff83811690831681811015615a9957615a9961588f565b039392505050565b600060808284031215615ab357600080fd5b6040516080810181811067ffffffffffffffff82111715615ad657615ad6615226565b604052825181526020830151615aeb816152dd565b60208201526040830151615afe816152dd565b60408201526060830151615b11816152dd565b60608201529392505050565b6020808252825182820181905260009190848201906040850190845b8181101561566257835160ff1683529284019291840191600101615b39565b60006101006001600160a01b03808c1684528a60208501528960408501528089166060850152507fffffffff00000000000000000000000000000000000000000000000000000000871660808401528560a08401528460c08401528060e0840152615bc5818401856151c6565b9b9a5050505050505050505050565b600082615bf157634e487b7160e01b600052601260045260246000fd5b500690565b6001600160a01b03841681528260208201526060604082015260006147ad60608301846151c6565b600181815b80851115615c59578160001904821115615c3f57615c3f61588f565b80851615615c4c57918102915b93841c9390800290615c23565b509250929050565b600082615c7057506001614887565b81615c7d57506000614887565b8160018114615c935760028114615c9d57615cb9565b6001915050614887565b60ff841115615cae57615cae61588f565b50506001821b614887565b5060208310610133831016604e8410600b8410161715615cdc575081810a614887565b615ce68383615c1e565b8060001904821115615cfa57615cfa61588f565b029392505050565b60006148848383615c6156fea26469706673582212208d58dc2faf84cd27a2fe7148712755bddc9594708de15b9cade55ff3563f63f364736f6c634300080a0033000000000000000000000000b0897686c545045afc77cf20ec7a532e3120e0f10000000000000000000000005fa5556ca9b39886ed448a2ae2a8a4a1f2b3bbba3137386232353566653762613462633639363662396634363362323863653538

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

000000000000000000000000b0897686c545045afc77cf20ec7a532e3120e0f10000000000000000000000005fa5556ca9b39886ed448a2ae2a8a4a1f2b3bbba3137386232353566653762613462633639363662396634363362323863653538

-----Decoded View---------------
Arg [0] : _link (address): 0xb0897686c545045afc77cf20ec7a532e3120e0f1
Arg [1] : _oracle (address): 0x5fa5556ca9b39886ed448a2ae2a8a4a1f2b3bbba
Arg [2] : jobId (bytes32): 0x3137386232353566653762613462633639363662396634363362323863653538

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000b0897686c545045afc77cf20ec7a532e3120e0f1
Arg [1] : 0000000000000000000000005fa5556ca9b39886ed448a2ae2a8a4a1f2b3bbba
Arg [2] : 3137386232353566653762613462633639363662396634363362323863653538


Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.