ETH Price: $3,382.93 (+0.23%)

Token

(0x9d90308d16b94c38048c782bdd8104a964758a23)
 

Overview

Max Total Supply

8,610 ERC-721 TOKEN*

Holders

8,464

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Filtered by Token Holder
singaporepolytechnic.eth
Balance
0 ERC-721 TOKEN*
0xa85a4d93bdff07a25fd6d440b9fbb0c4d20ad88c
Loading...
Loading
Loading...
Loading
Loading...
Loading

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

Contract Source Code Verified (Exact Match)

Contract Name:
WTFNFT

Compiler Version
v0.8.11+commit.d7f03943

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity Multiple files format)

File 8 of 8: WTFNFT.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;

import "./Metadata.sol";

interface Receiver {
	function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data) external returns (bytes4);
}


contract WTFNFT {

	struct User {
		uint256 balance;
		mapping(uint256 => uint256) list;
		mapping(address => bool) approved;
		mapping(uint256 => uint256) indexOf;
		uint256 tokenIndex;
	}

	struct Token {
		address user;
		address owner;
		address approved;
		uint128 totalFees;
		uint128 failFees;
		uint128 totalGas;
		uint128 avgGwei;
		uint128 totalDonated;
		uint64 totalTxs;
		uint64 failTxs;
	}

	struct Info {
		uint256 totalSupply;
		mapping(uint256 => Token) list;
		mapping(address => User) users;
		Metadata metadata;
		address wtf;
		address owner;
	}
	Info private info;

	mapping(bytes4 => bool) public supportsInterface;

	event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
	event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
	event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
	event Mint(address indexed owner, uint256 indexed tokenId, uint256 totalFees, uint256 failFees, uint256 totalGas, uint256 avgGwei, uint256 totalDonated, uint256 totalTxs, uint256 failTxs);


	modifier _onlyOwner() {
		require(msg.sender == owner());
		_;
	}


	constructor() {
		info.metadata = new Metadata(this);
		info.wtf = msg.sender;
		info.owner = 0xdEE79eD62B42e30EA7EbB6f1b7A3f04143D18b7F;
		supportsInterface[0x01ffc9a7] = true; // ERC-165
		supportsInterface[0x80ac58cd] = true; // ERC-721
		supportsInterface[0x5b5e139f] = true; // Metadata
		supportsInterface[0x780e9d63] = true; // Enumerable
	}

	function setOwner(address _owner) external _onlyOwner {
		info.owner = _owner;
	}

	function setMetadata(Metadata _metadata) external _onlyOwner {
		info.metadata = _metadata;
	}

	
	function mint(address _receiver, uint256 _totalFees, uint256 _failFees, uint256 _totalGas, uint256 _avgGwei, uint256 _totalDonated, uint256 _totalTxs, uint256 _failTxs) public {
		require(msg.sender == wtfAddress());
		uint256 _tokenId = info.totalSupply++;
		info.users[_receiver].tokenIndex = totalSupply();
		Token storage _newToken = info.list[_tokenId];
		_newToken.user = _receiver;
		_newToken.owner = _receiver;
		_newToken.totalFees = uint128(_totalFees);
		_newToken.failFees = uint128(_failFees);
		_newToken.totalGas = uint128(_totalGas);
		_newToken.avgGwei = uint128(_avgGwei);
		_newToken.totalDonated = uint128(_totalDonated);
		_newToken.totalTxs = uint64(_totalTxs);
		_newToken.failTxs = uint64(_failTxs);
		uint256 _index = info.users[_receiver].balance++;
		info.users[_receiver].indexOf[_tokenId] = _index + 1;
		info.users[_receiver].list[_index] = _tokenId;
		emit Transfer(address(0x0), _receiver, _tokenId);
		emit Mint(_receiver, _tokenId, _totalFees, _failFees, _totalGas, _avgGwei, _totalDonated, _totalTxs, _failTxs);
	}
	
	function approve(address _approved, uint256 _tokenId) external {
		require(msg.sender == ownerOf(_tokenId));
		info.list[_tokenId].approved = _approved;
		emit Approval(msg.sender, _approved, _tokenId);
	}

	function setApprovalForAll(address _operator, bool _approved) external {
		info.users[msg.sender].approved[_operator] = _approved;
		emit ApprovalForAll(msg.sender, _operator, _approved);
	}

	function transferFrom(address _from, address _to, uint256 _tokenId) external {
		_transfer(_from, _to, _tokenId);
	}

	function safeTransferFrom(address _from, address _to, uint256 _tokenId) external {
		safeTransferFrom(_from, _to, _tokenId, "");
	}

	function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes memory _data) public {
		_transfer(_from, _to, _tokenId);
		uint32 _size;
		assembly {
			_size := extcodesize(_to)
		}
		if (_size > 0) {
			require(Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data) == 0x150b7a02);
		}
	}


	function name() external view returns (string memory) {
		return info.metadata.name();
	}

	function symbol() external view returns (string memory) {
		return info.metadata.symbol();
	}

	function tokenURI(uint256 _tokenId) external view returns (string memory) {
		return info.metadata.tokenURI(_tokenId);
	}

	function metadataAddress() public view returns (address) {
		return address(info.metadata);
	}

	function wtfAddress() public view returns (address) {
		return info.wtf;
	}

	function owner() public view returns (address) {
		return info.owner;
	}

	function totalSupply() public view returns (uint256) {
		return info.totalSupply;
	}

	function balanceOf(address _owner) public view returns (uint256) {
		return info.users[_owner].balance;
	}

	function ownerOf(uint256 _tokenId) public view returns (address) {
		require(_tokenId < totalSupply());
		return info.list[_tokenId].owner;
	}

	function getUser(uint256 _tokenId) public view returns (address) {
		require(_tokenId < totalSupply());
		return info.list[_tokenId].user;
	}

	function getApproved(uint256 _tokenId) public view returns (address) {
		require(_tokenId < totalSupply());
		return info.list[_tokenId].approved;
	}

	function getTotalFees(uint256 _tokenId) public view returns (uint256) {
		require(_tokenId < totalSupply());
		return info.list[_tokenId].totalFees;
	}

	function getFailFees(uint256 _tokenId) public view returns (uint256) {
		require(_tokenId < totalSupply());
		return info.list[_tokenId].failFees;
	}

	function getTotalGas(uint256 _tokenId) public view returns (uint256) {
		require(_tokenId < totalSupply());
		return info.list[_tokenId].totalGas;
	}

	function getAvgGwei(uint256 _tokenId) public view returns (uint256) {
		require(_tokenId < totalSupply());
		return info.list[_tokenId].avgGwei;
	}

	function getTotalDonated(uint256 _tokenId) public view returns (uint256) {
		require(_tokenId < totalSupply());
		return info.list[_tokenId].totalDonated;
	}

	function getTotalTxs(uint256 _tokenId) public view returns (uint256) {
		require(_tokenId < totalSupply());
		return info.list[_tokenId].totalTxs;
	}

	function getFailTxs(uint256 _tokenId) public view returns (uint256) {
		require(_tokenId < totalSupply());
		return info.list[_tokenId].failTxs;
	}

	function isApprovedForAll(address _owner, address _operator) public view returns (bool) {
		return info.users[_owner].approved[_operator];
	}

	function tokenIdOf(address _user) public view returns (uint256) {
		uint256 _index = info.users[_user].tokenIndex;
		require(_index > 0);
		return _index - 1;
	}

	function tokenByIndex(uint256 _index) public view returns (uint256) {
		require(_index < totalSupply());
		return _index;
	}

	function tokenOfOwnerByIndex(address _owner, uint256 _index) public view returns (uint256) {
		require(_index < balanceOf(_owner));
		return info.users[_owner].list[_index];
	}

	function getTokenCompressedInfo(uint256 _tokenId) public view returns (uint256[7] memory compressedInfo) {
		compressedInfo[0] = getTotalFees(_tokenId);
		compressedInfo[1] = getFailFees(_tokenId);
		compressedInfo[2] = getTotalGas(_tokenId);
		compressedInfo[3] = getAvgGwei(_tokenId);
		compressedInfo[4] = getTotalDonated(_tokenId);
		compressedInfo[5] = getTotalTxs(_tokenId);
		compressedInfo[6] = getFailTxs(_tokenId);
	}

	function getToken(uint256 _tokenId) public view returns (address tokenOwner, address approved, address user, uint256[7] memory compressedInfo) {
		return (ownerOf(_tokenId), getApproved(_tokenId), getUser(_tokenId), getTokenCompressedInfo(_tokenId));
	}

	function getTokens(uint256[] memory _tokenIds) public view returns (address[] memory owners, address[] memory approveds, address[] memory users, uint256[7][] memory compressedInfos) {
		uint256 _length = _tokenIds.length;
		owners = new address[](_length);
		approveds = new address[](_length);
		users = new address[](_length);
		compressedInfos = new uint256[7][](_length);
		for (uint256 i = 0; i < _length; i++) {
			(owners[i], approveds[i], users[i], compressedInfos[i]) = getToken(_tokenIds[i]);
		}
	}

	function getTokensTable(uint256 _limit, uint256 _page, bool _isAsc) public view returns (uint256[] memory tokenIds, address[] memory owners, address[] memory approveds, address[] memory users, uint256[7][] memory compressedInfos, uint256 totalTokens, uint256 totalPages) {
		require(_limit > 0);
		totalTokens = totalSupply();

		if (totalTokens > 0) {
			totalPages = (totalTokens / _limit) + (totalTokens % _limit == 0 ? 0 : 1);
			require(_page < totalPages);

			uint256 _offset = _limit * _page;
			if (_page == totalPages - 1 && totalTokens % _limit != 0) {
				_limit = totalTokens % _limit;
			}

			tokenIds = new uint256[](_limit);
			for (uint256 i = 0; i < _limit; i++) {
				tokenIds[i] = tokenByIndex(_isAsc ? _offset + i : totalTokens - _offset - i - 1);
			}
		} else {
			totalPages = 0;
			tokenIds = new uint256[](0);
		}
		(owners, approveds, users, compressedInfos) = getTokens(tokenIds);
	}

	function getOwnerTokensTable(address _owner, uint256 _limit, uint256 _page, bool _isAsc) public view returns (uint256[] memory tokenIds, address[] memory approveds, address[] memory users, uint256[7][] memory compressedInfos, uint256 totalTokens, uint256 totalPages) {
		require(_limit > 0);
		totalTokens = balanceOf(_owner);

		if (totalTokens > 0) {
			totalPages = (totalTokens / _limit) + (totalTokens % _limit == 0 ? 0 : 1);
			require(_page < totalPages);

			uint256 _offset = _limit * _page;
			if (_page == totalPages - 1 && totalTokens % _limit != 0) {
				_limit = totalTokens % _limit;
			}

			tokenIds = new uint256[](_limit);
			for (uint256 i = 0; i < _limit; i++) {
				tokenIds[i] = tokenOfOwnerByIndex(_owner, _isAsc ? _offset + i : totalTokens - _offset - i - 1);
			}
		} else {
			totalPages = 0;
			tokenIds = new uint256[](0);
		}
		( , approveds, users, compressedInfos) = getTokens(tokenIds);
	}

	function allInfoFor(address _owner) external view returns (uint256 supply, uint256 ownerBalance) {
		return (totalSupply(), balanceOf(_owner));
	}

	
	function _transfer(address _from, address _to, uint256 _tokenId) internal {
		address _owner = ownerOf(_tokenId);
		address _approved = getApproved(_tokenId);
		require(_from == _owner);
		require(msg.sender == _owner || msg.sender == _approved || isApprovedForAll(_owner, msg.sender));

		info.list[_tokenId].owner = _to;
		if (_approved != address(0x0)) {
			info.list[_tokenId].approved = address(0x0);
			emit Approval(address(0x0), address(0x0), _tokenId);
		}

		uint256 _index = info.users[_from].indexOf[_tokenId] - 1;
		uint256 _moved = info.users[_from].list[info.users[_from].balance - 1];
		info.users[_from].list[_index] = _moved;
		info.users[_from].indexOf[_moved] = _index + 1;
		info.users[_from].balance--;
		delete info.users[_from].indexOf[_tokenId];
		uint256 _newIndex = info.users[_to].balance++;
		info.users[_to].indexOf[_tokenId] = _newIndex + 1;
		info.users[_to].list[_newIndex] = _tokenId;
		emit Transfer(_from, _to, _tokenId);
	}
}

File 1 of 8: ERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;

interface ERC20 {
	function allowance(address, address) external view returns (uint256);
	function balanceOf(address) external view returns (uint256);
	function transfer(address, uint256) external returns (bool);
	function transferFrom(address, address, uint256) external returns (bool);
}

File 2 of 8: Metadata.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;

import "./WTFNFT.sol";

interface PriceOracle {
	function getPrice() external view returns (uint256);
}


contract Metadata {
	
	string public name = "fees.wtf NFT";
	string public symbol = "fees.wtf";

	string constant private TABLE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

	WTFNFT public nft;
	PriceOracle public oracle;

	constructor(WTFNFT _nft) {
		nft = _nft;
		oracle = PriceOracle(0xe89b5B2770Aa1a6BcfAc6F3517510aB8e9146651);
	}

	function setPriceOracle(PriceOracle _oracle) external {
		require(msg.sender == nft.owner());
		oracle = _oracle;
	}


	function tokenURI(uint256 _tokenId) external view returns (string memory) {
		( , , address _user, uint256[7] memory _info) = nft.getToken(_tokenId);
		return rawTokenURI(_user, _info[0], _info[1], _info[2], _info[3], _info[4], _info[5], _info[6], oracle.getPrice());
	}

	function rawTokenURI(address _user, uint256 _totalFees, uint256 _failFees, uint256 _totalGas, uint256 _avgGwei, uint256 _totalDonated, uint256 _totalTxs, uint256 _failTxs, uint256 _price) public pure returns (string memory) {
		string memory _json = string(abi.encodePacked('{"name":"', _trimAddress(_user, 6), '","description":"[fees.wtf](https://fees.wtf) snapshot at block 13916450 for [', _address2str(_user), '](https://etherscan.io/address/', _address2str(_user), ')",'));
		_json = string(abi.encodePacked(_json, '"image":"data:image/svg+xml;base64,', _encode(bytes(getRawSVG(_totalFees, _failFees, _totalGas, _avgGwei, _totalDonated, _totalTxs, _failTxs, _price))), '","attributes":['));
		if (_totalFees > 0) {
			_json = string(abi.encodePacked(_json, '{"trait_type":"Total Fees","value":', _uint2str(_totalFees, 18, 5, false, true), '}'));
			_json = string(abi.encodePacked(_json, ',{"trait_type":"Fail Fees","value":', _uint2str(_failFees, 18, 5, false, true), '}'));
			_json = string(abi.encodePacked(_json, ',{"trait_type":"Total Gas","value":', _uint2str(_totalGas, 0, 0, false, false), '}'));
			_json = string(abi.encodePacked(_json, ',{"trait_type":"Average Gwei","value":', _uint2str(_avgGwei, 9, 5, false, true), '}'));
			_json = string(abi.encodePacked(_json, ',{"trait_type":"Total Transactions","value":', _uint2str(_totalTxs, 0, 0, false, false), '}'));
			_json = string(abi.encodePacked(_json, ',{"trait_type":"Failed Transactions","value":', _uint2str(_failTxs, 0, 0, false, false), '}'));
			_json = string(abi.encodePacked(_json, ',{"display_type":"number","trait_type":"Spender Level","value":', _uint2str(_logn(_totalFees / 1e13, 2), 0, 0, false, false), '}'));
			_json = string(abi.encodePacked(_json, ',{"display_type":"number","trait_type":"Oof Level","value":', _uint2str(_logn(_failFees / 1e13, 2), 0, 0, false, false), '}'));
		}
		if (_totalDonated > 0) {
			_json = string(abi.encodePacked(_json, _totalFees > 0 ? ',' : '', '{"display_type":"number","trait_type":"Donator Level","value":', _uint2str(_logn(_totalDonated / 1e14, 10) + 1, 0, 0, false, false), '}'));
		}
		_json = string(abi.encodePacked(_json, ']}'));
		return string(abi.encodePacked("data:application/json;base64,", _encode(bytes(_json))));
	}

	function getSVG(uint256 _tokenId) public view returns (string memory) {
		uint256[7] memory _info = nft.getTokenCompressedInfo(_tokenId);
		return getRawSVG(_info[0], _info[1], _info[2], _info[3], _info[4], _info[5], _info[6], oracle.getPrice());
	}

	function getRawSVG(uint256 _totalFees, uint256 _failFees, uint256 _totalGas, uint256 _avgGwei, uint256 _totalDonated, uint256 _totalTxs, uint256 _failTxs, uint256 _price) public pure returns (string memory svg) {
		svg = string(abi.encodePacked("<svg xmlns='http://www.w3.org/2000/svg' version='1.1' preserveAspectRatio='xMidYMid meet' viewBox='0 0 512 512' width='100%' height='100%'>"));
		svg = string(abi.encodePacked(svg, "<defs><style type='text/css'>text{text-anchor:middle;alignment-baseline:central;}tspan>tspan{fill:#03a9f4;font-weight:700;}</style></defs>"));
		svg = string(abi.encodePacked(svg, "<rect width='100%' height='100%' fill='#222222' />"));
		svg = string(abi.encodePacked(svg, "<text x='0' y='256' transform='translate(256)' fill='#f0f8ff' font-family='Arial,sans-serif' font-weight='600' font-size='30'>"));
		if (_totalFees > 0) {
			svg = string(abi.encodePacked(svg, unicode"<tspan x='0' dy='-183'>You spent <tspan>Ξ", _uint2str(_totalFees, 18, 5, true, false), "</tspan> on gas</tspan>"));
			svg = string(abi.encodePacked(svg, "<tspan x='0' dy='35'>before block 13916450.</tspan>"));
			svg = string(abi.encodePacked(svg, "<tspan x='0' dy='35'>Right now, that's</tspan>"));
			svg = string(abi.encodePacked(svg, "<tspan x='0' dy='35'><tspan>$", _uint2str(_totalFees * _price / 1e18, 18, 2, true, true), "</tspan>.</tspan>"));
			svg = string(abi.encodePacked(svg, "<tspan x='0' dy='70'>You used <tspan>", _uint2str(_totalGas, 0, 0, true, false), "</tspan></tspan>"));
			svg = string(abi.encodePacked(svg, "<tspan x='0' dy='35'>gas to send <tspan>", _uint2str(_totalTxs, 0, 0, true, false), "</tspan></tspan>"));
			svg = string(abi.encodePacked(svg, "<tspan x='0' dy='35'>transaction", _totalTxs == 1 ? "" : "s", ", with an average</tspan>"));
			svg = string(abi.encodePacked(svg, "<tspan x='0' dy='35'>price of <tspan>", _uint2str(_avgGwei, 9, 3, true, false), "</tspan> Gwei.</tspan>"));
			svg = string(abi.encodePacked(svg, "<tspan x='0' dy='70'><tspan>", _uint2str(_failTxs, 0, 0, true, false), "</tspan> of them failed,</tspan>"));
			svg = string(abi.encodePacked(svg, "<tspan x='0' dy='35'>costing you <tspan>", _failFees == 0 ? "nothing" : string(abi.encodePacked(unicode"Ξ", _uint2str(_failFees, 18, 5, true, false))), "</tspan>.</tspan></text>"));
		} else {
			svg = string(abi.encodePacked(svg, "<tspan x='0' dy='8'>Did not qualify.</tspan></text>"));
		}
		if (_totalDonated > 0) {
			for (uint256 i = 0; i <= _logn(_totalDonated / 1e14, 10); i++) {
				for (uint256 j = 0; j < 4; j++) {
					string memory _prefix = string(abi.encodePacked("<text x='", j < 2 ? "16" : "496", "' y='", j % 2 == 0 ? "18" : "498", "' font-size='10' transform='translate("));
					svg = string(abi.encodePacked(svg, _prefix, j < 2 ? "" : "-", _uint2str(16 * i, 0, 0, false, false), ")'>", unicode"❤️</text>"));
					if (i > 0) {
						svg = string(abi.encodePacked(svg, _prefix, "0,", j % 2 == 0 ? "" : "-", _uint2str(16 * i, 0, 0, false, false), ")'>", unicode"❤️</text>"));
					}
				}
			}
		}
		svg = string(abi.encodePacked(svg, "<text x='0' y='500' transform='translate(256)' fill='#f0f8ff' font-family='Arial,sans-serif' font-weight='600' font-size='10'><tspan>fees<tspan>.wtf</tspan></tspan></text></svg>"));
	}


	function _logn(uint256 _num, uint256 _n) internal pure returns (uint256) {
		require(_n > 0);
		uint256 _count = 0;
		while (_num > _n - 1) {
			_num /= _n;
			_count++;
		}
		return _count;
	}
	
	function _address2str(address _address) internal pure returns (string memory str) {
		str = "0x";
		for (uint256 i; i < 40; i++) {
			uint256 _hex = (uint160(_address) >> (4 * (39 - i))) % 16;
			bytes memory _char = new bytes(1);
			_char[0] = bytes1(uint8(_hex) + (_hex > 9 ? 87 : 48));
			str = string(abi.encodePacked(str, string(_char)));
		}
	}

	function _trimAddress(address _address, uint256 _padding) internal pure returns (string memory str) {
		require(_padding < 20);
		str = "";
		bytes memory _strAddress = bytes(_address2str(_address));
		uint256 _length = 2 * _padding + 2;
		for (uint256 i = 0; i < 2 * _padding + 2; i++) {
			bytes memory _char = new bytes(1);
			_char[0] = _strAddress[i < _padding + 2 ? i : 42 + i - _length];
			str = string(abi.encodePacked(str, string(_char)));
			if (i == _padding + 1) {
				str = string(abi.encodePacked(str, unicode"…"));
			}
		}
	}
	
	function _uint2str(uint256 _value, uint256 _scale, uint256 _maxDecimals, bool _commas, bool _full) internal pure returns (string memory str) {
		uint256 _d = _scale > _maxDecimals ? _maxDecimals : _scale;
		uint256 _n = _value / 10**(_scale > _d ? _scale - _d : 0);
		if (_n == 0) {
			return "0";
		}
		uint256 _digits = 1;
		uint256 _tmp = _n;
		while (_tmp > 9) {
			_tmp /= 10;
			_digits++;
		}
		_tmp = _digits > _d ? _digits : _d + 1;
		uint256 _offset = (!_full && _tmp > _d + 1 ? _tmp - _d - 1 > _d ? _d : _tmp - _d - 1 : 0);
		for (uint256 i = 0; i < _tmp - _offset; i++) {
			uint256 _dec = i < _tmp - _digits ? 0 : (_n / (10**(_tmp - i - 1))) % 10;
			bytes memory _char = new bytes(1);
			_char[0] = bytes1(uint8(_dec) + 48);
			str = string(abi.encodePacked(str, string(_char)));
			if (i < _tmp - _d - 1) {
				if (_commas && (i + 1) % 3 == (_tmp - _d) % 3) {
					str = string(abi.encodePacked(str, ","));
				}
			} else {
				if (!_full && (_n / 10**_offset) % 10**(_tmp - _offset - i - 1) == 0) {
					break;
				} else if (i == _tmp - _d - 1) {
					str = string(abi.encodePacked(str, "."));
				}
			}
		}
	}
	
	function _encode(bytes memory _data) internal pure returns (string memory result) {
		if (_data.length == 0) return '';
		string memory _table = TABLE;
		uint256 _encodedLen = 4 * ((_data.length + 2) / 3);
		result = new string(_encodedLen + 32);

		assembly {
			mstore(result, _encodedLen)
			let tablePtr := add(_table, 1)
			let dataPtr := _data
			let endPtr := add(dataPtr, mload(_data))
			let resultPtr := add(result, 32)

			for {} lt(dataPtr, endPtr) {}
			{
				dataPtr := add(dataPtr, 3)
				let input := mload(dataPtr)
				mstore(resultPtr, shl(248, mload(add(tablePtr, and(shr(18, input), 0x3F)))))
				resultPtr := add(resultPtr, 1)
				mstore(resultPtr, shl(248, mload(add(tablePtr, and(shr(12, input), 0x3F)))))
				resultPtr := add(resultPtr, 1)
				mstore(resultPtr, shl(248, mload(add(tablePtr, and(shr( 6, input), 0x3F)))))
				resultPtr := add(resultPtr, 1)
				mstore(resultPtr, shl(248, mload(add(tablePtr, and(        input,  0x3F)))))
				resultPtr := add(resultPtr, 1)
			}
			switch mod(mload(_data), 3)
			case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) }
			case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) }
		}
		return result;
	}
}

File 3 of 8: PRBMath.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.4;

/// @notice Emitted when the result overflows uint256.
error PRBMath__MulDivFixedPointOverflow(uint256 prod1);

/// @notice Emitted when the result overflows uint256.
error PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);

/// @notice Emitted when one of the inputs is type(int256).min.
error PRBMath__MulDivSignedInputTooSmall();

/// @notice Emitted when the intermediary absolute result overflows int256.
error PRBMath__MulDivSignedOverflow(uint256 rAbs);

/// @notice Emitted when the input is MIN_SD59x18.
error PRBMathSD59x18__AbsInputTooSmall();

/// @notice Emitted when ceiling a number overflows SD59x18.
error PRBMathSD59x18__CeilOverflow(int256 x);

/// @notice Emitted when one of the inputs is MIN_SD59x18.
error PRBMathSD59x18__DivInputTooSmall();

/// @notice Emitted when one of the intermediary unsigned results overflows SD59x18.
error PRBMathSD59x18__DivOverflow(uint256 rAbs);

/// @notice Emitted when the input is greater than 133.084258667509499441.
error PRBMathSD59x18__ExpInputTooBig(int256 x);

/// @notice Emitted when the input is greater than 192.
error PRBMathSD59x18__Exp2InputTooBig(int256 x);

/// @notice Emitted when flooring a number underflows SD59x18.
error PRBMathSD59x18__FloorUnderflow(int256 x);

/// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18.
error PRBMathSD59x18__FromIntOverflow(int256 x);

/// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18.
error PRBMathSD59x18__FromIntUnderflow(int256 x);

/// @notice Emitted when the product of the inputs is negative.
error PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);

/// @notice Emitted when multiplying the inputs overflows SD59x18.
error PRBMathSD59x18__GmOverflow(int256 x, int256 y);

/// @notice Emitted when the input is less than or equal to zero.
error PRBMathSD59x18__LogInputTooSmall(int256 x);

/// @notice Emitted when one of the inputs is MIN_SD59x18.
error PRBMathSD59x18__MulInputTooSmall();

/// @notice Emitted when the intermediary absolute result overflows SD59x18.
error PRBMathSD59x18__MulOverflow(uint256 rAbs);

/// @notice Emitted when the intermediary absolute result overflows SD59x18.
error PRBMathSD59x18__PowuOverflow(uint256 rAbs);

/// @notice Emitted when the input is negative.
error PRBMathSD59x18__SqrtNegativeInput(int256 x);

/// @notice Emitted when the calculating the square root overflows SD59x18.
error PRBMathSD59x18__SqrtOverflow(int256 x);

/// @notice Emitted when addition overflows UD60x18.
error PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);

/// @notice Emitted when ceiling a number overflows UD60x18.
error PRBMathUD60x18__CeilOverflow(uint256 x);

/// @notice Emitted when the input is greater than 133.084258667509499441.
error PRBMathUD60x18__ExpInputTooBig(uint256 x);

/// @notice Emitted when the input is greater than 192.
error PRBMathUD60x18__Exp2InputTooBig(uint256 x);

/// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18.
error PRBMathUD60x18__FromUintOverflow(uint256 x);

/// @notice Emitted when multiplying the inputs overflows UD60x18.
error PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);

/// @notice Emitted when the input is less than 1.
error PRBMathUD60x18__LogInputTooSmall(uint256 x);

/// @notice Emitted when the calculating the square root overflows UD60x18.
error PRBMathUD60x18__SqrtOverflow(uint256 x);

/// @notice Emitted when subtraction underflows UD60x18.
error PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);

/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library
/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point
/// representation. When it does not, it is explicitly mentioned in the NatSpec documentation.
library PRBMath {
	/// STRUCTS ///

	struct SD59x18 {
		int256 value;
	}

	struct UD60x18 {
		uint256 value;
	}

	/// STORAGE ///

	/// @dev How many trailing decimals can be represented.
	uint256 internal constant SCALE = 1e18;

	/// @dev Largest power of two divisor of SCALE.
	uint256 internal constant SCALE_LPOTD = 262144;

	/// @dev SCALE inverted mod 2^256.
	uint256 internal constant SCALE_INVERSE =
		78156646155174841979727994598816262306175212592076161876661_508869554232690281;

	/// FUNCTIONS ///

	/// @notice Calculates the binary exponent of x using the binary fraction method.
	/// @dev Has to use 192.64-bit fixed-point numbers.
	/// See https://ethereum.stackexchange.com/a/96594/24693.
	/// @param x The exponent as an unsigned 192.64-bit fixed-point number.
	/// @return result The result as an unsigned 60.18-decimal fixed-point number.
	function exp2(uint256 x) internal pure returns (uint256 result) {
		unchecked {
			// Start from 0.5 in the 192.64-bit fixed-point format.
			result = 0x800000000000000000000000000000000000000000000000;

			// Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows
			// because the initial result is 2^191 and all magic factors are less than 2^65.
			if (x & 0x8000000000000000 > 0) {
				result = (result * 0x16A09E667F3BCC909) >> 64;
			}
			if (x & 0x4000000000000000 > 0) {
				result = (result * 0x1306FE0A31B7152DF) >> 64;
			}
			if (x & 0x2000000000000000 > 0) {
				result = (result * 0x1172B83C7D517ADCE) >> 64;
			}
			if (x & 0x1000000000000000 > 0) {
				result = (result * 0x10B5586CF9890F62A) >> 64;
			}
			if (x & 0x800000000000000 > 0) {
				result = (result * 0x1059B0D31585743AE) >> 64;
			}
			if (x & 0x400000000000000 > 0) {
				result = (result * 0x102C9A3E778060EE7) >> 64;
			}
			if (x & 0x200000000000000 > 0) {
				result = (result * 0x10163DA9FB33356D8) >> 64;
			}
			if (x & 0x100000000000000 > 0) {
				result = (result * 0x100B1AFA5ABCBED61) >> 64;
			}
			if (x & 0x80000000000000 > 0) {
				result = (result * 0x10058C86DA1C09EA2) >> 64;
			}
			if (x & 0x40000000000000 > 0) {
				result = (result * 0x1002C605E2E8CEC50) >> 64;
			}
			if (x & 0x20000000000000 > 0) {
				result = (result * 0x100162F3904051FA1) >> 64;
			}
			if (x & 0x10000000000000 > 0) {
				result = (result * 0x1000B175EFFDC76BA) >> 64;
			}
			if (x & 0x8000000000000 > 0) {
				result = (result * 0x100058BA01FB9F96D) >> 64;
			}
			if (x & 0x4000000000000 > 0) {
				result = (result * 0x10002C5CC37DA9492) >> 64;
			}
			if (x & 0x2000000000000 > 0) {
				result = (result * 0x1000162E525EE0547) >> 64;
			}
			if (x & 0x1000000000000 > 0) {
				result = (result * 0x10000B17255775C04) >> 64;
			}
			if (x & 0x800000000000 > 0) {
				result = (result * 0x1000058B91B5BC9AE) >> 64;
			}
			if (x & 0x400000000000 > 0) {
				result = (result * 0x100002C5C89D5EC6D) >> 64;
			}
			if (x & 0x200000000000 > 0) {
				result = (result * 0x10000162E43F4F831) >> 64;
			}
			if (x & 0x100000000000 > 0) {
				result = (result * 0x100000B1721BCFC9A) >> 64;
			}
			if (x & 0x80000000000 > 0) {
				result = (result * 0x10000058B90CF1E6E) >> 64;
			}
			if (x & 0x40000000000 > 0) {
				result = (result * 0x1000002C5C863B73F) >> 64;
			}
			if (x & 0x20000000000 > 0) {
				result = (result * 0x100000162E430E5A2) >> 64;
			}
			if (x & 0x10000000000 > 0) {
				result = (result * 0x1000000B172183551) >> 64;
			}
			if (x & 0x8000000000 > 0) {
				result = (result * 0x100000058B90C0B49) >> 64;
			}
			if (x & 0x4000000000 > 0) {
				result = (result * 0x10000002C5C8601CC) >> 64;
			}
			if (x & 0x2000000000 > 0) {
				result = (result * 0x1000000162E42FFF0) >> 64;
			}
			if (x & 0x1000000000 > 0) {
				result = (result * 0x10000000B17217FBB) >> 64;
			}
			if (x & 0x800000000 > 0) {
				result = (result * 0x1000000058B90BFCE) >> 64;
			}
			if (x & 0x400000000 > 0) {
				result = (result * 0x100000002C5C85FE3) >> 64;
			}
			if (x & 0x200000000 > 0) {
				result = (result * 0x10000000162E42FF1) >> 64;
			}
			if (x & 0x100000000 > 0) {
				result = (result * 0x100000000B17217F8) >> 64;
			}
			if (x & 0x80000000 > 0) {
				result = (result * 0x10000000058B90BFC) >> 64;
			}
			if (x & 0x40000000 > 0) {
				result = (result * 0x1000000002C5C85FE) >> 64;
			}
			if (x & 0x20000000 > 0) {
				result = (result * 0x100000000162E42FF) >> 64;
			}
			if (x & 0x10000000 > 0) {
				result = (result * 0x1000000000B17217F) >> 64;
			}
			if (x & 0x8000000 > 0) {
				result = (result * 0x100000000058B90C0) >> 64;
			}
			if (x & 0x4000000 > 0) {
				result = (result * 0x10000000002C5C860) >> 64;
			}
			if (x & 0x2000000 > 0) {
				result = (result * 0x1000000000162E430) >> 64;
			}
			if (x & 0x1000000 > 0) {
				result = (result * 0x10000000000B17218) >> 64;
			}
			if (x & 0x800000 > 0) {
				result = (result * 0x1000000000058B90C) >> 64;
			}
			if (x & 0x400000 > 0) {
				result = (result * 0x100000000002C5C86) >> 64;
			}
			if (x & 0x200000 > 0) {
				result = (result * 0x10000000000162E43) >> 64;
			}
			if (x & 0x100000 > 0) {
				result = (result * 0x100000000000B1721) >> 64;
			}
			if (x & 0x80000 > 0) {
				result = (result * 0x10000000000058B91) >> 64;
			}
			if (x & 0x40000 > 0) {
				result = (result * 0x1000000000002C5C8) >> 64;
			}
			if (x & 0x20000 > 0) {
				result = (result * 0x100000000000162E4) >> 64;
			}
			if (x & 0x10000 > 0) {
				result = (result * 0x1000000000000B172) >> 64;
			}
			if (x & 0x8000 > 0) {
				result = (result * 0x100000000000058B9) >> 64;
			}
			if (x & 0x4000 > 0) {
				result = (result * 0x10000000000002C5D) >> 64;
			}
			if (x & 0x2000 > 0) {
				result = (result * 0x1000000000000162E) >> 64;
			}
			if (x & 0x1000 > 0) {
				result = (result * 0x10000000000000B17) >> 64;
			}
			if (x & 0x800 > 0) {
				result = (result * 0x1000000000000058C) >> 64;
			}
			if (x & 0x400 > 0) {
				result = (result * 0x100000000000002C6) >> 64;
			}
			if (x & 0x200 > 0) {
				result = (result * 0x10000000000000163) >> 64;
			}
			if (x & 0x100 > 0) {
				result = (result * 0x100000000000000B1) >> 64;
			}
			if (x & 0x80 > 0) {
				result = (result * 0x10000000000000059) >> 64;
			}
			if (x & 0x40 > 0) {
				result = (result * 0x1000000000000002C) >> 64;
			}
			if (x & 0x20 > 0) {
				result = (result * 0x10000000000000016) >> 64;
			}
			if (x & 0x10 > 0) {
				result = (result * 0x1000000000000000B) >> 64;
			}
			if (x & 0x8 > 0) {
				result = (result * 0x10000000000000006) >> 64;
			}
			if (x & 0x4 > 0) {
				result = (result * 0x10000000000000003) >> 64;
			}
			if (x & 0x2 > 0) {
				result = (result * 0x10000000000000001) >> 64;
			}
			if (x & 0x1 > 0) {
				result = (result * 0x10000000000000001) >> 64;
			}

			// We're doing two things at the same time:
			//
			//   1. Multiply the result by 2^n + 1, where "2^n" is the integer part and the one is added to account for
			//      the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191
			//      rather than 192.
			//   2. Convert the result to the unsigned 60.18-decimal fixed-point format.
			//
			// This works because 2^(191-ip) = 2^ip / 2^191, where "ip" is the integer part "2^n".
			result *= SCALE;
			result >>= (191 - (x >> 64));
		}
	}

	/// @notice Finds the zero-based index of the first one in the binary representation of x.
	/// @dev See the note on msb in the "Find First Set" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set
	/// @param x The uint256 number for which to find the index of the most significant bit.
	/// @return msb The index of the most significant bit as an uint256.
	function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {
		if (x >= 2**128) {
			x >>= 128;
			msb += 128;
		}
		if (x >= 2**64) {
			x >>= 64;
			msb += 64;
		}
		if (x >= 2**32) {
			x >>= 32;
			msb += 32;
		}
		if (x >= 2**16) {
			x >>= 16;
			msb += 16;
		}
		if (x >= 2**8) {
			x >>= 8;
			msb += 8;
		}
		if (x >= 2**4) {
			x >>= 4;
			msb += 4;
		}
		if (x >= 2**2) {
			x >>= 2;
			msb += 2;
		}
		if (x >= 2**1) {
			// No need to shift x any more.
			msb += 1;
		}
	}

	/// @notice Calculates floor(x*y÷denominator) with full precision.
	///
	/// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.
	///
	/// Requirements:
	/// - The denominator cannot be zero.
	/// - The result must fit within uint256.
	///
	/// Caveats:
	/// - This function does not work with fixed-point numbers.
	///
	/// @param x The multiplicand as an uint256.
	/// @param y The multiplier as an uint256.
	/// @param denominator The divisor as an uint256.
	/// @return result The result as an uint256.
	function mulDiv(
		uint256 x,
		uint256 y,
		uint256 denominator
	) internal pure returns (uint256 result) {
		// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
		// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
		// variables such that product = prod1 * 2^256 + prod0.
		uint256 prod0; // Least significant 256 bits of the product
		uint256 prod1; // Most significant 256 bits of the product
		assembly {
			let mm := mulmod(x, y, not(0))
			prod0 := mul(x, y)
			prod1 := sub(sub(mm, prod0), lt(mm, prod0))
		}

		// Handle non-overflow cases, 256 by 256 division.
		if (prod1 == 0) {
			unchecked {
				result = prod0 / denominator;
			}
			return result;
		}

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

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

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

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

		// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
		// See https://cs.stackexchange.com/q/138556/92363.
		unchecked {
			// Does not overflow because the denominator cannot be zero at this stage in the function.
			uint256 lpotdod = denominator & (~denominator + 1);
			assembly {
				// Divide denominator by lpotdod.
				denominator := div(denominator, lpotdod)

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

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

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

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

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

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

	/// @notice Calculates floor(x*y÷1e18) with full precision.
	///
	/// @dev Variant of "mulDiv" with constant folding, i.e. in which the denominator is always 1e18. Before returning the
	/// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of
	/// being rounded to 1e-18.  See "Listing 6" and text above it at https://accu.org/index.php/journals/1717.
	///
	/// Requirements:
	/// - The result must fit within uint256.
	///
	/// Caveats:
	/// - The body is purposely left uncommented; see the NatSpec comments in "PRBMath.mulDiv" to understand how this works.
	/// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations:
	///     1. x * y = type(uint256).max * SCALE
	///     2. (x * y) % SCALE >= SCALE / 2
	///
	/// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.
	/// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.
	/// @return result The result as an unsigned 60.18-decimal fixed-point number.
	function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {
		uint256 prod0;
		uint256 prod1;
		assembly {
			let mm := mulmod(x, y, not(0))
			prod0 := mul(x, y)
			prod1 := sub(sub(mm, prod0), lt(mm, prod0))
		}

		if (prod1 >= SCALE) {
			revert PRBMath__MulDivFixedPointOverflow(prod1);
		}

		uint256 remainder;
		uint256 roundUpUnit;
		assembly {
			remainder := mulmod(x, y, SCALE)
			roundUpUnit := gt(remainder, 499999999999999999)
		}

		if (prod1 == 0) {
			unchecked {
				result = (prod0 / SCALE) + roundUpUnit;
				return result;
			}
		}

		assembly {
			result := add(
				mul(
					or(
						div(sub(prod0, remainder), SCALE_LPOTD),
						mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))
					),
					SCALE_INVERSE
				),
				roundUpUnit
			)
		}
	}

	/// @notice Calculates floor(x*y÷denominator) with full precision.
	///
	/// @dev An extension of "mulDiv" for signed numbers. Works by computing the signs and the absolute values separately.
	///
	/// Requirements:
	/// - None of the inputs can be type(int256).min.
	/// - The result must fit within int256.
	///
	/// @param x The multiplicand as an int256.
	/// @param y The multiplier as an int256.
	/// @param denominator The divisor as an int256.
	/// @return result The result as an int256.
	function mulDivSigned(
		int256 x,
		int256 y,
		int256 denominator
	) internal pure returns (int256 result) {
		if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {
			revert PRBMath__MulDivSignedInputTooSmall();
		}

		// Get hold of the absolute values of x, y and the denominator.
		uint256 ax;
		uint256 ay;
		uint256 ad;
		unchecked {
			ax = x < 0 ? uint256(-x) : uint256(x);
			ay = y < 0 ? uint256(-y) : uint256(y);
			ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);
		}

		// Compute the absolute value of (x*y)÷denominator. The result must fit within int256.
		uint256 rAbs = mulDiv(ax, ay, ad);
		if (rAbs > uint256(type(int256).max)) {
			revert PRBMath__MulDivSignedOverflow(rAbs);
		}

		// Get the signs of x, y and the denominator.
		uint256 sx;
		uint256 sy;
		uint256 sd;
		assembly {
			sx := sgt(x, sub(0, 1))
			sy := sgt(y, sub(0, 1))
			sd := sgt(denominator, sub(0, 1))
		}

		// XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs.
		// If yes, the result should be negative.
		result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);
	}

	/// @notice Calculates the square root of x, rounding down.
	/// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
	///
	/// Caveats:
	/// - This function does not work with fixed-point numbers.
	///
	/// @param x The uint256 number for which to calculate the square root.
	/// @return result The result as an uint256.
	function sqrt(uint256 x) internal pure returns (uint256 result) {
		if (x == 0) {
			return 0;
		}

		// Set the initial guess to the least power of two that is greater than or equal to sqrt(x).
		uint256 xAux = uint256(x);
		result = 1;
		if (xAux >= 0x100000000000000000000000000000000) {
			xAux >>= 128;
			result <<= 64;
		}
		if (xAux >= 0x10000000000000000) {
			xAux >>= 64;
			result <<= 32;
		}
		if (xAux >= 0x100000000) {
			xAux >>= 32;
			result <<= 16;
		}
		if (xAux >= 0x10000) {
			xAux >>= 16;
			result <<= 8;
		}
		if (xAux >= 0x100) {
			xAux >>= 8;
			result <<= 4;
		}
		if (xAux >= 0x10) {
			xAux >>= 4;
			result <<= 2;
		}
		if (xAux >= 0x8) {
			result <<= 1;
		}

		// The operations can never overflow because the result is max 2^127 when it enters this block.
		unchecked {
			result = (result + x / result) >> 1;
			result = (result + x / result) >> 1;
			result = (result + x / result) >> 1;
			result = (result + x / result) >> 1;
			result = (result + x / result) >> 1;
			result = (result + x / result) >> 1;
			result = (result + x / result) >> 1; // Seven iterations should be enough
			uint256 roundedDownResult = x / result;
			return result >= roundedDownResult ? roundedDownResult : result;
		}
	}
}

File 4 of 8: PRBMathUD60x18.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.4;

import "./PRBMath.sol";

/// @title PRBMathUD60x18
/// @author Paul Razvan Berg
/// @notice Smart contract library for advanced fixed-point math that works with uint256 numbers considered to have 18
/// trailing decimals. We call this number representation unsigned 60.18-decimal fixed-point, since there can be up to 60
/// digits in the integer part and up to 18 decimals in the fractional part. The numbers are bound by the minimum and the
/// maximum values permitted by the Solidity type uint256.
library PRBMathUD60x18 {
	/// @dev Half the SCALE number.
	uint256 internal constant HALF_SCALE = 5e17;

	/// @dev log2(e) as an unsigned 60.18-decimal fixed-point number.
	uint256 internal constant LOG2_E = 1_442695040888963407;

	/// @dev The maximum value an unsigned 60.18-decimal fixed-point number can have.
	uint256 internal constant MAX_UD60x18 =
		115792089237316195423570985008687907853269984665640564039457_584007913129639935;

	/// @dev The maximum whole value an unsigned 60.18-decimal fixed-point number can have.
	uint256 internal constant MAX_WHOLE_UD60x18 =
		115792089237316195423570985008687907853269984665640564039457_000000000000000000;

	/// @dev How many trailing decimals can be represented.
	uint256 internal constant SCALE = 1e18;

	/// @notice Calculates the arithmetic average of x and y, rounding down.
	/// @param x The first operand as an unsigned 60.18-decimal fixed-point number.
	/// @param y The second operand as an unsigned 60.18-decimal fixed-point number.
	/// @return result The arithmetic average as an unsigned 60.18-decimal fixed-point number.
	function avg(uint256 x, uint256 y) internal pure returns (uint256 result) {
		// The operations can never overflow.
		unchecked {
			// The last operand checks if both x and y are odd and if that is the case, we add 1 to the result. We need
			// to do this because if both numbers are odd, the 0.5 remainder gets truncated twice.
			result = (x >> 1) + (y >> 1) + (x & y & 1);
		}
	}

	/// @notice Yields the least unsigned 60.18 decimal fixed-point number greater than or equal to x.
	///
	/// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts.
	/// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.
	///
	/// Requirements:
	/// - x must be less than or equal to MAX_WHOLE_UD60x18.
	///
	/// @param x The unsigned 60.18-decimal fixed-point number to ceil.
	/// @param result The least integer greater than or equal to x, as an unsigned 60.18-decimal fixed-point number.
	function ceil(uint256 x) internal pure returns (uint256 result) {
		if (x > MAX_WHOLE_UD60x18) {
			revert PRBMathUD60x18__CeilOverflow(x);
		}
		assembly {
			// Equivalent to "x % SCALE" but faster.
			let remainder := mod(x, SCALE)

			// Equivalent to "SCALE - remainder" but faster.
			let delta := sub(SCALE, remainder)

			// Equivalent to "x + delta * (remainder > 0 ? 1 : 0)" but faster.
			result := add(x, mul(delta, gt(remainder, 0)))
		}
	}

	/// @notice Divides two unsigned 60.18-decimal fixed-point numbers, returning a new unsigned 60.18-decimal fixed-point number.
	///
	/// @dev Uses mulDiv to enable overflow-safe multiplication and division.
	///
	/// Requirements:
	/// - The denominator cannot be zero.
	///
	/// @param x The numerator as an unsigned 60.18-decimal fixed-point number.
	/// @param y The denominator as an unsigned 60.18-decimal fixed-point number.
	/// @param result The quotient as an unsigned 60.18-decimal fixed-point number.
	function div(uint256 x, uint256 y) internal pure returns (uint256 result) {
		result = PRBMath.mulDiv(x, SCALE, y);
	}

	/// @notice Returns Euler's number as an unsigned 60.18-decimal fixed-point number.
	/// @dev See https://en.wikipedia.org/wiki/E_(mathematical_constant).
	function e() internal pure returns (uint256 result) {
		result = 2_718281828459045235;
	}

	/// @notice Calculates the natural exponent of x.
	///
	/// @dev Based on the insight that e^x = 2^(x * log2(e)).
	///
	/// Requirements:
	/// - All from "log2".
	/// - x must be less than 133.084258667509499441.
	///
	/// @param x The exponent as an unsigned 60.18-decimal fixed-point number.
	/// @return result The result as an unsigned 60.18-decimal fixed-point number.
	function exp(uint256 x) internal pure returns (uint256 result) {
		// Without this check, the value passed to "exp2" would be greater than 192.
		if (x >= 133_084258667509499441) {
			revert PRBMathUD60x18__ExpInputTooBig(x);
		}

		// Do the fixed-point multiplication inline to save gas.
		unchecked {
			uint256 doubleScaleProduct = x * LOG2_E;
			result = exp2((doubleScaleProduct + HALF_SCALE) / SCALE);
		}
	}

	/// @notice Calculates the binary exponent of x using the binary fraction method.
	///
	/// @dev See https://ethereum.stackexchange.com/q/79903/24693.
	///
	/// Requirements:
	/// - x must be 192 or less.
	/// - The result must fit within MAX_UD60x18.
	///
	/// @param x The exponent as an unsigned 60.18-decimal fixed-point number.
	/// @return result The result as an unsigned 60.18-decimal fixed-point number.
	function exp2(uint256 x) internal pure returns (uint256 result) {
		// 2^192 doesn't fit within the 192.64-bit format used internally in this function.
		if (x >= 192e18) {
			revert PRBMathUD60x18__Exp2InputTooBig(x);
		}

		unchecked {
			// Convert x to the 192.64-bit fixed-point format.
			uint256 x192x64 = (x << 64) / SCALE;

			// Pass x to the PRBMath.exp2 function, which uses the 192.64-bit fixed-point number representation.
			result = PRBMath.exp2(x192x64);
		}
	}

	/// @notice Yields the greatest unsigned 60.18 decimal fixed-point number less than or equal to x.
	/// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts.
	/// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.
	/// @param x The unsigned 60.18-decimal fixed-point number to floor.
	/// @param result The greatest integer less than or equal to x, as an unsigned 60.18-decimal fixed-point number.
	function floor(uint256 x) internal pure returns (uint256 result) {
		assembly {
			// Equivalent to "x % SCALE" but faster.
			let remainder := mod(x, SCALE)

			// Equivalent to "x - remainder * (remainder > 0 ? 1 : 0)" but faster.
			result := sub(x, mul(remainder, gt(remainder, 0)))
		}
	}

	/// @notice Yields the excess beyond the floor of x.
	/// @dev Based on the odd function definition https://en.wikipedia.org/wiki/Fractional_part.
	/// @param x The unsigned 60.18-decimal fixed-point number to get the fractional part of.
	/// @param result The fractional part of x as an unsigned 60.18-decimal fixed-point number.
	function frac(uint256 x) internal pure returns (uint256 result) {
		assembly {
			result := mod(x, SCALE)
		}
	}

	/// @notice Converts a number from basic integer form to unsigned 60.18-decimal fixed-point representation.
	///
	/// @dev Requirements:
	/// - x must be less than or equal to MAX_UD60x18 divided by SCALE.
	///
	/// @param x The basic integer to convert.
	/// @param result The same number in unsigned 60.18-decimal fixed-point representation.
	function fromUint(uint256 x) internal pure returns (uint256 result) {
		unchecked {
			if (x > MAX_UD60x18 / SCALE) {
				revert PRBMathUD60x18__FromUintOverflow(x);
			}
			result = x * SCALE;
		}
	}

	/// @notice Calculates geometric mean of x and y, i.e. sqrt(x * y), rounding down.
	///
	/// @dev Requirements:
	/// - x * y must fit within MAX_UD60x18, lest it overflows.
	///
	/// @param x The first operand as an unsigned 60.18-decimal fixed-point number.
	/// @param y The second operand as an unsigned 60.18-decimal fixed-point number.
	/// @return result The result as an unsigned 60.18-decimal fixed-point number.
	function gm(uint256 x, uint256 y) internal pure returns (uint256 result) {
		if (x == 0) {
			return 0;
		}

		unchecked {
			// Checking for overflow this way is faster than letting Solidity do it.
			uint256 xy = x * y;
			if (xy / x != y) {
				revert PRBMathUD60x18__GmOverflow(x, y);
			}

			// We don't need to multiply by the SCALE here because the x*y product had already picked up a factor of SCALE
			// during multiplication. See the comments within the "sqrt" function.
			result = PRBMath.sqrt(xy);
		}
	}

	/// @notice Calculates 1 / x, rounding toward zero.
	///
	/// @dev Requirements:
	/// - x cannot be zero.
	///
	/// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the inverse.
	/// @return result The inverse as an unsigned 60.18-decimal fixed-point number.
	function inv(uint256 x) internal pure returns (uint256 result) {
		unchecked {
			// 1e36 is SCALE * SCALE.
			result = 1e36 / x;
		}
	}

	/// @notice Calculates the natural logarithm of x.
	///
	/// @dev Based on the insight that ln(x) = log2(x) / log2(e).
	///
	/// Requirements:
	/// - All from "log2".
	///
	/// Caveats:
	/// - All from "log2".
	/// - This doesn't return exactly 1 for 2.718281828459045235, for that we would need more fine-grained precision.
	///
	/// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the natural logarithm.
	/// @return result The natural logarithm as an unsigned 60.18-decimal fixed-point number.
	function ln(uint256 x) internal pure returns (uint256 result) {
		// Do the fixed-point multiplication inline to save gas. This is overflow-safe because the maximum value that log2(x)
		// can return is 196205294292027477728.
		unchecked {
			result = (log2(x) * SCALE) / LOG2_E;
		}
	}

	/// @notice Calculates the common logarithm of x.
	///
	/// @dev First checks if x is an exact power of ten and it stops if yes. If it's not, calculates the common
	/// logarithm based on the insight that log10(x) = log2(x) / log2(10).
	///
	/// Requirements:
	/// - All from "log2".
	///
	/// Caveats:
	/// - All from "log2".
	///
	/// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the common logarithm.
	/// @return result The common logarithm as an unsigned 60.18-decimal fixed-point number.
	function log10(uint256 x) internal pure returns (uint256 result) {
		if (x < SCALE) {
			revert PRBMathUD60x18__LogInputTooSmall(x);
		}

		// Note that the "mul" in this block is the assembly multiplication operation, not the "mul" function defined
		// in this contract.
		// prettier-ignore
		assembly {
			switch x
			case 1 { result := mul(SCALE, sub(0, 18)) }
			case 10 { result := mul(SCALE, sub(1, 18)) }
			case 100 { result := mul(SCALE, sub(2, 18)) }
			case 1000 { result := mul(SCALE, sub(3, 18)) }
			case 10000 { result := mul(SCALE, sub(4, 18)) }
			case 100000 { result := mul(SCALE, sub(5, 18)) }
			case 1000000 { result := mul(SCALE, sub(6, 18)) }
			case 10000000 { result := mul(SCALE, sub(7, 18)) }
			case 100000000 { result := mul(SCALE, sub(8, 18)) }
			case 1000000000 { result := mul(SCALE, sub(9, 18)) }
			case 10000000000 { result := mul(SCALE, sub(10, 18)) }
			case 100000000000 { result := mul(SCALE, sub(11, 18)) }
			case 1000000000000 { result := mul(SCALE, sub(12, 18)) }
			case 10000000000000 { result := mul(SCALE, sub(13, 18)) }
			case 100000000000000 { result := mul(SCALE, sub(14, 18)) }
			case 1000000000000000 { result := mul(SCALE, sub(15, 18)) }
			case 10000000000000000 { result := mul(SCALE, sub(16, 18)) }
			case 100000000000000000 { result := mul(SCALE, sub(17, 18)) }
			case 1000000000000000000 { result := 0 }
			case 10000000000000000000 { result := SCALE }
			case 100000000000000000000 { result := mul(SCALE, 2) }
			case 1000000000000000000000 { result := mul(SCALE, 3) }
			case 10000000000000000000000 { result := mul(SCALE, 4) }
			case 100000000000000000000000 { result := mul(SCALE, 5) }
			case 1000000000000000000000000 { result := mul(SCALE, 6) }
			case 10000000000000000000000000 { result := mul(SCALE, 7) }
			case 100000000000000000000000000 { result := mul(SCALE, 8) }
			case 1000000000000000000000000000 { result := mul(SCALE, 9) }
			case 10000000000000000000000000000 { result := mul(SCALE, 10) }
			case 100000000000000000000000000000 { result := mul(SCALE, 11) }
			case 1000000000000000000000000000000 { result := mul(SCALE, 12) }
			case 10000000000000000000000000000000 { result := mul(SCALE, 13) }
			case 100000000000000000000000000000000 { result := mul(SCALE, 14) }
			case 1000000000000000000000000000000000 { result := mul(SCALE, 15) }
			case 10000000000000000000000000000000000 { result := mul(SCALE, 16) }
			case 100000000000000000000000000000000000 { result := mul(SCALE, 17) }
			case 1000000000000000000000000000000000000 { result := mul(SCALE, 18) }
			case 10000000000000000000000000000000000000 { result := mul(SCALE, 19) }
			case 100000000000000000000000000000000000000 { result := mul(SCALE, 20) }
			case 1000000000000000000000000000000000000000 { result := mul(SCALE, 21) }
			case 10000000000000000000000000000000000000000 { result := mul(SCALE, 22) }
			case 100000000000000000000000000000000000000000 { result := mul(SCALE, 23) }
			case 1000000000000000000000000000000000000000000 { result := mul(SCALE, 24) }
			case 10000000000000000000000000000000000000000000 { result := mul(SCALE, 25) }
			case 100000000000000000000000000000000000000000000 { result := mul(SCALE, 26) }
			case 1000000000000000000000000000000000000000000000 { result := mul(SCALE, 27) }
			case 10000000000000000000000000000000000000000000000 { result := mul(SCALE, 28) }
			case 100000000000000000000000000000000000000000000000 { result := mul(SCALE, 29) }
			case 1000000000000000000000000000000000000000000000000 { result := mul(SCALE, 30) }
			case 10000000000000000000000000000000000000000000000000 { result := mul(SCALE, 31) }
			case 100000000000000000000000000000000000000000000000000 { result := mul(SCALE, 32) }
			case 1000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 33) }
			case 10000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 34) }
			case 100000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 35) }
			case 1000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 36) }
			case 10000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 37) }
			case 100000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 38) }
			case 1000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 39) }
			case 10000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 40) }
			case 100000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 41) }
			case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 42) }
			case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 43) }
			case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 44) }
			case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 45) }
			case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 46) }
			case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 47) }
			case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 48) }
			case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 49) }
			case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 50) }
			case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 51) }
			case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 52) }
			case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 53) }
			case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 54) }
			case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 55) }
			case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 56) }
			case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 57) }
			case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 58) }
			case 100000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 59) }
			default {
				result := MAX_UD60x18
			}
		}

		if (result == MAX_UD60x18) {
			// Do the fixed-point division inline to save gas. The denominator is log2(10).
			unchecked {
				result = (log2(x) * SCALE) / 3_321928094887362347;
			}
		}
	}

	/// @notice Calculates the binary logarithm of x.
	///
	/// @dev Based on the iterative approximation algorithm.
	/// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation
	///
	/// Requirements:
	/// - x must be greater than or equal to SCALE, otherwise the result would be negative.
	///
	/// Caveats:
	/// - The results are nor perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation.
	///
	/// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the binary logarithm.
	/// @return result The binary logarithm as an unsigned 60.18-decimal fixed-point number.
	function log2(uint256 x) internal pure returns (uint256 result) {
		if (x < SCALE) {
			revert PRBMathUD60x18__LogInputTooSmall(x);
		}
		unchecked {
			// Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n).
			uint256 n = PRBMath.mostSignificantBit(x / SCALE);

			// The integer part of the logarithm as an unsigned 60.18-decimal fixed-point number. The operation can't overflow
			// because n is maximum 255 and SCALE is 1e18.
			result = n * SCALE;

			// This is y = x * 2^(-n).
			uint256 y = x >> n;

			// If y = 1, the fractional part is zero.
			if (y == SCALE) {
				return result;
			}

			// Calculate the fractional part via the iterative approximation.
			// The "delta >>= 1" part is equivalent to "delta /= 2", but shifting bits is faster.
			for (uint256 delta = HALF_SCALE; delta > 0; delta >>= 1) {
				y = (y * y) / SCALE;

				// Is y^2 > 2 and so in the range [2,4)?
				if (y >= 2 * SCALE) {
					// Add the 2^(-m) factor to the logarithm.
					result += delta;

					// Corresponds to z/2 on Wikipedia.
					y >>= 1;
				}
			}
		}
	}

	/// @notice Multiplies two unsigned 60.18-decimal fixed-point numbers together, returning a new unsigned 60.18-decimal
	/// fixed-point number.
	/// @dev See the documentation for the "PRBMath.mulDivFixedPoint" function.
	/// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.
	/// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.
	/// @return result The product as an unsigned 60.18-decimal fixed-point number.
	function mul(uint256 x, uint256 y) internal pure returns (uint256 result) {
		result = PRBMath.mulDivFixedPoint(x, y);
	}

	/// @notice Returns PI as an unsigned 60.18-decimal fixed-point number.
	function pi() internal pure returns (uint256 result) {
		result = 3_141592653589793238;
	}

	/// @notice Raises x to the power of y.
	///
	/// @dev Based on the insight that x^y = 2^(log2(x) * y).
	///
	/// Requirements:
	/// - All from "exp2", "log2" and "mul".
	///
	/// Caveats:
	/// - All from "exp2", "log2" and "mul".
	/// - Assumes 0^0 is 1.
	///
	/// @param x Number to raise to given power y, as an unsigned 60.18-decimal fixed-point number.
	/// @param y Exponent to raise x to, as an unsigned 60.18-decimal fixed-point number.
	/// @return result x raised to power y, as an unsigned 60.18-decimal fixed-point number.
	function pow(uint256 x, uint256 y) internal pure returns (uint256 result) {
		if (x == 0) {
			result = y == 0 ? SCALE : uint256(0);
		} else {
			result = exp2(mul(log2(x), y));
		}
	}

	/// @notice Raises x (unsigned 60.18-decimal fixed-point number) to the power of y (basic unsigned integer) using the
	/// famous algorithm "exponentiation by squaring".
	///
	/// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring
	///
	/// Requirements:
	/// - The result must fit within MAX_UD60x18.
	///
	/// Caveats:
	/// - All from "mul".
	/// - Assumes 0^0 is 1.
	///
	/// @param x The base as an unsigned 60.18-decimal fixed-point number.
	/// @param y The exponent as an uint256.
	/// @return result The result as an unsigned 60.18-decimal fixed-point number.
	function powu(uint256 x, uint256 y) internal pure returns (uint256 result) {
		// Calculate the first iteration of the loop in advance.
		result = y & 1 > 0 ? x : SCALE;

		// Equivalent to "for(y /= 2; y > 0; y /= 2)" but faster.
		for (y >>= 1; y > 0; y >>= 1) {
			x = PRBMath.mulDivFixedPoint(x, x);

			// Equivalent to "y % 2 == 1" but faster.
			if (y & 1 > 0) {
				result = PRBMath.mulDivFixedPoint(result, x);
			}
		}
	}

	/// @notice Returns 1 as an unsigned 60.18-decimal fixed-point number.
	function scale() internal pure returns (uint256 result) {
		result = SCALE;
	}

	/// @notice Calculates the square root of x, rounding down.
	/// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
	///
	/// Requirements:
	/// - x must be less than MAX_UD60x18 / SCALE.
	///
	/// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the square root.
	/// @return result The result as an unsigned 60.18-decimal fixed-point .
	function sqrt(uint256 x) internal pure returns (uint256 result) {
		unchecked {
			if (x > MAX_UD60x18 / SCALE) {
				revert PRBMathUD60x18__SqrtOverflow(x);
			}
			// Multiply x by the SCALE to account for the factor of SCALE that is picked up when multiplying two unsigned
			// 60.18-decimal fixed-point numbers together (in this case, those two numbers are both the square root).
			result = PRBMath.sqrt(x * SCALE);
		}
	}

	/// @notice Converts a unsigned 60.18-decimal fixed-point number to basic integer form, rounding down in the process.
	/// @param x The unsigned 60.18-decimal fixed-point number to convert.
	/// @return result The same number in basic integer form.
	function toUint(uint256 x) internal pure returns (uint256 result) {
		unchecked {
			result = x / SCALE;
		}
	}
}

File 5 of 8: StakingRewards.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;

import "./WTF.sol";
import "./ERC20.sol";
import "./PRBMathUD60x18.sol";

contract StakingRewards {

	using PRBMathUD60x18 for uint256;

	uint256 constant private FLOAT_SCALAR = 2**64;
	uint256 constant private PERCENT_FEE = 5; // only for WTF staking
	uint256 constant private X_TICK = 30 days;

	struct User {
		uint256 deposited;
		int256 scaledPayout;
	}

	struct Info {
		uint256 totalRewards;
		uint256 startTime;
		uint256 lastUpdated;
		uint256 pendingFee;
		uint256 scaledRewardsPerToken;
		uint256 totalDeposited;
		mapping(address => User) users;
		WTF wtf;
		ERC20 token;
	}
	Info private info;


	event Deposit(address indexed user, uint256 amount, uint256 fee);
	event Withdraw(address indexed user, uint256 amount, uint256 fee);
	event Claim(address indexed user, uint256 amount);
	event Reinvest(address indexed user, uint256 amount);
	event Reward(uint256 amount);


	constructor(uint256 _totalRewards, uint256 _stakingRewardsStart, ERC20 _token) {
		info.totalRewards = _totalRewards;
		info.startTime = block.timestamp < _stakingRewardsStart ? _stakingRewardsStart : block.timestamp;
		info.lastUpdated = startTime();
		info.wtf = WTF(msg.sender);
		info.token = _token;
	}

	function update() public {
		uint256 _now = block.timestamp;
		if (_now > info.lastUpdated && totalDeposited() > 0) {
			uint256 _reward = info.totalRewards.mul(_delta(_getX(info.lastUpdated), _getX(_now)));
			if (info.pendingFee > 0) {
				_reward += info.pendingFee;
				info.pendingFee = 0;
			}
			uint256 _balanceBefore = info.wtf.balanceOf(address(this));
			info.wtf.claimRewards();
			_reward += info.wtf.balanceOf(address(this)) - _balanceBefore;
			info.lastUpdated = _now;
			_disburse(_reward);
		}
	}

	function deposit(uint256 _amount) external {
		depositFor(msg.sender, _amount);
	}

	function depositFor(address _user, uint256 _amount) public {
		require(_amount > 0);
		update();
		uint256 _balanceBefore = info.token.balanceOf(address(this));
		info.token.transferFrom(msg.sender, address(this), _amount);
		uint256 _amountReceived = info.token.balanceOf(address(this)) - _balanceBefore;
		_deposit(_user, _amountReceived);
	}

	function tokenCallback(address _from, uint256 _tokens, bytes calldata) external returns (bool) {
		require(_isWTF() && msg.sender == tokenAddress());
		require(_tokens > 0);
		update();
		_deposit(_from, _tokens);
		return true;
	}

	function disburse(uint256 _amount) public {
		require(_amount > 0);
		update();
		uint256 _balanceBefore = info.wtf.balanceOf(address(this));
		info.wtf.transferFrom(msg.sender, address(this), _amount);
		uint256 _amountReceived = info.wtf.balanceOf(address(this)) - _balanceBefore;
		_processFee(_amountReceived);
	}

	function withdrawAll() public {
		uint256 _deposited = depositedOf(msg.sender);
		if (_deposited > 0) {
			withdraw(_deposited);
		}
	}

	function withdraw(uint256 _amount) public {
		require(_amount > 0 && _amount <= depositedOf(msg.sender));
		update();
		info.totalDeposited -= _amount;
		info.users[msg.sender].deposited -= _amount;
		info.users[msg.sender].scaledPayout -= int256(_amount * info.scaledRewardsPerToken);
		uint256 _fee = _calculateFee(_amount);
		info.token.transfer(msg.sender, _amount - _fee);
		_processFee(_fee);
		emit Withdraw(msg.sender, _amount, _fee);
	}

	function claim() public {
		update();
		uint256 _rewards = rewardsOf(msg.sender);
		if (_rewards > 0) {
			info.users[msg.sender].scaledPayout += int256(_rewards * FLOAT_SCALAR);
			info.wtf.transfer(msg.sender, _rewards);
			emit Claim(msg.sender, _rewards);
		}
	}

	function reinvest() public {
		require(_isWTF());
		update();
		uint256 _rewards = rewardsOf(msg.sender);
		if (_rewards > 0) {
			info.users[msg.sender].scaledPayout += int256(_rewards * FLOAT_SCALAR);
			_deposit(msg.sender, _rewards);
			emit Reinvest(msg.sender, _rewards);
		}
	}

	
	function wtfAddress() public view returns (address) {
		return address(info.wtf);
	}
	
	function tokenAddress() public view returns (address) {
		return address(info.token);
	}

	function startTime() public view returns (uint256) {
		return info.startTime;
	}

	function totalDeposited() public view returns (uint256) {
		return info.totalDeposited;
	}

	function depositedOf(address _user) public view returns (uint256) {
		return info.users[_user].deposited;
	}
	
	function rewardsOf(address _user) public view returns (uint256) {
		return uint256(int256(info.scaledRewardsPerToken * depositedOf(_user)) - info.users[_user].scaledPayout) / FLOAT_SCALAR;
	}
	
	function currentRatePerDay() public view returns (uint256) {
		if (block.timestamp < startTime()) {
			return info.totalRewards.mul(_delta(_getX(startTime()), _getX(startTime() + 24 hours)));
		} else {
			return info.totalRewards.mul(_delta(_getX(block.timestamp), _getX(block.timestamp + 24 hours)));
		}
	}

	function totalDistributed() public view returns (uint256) {
		return info.totalRewards.mul(_sum(_getX(block.timestamp)));
	}

	function allInfoFor(address _user) external view returns (uint256 startingTime, uint256 totalRewardsDistributed, uint256 rewardsRatePerDay, uint256 currentFeePercent, uint256 totalTokensDeposited, uint256 virtualRewards, uint256 userWTF, uint256 userBalance, uint256 userAllowance, uint256 userDeposited, uint256 userRewards) {
		startingTime = startTime();
		totalRewardsDistributed = totalDistributed();
		rewardsRatePerDay = currentRatePerDay();
		currentFeePercent = _calculateFee(1e20);
		totalTokensDeposited = totalDeposited();
		virtualRewards = block.timestamp > info.lastUpdated ? info.totalRewards.mul(_delta(_getX(info.lastUpdated), _getX(block.timestamp))) : 0;
		userWTF = info.wtf.balanceOf(_user);
		userBalance = info.token.balanceOf(_user);
		userAllowance = info.token.allowance(_user, address(this));
		userDeposited = depositedOf(_user);
		userRewards = rewardsOf(_user);
	}

	
	function _deposit(address _user, uint256 _amount) internal {
		uint256 _fee = _calculateFee(_amount);
		uint256 _deposited = _amount - _fee;
		info.totalDeposited += _deposited;
		info.users[_user].deposited += _deposited;
		info.users[_user].scaledPayout += int256(_deposited * info.scaledRewardsPerToken);
		_processFee(_fee);
		emit Deposit(_user, _amount, _fee);
	}
	
	function _processFee(uint256 _fee) internal {
		if (_fee > 0) {
			if (block.timestamp < startTime() || totalDeposited() == 0) {
				info.pendingFee += _fee;
			} else {
				_disburse(_fee);
			}
		}
	}

	function _disburse(uint256 _amount) internal {
		info.scaledRewardsPerToken += _amount * FLOAT_SCALAR / totalDeposited();
		emit Reward(_amount);
	}


	function _isWTF() internal view returns (bool) {
		return wtfAddress() == tokenAddress();
	}

	function _calculateFee(uint256 _amount) internal view returns (uint256) {
		return _isWTF() ? (_amount * PERCENT_FEE / 100).mul(1e18 - _sum(_getX(block.timestamp))) : 0;
	}
	
	function _getX(uint256 t) internal view returns (uint256) {
		uint256 _start = startTime();
		if (t < _start) {
			return 0;
		} else {
			return ((t - _start) * 1e18).div(X_TICK * 1e18);
		}
	}

	function _sum(uint256 x) internal pure returns (uint256) {
		uint256 _e2x = x.exp2();
		return (_e2x - 1e18).div(_e2x);
	}

	function _delta(uint256 x1, uint256 x2) internal pure returns (uint256) {
		require(x2 >= x1);
		return _sum(x2) - _sum(x1);
	}
}

File 6 of 8: Treasury.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;

import "./ERC20.sol";
import "./WTF.sol";
import "./StakingRewards.sol";


contract FeeManager {

	WTF private wtf;

	constructor() {
		wtf = WTF(msg.sender);
	}

	function disburse() external {
		wtf.claimRewards();
		uint256 _balance = wtf.balanceOf(address(this));
		if (_balance > 0) {
			uint256 _oneFifth = _balance / 5;
			Treasury(payable(wtf.treasuryAddress())).collect();
			wtf.transfer(wtf.treasuryAddress(), _oneFifth); // 20%
			StakingRewards(wtf.stakingRewardsAddress()).disburse(_oneFifth); // 20%
			StakingRewards(wtf.lpStakingRewardsAddress()).disburse(3 * _oneFifth); // 60%
		}
	}


	function wtfAddress() external view returns (address) {
		return address(wtf);
	}
}


contract TeamReferral {
	receive() external payable {}
	function release() external {
		address _this = address(this);
		require(_this.balance > 0);
		payable(0x6129E7bCb71C0d7D4580141C4E6a995f16293F42).transfer(_this.balance / 10); // 10%
		payable(0xc9AebdD8fD0d52c35A32fD9155467Cf28Ce474c3).transfer(_this.balance / 3); // 30%
		payable(0xdEE79eD62B42e30EA7EbB6f1b7A3f04143D18b7F).transfer(_this.balance / 2); // 30%
		payable(0x575446Aa9E9647C40edB7a467e45C5916add1538).transfer(_this.balance); // 30%
	}
}


contract Treasury {

	address public owner;
	uint256 public lockedUntil;
	WTF private wtf;

	modifier _onlyOwner() {
		require(msg.sender == owner);
		_;
	}

	constructor() {
		owner = 0x65dd4990719bE9B20322e4E8D3Bd77a4401a0357;
		lockedUntil = block.timestamp + 30 days;
		wtf = WTF(msg.sender);
	}

	receive() external payable {}

	function setOwner(address _owner) external _onlyOwner {
		owner = _owner;
	}

	function transferETH(address payable _destination, uint256 _amount) external _onlyOwner {
		require(isUnlocked());
		_destination.transfer(_amount);
	}

	function transferTokens(ERC20 _token, address _destination, uint256 _amount) external _onlyOwner {
		require(isUnlocked());
		_token.transfer(_destination, _amount);
	}

	function collect() external {
		wtf.claimRewards();
	}


	function isUnlocked() public view returns (bool) {
		return block.timestamp > lockedUntil;
	}

	function wtfAddress() external view returns (address) {
		return address(wtf);
	}
}

File 7 of 8: WTF.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;

import "./WTFNFT.sol";
import "./Treasury.sol";
import "./StakingRewards.sol";

interface Callable {
	function tokenCallback(address _from, uint256 _tokens, bytes calldata _data) external returns (bool);
}

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

interface Factory {
	function createPair(address, address) external returns (address);
}

interface Pair {
	function token0() external view returns (address);
	function totalSupply() external view returns (uint256);
	function balanceOf(address) external view returns (uint256);
	function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
}


contract WTF {

	uint256 constant private FLOAT_SCALAR = 2**64;
	uint256 constant private UINT_MAX = type(uint256).max;
	uint256 constant private TRANSFER_FEE_SCALE = 1000; // 1 = 0.1%
	uint256 constant private WTF_STAKING_SUPPLY = 2e25; // 20M WTF
	uint256 constant private LP_STAKING_SUPPLY = 4e25; // 40M WTF
	uint256 constant private TREASURY_SUPPLY = 4e25; // 40M WTF
	uint256 constant private BASE_UPGRADE_COST = 1e19; // 10 WTF
	uint256 constant private SERVICE_FEE = 0.01 ether;

	string constant public name = "fees.wtf";
	string constant public symbol = "WTF";
	uint8 constant public decimals = 18;

	struct User {
		uint256 balance;
		mapping(address => uint256) allowance;
		int256 scaledPayout;
		uint256 reflinkLevel;
		bool unlocked;
	}

	struct Info {
		bytes32 merkleRoot;
		uint256 openingTime;
		uint256 closingTime;
		uint256 totalSupply;
		uint256 scaledRewardsPerToken;
		mapping(uint256 => uint256) claimedWTFBitMap;
		mapping(uint256 => uint256) claimedNFTBitMap;
		mapping(address => User) users;
		mapping(address => bool) toWhitelist;
		mapping(address => bool) fromWhitelist;
		address owner;
		Router router;
		Pair pair;
		bool weth0;
		WTFNFT nft;
		TeamReferral team;
		Treasury treasury;
		StakingRewards stakingRewards;
		StakingRewards lpStakingRewards;
		address feeManager;
		uint256 transferFee;
		uint256 feeManagerPercent;
	}
	Info private info;


	event Transfer(address indexed from, address indexed to, uint256 tokens);
	event Approval(address indexed owner, address indexed spender, uint256 tokens);
	event WhitelistUpdated(address indexed user, bool fromWhitelisted, bool toWhitelisted);
	event ReflinkRewards(address indexed referrer, uint256 amount);
	event ClaimRewards(address indexed user, uint256 amount);
	event Reward(uint256 amount);

	modifier _onlyOwner() {
		require(msg.sender == owner());
		_;
	}


	constructor(bytes32 _merkleRoot, uint256 _openingTime, uint256 _stakingRewardsStart) {
		info.merkleRoot = _merkleRoot;
		info.openingTime = block.timestamp < _openingTime ? _openingTime : block.timestamp;
		info.closingTime = openingTime() + 30 days;
		info.router = Router(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
		info.pair = Pair(Factory(info.router.factory()).createPair(info.router.WETH(), address(this)));
		info.weth0 = info.pair.token0() == info.router.WETH();
		info.transferFee = 40; // 4%
		info.feeManagerPercent = 25; // 25%
		info.owner = 0x65dd4990719bE9B20322e4E8D3Bd77a4401a0357;
		info.nft = new WTFNFT();
		info.team = new TeamReferral();
		info.treasury = new Treasury();
		_mint(treasuryAddress(), TREASURY_SUPPLY);
		info.stakingRewards = new StakingRewards(WTF_STAKING_SUPPLY, _stakingRewardsStart, ERC20(address(this)));
		_mint(stakingRewardsAddress(), WTF_STAKING_SUPPLY);
		info.lpStakingRewards = new StakingRewards(LP_STAKING_SUPPLY, _stakingRewardsStart, ERC20(pairAddress()));
		_mint(lpStakingRewardsAddress(), LP_STAKING_SUPPLY);
		info.feeManager = address(new FeeManager());
		_approve(feeManagerAddress(), stakingRewardsAddress(), UINT_MAX);
		_approve(feeManagerAddress(), lpStakingRewardsAddress(), UINT_MAX);
	}

	function setOwner(address _owner) external _onlyOwner {
		info.owner = _owner;
	}

	function setFeeManager(address _feeManager) external _onlyOwner {
		info.feeManager = _feeManager;
	}

	function setClosingTime(uint256 _closingTime) external _onlyOwner {
		info.closingTime = _closingTime;
	}

	function setTransferFee(uint256 _transferFee) external _onlyOwner {
		require(_transferFee <= 100); // ≤10%
		info.transferFee = _transferFee;
	}

	function setFeeManagerPercent(uint256 _feeManagerPercent) external _onlyOwner {
		require(_feeManagerPercent <= 100);
		info.feeManagerPercent = _feeManagerPercent;
	}

	function setWhitelisted(address _address, bool _fromWhitelisted, bool _toWhitelisted) external _onlyOwner {
		info.fromWhitelist[_address] = _fromWhitelisted;
		info.toWhitelist[_address] = _toWhitelisted;
		emit WhitelistUpdated(_address, _fromWhitelisted, _toWhitelisted);
	}


	function disburse(uint256 _amount) external {
		require(_amount > 0);
		uint256 _balanceBefore = balanceOf(address(this));
		_transfer(msg.sender, address(this), _amount);
		uint256 _amountReceived = balanceOf(address(this)) - _balanceBefore;
		_disburse(_amountReceived);
	}

	function sweep() external {
		if (address(this).balance > 0) {
			teamAddress().transfer(address(this).balance);
		}
	}

	function upgradeReflink(uint256 _toLevel) external {
		uint256 _currentLevel = reflinkLevel(msg.sender);
		require(_currentLevel < _toLevel);
		uint256 _totalCost = 0;
		for (uint256 i = _currentLevel; i < _toLevel; i++) {
			_totalCost += upgradeCost(i);
		}
		burn(_totalCost);
		info.users[msg.sender].reflinkLevel = _toLevel;
	}

	function unlock(address _account, address payable _referrer) external payable {
		require(block.timestamp < closingTime());
		require(!isUnlocked(_account));
		require(msg.value == SERVICE_FEE);
		uint256 _refFee = 0;
		if (_referrer != address(0x0)) {
			_refFee = SERVICE_FEE * reflinkPercent(_referrer) / 100;
			!_referrer.send(_refFee);
			emit ReflinkRewards(_referrer, _refFee);
		}
		uint256 _remaining = SERVICE_FEE - _refFee;
		teamAddress().transfer(_remaining);
		emit ReflinkRewards(teamAddress(), _remaining);
		info.users[_account].unlocked = true;
	}
	
	function claim(address _account, uint256[9] calldata _data, bytes32[] calldata _proof) external {
		// Data array in format: (index, amount, totalFees, failFees, totalGas, avgGwei, totalDonated, totalTxs, failTxs)
		claimWTF(_account, _data, _proof);
		claimNFT(_account, _data, _proof);
	}
	
	function claimWTF(address _account, uint256[9] calldata _data, bytes32[] calldata _proof) public {
		require(isOpen());
		require(isUnlocked(_account));
		uint256 _index = _data[0];
		uint256 _amount = _data[1];
		require(!isClaimedWTF(_index));
		require(_verify(_proof, keccak256(abi.encodePacked(_account, _data))));
		uint256 _claimedWordIndex = _index / 256;
		uint256 _claimedBitIndex = _index % 256;
		info.claimedWTFBitMap[_claimedWordIndex] = info.claimedWTFBitMap[_claimedWordIndex] | (1 << _claimedBitIndex);
		_mint(_account, _amount);
	}

	function claimNFT(address _account, uint256[9] calldata _data, bytes32[] calldata _proof) public {
		require(isOpen());
		require(isUnlocked(_account));
		uint256 _index = _data[0];
		require(!isClaimedNFT(_index));
		require(_verify(_proof, keccak256(abi.encodePacked(_account, _data))));
		uint256 _claimedWordIndex = _index / 256;
		uint256 _claimedBitIndex = _index % 256;
		info.claimedNFTBitMap[_claimedWordIndex] = info.claimedNFTBitMap[_claimedWordIndex] | (1 << _claimedBitIndex);
		info.nft.mint(_account, _data[2], _data[3], _data[4], _data[5], _data[6], _data[7], _data[8]);
	}

	function claimRewards() external {
		boostRewards();
		uint256 _rewards = rewardsOf(msg.sender);
		if (_rewards > 0) {
			info.users[msg.sender].scaledPayout += int256(_rewards * FLOAT_SCALAR);
			_transfer(address(this), msg.sender, _rewards);
			emit ClaimRewards(msg.sender, _rewards);
		}
	}

	function boostRewards() public {
		address _this = address(this);
		uint256 _rewards = rewardsOf(_this);
		if (_rewards > 0) {
			info.users[_this].scaledPayout += int256(_rewards * FLOAT_SCALAR);
			_disburse(_rewards);
			emit ClaimRewards(_this, _rewards);
		}
	}

	function burn(uint256 _tokens) public {
		require(balanceOf(msg.sender) >= _tokens);
		info.totalSupply -= _tokens;
		info.users[msg.sender].balance -= _tokens;
		info.users[msg.sender].scaledPayout -= int256(_tokens * info.scaledRewardsPerToken);
		emit Transfer(msg.sender, address(0x0), _tokens);
	}

	function transfer(address _to, uint256 _tokens) external returns (bool) {
		return _transfer(msg.sender, _to, _tokens);
	}

	function approve(address _spender, uint256 _tokens) external returns (bool) {
		return _approve(msg.sender, _spender, _tokens);
	}

	function transferFrom(address _from, address _to, uint256 _tokens) external returns (bool) {
		uint256 _allowance = allowance(_from, msg.sender);
		require(_allowance >= _tokens);
		if (_allowance != UINT_MAX) {
			info.users[_from].allowance[msg.sender] -= _tokens;
		}
		return _transfer(_from, _to, _tokens);
	}

	function transferAndCall(address _to, uint256 _tokens, bytes calldata _data) external returns (bool) {
		uint256 _balanceBefore = balanceOf(_to);
		_transfer(msg.sender, _to, _tokens);
		uint256 _tokensReceived = balanceOf(_to) - _balanceBefore;
		uint32 _size;
		assembly {
			_size := extcodesize(_to)
		}
		if (_size > 0) {
			require(Callable(_to).tokenCallback(msg.sender, _tokensReceived, _data));
		}
		return true;
	}
	

	function pairAddress() public view returns (address) {
		return address(info.pair);
	}

	function nftAddress() external view returns (address) {
		return address(info.nft);
	}

	function teamAddress() public view returns (address payable) {
		return payable(address(info.team));
	}

	function treasuryAddress() public view returns (address) {
		return address(info.treasury);
	}

	function stakingRewardsAddress() public view returns (address) {
		return address(info.stakingRewards);
	}

	function lpStakingRewardsAddress() public view returns (address) {
		return address(info.lpStakingRewards);
	}

	function feeManagerAddress() public view returns (address) {
		return info.feeManager;
	}

	function owner() public view returns (address) {
		return info.owner;
	}

	function transferFee() public view returns (uint256) {
		return info.transferFee;
	}

	function feeManagerPercent() public view returns (uint256) {
		return info.feeManagerPercent;
	}

	function isFromWhitelisted(address _address) public view returns (bool) {
		return info.fromWhitelist[_address];
	}

	function isToWhitelisted(address _address) public view returns (bool) {
		return info.toWhitelist[_address];
	}

	function merkleRoot() public view returns (bytes32) {
		return info.merkleRoot;
	}

	function openingTime() public view returns (uint256) {
		return info.openingTime;
	}

	function closingTime() public view returns (uint256) {
		return info.closingTime;
	}

	function isOpen() public view returns (bool) {
		return block.timestamp > openingTime() && block.timestamp < closingTime();
	}

	function isUnlocked(address _user) public view returns (bool) {
		return info.users[_user].unlocked;
	}

	function isClaimedWTF(uint256 _index) public view returns (bool) {
		uint256 _claimedWordIndex = _index / 256;
		uint256 _claimedBitIndex = _index % 256;
		uint256 _claimedWord = info.claimedWTFBitMap[_claimedWordIndex];
		uint256 _mask = (1 << _claimedBitIndex);
		return _claimedWord & _mask == _mask;
	}

	function isClaimedNFT(uint256 _index) public view returns (bool) {
		uint256 _claimedWordIndex = _index / 256;
		uint256 _claimedBitIndex = _index % 256;
		uint256 _claimedWord = info.claimedNFTBitMap[_claimedWordIndex];
		uint256 _mask = (1 << _claimedBitIndex);
		return _claimedWord & _mask == _mask;
	}
	
	function totalSupply() public view returns (uint256) {
		return info.totalSupply;
	}

	function balanceOf(address _user) public view returns (uint256) {
		return info.users[_user].balance;
	}

	function rewardsOf(address _user) public view returns (uint256) {
		return uint256(int256(info.scaledRewardsPerToken * balanceOf(_user)) - info.users[_user].scaledPayout) / FLOAT_SCALAR;
	}

	function allowance(address _user, address _spender) public view returns (uint256) {
		return info.users[_user].allowance[_spender];
	}

	function reflinkLevel(address _user) public view returns (uint256) {
		return info.users[_user].reflinkLevel;
	}

	function reflinkPercent(address _user) public view returns (uint256) {
		return 10 * (reflinkLevel(_user) + 1);
	}

	function upgradeCost(uint256 _reflinkLevel) public pure returns (uint256) {
		require(_reflinkLevel < 4);
		return BASE_UPGRADE_COST * 10**_reflinkLevel;
	}

	function reflinkInfoFor(address _user) external view returns (uint256 balance, uint256 level, uint256 percent) {
		return (balanceOf(_user), reflinkLevel(_user), reflinkPercent(_user));
	}

	function claimInfoFor(uint256 _index, address _user) external view returns (uint256 openTime, uint256 closeTime, bool unlocked, bool claimedWTF, bool claimedNFT, uint256 wethReserve, uint256 wtfReserve) {
		openTime = openingTime();
		closeTime = closingTime();
		unlocked = isUnlocked(_user);
		claimedWTF = isClaimedWTF(_index);
		claimedNFT = isClaimedNFT(_index);
		( , , wethReserve, wtfReserve, , , ) = allInfoFor(address(0x0));
	}

	function allInfoFor(address _user) public view returns (uint256 totalTokens, uint256 totalLPTokens, uint256 wethReserve, uint256 wtfReserve, uint256 userBalance, uint256 userRewards, uint256 userLPBalance) {
		totalTokens = totalSupply();
		totalLPTokens = info.pair.totalSupply();
		(uint256 _res0, uint256 _res1, ) = info.pair.getReserves();
		wethReserve = info.weth0 ? _res0 : _res1;
		wtfReserve = info.weth0 ? _res1 : _res0;
		userBalance = balanceOf(_user);
		userRewards = rewardsOf(_user);
		userLPBalance = info.pair.balanceOf(_user);
	}


	function _mint(address _account, uint256 _amount) internal {
		info.totalSupply += _amount;
		info.users[_account].balance += _amount;
		info.users[_account].scaledPayout += int256(_amount * info.scaledRewardsPerToken);
		emit Transfer(address(0x0), _account, _amount);
	}
	
	function _approve(address _owner, address _spender, uint256 _tokens) internal returns (bool) {
		info.users[_owner].allowance[_spender] = _tokens;
		emit Approval(_owner, _spender, _tokens);
		return true;
	}
	
	function _transfer(address _from, address _to, uint256 _tokens) internal returns (bool) {
		require(balanceOf(_from) >= _tokens);
		info.users[_from].balance -= _tokens;
		info.users[_from].scaledPayout -= int256(_tokens * info.scaledRewardsPerToken);
		uint256 _fee = 0;
		if (!_isExcludedFromFee(_from, _to)) {
			_fee = _tokens * transferFee() / TRANSFER_FEE_SCALE;
			address _this = address(this);
			info.users[_this].balance += _fee;
			info.users[_this].scaledPayout += int256(_fee * info.scaledRewardsPerToken);
			emit Transfer(_from, _this, _fee);
		}
		uint256 _transferred = _tokens - _fee;
		info.users[_to].balance += _transferred;
		info.users[_to].scaledPayout += int256(_transferred * info.scaledRewardsPerToken);
		emit Transfer(_from, _to, _transferred);
		if (_fee > 0) {
			uint256 _feeManagerRewards = _fee * feeManagerPercent() / 100;
			info.users[feeManagerAddress()].scaledPayout -= int256(_feeManagerRewards * FLOAT_SCALAR);
			_disburse(_fee - _feeManagerRewards);
		}
		return true;
	}

	function _disburse(uint256 _amount) internal {
		if (_amount > 0) {
			info.scaledRewardsPerToken += _amount * FLOAT_SCALAR / totalSupply();
			emit Reward(_amount);
		}
	}


	function _isExcludedFromFee(address _from, address _to) internal view returns (bool) {
		return isFromWhitelisted(_from) || isToWhitelisted(_to)
			|| _from == address(this) || _to == address(this)
			|| _from == feeManagerAddress() || _to == feeManagerAddress()
			|| _from == treasuryAddress() || _to == treasuryAddress()
			|| _from == stakingRewardsAddress() || _to == stakingRewardsAddress()
			|| _from == lpStakingRewardsAddress() || _to == lpStakingRewardsAddress();
	}
	
	function _verify(bytes32[] memory _proof, bytes32 _leaf) internal view returns (bool) {
		bytes32 _computedHash = _leaf;
		for (uint256 i = 0; i < _proof.length; i++) {
			bytes32 _proofElement = _proof[i];
			if (_computedHash <= _proofElement) {
				_computedHash = keccak256(abi.encodePacked(_computedHash, _proofElement));
			} else {
				_computedHash = keccak256(abi.encodePacked(_proofElement, _computedHash));
			}
		}
		return _computedHash == merkleRoot();
	}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalFees","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"failFees","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalGas","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"avgGwei","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalDonated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalTxs","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"failTxs","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"allInfoFor","outputs":[{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"ownerBalance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_approved","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getAvgGwei","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getFailFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getFailTxs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint256","name":"_limit","type":"uint256"},{"internalType":"uint256","name":"_page","type":"uint256"},{"internalType":"bool","name":"_isAsc","type":"bool"}],"name":"getOwnerTokensTable","outputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"address[]","name":"approveds","type":"address[]"},{"internalType":"address[]","name":"users","type":"address[]"},{"internalType":"uint256[7][]","name":"compressedInfos","type":"uint256[7][]"},{"internalType":"uint256","name":"totalTokens","type":"uint256"},{"internalType":"uint256","name":"totalPages","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getToken","outputs":[{"internalType":"address","name":"tokenOwner","type":"address"},{"internalType":"address","name":"approved","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256[7]","name":"compressedInfo","type":"uint256[7]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getTokenCompressedInfo","outputs":[{"internalType":"uint256[7]","name":"compressedInfo","type":"uint256[7]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"getTokens","outputs":[{"internalType":"address[]","name":"owners","type":"address[]"},{"internalType":"address[]","name":"approveds","type":"address[]"},{"internalType":"address[]","name":"users","type":"address[]"},{"internalType":"uint256[7][]","name":"compressedInfos","type":"uint256[7][]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_limit","type":"uint256"},{"internalType":"uint256","name":"_page","type":"uint256"},{"internalType":"bool","name":"_isAsc","type":"bool"}],"name":"getTokensTable","outputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"address[]","name":"owners","type":"address[]"},{"internalType":"address[]","name":"approveds","type":"address[]"},{"internalType":"address[]","name":"users","type":"address[]"},{"internalType":"uint256[7][]","name":"compressedInfos","type":"uint256[7][]"},{"internalType":"uint256","name":"totalTokens","type":"uint256"},{"internalType":"uint256","name":"totalPages","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getTotalDonated","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getTotalFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getTotalGas","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getTotalTxs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getUser","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_totalFees","type":"uint256"},{"internalType":"uint256","name":"_failFees","type":"uint256"},{"internalType":"uint256","name":"_totalGas","type":"uint256"},{"internalType":"uint256","name":"_avgGwei","type":"uint256"},{"internalType":"uint256","name":"_totalDonated","type":"uint256"},{"internalType":"uint256","name":"_totalTxs","type":"uint256"},{"internalType":"uint256","name":"_failTxs","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Metadata","name":"_metadata","type":"address"}],"name":"setMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"tokenIdOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wtfAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

608060405234801561001057600080fd5b503060405161001e90610156565b6001600160a01b039091168152602001604051809103906000f08015801561004a573d6000803e3d6000fd5b50600380546001600160a01b03929092166001600160a01b0319928316179055600480548216331790556005805490911673dee79ed62b42e30ea7ebb6f1b7a3f04143d18b7f17905560066020527f477a984de5936bcb02475f64e0ea676103106ac0785c67bf7e9e846450b51ef6805460ff1990811660019081179092557fd544553a2e70858ffdf1e1169f6f124859d29ddf2686bcabf4e6f71bc630442280548216831790557fcc41b8fe3dd37df8e4a56c49f4e83a8fb6899f1fe8f1ddc40678281e8ec62212805482168317905563780e9d6360e01b6000527fa99870648958e45dc5b37a02b811cf5f899ba384167c205b3dcb1f6df5e4737280549091169091179055610164565b612da180620021d083390190565b61205c80620001746000396000f3fe608060405234801561001057600080fd5b50600436106102275760003560e01c8063767bbd5b11610130578063b0467deb116100b8578063e4b50cb81161007c578063e4b50cb81461051a578063e985e9c51461053d578063f00637951461057a578063f3cb83851461059f578063f5fe58b8146105b257600080fd5b8063b0467deb146104bb578063b3a7eb59146104ce578063b88d4fde146104e1578063c87b56dd146104f4578063dfe6e5121461050757600080fd5b8063a22cb465116100ff578063a22cb4651461044f578063a3739f7114610462578063a46a932f14610475578063a9e566c014610488578063ab2a1941146104a857600080fd5b8063767bbd5b14610410578063773c02d4146104235780638da5cb5b1461043657806395d89b411461044757600080fd5b806332ba0a1e116101b35780636352211e116101825780636352211e1461038c5780636bd5ff2f1461039f5780636eb3500d146103c55780636ff92f50146103d657806370a08231146103e757600080fd5b806332ba0a1e1461031b57806342842e0e1461033e5780634f6ccce71461035157806357f6b8121461036457600080fd5b8063113f2d9e116101fa578063113f2d9e146102b957806313af4035146102da57806318160ddd146102ed57806323b872dd146102f55780632f745c591461030857600080fd5b806301ffc9a71461022c57806306fdde0314610264578063081812fc14610279578063095ea7b3146102a4575b600080fd5b61024f61023a3660046117ca565b60066020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b61026c6105c5565b60405161025b9190611843565b61028c610287366004611856565b61063c565b6040516001600160a01b03909116815260200161025b565b6102b76102b2366004611884565b61066a565b005b6102cc6102c7366004611856565b6106ec565b60405190815260200161025b565b6102b76102e83660046118b0565b610721565b6000546102cc565b6102b76103033660046118cd565b61075a565b6102cc610316366004611884565b61076a565b61032e610329366004611954565b6107bd565b60405161025b9493929190611a9a565b6102b761034c3660046118cd565b6109b5565b6102cc61035f366004611856565b6109d0565b6103776103723660046118b0565b6109e3565b6040805192835260208301919091520161025b565b61028c61039a366004611856565b610a11565b6103b26103ad366004611b07565b610a40565b60405161025b9796959493929190611b6c565b6003546001600160a01b031661028c565b6004546001600160a01b031661028c565b6102cc6103f53660046118b0565b6001600160a01b031660009081526002602052604090205490565b6102cc61041e366004611856565b610bcb565b6102cc6104313660046118b0565b610c00565b6005546001600160a01b031661028c565b61026c610c38565b6102b761045d366004611be4565b610c82565b6102cc610470366004611856565b610cef565b6102b7610483366004611c19565b610d1d565b61049b610496366004611856565b611035565b60405161025b9190611c77565b6102cc6104b6366004611856565b6110a1565b61028c6104c9366004611856565b6110d6565b6102cc6104dc366004611856565b611101565b6102b76104ef366004611cac565b611136565b61026c610502366004611856565b6111e7565b6102cc610515366004611856565b611259565b61052d610528366004611856565b611287565b60405161025b9493929190611d5a565b61024f61054b366004611d91565b6001600160a01b0391821660009081526002602081815260408084209490951683529201909152205460ff1690565b61058d610588366004611dca565b6112c7565b60405161025b96959493929190611e12565b6102b76105ad3660046118b0565b611468565b6102cc6105c0366004611856565b6114a1565b600354604080516306fdde0360e01b815290516060926001600160a01b0316916306fdde039160048083019260009291908290030181865afa15801561060f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106379190810190611e75565b905090565b60008054821061064b57600080fd5b506000908152600160205260409020600201546001600160a01b031690565b61067381610a11565b6001600160a01b0316336001600160a01b03161461069057600080fd5b60008181526001602052604080822060020180546001600160a01b0319166001600160a01b0386169081179091559051839233917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259190a45050565b6000805482106106fb57600080fd5b50600090815260016020526040902060050154600160c01b90046001600160401b031690565b6005546001600160a01b0316331461073857600080fd5b600580546001600160a01b0319166001600160a01b0392909216919091179055565b6107658383836114cf565b505050565b6001600160a01b038216600090815260026020526040812054821061078e57600080fd5b506001600160a01b03821660009081526002602090815260408083208484526001019091529020545b92915050565b606080606080600085519050806001600160401b038111156107e1576107e161190e565b60405190808252806020026020018201604052801561080a578160200160208202803683370190505b509450806001600160401b038111156108255761082561190e565b60405190808252806020026020018201604052801561084e578160200160208202803683370190505b509350806001600160401b038111156108695761086961190e565b604051908082528060200260200182016040528015610892578160200160208202803683370190505b509250806001600160401b038111156108ad576108ad61190e565b6040519080825280602002602001820160405280156108e657816020015b6108d3611793565b8152602001906001900390816108cb5790505b50915060005b818110156109ac5761091687828151811061090957610909611ee2565b6020026020010151611287565b89858151811061092857610928611ee2565b6020026020010189868151811061094157610941611ee2565b6020026020010189878151811061095a5761095a611ee2565b6020026020010189888151811061097357610973611ee2565b60209081029190910101939093526001600160a01b039384169092529282169052919091169052806109a481611f0e565b9150506108ec565b50509193509193565b61076583838360405180602001604052806000815250611136565b6000805482106109df57600080fd5b5090565b6000806109ef60005490565b6001600160a01b03841660009081526002602052604090205491509150915091565b600080548210610a2057600080fd5b50600090815260016020819052604090912001546001600160a01b031690565b606080606080606060008060008a11610a5857600080fd5b60005491508115610b9a57610a6d8a83611f3f565b15610a79576001610a7c565b60005b60ff16610a898b84611f53565b610a939190611f67565b9050808910610aa157600080fd5b6000610aad8a8c611f7f565b9050610aba600183611f9e565b8a148015610ad05750610acd8b84611f3f565b15155b15610ae257610adf8b84611f3f565b9a505b8a6001600160401b03811115610afa57610afa61190e565b604051908082528060200260200182016040528015610b23578160200160208202803683370190505b50975060005b8b811015610b9357610b648a610b5a57600182610b468588611f9e565b610b509190611f9e565b61035f9190611f9e565b61035f8284611f67565b898281518110610b7657610b76611ee2565b602090810291909101015280610b8b81611f0e565b915050610b29565b5050610bae565b506040805160008082526020820190925296505b610bb7876107bd565b999d929c50909a5098509195509350915050565b600080548210610bda57600080fd5b50600090815260016020526040902060030154600160801b90046001600160801b031690565b6001600160a01b03811660009081526002602052604081206004015480610c2657600080fd5b610c31600182611f9e565b9392505050565b600354604080516395d89b4160e01b815290516060926001600160a01b0316916395d89b419160048083019260009291908290030181865afa15801561060f573d6000803e3d6000fd5b3360008181526002602081815260408084206001600160a01b0388168086529301825292839020805460ff191686151590811790915592519283529092917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b600080548210610cfe57600080fd5b506000908152600160205260409020600501546001600160801b031690565b6004546001600160a01b03163314610d3457600080fd5b600080548180610d4383611f0e565b919050559050610d5260005490565b600060020160008b6001600160a01b03166001600160a01b031681526020019081526020016000206004018190555060008060010160008381526020019081526020016000209050898160000160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550898160010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550888160030160006101000a8154816001600160801b0302191690836001600160801b03160217905550878160030160106101000a8154816001600160801b0302191690836001600160801b03160217905550868160040160006101000a8154816001600160801b0302191690836001600160801b03160217905550858160040160106101000a8154816001600160801b0302191690836001600160801b03160217905550848160050160006101000a8154816001600160801b0302191690836001600160801b03160217905550838160050160106101000a8154816001600160401b0302191690836001600160401b03160217905550828160050160186101000a8154816001600160401b0302191690836001600160401b0316021790555060008060020160008c6001600160a01b03166001600160a01b031681526020019081526020016000206000016000815480929190610f4890611f0e565b909155509050610f59816001611f67565b6001600160a01b038c166000818152600260209081526040808320888452600381018352818420959095558583526001909401905282812086905591518592907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4604080518b8152602081018b9052908101899052606081018890526080810187905260a0810186905260c0810185905283906001600160a01b038d16907f7cc62fff527c1d370281620d7f175585dac25557e85f8bedc8e74b984e3bf2e79060e00160405180910390a35050505050505050505050565b61103d611793565b611046826114a1565b815261105182610bcb565b602082015261105f82611259565b604082015261106d82611101565b606082015261107b82610cef565b6080820152611089826110a1565b60a0820152611097826106ec565b60c0820152919050565b6000805482106110b057600080fd5b50600090815260016020526040902060050154600160801b90046001600160401b031690565b6000805482106110e557600080fd5b506000908152600160205260409020546001600160a01b031690565b60008054821061111057600080fd5b50600090815260016020526040902060040154600160801b90046001600160801b031690565b6111418484846114cf565b823b63ffffffff8116156111e057604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290611181903390899088908890600401611fb5565b6020604051808303816000875af11580156111a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111c49190611ff2565b6001600160e01b03191663150b7a0260e01b146111e057600080fd5b5050505050565b60035460405163c87b56dd60e01b8152600481018390526060916001600160a01b03169063c87b56dd90602401600060405180830381865afa158015611231573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107b79190810190611e75565b60008054821061126857600080fd5b506000908152600160205260409020600401546001600160801b031690565b6000806000611294611793565b61129d85610a11565b6112a68661063c565b6112af876110d6565b6112b888611035565b93509350935093509193509193565b606080606080600080600089116112dd57600080fd5b6001600160a01b038a1660009081526002602052604090205491508115611436576113088983611f3f565b15611314576001611317565b60005b60ff166113248a84611f53565b61132e9190611f67565b905080881061133c57600080fd5b6000611348898b611f7f565b9050611355600183611f9e565b8914801561136b57506113688a84611f3f565b15155b1561137d5761137a8a84611f3f565b99505b896001600160401b038111156113955761139561190e565b6040519080825280602002602001820160405280156113be578160200160208202803683370190505b50965060005b8a81101561142f576114008c8a6113f6576001836113e28689611f9e565b6113ec9190611f9e565b6103169190611f9e565b6103168385611f67565b88828151811061141257611412611ee2565b60209081029190910101528061142781611f0e565b9150506113c4565b505061144a565b506040805160008082526020820190925295505b611453866107bd565b989d919c509a50969850919650949350505050565b6005546001600160a01b0316331461147f57600080fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6000805482106114b057600080fd5b506000908152600160205260409020600301546001600160801b031690565b60006114da82610a11565b905060006114e78361063c565b9050816001600160a01b0316856001600160a01b03161461150757600080fd5b336001600160a01b03831614806115265750336001600160a01b038216145b8061155657506001600160a01b0382166000908152600260208181526040808420338552909201905290205460ff165b61155f57600080fd5b60008381526001602081905260409091200180546001600160a01b0319166001600160a01b03868116919091179091558116156115e25760008381526001602052604080822060020180546001600160a01b03191690555184919081907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925908290a45b6001600160a01b038516600090815260026020908152604080832086845260030190915281205461161590600190611f9e565b6001600160a01b03871660009081526002602052604081208054929350909160019182019183916116469190611f9e565b815260208082019290925260409081016000908120546001600160a01b038b168252600284528282208683526001908101909452919020819055915061168d908390611f67565b6001600160a01b038816600081815260026020818152604080842087855260038101835290842095909555928252909152815491906116cb8361200f565b90915550506001600160a01b0380881660009081526002602081815260408084208a85526003018252808420849055938a168352529081208054908261171083611f0e565b909155509050611721816001611f67565b6001600160a01b0380891660008181526002602090815260408083208c845260038101835281842096909655868352600190950190528381208a90559251899391928c16917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a45050505050505050565b6040518060e001604052806007906020820280368337509192915050565b6001600160e01b0319811681146117c757600080fd5b50565b6000602082840312156117dc57600080fd5b8135610c31816117b1565b60005b838110156118025781810151838201526020016117ea565b83811115611811576000848401525b50505050565b6000815180845261182f8160208601602086016117e7565b601f01601f19169290920160200192915050565b602081526000610c316020830184611817565b60006020828403121561186857600080fd5b5035919050565b6001600160a01b03811681146117c757600080fd5b6000806040838503121561189757600080fd5b82356118a28161186f565b946020939093013593505050565b6000602082840312156118c257600080fd5b8135610c318161186f565b6000806000606084860312156118e257600080fd5b83356118ed8161186f565b925060208401356118fd8161186f565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561194c5761194c61190e565b604052919050565b6000602080838503121561196757600080fd5b82356001600160401b038082111561197e57600080fd5b818501915085601f83011261199257600080fd5b8135818111156119a4576119a461190e565b8060051b91506119b5848301611924565b81815291830184019184810190888411156119cf57600080fd5b938501935b838510156119ed578435825293850193908501906119d4565b98975050505050505050565b600081518084526020808501945080840160005b83811015611a325781516001600160a01b031687529582019590820190600101611a0d565b509495945050505050565b8060005b6007811015611811578151845260209384019390910190600101611a41565b600081518084526020808501945080840160005b83811015611a3257611a87878351611a3d565b60e0969096019590820190600101611a74565b608081526000611aad60808301876119f9565b8281036020840152611abf81876119f9565b90508281036040840152611ad381866119f9565b90508281036060840152611ae78185611a60565b979650505050505050565b80358015158114611b0257600080fd5b919050565b600080600060608486031215611b1c57600080fd5b8335925060208401359150611b3360408501611af2565b90509250925092565b600081518084526020808501945080840160005b83811015611a3257815187529582019590820190600101611b50565b60e081526000611b7f60e083018a611b3c565b8281036020840152611b91818a6119f9565b90508281036040840152611ba581896119f9565b90508281036060840152611bb981886119f9565b90508281036080840152611bcd8187611a60565b60a0840195909552505060c0015295945050505050565b60008060408385031215611bf757600080fd5b8235611c028161186f565b9150611c1060208401611af2565b90509250929050565b600080600080600080600080610100898b031215611c3657600080fd5b8835611c418161186f565b9a60208a01359a5060408a013599606081013599506080810135985060a0810135975060c0810135965060e00135945092505050565b60e081016107b78284611a3d565b60006001600160401b03821115611c9e57611c9e61190e565b50601f01601f191660200190565b60008060008060808587031215611cc257600080fd5b8435611ccd8161186f565b93506020850135611cdd8161186f565b92506040850135915060608501356001600160401b03811115611cff57600080fd5b8501601f81018713611d1057600080fd5b8035611d23611d1e82611c85565b611924565b818152886020838501011115611d3857600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b6001600160a01b0385811682528481166020830152831660408201526101408101611d886060830184611a3d565b95945050505050565b60008060408385031215611da457600080fd5b8235611daf8161186f565b91506020830135611dbf8161186f565b809150509250929050565b60008060008060808587031215611de057600080fd5b8435611deb8161186f565b93506020850135925060408501359150611e0760608601611af2565b905092959194509250565b60c081526000611e2560c0830189611b3c565b8281036020840152611e3781896119f9565b90508281036040840152611e4b81886119f9565b90508281036060840152611e5f8187611a60565b6080840195909552505060a00152949350505050565b600060208284031215611e8757600080fd5b81516001600160401b03811115611e9d57600080fd5b8201601f81018413611eae57600080fd5b8051611ebc611d1e82611c85565b818152856020838501011115611ed157600080fd5b611d888260208301602086016117e7565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415611f2257611f22611ef8565b5060010190565b634e487b7160e01b600052601260045260246000fd5b600082611f4e57611f4e611f29565b500690565b600082611f6257611f62611f29565b500490565b60008219821115611f7a57611f7a611ef8565b500190565b6000816000190483118215151615611f9957611f99611ef8565b500290565b600082821015611fb057611fb0611ef8565b500390565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611fe890830184611817565b9695505050505050565b60006020828403121561200457600080fd5b8151610c31816117b1565b60008161201e5761201e611ef8565b50600019019056fea264697066735822122012b4dd25fc2261f595a9d722f269b7d04e7f63401ca7c429ef3f73854b39eb7764736f6c634300080b003360c0604052600c60808190526b1999595ccb9ddd198813919560a21b60a09081526200002f9160009190620000d5565b50604080518082019091526008808252673332b2b9973bba3360c11b60209092019182526200006191600191620000d5565b503480156200006f57600080fd5b5060405162002da138038062002da183398101604081905262000092916200017b565b600280546001600160a01b039092166001600160a01b03199283161790556003805490911673e89b5b2770aa1a6bcfac6f3517510ab8e9146651179055620001ea565b828054620000e390620001ad565b90600052602060002090601f01602090048101928262000107576000855562000152565b82601f106200012257805160ff191683800117855562000152565b8280016001018555821562000152579182015b828111156200015257825182559160200191906001019062000135565b506200016092915062000164565b5090565b5b8082111562000160576000815560010162000165565b6000602082840312156200018e57600080fd5b81516001600160a01b0381168114620001a657600080fd5b9392505050565b600181811c90821680620001c257607f821691505b60208210811415620001e457634e487b7160e01b600052602260045260246000fd5b50919050565b612ba780620001fa6000396000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c80637dc0d1d0116100665780637dc0d1d01461010957806395d89b411461011c578063be985ac914610124578063c1be1fc714610137578063c87b56dd1461014a57600080fd5b806306fdde031461009857806347ccca02146100b6578063530e784f146100e157806375f6b112146100f6575b600080fd5b6100a061015d565b6040516100ad91906115be565b60405180910390f35b6002546100c9906001600160a01b031681565b6040516001600160a01b0390911681526020016100ad565b6100f46100ef366004611609565b6101eb565b005b6100a0610104366004611626565b6102a1565b6003546100c9906001600160a01b031681565b6100a06108a7565b6100a061013236600461167b565b6108b4565b6100a0610145366004611694565b6109c9565b6100a061015836600461167b565b610cdb565b6000805461016a906116fc565b80601f0160208091040260200160405190810160405280929190818152602001828054610196906116fc565b80156101e35780601f106101b8576101008083540402835291602001916101e3565b820191906000526020600020905b8154815290600101906020018083116101c657829003601f168201915b505050505081565b600260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561023e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102629190611731565b6001600160a01b0316336001600160a01b03161461027f57600080fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b606060405160200161035c907f3c73766720786d6c6e733d27687474703a2f2f7777772e77332e6f72672f323081527f30302f737667272076657273696f6e3d27312e3127207072657365727665417360208201527f70656374526174696f3d27784d6964594d6964206d656574272076696577426f60408201527f783d273020302035313220353132272077696474683d2731303025272068656960608201526a33b43a1e9398981812939f60a91b6080820152608b0190565b60405160208183030381529060405290508060405160200161037e919061174e565b6040516020818303038152906040529050806040516020016103a09190611814565b6040516020818303038152906040529050806040516020016103c29190611870565b60408051601f198184030181529190529050881561065057806103ec8a6012600560016000610e20565b6040516020016103fd929190611923565b60405160208183030381529060405290508060405160200161041f91906119b9565b6040516020818303038152906040529050806040516020016104419190611a16565b60408051601f19818403018152919052905080610480670de0b6b3a764000061046a858d611a84565b6104749190611ab9565b60126002600180610e20565b604051602001610491929190611acd565b6040516020818303038152906040529050806104b38860008060016000610e20565b6040516020016104c4929190611b43565b6040516020818303038152906040529050806104e68560008060016000610e20565b6040516020016104f7929190611bc7565b6040516020818303038152906040529050808460011461053057604051806040016040528060018152602001607360f81b815250610541565b604051806020016040528060008152505b604051602001610552929190611c4e565b604051602081830303815290604052905080610575876009600360016000610e20565b604051602001610586929190611cd1565b6040516020818303038152906040529050806105a88460008060016000610e20565b6040516020016105b9929190611d5b565b60405160208183030381529060405290508088600014610608576105e4896012600560016000610e20565b6040516020016105f49190611ddd565b604051602081830303815290604052610629565b604051806040016040528060078152602001666e6f7468696e6760c81b8152505b60405160200161063a929190611e08565b6040516020818303038152906040529050610673565b806040516020016106619190611e9c565b60405160208183030381529060405290505b84156108795760005b61069661068f655af3107a400088611ab9565b600a611163565b81116108775760005b6004811015610864576000600282106106d357604051806040016040528060038152602001621a1c9b60e91b8152506106ef565b60405180604001604052806002815260200161189b60f11b8152505b6106fa600284611ef9565b15610720576040518060400160405280600381526020016206872760eb1b81525061073c565b60405180604001604052806002815260200161062760f31b8152505b60405160200161074d929190611f0d565b604051602081830303815290604052905083816002841061078757604051806040016040528060018152602001602d60f81b815250610798565b604051806020016040528060008152505b6107b16107a6876010611a84565b600080600080610e20565b6040516020016107c49493929190611f9b565b60408051601f19818403018152919052935082156108515783816107e9600285611ef9565b1561080d57604051806040016040528060018152602001602d60f81b81525061081e565b604051806020016040528060008152505b61082c6107a6876010611a84565b60405160200161083f9493929190612016565b60405160208183030381529060405293505b508061085c816120a4565b91505061069f565b508061086f816120a4565b91505061067c565b505b8060405160200161088a91906120bf565b604051602081830303815290604052905098975050505050505050565b6001805461016a906116fc565b6002546040516302a7959b60e61b8152600481018390526060916000916001600160a01b039091169063a9e566c09060240160e060405180830381865afa158015610903573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109279190612244565b80516020808301516040808501516060860151608087015160a088015160c08901516003548651634c6afee560e11b815296519a9b506109c29a9798959794969395929491936001600160a01b03909116926398d5fdca926004838101938290030181865afa15801561099e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101049190612276565b9392505050565b606060006109d88b60066111ad565b6109e18c61131d565b6109ea8d61131d565b6040516020016109fc9392919061228f565b604051602081830303815290604052905080610a26610a218c8c8c8c8c8c8c8c6102a1565b61142a565b604051602001610a37929190612389565b60408051601f1981840301815291905290508915610bfd5780610a618b6012600560006001610e20565b604051602001610a7292919061240b565b604051602081830303815290604052905080610a958a6012600560006001610e20565b604051602001610aa692919061247e565b604051602081830303815290604052905080610ac789600080600080610e20565b604051602001610ad89291906124d7565b604051602081830303815290604052905080610afb886009600560006001610e20565b604051602001610b0c929190612530565b604051602081830303815290604052905080610b2d86600080600080610e20565b604051602001610b3e9291906125a6565b604051602081830303815290604052905080610b5f85600080600080610e20565b604051602001610b70929190612622565b60408051601f19818403018152919052905080610ba06107a6610b996509184e72a0008e611ab9565b6002611163565b604051602001610bb192919061269f565b60408051601f19818403018152919052905080610bda6107a6610b996509184e72a0008d611ab9565b604051602001610beb92919061272c565b60405160208183030381529060405290505b8515610c81578060008b11610c215760405180602001604052806000815250610c3c565b604051806040016040528060018152602001600b60fa1b8152505b610c5d610c5261068f655af3107a40008b611ab9565b6107a69060016127b9565b604051602001610c6f939291906127d1565b60405160208183030381529060405290505b80604051602001610c929190612874565b6040516020818303038152906040529050610cac8161142a565b604051602001610cbc919061289a565b6040516020818303038152906040529150509998505050505050505050565b600254604051631c96a19760e31b81526004810183905260609160009182916001600160a01b03169063e4b50cb89060240161014060405180830381865afa158015610d2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d4f91906128df565b935093505050610e188282600060078110610d6c57610d6c612260565b6020020151836001602002015184600260200201518560036020020151866004602002015187600560200201518860066020020151600360009054906101000a90046001600160a01b03166001600160a01b03166398d5fdca6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610df4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101459190612276565b949350505050565b60606000848611610e315785610e33565b845b90506000818711610e45576000610e4f565b610e4f828861293d565b610e5a90600a612a3a565b610e649089611ab9565b905080610e8e57604051806040016040528060018152602001600360fc1b8152509250505061115a565b6001815b6009811115610eba57610ea6600a82611ab9565b905081610eb2816120a4565b925050610e92565b838211610ed157610ecc8460016127b9565b610ed3565b815b9050600086158015610eee5750610eeb8560016127b9565b82115b610ef9576000610f32565b846001610f06828561293d565b610f10919061293d565b11610f30576001610f21868461293d565b610f2b919061293d565b610f32565b845b905060005b610f41828461293d565b811015611153576000610f54858561293d565b8210610f9657600a6001610f68848761293d565b610f72919061293d565b610f7d90600a612a3a565b610f879088611ab9565b610f919190611ef9565b610f99565b60005b60408051600180825281830190925291925060009190602082018180368337019050509050610fc9826030612a46565b60f81b81600081518110610fdf57610fdf612260565b60200101906001600160f81b031916908160001a9053508881604051602001611009929190612a6b565b60408051601f1981840301815291905298506001611027898761293d565b611031919061293d565b83101561109c578a801561106f5750600361104c898761293d565b6110569190611ef9565b60036110638560016127b9565b61106d9190611ef9565b145b1561109757886040516020016110859190612a9a565b60405160208183030381529060405298505b61113e565b891580156110f257506001836110b2868861293d565b6110bc919061293d565b6110c6919061293d565b6110d190600a612a3a565b6110dc85600a612a3a565b6110e69089611ab9565b6110f09190611ef9565b155b156110fe575050611153565b600161110a898761293d565b611114919061293d565b83141561113e578860405160200161112c9190612abf565b60405160208183030381529060405298505b5050808061114b906120a4565b915050610f37565b5050505050505b95945050505050565b600080821161117157600080fd5b60005b61117f60018461293d565b8411156111a4576111908385611ab9565b93508061119c816120a4565b915050611174565b90505b92915050565b6060601482106111bc57600080fd5b50604080516020810190915260008082526111d68461131d565b905060006111e5846002611a84565b6111f09060026127b9565b905060005b611200856002611a84565b61120b9060026127b9565b811015611314576040805160018082528183019092526000916020820181803683370190505090508361123f8760026127b9565b8310611260578361125184602a6127b9565b61125b919061293d565b611262565b825b8151811061127257611272612260565b602001015160f81c60f81b8160008151811061129057611290612260565b60200101906001600160f81b031916908160001a90535084816040516020016112ba929190612a6b565b60408051601f1981840301815291905294506112d78660016127b9565b82141561130157846040516020016112ef9190612ae4565b60405160208183030381529060405294505b508061130c816120a4565b9150506111f5565b50505092915050565b604080518082019091526002815261060f60f31b602082015260005b6028811015611424576000601061135183602761293d565b61135c906004611a84565b856001600160a01b0316901c6113729190612b0b565b6040805160018082528183019092526001600160a01b0392909216925060009190602082018180368337019050509050600982116113b15760306113b4565b60575b6113be9083612a46565b60f81b816000815181106113d4576113d4612260565b60200101906001600160f81b031916908160001a90535083816040516020016113fe929190612a6b565b60405160208183030381529060405293505050808061141c906120a4565b915050611339565b50919050565b606081516000141561144a57505060408051602081019091526000815290565b6000604051806060016040528060408152602001612b32604091399050600060038451600261147991906127b9565b6114839190611ab9565b61148e906004611a84565b905061149b8160206127b9565b67ffffffffffffffff8111156114b3576114b36121b2565b6040519080825280601f01601f1916602001820160405280156114dd576020820181803683370190505b509250808352600182018485518101602086015b8183101561154b5760039283018051603f601282901c811687015160f890811b8552600c83901c8216880151811b6001860152600683901c8216880151811b60028601529116860151901b938201939093526004016114f1565b600388510660018114611565576002811461157657611582565b613d3d60f01b600119830152611582565b603d60f81b6000198301525b50505050505050919050565b60005b838110156115a9578181015183820152602001611591565b838111156115b8576000848401525b50505050565b60208152600082518060208401526115dd81604085016020870161158e565b601f01601f19169190910160400192915050565b6001600160a01b038116811461160657600080fd5b50565b60006020828403121561161b57600080fd5b81356111a4816115f1565b600080600080600080600080610100898b03121561164357600080fd5b505086359860208801359850604088013597606081013597506080810135965060a0810135955060c0810135945060e0013592509050565b60006020828403121561168d57600080fd5b5035919050565b60008060008060008060008060006101208a8c0312156116b357600080fd5b89356116be816115f1565b9b60208b01359b5060408b01359a60608101359a506080810135995060a0810135985060c0810135975060e081013596506101000135945092505050565b600181811c9082168061171057607f821691505b6020821081141561142457634e487b7160e01b600052602260045260246000fd5b60006020828403121561174357600080fd5b81516111a4816115f1565b6000825161176081846020870161158e565b7f3c646566733e3c7374796c6520747970653d27746578742f637373273e7465789201918252507f747b746578742d616e63686f723a6d6964646c653b616c69676e6d656e742d6260208201527f6173656c696e653a63656e7472616c3b7d747370616e3e747370616e7b66696c60408201527f6c3a233033613966343b666f6e742d7765696768743a3730303b7d3c2f73747960608201526936329f1e17b232b3399f60b11b6080820152608a01919050565b6000825161182681846020870161158e565b7f3c726563742077696474683d273130302527206865696768743d27313030252792019182525071103334b6361e93919919191919191390179f60711b6020820152603201919050565b6000825161188281846020870161158e565b7f3c7465787420783d27302720793d2732353627207472616e73666f726d3d27749201918252507f72616e736c6174652832353629272066696c6c3d27236630663866662720666f60208201527f6e742d66616d696c793d27417269616c2c73616e732d73657269662720666f6e60408201527f742d7765696768743d273630302720666f6e742d73697a653d273330273e00006060820152607e01919050565b6000835161193581846020880161158e565b80830190507f3c747370616e20783d2730272064793d272d313833273e596f75207370656e74815269101e3a39b830b71f674f60b11b6020820152835161198381602a84016020880161158e565b7f3c2f747370616e3e206f6e206761733c2f747370616e3e000000000000000000602a9290910191820152604101949350505050565b600082516119cb81846020870161158e565b7f3c747370616e20783d2730272064793d273335273e6265666f726520626c6f6392019182525072359018999c989b1a1a98171e17ba39b830b71f60691b6020820152603301919050565b60008251611a2881846020870161158e565b7f3c747370616e20783d2730272064793d273335273e5269676874206e6f772c209201918252506d3a3430ba13b99e17ba39b830b71f60911b6020820152602e01919050565b634e487b7160e01b600052601160045260246000fd5b6000816000190483118215151615611a9e57611a9e611a6e565b500290565b634e487b7160e01b600052601260045260246000fd5b600082611ac857611ac8611aa3565b500490565b60008351611adf81846020880161158e565b7f3c747370616e20783d2730272064793d273335273e3c747370616e3e240000009083019081528351611b1981601d84016020880161158e565b701e17ba39b830b71f171e17ba39b830b71f60791b601d9290910191820152602e01949350505050565b60008351611b5581846020880161158e565b80830190507f3c747370616e20783d2730272064793d273730273e596f752075736564203c7481526439b830b71f60d91b60208201528351611b9e81602584016020880161158e565b6f1e17ba39b830b71f1e17ba39b830b71f60811b60259290910191820152603501949350505050565b60008351611bd981846020880161158e565b80830190507f3c747370616e20783d2730272064793d273335273e67617320746f2073656e64815267101e3a39b830b71f60c11b60208201528351611c2581602884016020880161158e565b6f1e17ba39b830b71f1e17ba39b830b71f60811b60289290910191820152603801949350505050565b60008351611c6081846020880161158e565b80830190507f3c747370616e20783d2730272064793d273335273e7472616e73616374696f6e81528351611c9b81602084016020880161158e565b7f2c207769746820616e20617665726167653c2f747370616e3e0000000000000060209290910191820152603901949350505050565b60008351611ce381846020880161158e565b80830190507f3c747370616e20783d2730272064793d273335273e7072696365206f66203c7481526439b830b71f60d91b60208201528351611d2c81602584016020880161158e565b751e17ba39b830b71f1023bbb2b4971e17ba39b830b71f60511b60259290910191820152603b01949350505050565b60008351611d6d81846020880161158e565b7f3c747370616e20783d2730272064793d273730273e3c747370616e3e000000009083019081528351611da781601c84016020880161158e565b7f3c2f747370616e3e206f66207468656d206661696c65642c3c2f747370616e3e601c9290910191820152603c01949350505050565b61674f60f11b81528151600090611dfb81600285016020870161158e565b9190910160020192915050565b60008351611e1a81846020880161158e565b80830190507f3c747370616e20783d2730272064793d273335273e636f7374696e6720796f75815267101e3a39b830b71f60c11b60208201528351611e6681602884016020880161158e565b7f3c2f747370616e3e2e3c2f747370616e3e3c2f746578743e000000000000000060289290910191820152604001949350505050565b60008251611eae81846020870161158e565b7f3c747370616e20783d2730272064793d2738273e446964206e6f74207175616c9201918252507234b33c971e17ba39b830b71f1e17ba32bc3a1f60691b6020820152603301919050565b600082611f0857611f08611aa3565b500690565b683c7465787420783d2760b81b815260008351611f3181600985016020880161158e565b642720793d2760d81b6009918401918201528351611f5681600e84016020880161158e565b7f2720666f6e742d73697a653d27313027207472616e73666f726d3d277472616e600e9290910191820152650e6d8c2e8ca560d31b602e820152603401949350505050565b60008551611fad818460208a0161158e565b855190830190611fc1818360208a0161158e565b8551910190611fd481836020890161158e565b8451910190611fe781836020880161158e565b6214939f60e91b91019081526c714ed277dc479e17ba32bc3a1f60991b60038201526010019695505050505050565b60008551612028818460208a0161158e565b85519083019061203c818360208a0161158e565b610c0b60f21b9101908152845161205a81600284016020890161158e565b845191019061207081600284016020880161158e565b6214939f60e91b600292909101918201526c714ed277dc479e17ba32bc3a1f60991b60058201526012019695505050505050565b60006000198214156120b8576120b8611a6e565b5060010190565b600082516120d181846020870161158e565b7f3c7465787420783d27302720793d2735303027207472616e73666f726d3d27749201918252507f72616e736c6174652832353629272066696c6c3d27236630663866662720666f60208201527f6e742d66616d696c793d27417269616c2c73616e732d73657269662720666f6e60408201527f742d7765696768743d273630302720666f6e742d73697a653d273130273e3c7460608201527f7370616e3e666565733c747370616e3e2e7774663c2f747370616e3e3c2f74736080820152703830b71f1e17ba32bc3a1f1e17b9bb339f60791b60a082015260b101919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126121d957600080fd5b60405160e0810181811067ffffffffffffffff8211171561220a57634e487b7160e01b600052604160045260246000fd5b6040528060e084018581111561221f57600080fd5b845b81811015612239578051835260209283019201612221565b509195945050505050565b600060e0828403121561225657600080fd5b6109c283836121c8565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561228857600080fd5b5051919050565b683d913730b6b2911d1160b91b815283516000906122b481600985016020890161158e565b7f222c226465736372697074696f6e223a225b666565732e7774665d28687474706009918401918201527f733a2f2f666565732e7774662920736e617073686f7420617420626c6f636b2060298201526d313339313634353020666f72205b60901b6049820152845161232e81605784016020890161158e565b7f5d2868747470733a2f2f65746865727363616e2e696f2f616464726573732f0060579290910191820152835161236c81607684016020880161158e565b620a488b60ea1b6076929091019182015260790195945050505050565b6000835161239b81846020880161158e565b80830190507f22696d616765223a22646174613a696d6167652f7376672b786d6c3b626173658152620d8d0b60ea1b602082015283516123e281602384016020880161158e565b6f222c2261747472696275746573223a5b60801b60239290910191820152603301949350505050565b6000835161241d81846020880161158e565b80830190507f7b2274726169745f74797065223a22546f74616c2046656573222c2276616c7581526232911d60e91b6020820152835161246481602384016020880161158e565b607d60f81b60239290910191820152602401949350505050565b6000835161249081846020880161158e565b80830190507f2c7b2274726169745f74797065223a224661696c2046656573222c2276616c7581526232911d60e91b6020820152835161246481602384016020880161158e565b600083516124e981846020880161158e565b80830190507f2c7b2274726169745f74797065223a22546f74616c20476173222c2276616c7581526232911d60e91b6020820152835161246481602384016020880161158e565b6000835161254281846020880161158e565b80830190507f2c7b2274726169745f74797065223a22417665726167652047776569222c227681526530b63ab2911d60d11b6020820152835161258c81602684016020880161158e565b607d60f81b60269290910191820152602701949350505050565b600083516125b881846020880161158e565b80830190507f2c7b2274726169745f74797065223a22546f74616c205472616e73616374696f81526b37399116113b30b63ab2911d60a11b6020820152835161260881602c84016020880161158e565b607d60f81b602c9290910191820152602d01949350505050565b6000835161263481846020880161158e565b80830190507f2c7b2274726169745f74797065223a224661696c6564205472616e736163746981526c37b7399116113b30b63ab2911d60991b6020820152835161268581602d84016020880161158e565b607d60f81b602d9290910191820152602e01949350505050565b600083516126b181846020880161158e565b80830190507f2c7b22646973706c61795f74797065223a226e756d626572222c22747261697481527f5f74797065223a225370656e646572204c6576656c222c2276616c7565223a006020820152835161271281603f84016020880161158e565b607d60f81b603f9290910191820152604001949350505050565b6000835161273e81846020880161158e565b80830190507f2c7b22646973706c61795f74797065223a226e756d626572222c22747261697481527f5f74797065223a224f6f66204c6576656c222c2276616c7565223a00000000006020820152835161279f81603b84016020880161158e565b607d60f81b603b9290910191820152603c01949350505050565b600082198211156127cc576127cc611a6e565b500190565b600084516127e381846020890161158e565b8451908301906127f781836020890161158e565b8082019150507f7b22646973706c61795f74797065223a226e756d626572222c2274726169745f81527f74797065223a22446f6e61746f72204c6576656c222c2276616c7565223a00006020820152835161285981603e84016020880161158e565b607d60f81b603e9290910191820152603f0195945050505050565b6000825161288681846020870161158e565b615d7d60f01b920191825250600201919050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008152600082516128d281601d85016020870161158e565b91909101601d0192915050565b60008060008061014085870312156128f657600080fd5b8451612901816115f1565b6020860151909450612912816115f1565b6040860151909350612923816115f1565b915061293286606087016121c8565b905092959194509250565b60008282101561294f5761294f611a6e565b500390565b600181600019825b808611156129905782820483111561297657612976611a6e565b8086161561298357928202925b94851c949180029161295c565b50509250929050565b6000826129a8575060016111a7565b816129b5575060006111a7565b81600181146129cb57600281146129d5576129f1565b60019150506111a7565b60ff8411156129e6576129e6611a6e565b50506001821b6111a7565b5060208310610133831016604e8410600b8410161715612a14575081810a6111a7565b612a1e8383612954565b8060001904821115612a3257612a32611a6e565b029392505050565b60006109c28383612999565b600060ff821660ff84168060ff03821115612a6357612a63611a6e565b019392505050565b60008351612a7d81846020880161158e565b835190830190612a9181836020880161158e565b01949350505050565b60008251612aac81846020870161158e565b600b60fa1b920191825250600101919050565b60008251612ad181846020870161158e565b601760f91b920191825250600101919050565b60008251612af681846020870161158e565b6271405360e91b920191825250600301919050565b60006001600160a01b0383811680612b2557612b25611aa3565b9216919091069291505056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa26469706673582212208e2b5e515fb02168298df9697376a6434523e033f88d7913a9684bb0cf33e5e964736f6c634300080b0033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102275760003560e01c8063767bbd5b11610130578063b0467deb116100b8578063e4b50cb81161007c578063e4b50cb81461051a578063e985e9c51461053d578063f00637951461057a578063f3cb83851461059f578063f5fe58b8146105b257600080fd5b8063b0467deb146104bb578063b3a7eb59146104ce578063b88d4fde146104e1578063c87b56dd146104f4578063dfe6e5121461050757600080fd5b8063a22cb465116100ff578063a22cb4651461044f578063a3739f7114610462578063a46a932f14610475578063a9e566c014610488578063ab2a1941146104a857600080fd5b8063767bbd5b14610410578063773c02d4146104235780638da5cb5b1461043657806395d89b411461044757600080fd5b806332ba0a1e116101b35780636352211e116101825780636352211e1461038c5780636bd5ff2f1461039f5780636eb3500d146103c55780636ff92f50146103d657806370a08231146103e757600080fd5b806332ba0a1e1461031b57806342842e0e1461033e5780634f6ccce71461035157806357f6b8121461036457600080fd5b8063113f2d9e116101fa578063113f2d9e146102b957806313af4035146102da57806318160ddd146102ed57806323b872dd146102f55780632f745c591461030857600080fd5b806301ffc9a71461022c57806306fdde0314610264578063081812fc14610279578063095ea7b3146102a4575b600080fd5b61024f61023a3660046117ca565b60066020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b61026c6105c5565b60405161025b9190611843565b61028c610287366004611856565b61063c565b6040516001600160a01b03909116815260200161025b565b6102b76102b2366004611884565b61066a565b005b6102cc6102c7366004611856565b6106ec565b60405190815260200161025b565b6102b76102e83660046118b0565b610721565b6000546102cc565b6102b76103033660046118cd565b61075a565b6102cc610316366004611884565b61076a565b61032e610329366004611954565b6107bd565b60405161025b9493929190611a9a565b6102b761034c3660046118cd565b6109b5565b6102cc61035f366004611856565b6109d0565b6103776103723660046118b0565b6109e3565b6040805192835260208301919091520161025b565b61028c61039a366004611856565b610a11565b6103b26103ad366004611b07565b610a40565b60405161025b9796959493929190611b6c565b6003546001600160a01b031661028c565b6004546001600160a01b031661028c565b6102cc6103f53660046118b0565b6001600160a01b031660009081526002602052604090205490565b6102cc61041e366004611856565b610bcb565b6102cc6104313660046118b0565b610c00565b6005546001600160a01b031661028c565b61026c610c38565b6102b761045d366004611be4565b610c82565b6102cc610470366004611856565b610cef565b6102b7610483366004611c19565b610d1d565b61049b610496366004611856565b611035565b60405161025b9190611c77565b6102cc6104b6366004611856565b6110a1565b61028c6104c9366004611856565b6110d6565b6102cc6104dc366004611856565b611101565b6102b76104ef366004611cac565b611136565b61026c610502366004611856565b6111e7565b6102cc610515366004611856565b611259565b61052d610528366004611856565b611287565b60405161025b9493929190611d5a565b61024f61054b366004611d91565b6001600160a01b0391821660009081526002602081815260408084209490951683529201909152205460ff1690565b61058d610588366004611dca565b6112c7565b60405161025b96959493929190611e12565b6102b76105ad3660046118b0565b611468565b6102cc6105c0366004611856565b6114a1565b600354604080516306fdde0360e01b815290516060926001600160a01b0316916306fdde039160048083019260009291908290030181865afa15801561060f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106379190810190611e75565b905090565b60008054821061064b57600080fd5b506000908152600160205260409020600201546001600160a01b031690565b61067381610a11565b6001600160a01b0316336001600160a01b03161461069057600080fd5b60008181526001602052604080822060020180546001600160a01b0319166001600160a01b0386169081179091559051839233917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259190a45050565b6000805482106106fb57600080fd5b50600090815260016020526040902060050154600160c01b90046001600160401b031690565b6005546001600160a01b0316331461073857600080fd5b600580546001600160a01b0319166001600160a01b0392909216919091179055565b6107658383836114cf565b505050565b6001600160a01b038216600090815260026020526040812054821061078e57600080fd5b506001600160a01b03821660009081526002602090815260408083208484526001019091529020545b92915050565b606080606080600085519050806001600160401b038111156107e1576107e161190e565b60405190808252806020026020018201604052801561080a578160200160208202803683370190505b509450806001600160401b038111156108255761082561190e565b60405190808252806020026020018201604052801561084e578160200160208202803683370190505b509350806001600160401b038111156108695761086961190e565b604051908082528060200260200182016040528015610892578160200160208202803683370190505b509250806001600160401b038111156108ad576108ad61190e565b6040519080825280602002602001820160405280156108e657816020015b6108d3611793565b8152602001906001900390816108cb5790505b50915060005b818110156109ac5761091687828151811061090957610909611ee2565b6020026020010151611287565b89858151811061092857610928611ee2565b6020026020010189868151811061094157610941611ee2565b6020026020010189878151811061095a5761095a611ee2565b6020026020010189888151811061097357610973611ee2565b60209081029190910101939093526001600160a01b039384169092529282169052919091169052806109a481611f0e565b9150506108ec565b50509193509193565b61076583838360405180602001604052806000815250611136565b6000805482106109df57600080fd5b5090565b6000806109ef60005490565b6001600160a01b03841660009081526002602052604090205491509150915091565b600080548210610a2057600080fd5b50600090815260016020819052604090912001546001600160a01b031690565b606080606080606060008060008a11610a5857600080fd5b60005491508115610b9a57610a6d8a83611f3f565b15610a79576001610a7c565b60005b60ff16610a898b84611f53565b610a939190611f67565b9050808910610aa157600080fd5b6000610aad8a8c611f7f565b9050610aba600183611f9e565b8a148015610ad05750610acd8b84611f3f565b15155b15610ae257610adf8b84611f3f565b9a505b8a6001600160401b03811115610afa57610afa61190e565b604051908082528060200260200182016040528015610b23578160200160208202803683370190505b50975060005b8b811015610b9357610b648a610b5a57600182610b468588611f9e565b610b509190611f9e565b61035f9190611f9e565b61035f8284611f67565b898281518110610b7657610b76611ee2565b602090810291909101015280610b8b81611f0e565b915050610b29565b5050610bae565b506040805160008082526020820190925296505b610bb7876107bd565b999d929c50909a5098509195509350915050565b600080548210610bda57600080fd5b50600090815260016020526040902060030154600160801b90046001600160801b031690565b6001600160a01b03811660009081526002602052604081206004015480610c2657600080fd5b610c31600182611f9e565b9392505050565b600354604080516395d89b4160e01b815290516060926001600160a01b0316916395d89b419160048083019260009291908290030181865afa15801561060f573d6000803e3d6000fd5b3360008181526002602081815260408084206001600160a01b0388168086529301825292839020805460ff191686151590811790915592519283529092917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b600080548210610cfe57600080fd5b506000908152600160205260409020600501546001600160801b031690565b6004546001600160a01b03163314610d3457600080fd5b600080548180610d4383611f0e565b919050559050610d5260005490565b600060020160008b6001600160a01b03166001600160a01b031681526020019081526020016000206004018190555060008060010160008381526020019081526020016000209050898160000160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550898160010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550888160030160006101000a8154816001600160801b0302191690836001600160801b03160217905550878160030160106101000a8154816001600160801b0302191690836001600160801b03160217905550868160040160006101000a8154816001600160801b0302191690836001600160801b03160217905550858160040160106101000a8154816001600160801b0302191690836001600160801b03160217905550848160050160006101000a8154816001600160801b0302191690836001600160801b03160217905550838160050160106101000a8154816001600160401b0302191690836001600160401b03160217905550828160050160186101000a8154816001600160401b0302191690836001600160401b0316021790555060008060020160008c6001600160a01b03166001600160a01b031681526020019081526020016000206000016000815480929190610f4890611f0e565b909155509050610f59816001611f67565b6001600160a01b038c166000818152600260209081526040808320888452600381018352818420959095558583526001909401905282812086905591518592907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4604080518b8152602081018b9052908101899052606081018890526080810187905260a0810186905260c0810185905283906001600160a01b038d16907f7cc62fff527c1d370281620d7f175585dac25557e85f8bedc8e74b984e3bf2e79060e00160405180910390a35050505050505050505050565b61103d611793565b611046826114a1565b815261105182610bcb565b602082015261105f82611259565b604082015261106d82611101565b606082015261107b82610cef565b6080820152611089826110a1565b60a0820152611097826106ec565b60c0820152919050565b6000805482106110b057600080fd5b50600090815260016020526040902060050154600160801b90046001600160401b031690565b6000805482106110e557600080fd5b506000908152600160205260409020546001600160a01b031690565b60008054821061111057600080fd5b50600090815260016020526040902060040154600160801b90046001600160801b031690565b6111418484846114cf565b823b63ffffffff8116156111e057604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290611181903390899088908890600401611fb5565b6020604051808303816000875af11580156111a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111c49190611ff2565b6001600160e01b03191663150b7a0260e01b146111e057600080fd5b5050505050565b60035460405163c87b56dd60e01b8152600481018390526060916001600160a01b03169063c87b56dd90602401600060405180830381865afa158015611231573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107b79190810190611e75565b60008054821061126857600080fd5b506000908152600160205260409020600401546001600160801b031690565b6000806000611294611793565b61129d85610a11565b6112a68661063c565b6112af876110d6565b6112b888611035565b93509350935093509193509193565b606080606080600080600089116112dd57600080fd5b6001600160a01b038a1660009081526002602052604090205491508115611436576113088983611f3f565b15611314576001611317565b60005b60ff166113248a84611f53565b61132e9190611f67565b905080881061133c57600080fd5b6000611348898b611f7f565b9050611355600183611f9e565b8914801561136b57506113688a84611f3f565b15155b1561137d5761137a8a84611f3f565b99505b896001600160401b038111156113955761139561190e565b6040519080825280602002602001820160405280156113be578160200160208202803683370190505b50965060005b8a81101561142f576114008c8a6113f6576001836113e28689611f9e565b6113ec9190611f9e565b6103169190611f9e565b6103168385611f67565b88828151811061141257611412611ee2565b60209081029190910101528061142781611f0e565b9150506113c4565b505061144a565b506040805160008082526020820190925295505b611453866107bd565b989d919c509a50969850919650949350505050565b6005546001600160a01b0316331461147f57600080fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6000805482106114b057600080fd5b506000908152600160205260409020600301546001600160801b031690565b60006114da82610a11565b905060006114e78361063c565b9050816001600160a01b0316856001600160a01b03161461150757600080fd5b336001600160a01b03831614806115265750336001600160a01b038216145b8061155657506001600160a01b0382166000908152600260208181526040808420338552909201905290205460ff165b61155f57600080fd5b60008381526001602081905260409091200180546001600160a01b0319166001600160a01b03868116919091179091558116156115e25760008381526001602052604080822060020180546001600160a01b03191690555184919081907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925908290a45b6001600160a01b038516600090815260026020908152604080832086845260030190915281205461161590600190611f9e565b6001600160a01b03871660009081526002602052604081208054929350909160019182019183916116469190611f9e565b815260208082019290925260409081016000908120546001600160a01b038b168252600284528282208683526001908101909452919020819055915061168d908390611f67565b6001600160a01b038816600081815260026020818152604080842087855260038101835290842095909555928252909152815491906116cb8361200f565b90915550506001600160a01b0380881660009081526002602081815260408084208a85526003018252808420849055938a168352529081208054908261171083611f0e565b909155509050611721816001611f67565b6001600160a01b0380891660008181526002602090815260408083208c845260038101835281842096909655868352600190950190528381208a90559251899391928c16917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a45050505050505050565b6040518060e001604052806007906020820280368337509192915050565b6001600160e01b0319811681146117c757600080fd5b50565b6000602082840312156117dc57600080fd5b8135610c31816117b1565b60005b838110156118025781810151838201526020016117ea565b83811115611811576000848401525b50505050565b6000815180845261182f8160208601602086016117e7565b601f01601f19169290920160200192915050565b602081526000610c316020830184611817565b60006020828403121561186857600080fd5b5035919050565b6001600160a01b03811681146117c757600080fd5b6000806040838503121561189757600080fd5b82356118a28161186f565b946020939093013593505050565b6000602082840312156118c257600080fd5b8135610c318161186f565b6000806000606084860312156118e257600080fd5b83356118ed8161186f565b925060208401356118fd8161186f565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561194c5761194c61190e565b604052919050565b6000602080838503121561196757600080fd5b82356001600160401b038082111561197e57600080fd5b818501915085601f83011261199257600080fd5b8135818111156119a4576119a461190e565b8060051b91506119b5848301611924565b81815291830184019184810190888411156119cf57600080fd5b938501935b838510156119ed578435825293850193908501906119d4565b98975050505050505050565b600081518084526020808501945080840160005b83811015611a325781516001600160a01b031687529582019590820190600101611a0d565b509495945050505050565b8060005b6007811015611811578151845260209384019390910190600101611a41565b600081518084526020808501945080840160005b83811015611a3257611a87878351611a3d565b60e0969096019590820190600101611a74565b608081526000611aad60808301876119f9565b8281036020840152611abf81876119f9565b90508281036040840152611ad381866119f9565b90508281036060840152611ae78185611a60565b979650505050505050565b80358015158114611b0257600080fd5b919050565b600080600060608486031215611b1c57600080fd5b8335925060208401359150611b3360408501611af2565b90509250925092565b600081518084526020808501945080840160005b83811015611a3257815187529582019590820190600101611b50565b60e081526000611b7f60e083018a611b3c565b8281036020840152611b91818a6119f9565b90508281036040840152611ba581896119f9565b90508281036060840152611bb981886119f9565b90508281036080840152611bcd8187611a60565b60a0840195909552505060c0015295945050505050565b60008060408385031215611bf757600080fd5b8235611c028161186f565b9150611c1060208401611af2565b90509250929050565b600080600080600080600080610100898b031215611c3657600080fd5b8835611c418161186f565b9a60208a01359a5060408a013599606081013599506080810135985060a0810135975060c0810135965060e00135945092505050565b60e081016107b78284611a3d565b60006001600160401b03821115611c9e57611c9e61190e565b50601f01601f191660200190565b60008060008060808587031215611cc257600080fd5b8435611ccd8161186f565b93506020850135611cdd8161186f565b92506040850135915060608501356001600160401b03811115611cff57600080fd5b8501601f81018713611d1057600080fd5b8035611d23611d1e82611c85565b611924565b818152886020838501011115611d3857600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b6001600160a01b0385811682528481166020830152831660408201526101408101611d886060830184611a3d565b95945050505050565b60008060408385031215611da457600080fd5b8235611daf8161186f565b91506020830135611dbf8161186f565b809150509250929050565b60008060008060808587031215611de057600080fd5b8435611deb8161186f565b93506020850135925060408501359150611e0760608601611af2565b905092959194509250565b60c081526000611e2560c0830189611b3c565b8281036020840152611e3781896119f9565b90508281036040840152611e4b81886119f9565b90508281036060840152611e5f8187611a60565b6080840195909552505060a00152949350505050565b600060208284031215611e8757600080fd5b81516001600160401b03811115611e9d57600080fd5b8201601f81018413611eae57600080fd5b8051611ebc611d1e82611c85565b818152856020838501011115611ed157600080fd5b611d888260208301602086016117e7565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415611f2257611f22611ef8565b5060010190565b634e487b7160e01b600052601260045260246000fd5b600082611f4e57611f4e611f29565b500690565b600082611f6257611f62611f29565b500490565b60008219821115611f7a57611f7a611ef8565b500190565b6000816000190483118215151615611f9957611f99611ef8565b500290565b600082821015611fb057611fb0611ef8565b500390565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611fe890830184611817565b9695505050505050565b60006020828403121561200457600080fd5b8151610c31816117b1565b60008161201e5761201e611ef8565b50600019019056fea264697066735822122012b4dd25fc2261f595a9d722f269b7d04e7f63401ca7c429ef3f73854b39eb7764736f6c634300080b0033

Deployed Bytecode Sourcemap

237:10761:7:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;826:48;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;565:14:8;;558:22;540:41;;528:2;513:18;826:48:7;;;;;;;;3964:89;;;:::i;:::-;;;;;;;:::i;5011:149::-;;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;1692:32:8;;;1674:51;;1662:2;1647:18;5011:149:7;1528:203:8;2989:205:7;;;;;;:::i;:::-;;:::i;:::-;;6083:147;;;;;;:::i;:::-;;:::i;:::-;;;2338:25:8;;;2326:2;2311:18;6083:147:7;2192:177:8;1752:81:7;;;;;;:::i;:::-;;:::i;4526:84::-;4570:7;4590:16;4526:84;;3390:116;;;;;;:::i;:::-;;:::i;6668:176::-;;;;;;:::i;:::-;;:::i;7533:509::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;:::i;3509:131::-;;;;;;:::i;:::-;;:::i;6541:124::-;;;;;;:::i;:::-;;:::i;9885:146::-;;;;;;:::i;:::-;;:::i;:::-;;;;6819:25:8;;;6875:2;6860:18;;6853:34;;;;6792:18;9885:146:7;6645:248:8;4722:142:7;;;;;;:::i;:::-;;:::i;8045:912::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;;;;:::i;4276:94::-;4352:13;;-1:-1:-1;;;;;4352:13:7;4276:94;;4373:75;4436:8;;-1:-1:-1;;;;;4436:8:7;4373:75;;4613:106;;;;;;:::i;:::-;-1:-1:-1;;;;;4689:18:7;4669:7;4689:18;;;:10;:18;;;;;:26;;4613:106;5317:149;;;;;;:::i;:::-;;:::i;6377:161::-;;;;;;:::i;:::-;;:::i;4451:72::-;4509:10;;-1:-1:-1;;;;;4509:10:7;4451:72;;4056:93;;;:::i;3197:190::-;;;;;;:::i;:::-;;:::i;5771:157::-;;;;;;:::i;:::-;;:::i;1935:1050::-;;;;;;:::i;:::-;;:::i;6847:427::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;5931:149::-;;;;;;:::i;:::-;;:::i;4867:141::-;;;;;;:::i;:::-;;:::i;5621:147::-;;;;;;:::i;:::-;;:::i;3643:317::-;;;;;;:::i;:::-;;:::i;4152:121::-;;;;;;:::i;:::-;;:::i;5469:149::-;;;;;;:::i;:::-;;:::i;7277:253::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;:::i;6233:141::-;;;;;;:::i;:::-;-1:-1:-1;;;;;6332:18:7;;;6315:4;6332:18;;;:10;:18;;;;;;;;:38;;;;;;:27;;:38;;;;;;;;6233:141;8960:922;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;;;:::i;1836:94::-;;;;;;:::i;:::-;;:::i;5163:151::-;;;;;;:::i;:::-;;:::i;3964:89::-;4029:13;;:20;;;-1:-1:-1;;;4029:20:7;;;;4003:13;;-1:-1:-1;;;;;4029:13:7;;:18;;:20;;;;;:4;;:20;;;;;;;:13;:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4029:20:7;;;;;;;;;;;;:::i;:::-;4022:27;;3964:89;:::o;5011:149::-;5071:7;4590:16;;5092:8;:24;5084:33;;;;;;-1:-1:-1;5128:4:7;:19;;;:9;:19;;;;;:28;;;-1:-1:-1;;;;;5128:28:7;;5011:149::o;2989:205::-;3078:17;3086:8;3078:7;:17::i;:::-;-1:-1:-1;;;;;3064:31:7;:10;-1:-1:-1;;;;;3064:31:7;;3056:40;;;;;;3100:4;:19;;;:9;:19;;;;;;:28;;:40;;-1:-1:-1;;;;;;3100:40:7;-1:-1:-1;;;;;3100:40:7;;;;;;;;3149:41;;3100:19;;3158:10;;3149:41;;3100:4;3149:41;2989:205;;:::o;6083:147::-;6142:7;4590:16;;6163:8;:24;6155:33;;;;;;-1:-1:-1;6199:4:7;:19;;;:9;:19;;;;;:27;;;-1:-1:-1;;;6199:27:7;;-1:-1:-1;;;;;6199:27:7;;6083:147::o;1752:81::-;4509:10;;-1:-1:-1;;;;;4509:10:7;1366;:21;1358:30;;;;;;1810:10:::1;:19:::0;;-1:-1:-1;;;;;;1810:19:7::1;-1:-1:-1::0;;;;;1810:19:7;;;::::1;::::0;;;::::1;::::0;;1752:81::o;3390:116::-;3471:31;3481:5;3488:3;3493:8;3471:9;:31::i;:::-;3390:116;;;:::o;6668:176::-;-1:-1:-1;;;;;4689:18:7;;6750:7;4689:18;;;:10;:18;;;;;:26;6771:6;:26;6763:35;;;;;;-1:-1:-1;;;;;;6809:18:7;;:4;:18;;;:10;:18;;;;;;;;:31;;;:23;;:31;;;;;;6668:176;;;;;:::o;7533:509::-;7601:23;7626:26;7654:22;7678:35;7719:15;7737:9;:16;7719:34;;7780:7;-1:-1:-1;;;;;7766:22:7;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;7766:22:7;;7757:31;;7818:7;-1:-1:-1;;;;;7804:22:7;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;7804:22:7;;7792:34;;7852:7;-1:-1:-1;;;;;7838:22:7;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;7838:22:7;;7830:30;;7899:7;-1:-1:-1;;;;;7882:25:7;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;7864:43;;7916:9;7911:128;7935:7;7931:1;:11;7911:128;;;8012:22;8021:9;8031:1;8021:12;;;;;;;;:::i;:::-;;;;;;;8012:8;:22::i;:::-;7955:6;7962:1;7955:9;;;;;;;;:::i;:::-;;;;;;7966;7976:1;7966:12;;;;;;;;:::i;:::-;;;;;;7980:5;7986:1;7980:8;;;;;;;;:::i;:::-;;;;;;7990:15;8006:1;7990:18;;;;;;;;:::i;:::-;;;;;;;;;;7954:80;;;;-1:-1:-1;;;;;7954:80:7;;;;;;;;;;;;;;;;;7944:3;;;;:::i;:::-;;;;7911:128;;;;7715:327;7533:509;;;;;:::o;3509:131::-;3594:42;3611:5;3618:3;3623:8;3594:42;;;;;;;;;;;;:16;:42::i;6541:124::-;6600:7;4590:16;;6621:6;:22;6613:31;;;;;;-1:-1:-1;6655:6:7;6541:124::o;9885:146::-;9944:14;9960:20;9994:13;4570:7;4590:16;;4526:84;9994:13;-1:-1:-1;;;;;4689:18:7;;4669:7;4689:18;;;:10;:18;;;;;:26;9986:41;;;;9885:146;;;:::o;4722:142::-;4778:7;4590:16;;4799:8;:24;4791:33;;;;;;-1:-1:-1;4835:4:7;:19;;;:9;:19;;;;;;;;:25;;-1:-1:-1;;;;;4835:25:7;;4722:142::o;8045:912::-;8134:25;8161:23;8186:26;8214:22;8238:35;8275:19;8296:18;8337:1;8328:6;:10;8320:19;;;;;;4570:7;4590:16;8343:27;-1:-1:-1;8379:15:7;;8375:510;;8440:20;8454:6;8440:11;:20;:::i;:::-;:25;:33;;8472:1;8440:33;;;8468:1;8440:33;8414:60;;8415:20;8429:6;8415:11;:20;:::i;:::-;8414:60;;;;:::i;:::-;8401:73;;8495:10;8487:5;:18;8479:27;;;;;;8512:15;8530:14;8539:5;8530:6;:14;:::i;:::-;8512:32;-1:-1:-1;8562:14:7;8575:1;8562:10;:14;:::i;:::-;8553:5;:23;:52;;;;-1:-1:-1;8580:20:7;8594:6;8580:11;:20;:::i;:::-;:25;;8553:52;8549:99;;;8622:20;8636:6;8622:11;:20;:::i;:::-;8613:29;;8549:99;8678:6;-1:-1:-1;;;;;8664:21:7;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;8664:21:7;;8653:32;;8695:9;8690:129;8714:6;8710:1;:10;8690:129;;;8747:66;8760:6;:52;;8811:1;8807;8783:21;8797:7;8783:11;:21;:::i;:::-;:25;;;;:::i;:::-;:29;;;;:::i;8760:52::-;8769:11;8779:1;8769:7;:11;:::i;8747:66::-;8733:8;8742:1;8733:11;;;;;;;;:::i;:::-;;;;;;;;;;:80;8722:3;;;;:::i;:::-;;;;8690:129;;;;8396:427;8375:510;;;-1:-1:-1;8864:16:7;;;8847:1;8864:16;;;;;;;;;8853:27;;8375:510;8934:19;8944:8;8934:9;:19::i;:::-;8045:912;;8888:65;;-1:-1:-1;8888:65:7;;-1:-1:-1;8888:65:7;-1:-1:-1;8045:912:7;;-1:-1:-1;8045:912:7;-1:-1:-1;8045:912:7;-1:-1:-1;;8045:912:7:o;5317:149::-;5377:7;4590:16;;5398:8;:24;5390:33;;;;;;-1:-1:-1;5434:4:7;:19;;;:9;:19;;;;;:28;;;-1:-1:-1;;;5434:28:7;;-1:-1:-1;;;;;5434:28:7;;5317:149::o;6377:161::-;-1:-1:-1;;;;;6462:17:7;;6432:7;6462:17;;;:10;:17;;;;;:28;;;6502:10;6494:19;;;;;;6524:10;6533:1;6524:6;:10;:::i;:::-;6517:17;6377:161;-1:-1:-1;;;6377:161:7:o;4056:93::-;4123:13;;:22;;;-1:-1:-1;;;4123:22:7;;;;4097:13;;-1:-1:-1;;;;;4123:13:7;;:20;;:22;;;;;:4;;:22;;;;;;;:13;:22;;;;;;;;;;;;;;3197:190;3283:10;3272:4;:22;;;:10;:22;;;;;;;;-1:-1:-1;;;;;3272:42:7;;;;;:31;;:42;;;;;;:54;;-1:-1:-1;;3272:54:7;;;;;;;;;;3335:48;;540:41:8;;;3272:42:7;;3283:10;3335:48;;513:18:8;3335:48:7;;;;;;;3197:190;;:::o;5771:157::-;5835:7;4590:16;;5856:8;:24;5848:33;;;;;;-1:-1:-1;5892:4:7;:19;;;:9;:19;;;;;:32;;;-1:-1:-1;;;;;5892:32:7;;5771:157::o;1935:1050::-;4436:8;;-1:-1:-1;;;;;4436:8:7;2123:10;:26;2115:35;;;;;;2154:16;2173:18;;2154:16;;2173:18;;;:::i;:::-;;;;;2154:37;;2230:13;4570:7;4590:16;;4526:84;2230:13;2195:4;:10;;:21;2206:9;-1:-1:-1;;;;;2195:21:7;-1:-1:-1;;;;;2195:21:7;;;;;;;;;;;;:32;;:48;;;;2247:23;2273:4;:9;;:19;2283:8;2273:19;;;;;;;;;;;2247:45;;2313:9;2296;:14;;;:26;;;;;-1:-1:-1;;;;;2296:26:7;;;;;-1:-1:-1;;;;;2296:26:7;;;;;;2344:9;2326;:15;;;:27;;;;;-1:-1:-1;;;;;2326:27:7;;;;;-1:-1:-1;;;;;2326:27:7;;;;;;2387:10;2357:9;:19;;;:41;;;;;-1:-1:-1;;;;;2357:41:7;;;;;-1:-1:-1;;;;;2357:41:7;;;;;;2431:9;2402;:18;;;:39;;;;;-1:-1:-1;;;;;2402:39:7;;;;;-1:-1:-1;;;;;2402:39:7;;;;;;2474:9;2445;:18;;;:39;;;;;-1:-1:-1;;;;;2445:39:7;;;;;-1:-1:-1;;;;;2445:39:7;;;;;;2516:8;2488:9;:17;;;:37;;;;;-1:-1:-1;;;;;2488:37:7;;;;;-1:-1:-1;;;;;2488:37:7;;;;;;2562:13;2529:9;:22;;;:47;;;;;-1:-1:-1;;;;;2529:47:7;;;;;-1:-1:-1;;;;;2529:47:7;;;;;;2608:9;2580;:18;;;:38;;;;;-1:-1:-1;;;;;2580:38:7;;;;;-1:-1:-1;;;;;2580:38:7;;;;;;2649:8;2622:9;:17;;;:36;;;;;-1:-1:-1;;;;;2622:36:7;;;;;-1:-1:-1;;;;;2622:36:7;;;;;;2662:14;2679:4;:10;;:21;2690:9;-1:-1:-1;;;;;2679:21:7;-1:-1:-1;;;;;2679:21:7;;;;;;;;;;;;:29;;;:31;;;;;;;;;:::i;:::-;;;;-1:-1:-1;2662:48:7;-1:-1:-1;2756:10:7;2662:48;2765:1;2756:10;:::i;:::-;-1:-1:-1;;;;;2714:21:7;;:4;:21;;;:10;:21;;;;;;;;:39;;;:29;;;:39;;;;;:52;;;;2770:34;;;:26;;;;:34;;;;;:45;;;2824:43;;2744:8;;2714:4;2824:43;;2714:4;;2824:43;2876:105;;;16506:25:8;;;16562:2;16547:18;;16540:34;;;16590:18;;;16583:34;;;16648:2;16633:18;;16626:34;;;16691:3;16676:19;;16669:35;;;16735:3;16720:19;;16713:35;;;16779:3;16764:19;;16757:35;;;2892:8:7;;-1:-1:-1;;;;;2876:105:7;;;;;16493:3:8;16478:19;2876:105:7;;;;;;;2111:874;;;1935:1050;;;;;;;;:::o;6847:427::-;6918:32;;:::i;:::-;6976:22;6989:8;6976:12;:22::i;:::-;6956:42;;7022:21;7034:8;7022:11;:21::i;:::-;7002:17;;;:41;7067:21;7079:8;7067:11;:21::i;:::-;7047:17;;;:41;7112:20;7123:8;7112:10;:20::i;:::-;7092:17;;;:40;7156:25;7172:8;7156:15;:25::i;:::-;7136:17;;;:45;7205:21;7217:8;7205:11;:21::i;:::-;7185:17;;;:41;7250:20;7261:8;7250:10;:20::i;:::-;7230:17;;;:40;:14;6847:427;-1:-1:-1;6847:427:7:o;5931:149::-;5991:7;4590:16;;6012:8;:24;6004:33;;;;;;-1:-1:-1;6048:4:7;:19;;;:9;:19;;;;;:28;;;-1:-1:-1;;;6048:28:7;;-1:-1:-1;;;;;6048:28:7;;5931:149::o;4867:141::-;4923:7;4590:16;;4944:8;:24;4936:33;;;;;;-1:-1:-1;4980:4:7;:19;;;:9;:19;;;;;:24;-1:-1:-1;;;;;4980:24:7;;4867:141::o;5621:147::-;5680:7;4590:16;;5701:8;:24;5693:33;;;;;;-1:-1:-1;5737:4:7;:19;;;:9;:19;;;;;:27;;;-1:-1:-1;;;5737:27:7;;-1:-1:-1;;;;;5737:27:7;;5621:147::o;3643:317::-;3746:31;3756:5;3763:3;3768:8;3746:9;:31::i;:::-;3820:16;;3847:9;;;;3843:114;;3871:66;;-1:-1:-1;;;3871:66:7;;-1:-1:-1;;;;;3871:30:7;;;;;:66;;3902:10;;3914:5;;3921:8;;3931:5;;3871:66;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;3871:80:7;;3941:10;3871:80;;;3863:89;;;;;;3742:218;3643:317;;;;:::o;4152:121::-;4237:13;;:32;;-1:-1:-1;;;4237:32:7;;;;;2338:25:8;;;4211:13:7;;-1:-1:-1;;;;;4237:13:7;;:22;;2311:18:8;;4237:32:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4237:32:7;;;;;;;;;;;;:::i;5469:149::-;5529:7;4590:16;;5550:8;:24;5542:33;;;;;;-1:-1:-1;5586:4:7;:19;;;:9;:19;;;;;:28;;;-1:-1:-1;;;;;5586:28:7;;5469:149::o;7277:253::-;7334:18;7354:16;7372:12;7386:32;;:::i;:::-;7432:17;7440:8;7432:7;:17::i;:::-;7451:21;7463:8;7451:11;:21::i;:::-;7474:17;7482:8;7474:7;:17::i;:::-;7493:32;7516:8;7493:22;:32::i;:::-;7424:102;;;;;;;;7277:253;;;;;:::o;8960:922::-;9070:25;9097:26;9125:22;9149:35;9186:19;9207:18;9248:1;9239:6;:10;9231:19;;;;;;-1:-1:-1;;;;;4689:18:7;;4669:7;4689:18;;;:10;:18;;;;;:26;9254:31;-1:-1:-1;9294:15:7;;9290:525;;9355:20;9369:6;9355:11;:20;:::i;:::-;:25;:33;;9387:1;9355:33;;;9383:1;9355:33;9329:60;;9330:20;9344:6;9330:11;:20;:::i;:::-;9329:60;;;;:::i;:::-;9316:73;;9410:10;9402:5;:18;9394:27;;;;;;9427:15;9445:14;9454:5;9445:6;:14;:::i;:::-;9427:32;-1:-1:-1;9477:14:7;9490:1;9477:10;:14;:::i;:::-;9468:5;:23;:52;;;;-1:-1:-1;9495:20:7;9509:6;9495:11;:20;:::i;:::-;:25;;9468:52;9464:99;;;9537:20;9551:6;9537:11;:20;:::i;:::-;9528:29;;9464:99;9593:6;-1:-1:-1;;;;;9579:21:7;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;9579:21:7;;9568:32;;9610:9;9605:144;9629:6;9625:1;:10;9605:144;;;9662:81;9682:6;9690;:52;;9741:1;9737;9713:21;9727:7;9713:11;:21;:::i;:::-;:25;;;;:::i;:::-;:29;;;;:::i;9690:52::-;9699:11;9709:1;9699:7;:11;:::i;9662:81::-;9648:8;9657:1;9648:11;;;;;;;;:::i;:::-;;;;;;;;;;:95;9637:3;;;;:::i;:::-;;;;9605:144;;;;9311:442;9290:525;;;-1:-1:-1;9794:16:7;;;9777:1;9794:16;;;;;;;;;9783:27;;9290:525;9859:19;9869:8;9859:9;:19::i;:::-;8960:922;;9818:60;;-1:-1:-1;9818:60:7;-1:-1:-1;9818:60:7;;-1:-1:-1;8960:922:7;;-1:-1:-1;8960:922:7;;-1:-1:-1;;;;8960:922:7:o;1836:94::-;4509:10;;-1:-1:-1;;;;;4509:10:7;1366;:21;1358:30;;;;;;1901:13:::1;:25:::0;;-1:-1:-1;;;;;;1901:25:7::1;-1:-1:-1::0;;;;;1901:25:7;;;::::1;::::0;;;::::1;::::0;;1836:94::o;5163:151::-;5224:7;4590:16;;5245:8;:24;5237:33;;;;;;-1:-1:-1;5281:4:7;:19;;;:9;:19;;;;;:29;;;-1:-1:-1;;;;;5281:29:7;;5163:151::o;10036:960::-;10114:14;10131:17;10139:8;10131:7;:17::i;:::-;10114:34;;10152:17;10172:21;10184:8;10172:11;:21::i;:::-;10152:41;;10214:6;-1:-1:-1;;;;;10205:15:7;:5;-1:-1:-1;;;;;10205:15:7;;10197:24;;;;;;10233:10;-1:-1:-1;;;;;10233:20:7;;;;:47;;-1:-1:-1;10257:10:7;-1:-1:-1;;;;;10257:23:7;;;10233:47;:87;;;-1:-1:-1;;;;;;6332:18:7;;6315:4;6332:18;;;:10;:18;;;;;;;;10309:10;6332:38;;:27;;;:38;;;;;;;10284:36;10225:96;;;;;;10326:4;:19;;;:9;:19;;;;;;;;:25;:31;;-1:-1:-1;;;;;;10326:31:7;-1:-1:-1;;;;;10326:31:7;;;;;;;;;;10365:25;;;10361:140;;10436:3;10397:19;;;:9;:19;;;;;;:28;;:43;;-1:-1:-1;;;;;;10397:43:7;;;10450:46;10407:8;;10436:3;;;10450:46;;10436:3;;10450:46;10361:140;-1:-1:-1;;;;;10522:17:7;;10505:14;10522:17;;;:10;:17;;;;;;;;:35;;;:25;;:35;;;;;;:39;;10560:1;;10522:39;:::i;:::-;-1:-1:-1;;;;;10582:17:7;;10565:14;10582:17;;;:10;:17;;;;;10605:25;;10505:56;;-1:-1:-1;10565:14:7;;10582:22;;;;;10565:14;;10605:29;;10582:22;10605:29;:::i;:::-;10582:53;;;;;;;;;;;;;;-1:-1:-1;10582:53:7;;;;-1:-1:-1;;;;;10639:17:7;;;;:10;:17;;;;;:30;;;:22;;;;:30;;;;;;:39;;;10582:53;-1:-1:-1;10718:10:7;;10662:6;;10718:10;:::i;:::-;-1:-1:-1;;;;;10682:17:7;;:4;:17;;;:10;:17;;;;;;;;:33;;;:25;;;:33;;;;;:46;;;;10732:17;;;;;;:27;;;10682:17;10732:27;;;:::i;:::-;;;;-1:-1:-1;;;;;;;10770:17:7;;;:4;:17;;;:10;:17;;;;;;;;:35;;;:25;;:35;;;;;10763:42;;;10829:15;;;;;;;;;:25;;;10770:4;10829:25;;;:::i;:::-;;;;-1:-1:-1;10809:45:7;-1:-1:-1;10894:13:7;10809:45;10906:1;10894:13;:::i;:::-;-1:-1:-1;;;;;10858:15:7;;;:4;:15;;;:10;:15;;;;;;;;:33;;;:23;;;:33;;;;;:49;;;;10911:31;;;:20;;;;:31;;;;;:42;;;10962:30;;10882:8;;10858:15;;10962:30;;;;;;10110:886;;;;;10036:960;;;:::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;:::o;14:131:8:-;-1:-1:-1;;;;;;88:32:8;;78:43;;68:71;;135:1;132;125:12;68:71;14:131;:::o;150:245::-;208:6;261:2;249:9;240:7;236:23;232:32;229:52;;;277:1;274;267:12;229:52;316:9;303:23;335:30;359:5;335:30;:::i;592:258::-;664:1;674:113;688:6;685:1;682:13;674:113;;;764:11;;;758:18;745:11;;;738:39;710:2;703:10;674:113;;;805:6;802:1;799:13;796:48;;;840:1;831:6;826:3;822:16;815:27;796:48;;592:258;;;:::o;855:::-;897:3;935:5;929:12;962:6;957:3;950:19;978:63;1034:6;1027:4;1022:3;1018:14;1011:4;1004:5;1000:16;978:63;:::i;:::-;1095:2;1074:15;-1:-1:-1;;1070:29:8;1061:39;;;;1102:4;1057:50;;855:258;-1:-1:-1;;855:258:8:o;1118:220::-;1267:2;1256:9;1249:21;1230:4;1287:45;1328:2;1317:9;1313:18;1305:6;1287:45;:::i;1343:180::-;1402:6;1455:2;1443:9;1434:7;1430:23;1426:32;1423:52;;;1471:1;1468;1461:12;1423:52;-1:-1:-1;1494:23:8;;1343:180;-1:-1:-1;1343:180:8:o;1736:131::-;-1:-1:-1;;;;;1811:31:8;;1801:42;;1791:70;;1857:1;1854;1847:12;1872:315;1940:6;1948;2001:2;1989:9;1980:7;1976:23;1972:32;1969:52;;;2017:1;2014;2007:12;1969:52;2056:9;2043:23;2075:31;2100:5;2075:31;:::i;:::-;2125:5;2177:2;2162:18;;;;2149:32;;-1:-1:-1;;;1872:315:8:o;2374:247::-;2433:6;2486:2;2474:9;2465:7;2461:23;2457:32;2454:52;;;2502:1;2499;2492:12;2454:52;2541:9;2528:23;2560:31;2585:5;2560:31;:::i;2626:456::-;2703:6;2711;2719;2772:2;2760:9;2751:7;2747:23;2743:32;2740:52;;;2788:1;2785;2778:12;2740:52;2827:9;2814:23;2846:31;2871:5;2846:31;:::i;:::-;2896:5;-1:-1:-1;2953:2:8;2938:18;;2925:32;2966:33;2925:32;2966:33;:::i;:::-;2626:456;;3018:7;;-1:-1:-1;;;3072:2:8;3057:18;;;;3044:32;;2626:456::o;3087:127::-;3148:10;3143:3;3139:20;3136:1;3129:31;3179:4;3176:1;3169:15;3203:4;3200:1;3193:15;3219:275;3290:2;3284:9;3355:2;3336:13;;-1:-1:-1;;3332:27:8;3320:40;;-1:-1:-1;;;;;3375:34:8;;3411:22;;;3372:62;3369:88;;;3437:18;;:::i;:::-;3473:2;3466:22;3219:275;;-1:-1:-1;3219:275:8:o;3499:946::-;3583:6;3614:2;3657;3645:9;3636:7;3632:23;3628:32;3625:52;;;3673:1;3670;3663:12;3625:52;3713:9;3700:23;-1:-1:-1;;;;;3783:2:8;3775:6;3772:14;3769:34;;;3799:1;3796;3789:12;3769:34;3837:6;3826:9;3822:22;3812:32;;3882:7;3875:4;3871:2;3867:13;3863:27;3853:55;;3904:1;3901;3894:12;3853:55;3940:2;3927:16;3962:2;3958;3955:10;3952:36;;;3968:18;;:::i;:::-;4014:2;4011:1;4007:10;3997:20;;4037:28;4061:2;4057;4053:11;4037:28;:::i;:::-;4099:15;;;4169:11;;;4165:20;;;4130:12;;;;4197:19;;;4194:39;;;4229:1;4226;4219:12;4194:39;4253:11;;;;4273:142;4289:6;4284:3;4281:15;4273:142;;;4355:17;;4343:30;;4306:12;;;;4393;;;;4273:142;;;4434:5;3499:946;-1:-1:-1;;;;;;;;3499:946:8:o;4450:461::-;4503:3;4541:5;4535:12;4568:6;4563:3;4556:19;4594:4;4623:2;4618:3;4614:12;4607:19;;4660:2;4653:5;4649:14;4681:1;4691:195;4705:6;4702:1;4699:13;4691:195;;;4770:13;;-1:-1:-1;;;;;4766:39:8;4754:52;;4826:12;;;;4861:15;;;;4802:1;4720:9;4691:195;;;-1:-1:-1;4902:3:8;;4450:461;-1:-1:-1;;;;;4450:461:8:o;4916:326::-;5009:5;5032:1;5042:194;5056:4;5053:1;5050:11;5042:194;;;5115:13;;5103:26;;5152:4;5176:12;;;;5211:15;;;;5076:1;5069:9;5042:194;;5247:461;5306:3;5344:5;5338:12;5371:6;5366:3;5359:19;5397:4;5426:2;5421:3;5417:12;5410:19;;5463:2;5456:5;5452:14;5484:1;5494:189;5508:6;5505:1;5502:13;5494:189;;;5557:44;5597:3;5588:6;5582:13;5557:44;:::i;:::-;5630:4;5621:14;;;;;5658:15;;;;5530:1;5523:9;5494:189;;5713:927;6172:3;6161:9;6154:22;6135:4;6199:57;6251:3;6240:9;6236:19;6228:6;6199:57;:::i;:::-;6304:9;6296:6;6292:22;6287:2;6276:9;6272:18;6265:50;6338:44;6375:6;6367;6338:44;:::i;:::-;6324:58;;6430:9;6422:6;6418:22;6413:2;6402:9;6398:18;6391:50;6464:44;6501:6;6493;6464:44;:::i;:::-;6450:58;;6556:9;6548:6;6544:22;6539:2;6528:9;6524:18;6517:50;6584;6627:6;6619;6584:50;:::i;:::-;6576:58;5713:927;-1:-1:-1;;;;;;;5713:927:8:o;6898:160::-;6963:20;;7019:13;;7012:21;7002:32;;6992:60;;7048:1;7045;7038:12;6992:60;6898:160;;;:::o;7063:316::-;7137:6;7145;7153;7206:2;7194:9;7185:7;7181:23;7177:32;7174:52;;;7222:1;7219;7212:12;7174:52;7258:9;7245:23;7235:33;;7315:2;7304:9;7300:18;7287:32;7277:42;;7338:35;7369:2;7358:9;7354:18;7338:35;:::i;:::-;7328:45;;7063:316;;;;;:::o;7384:435::-;7437:3;7475:5;7469:12;7502:6;7497:3;7490:19;7528:4;7557:2;7552:3;7548:12;7541:19;;7594:2;7587:5;7583:14;7615:1;7625:169;7639:6;7636:1;7633:13;7625:169;;;7700:13;;7688:26;;7734:12;;;;7769:15;;;;7661:1;7654:9;7625:169;;7824:1276;8417:3;8406:9;8399:22;8380:4;8444:57;8496:3;8485:9;8481:19;8473:6;8444:57;:::i;:::-;8549:9;8541:6;8537:22;8532:2;8521:9;8517:18;8510:50;8583:44;8620:6;8612;8583:44;:::i;:::-;8569:58;;8675:9;8667:6;8663:22;8658:2;8647:9;8643:18;8636:50;8709:44;8746:6;8738;8709:44;:::i;:::-;8695:58;;8801:9;8793:6;8789:22;8784:2;8773:9;8769:18;8762:50;8835:44;8872:6;8864;8835:44;:::i;:::-;8821:58;;8928:9;8920:6;8916:22;8910:3;8899:9;8895:19;8888:51;8956:50;8999:6;8991;8956:50;:::i;:::-;9037:3;9022:19;;9015:35;;;;-1:-1:-1;;9081:3:8;9066:19;9059:35;8948:58;7824:1276;-1:-1:-1;;;;;7824:1276:8:o;9105:315::-;9170:6;9178;9231:2;9219:9;9210:7;9206:23;9202:32;9199:52;;;9247:1;9244;9237:12;9199:52;9286:9;9273:23;9305:31;9330:5;9305:31;:::i;:::-;9355:5;-1:-1:-1;9379:35:8;9410:2;9395:18;;9379:35;:::i;:::-;9369:45;;9105:315;;;;;:::o;9425:728::-;9547:6;9555;9563;9571;9579;9587;9595;9603;9656:3;9644:9;9635:7;9631:23;9627:33;9624:53;;;9673:1;9670;9663:12;9624:53;9712:9;9699:23;9731:31;9756:5;9731:31;:::i;:::-;9781:5;9833:2;9818:18;;9805:32;;-1:-1:-1;9884:2:8;9869:18;;9856:32;;9935:2;9920:18;;9907:32;;-1:-1:-1;9986:3:8;9971:19;;9958:33;;-1:-1:-1;10038:3:8;10023:19;;10010:33;;-1:-1:-1;10090:3:8;10075:19;;10062:33;;-1:-1:-1;10142:3:8;10127:19;10114:33;;-1:-1:-1;9425:728:8;-1:-1:-1;;;9425:728:8:o;10158:242::-;10338:3;10323:19;;10351:43;10327:9;10376:6;10351:43;:::i;10405:186::-;10453:4;-1:-1:-1;;;;;10478:6:8;10475:30;10472:56;;;10508:18;;:::i;:::-;-1:-1:-1;10574:2:8;10553:15;-1:-1:-1;;10549:29:8;10580:4;10545:40;;10405:186::o;10596:1016::-;10691:6;10699;10707;10715;10768:3;10756:9;10747:7;10743:23;10739:33;10736:53;;;10785:1;10782;10775:12;10736:53;10824:9;10811:23;10843:31;10868:5;10843:31;:::i;:::-;10893:5;-1:-1:-1;10950:2:8;10935:18;;10922:32;10963:33;10922:32;10963:33;:::i;:::-;11015:7;-1:-1:-1;11069:2:8;11054:18;;11041:32;;-1:-1:-1;11124:2:8;11109:18;;11096:32;-1:-1:-1;;;;;11140:30:8;;11137:50;;;11183:1;11180;11173:12;11137:50;11206:22;;11259:4;11251:13;;11247:27;-1:-1:-1;11237:55:8;;11288:1;11285;11278:12;11237:55;11324:2;11311:16;11349:48;11365:31;11393:2;11365:31;:::i;:::-;11349:48;:::i;:::-;11420:2;11413:5;11406:17;11460:7;11455:2;11450;11446;11442:11;11438:20;11435:33;11432:53;;;11481:1;11478;11471:12;11432:53;11536:2;11531;11527;11523:11;11518:2;11511:5;11507:14;11494:45;11580:1;11575:2;11570;11563:5;11559:14;11555:23;11548:34;11601:5;11591:15;;;;;10596:1016;;;;;;;:::o;11617:520::-;-1:-1:-1;;;;;11950:15:8;;;11932:34;;12002:15;;;11997:2;11982:18;;11975:43;12054:15;;12049:2;12034:18;;12027:43;11881:3;11866:19;;12079:52;12127:2;12112:18;;12104:6;12079:52;:::i;:::-;11617:520;;;;;;;:::o;12142:388::-;12210:6;12218;12271:2;12259:9;12250:7;12246:23;12242:32;12239:52;;;12287:1;12284;12277:12;12239:52;12326:9;12313:23;12345:31;12370:5;12345:31;:::i;:::-;12395:5;-1:-1:-1;12452:2:8;12437:18;;12424:32;12465:33;12424:32;12465:33;:::i;:::-;12517:7;12507:17;;;12142:388;;;;;:::o;12535:452::-;12618:6;12626;12634;12642;12695:3;12683:9;12674:7;12670:23;12666:33;12663:53;;;12712:1;12709;12702:12;12663:53;12751:9;12738:23;12770:31;12795:5;12770:31;:::i;:::-;12820:5;-1:-1:-1;12872:2:8;12857:18;;12844:32;;-1:-1:-1;12923:2:8;12908:18;;12895:32;;-1:-1:-1;12946:35:8;12977:2;12962:18;;12946:35;:::i;:::-;12936:45;;12535:452;;;;;;;:::o;12992:1071::-;13507:3;13496:9;13489:22;13470:4;13534:57;13586:3;13575:9;13571:19;13563:6;13534:57;:::i;:::-;13639:9;13631:6;13627:22;13622:2;13611:9;13607:18;13600:50;13673:44;13710:6;13702;13673:44;:::i;:::-;13659:58;;13765:9;13757:6;13753:22;13748:2;13737:9;13733:18;13726:50;13799:44;13836:6;13828;13799:44;:::i;:::-;13785:58;;13891:9;13883:6;13879:22;13874:2;13863:9;13859:18;13852:50;13919;13962:6;13954;13919:50;:::i;:::-;14000:3;13985:19;;13978:35;;;;-1:-1:-1;;14044:3:8;14029:19;14022:35;13911:58;12992:1071;-1:-1:-1;;;;12992:1071:8:o;14337:635::-;14417:6;14470:2;14458:9;14449:7;14445:23;14441:32;14438:52;;;14486:1;14483;14476:12;14438:52;14519:9;14513:16;-1:-1:-1;;;;;14544:6:8;14541:30;14538:50;;;14584:1;14581;14574:12;14538:50;14607:22;;14660:4;14652:13;;14648:27;-1:-1:-1;14638:55:8;;14689:1;14686;14679:12;14638:55;14718:2;14712:9;14743:48;14759:31;14787:2;14759:31;:::i;14743:48::-;14814:2;14807:5;14800:17;14854:7;14849:2;14844;14840;14836:11;14832:20;14829:33;14826:53;;;14875:1;14872;14865:12;14826:53;14888:54;14939:2;14934;14927:5;14923:14;14918:2;14914;14910:11;14888:54;:::i;14977:127::-;15038:10;15033:3;15029:20;15026:1;15019:31;15069:4;15066:1;15059:15;15093:4;15090:1;15083:15;15109:127;15170:10;15165:3;15161:20;15158:1;15151:31;15201:4;15198:1;15191:15;15225:4;15222:1;15215:15;15241:135;15280:3;-1:-1:-1;;15301:17:8;;15298:43;;;15321:18;;:::i;:::-;-1:-1:-1;15368:1:8;15357:13;;15241:135::o;15381:127::-;15442:10;15437:3;15433:20;15430:1;15423:31;15473:4;15470:1;15463:15;15497:4;15494:1;15487:15;15513:112;15545:1;15571;15561:35;;15576:18;;:::i;:::-;-1:-1:-1;15610:9:8;;15513:112::o;15630:120::-;15670:1;15696;15686:35;;15701:18;;:::i;:::-;-1:-1:-1;15735:9:8;;15630:120::o;15755:128::-;15795:3;15826:1;15822:6;15819:1;15816:13;15813:39;;;15832:18;;:::i;:::-;-1:-1:-1;15868:9:8;;15755:128::o;15888:168::-;15928:7;15994:1;15990;15986:6;15982:14;15979:1;15976:21;15971:1;15964:9;15957:17;15953:45;15950:71;;;16001:18;;:::i;:::-;-1:-1:-1;16041:9:8;;15888:168::o;16061:125::-;16101:4;16129:1;16126;16123:8;16120:34;;;16134:18;;:::i;:::-;-1:-1:-1;16171:9:8;;16061:125::o;16803:489::-;-1:-1:-1;;;;;17072:15:8;;;17054:34;;17124:15;;17119:2;17104:18;;17097:43;17171:2;17156:18;;17149:34;;;17219:3;17214:2;17199:18;;17192:31;;;16997:4;;17240:46;;17266:19;;17258:6;17240:46;:::i;:::-;17232:54;16803:489;-1:-1:-1;;;;;;16803:489:8:o;17297:249::-;17366:6;17419:2;17407:9;17398:7;17394:23;17390:32;17387:52;;;17435:1;17432;17425:12;17387:52;17467:9;17461:16;17486:30;17510:5;17486:30;:::i;17551:136::-;17590:3;17618:5;17608:39;;17627:18;;:::i;:::-;-1:-1:-1;;;17663:18:8;;17551:136::o

Swarm Source

ipfs://8e2b5e515fb02168298df9697376a6434523e033f88d7913a9684bb0cf33e5e9
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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