Contract Address Details
contract

0xe3D32266974f1E8f8549cAf9F54977040e7D1c07

Contract Name
UniswapV2Locker
Creator
0x60e2e1–b2099a at 0xa8ccb5–8e3ab2
Balance
0 xDAI ( )
Tokens
Fetching tokens...
Transactions
Transfers
Gas Used
Last Balance Update
18760714
This contract has been verified via Sourcify. View contract in Sourcify repository
Contract name:
UniswapV2Locker




Optimization enabled
false
Compiler version
v0.6.12+commit.27d51765




EVM Version
istanbul




Verified at
2021-02-10 14:11:37.411128Z

Contract source code

// SPDX-License-Identifier: UNLICENSED
// Forked from Ethereum mainnet for Honeyswap on xDai
// This contract locks Honeyswap v2 liquidity tokens. Used to give investors peace of mind a token team has locked liquidity
// and that the univ2 tokens cannot be removed from uniswap until the specified unlock date has been reached.
pragma solidity 0.6.12;
import "./TransferHelper.sol";
import "./EnumerableSet.sol";
import "./SafeMath.sol";
import "./Ownable.sol";
import "./ReentrancyGuard.sol";
interface IUniswapV2Pair {
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
}
interface IERCBurn {
function burn(uint256 _amount) external;
function approve(address spender, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external returns (uint256);
function balanceOf(address account) external view returns (uint256);
}
interface IUniFactory {
function getPair(address tokenA, address tokenB) external view returns (address);
}
interface IMigrator {
function migrate(address lpToken, uint256 amount, uint256 unlockDate, address owner) external returns (bool);
}
contract UniswapV2Locker is Ownable, ReentrancyGuard {
using SafeMath for uint256;
using EnumerableSet for EnumerableSet.AddressSet;
IUniFactory public uniswapFactory;
struct UserInfo {
EnumerableSet.AddressSet lockedTokens; // records all tokens the user has locked
mapping(address => uint256[]) locksForToken; // map erc20 address to lock id for that token
}
struct TokenLock {
uint256 lockDate; // the date the token was locked
uint256 amount; // the amount of tokens still locked (initialAmount minus withdrawls)
uint256 initialAmount; // the initial lock amount
uint256 unlockDate; // the date the token can be withdrawn
uint256 lockID; // lockID nonce per uni pair
address owner;
}
mapping(address => UserInfo) private users;
EnumerableSet.AddressSet private lockedTokens;
mapping(address => TokenLock[]) public tokenLocks; //map univ2 pair to all its locks
struct FeeStruct {
uint256 ethFee; // Small eth fee to prevent spam on the platform
IERCBurn secondaryFeeToken; // UNCX or UNCL
uint256 secondaryTokenFee; // optional, UNCX or UNCL
uint256 secondaryTokenDiscount; // discount on liquidity fee for burning secondaryToken
uint256 liquidityFee; // fee on univ2 liquidity tokens
uint256 referralPercent; // fee for referrals
IERCBurn referralToken; // token the refferer must hold to qualify as a referrer
uint256 referralHold; // balance the referrer must hold to qualify as a referrer
uint256 referralDiscount; // discount on flatrate fees for using a valid referral address
}
FeeStruct public gFees;
EnumerableSet.AddressSet private feeWhitelist;
address payable devaddr;
IMigrator migrator;
event onDeposit(address lpToken, address user, uint256 amount, uint256 lockDate, uint256 unlockDate);
event onWithdraw(address lpToken, uint256 amount);
constructor(IUniFactory _uniswapFactory) public {
devaddr = msg.sender;
gFees.referralPercent = 250; // 25%
gFees.ethFee = 1e18;
gFees.secondaryTokenFee = 100e18;
gFees.secondaryTokenDiscount = 200; // 20%
gFees.liquidityFee = 10; // 1%
gFees.referralHold = 10e18;
gFees.referralDiscount = 100; // 10%
uniswapFactory = _uniswapFactory;
}
function setDev(address payable _devaddr) public onlyOwner {
devaddr = _devaddr;
}
/**
* @notice set the migrator contract which allows locked lp tokens to be migrated to uniswap v3
*/
function setMigrator(IMigrator _migrator) public onlyOwner {
migrator = _migrator;
}
function setSecondaryFeeToken(address _secondaryFeeToken) public onlyOwner {
gFees.secondaryFeeToken = IERCBurn(_secondaryFeeToken);
}
/**
* @notice referrers need to hold the specified token and hold amount to be elegible for referral fees
*/
function setReferralTokenAndHold(IERCBurn _referralToken, uint256 _hold) public onlyOwner {
gFees.referralToken = _referralToken;
gFees.referralHold = _hold;
}
function setFees(uint256 _referralPercent, uint256 _referralDiscount, uint256 _ethFee, uint256 _secondaryTokenFee, uint256 _secondaryTokenDiscount, uint256 _liquidityFee) public onlyOwner {
gFees.referralPercent = _referralPercent;
gFees.referralDiscount = _referralDiscount;
gFees.ethFee = _ethFee;
gFees.secondaryTokenFee = _secondaryTokenFee;
gFees.secondaryTokenDiscount = _secondaryTokenDiscount;
gFees.liquidityFee = _liquidityFee;
}
/**
* @notice whitelisted accounts dont pay flatrate fees on locking
*/
function whitelistFeeAccount(address _user, bool _add) public onlyOwner {
if (_add) {
feeWhitelist.add(_user);
} else {
feeWhitelist.remove(_user);
}
}
/**
* @notice Creates a new lock
* @param _lpToken the univ2 token address
* @param _amount amount of LP tokens to lock
* @param _unlock_date the unix timestamp (in seconds) until unlock
* @param _referral the referrer address if any or address(0) for none
* @param _fee_in_eth fees can be paid in eth or in a secondary token such as UNCX with a discount on univ2 tokens
* @param _withdrawer the user who can withdraw liquidity once the lock expires.
*/
function lockLPToken (address _lpToken, uint256 _amount, uint256 _unlock_date, address payable _referral, bool _fee_in_eth, address payable _withdrawer) external payable nonReentrant {
require(_unlock_date < 10000000000, 'TIMESTAMP INVALID'); // prevents errors when timestamp entered in milliseconds
require(_amount > 0, 'INSUFFICIENT');
// ensure this pair is a univ2 pair by querying the factory
IUniswapV2Pair lpair = IUniswapV2Pair(address(_lpToken));
address factoryPairAddress = uniswapFactory.getPair(lpair.token0(), lpair.token1());
require(factoryPairAddress == address(_lpToken), 'NOT UNIV2');
TransferHelper.safeTransferFrom(_lpToken, address(msg.sender), address(this), _amount);
if (_referral != address(0) && address(gFees.referralToken) != address(0)) {
require(gFees.referralToken.balanceOf(_referral) >= gFees.referralHold, 'INADEQUATE BALANCE');
}
// flatrate fees
if (!feeWhitelist.contains(msg.sender)) {
if (_fee_in_eth) { // charge fee in eth
uint256 ethFee = gFees.ethFee;
if (_referral != address(0)) {
ethFee = ethFee.mul(1000 - gFees.referralDiscount).div(1000);
}
require(msg.value == ethFee, 'FEE NOT MET');
uint256 devFee = ethFee;
if (ethFee != 0 && _referral != address(0)) { // referral fee
uint256 referralFee = devFee.mul(gFees.referralPercent).div(1000);
_referral.transfer(referralFee);
devFee = devFee.sub(referralFee);
}
devaddr.transfer(devFee);
} else { // charge fee in token
uint256 burnFee = gFees.secondaryTokenFee;
if (_referral != address(0)) {
burnFee = burnFee.mul(1000 - gFees.referralDiscount).div(1000);
}
TransferHelper.safeTransferFrom(address(gFees.secondaryFeeToken), address(msg.sender), address(this), burnFee);
if (gFees.referralPercent != 0 && _referral != address(0)) { // referral fee
uint256 referralFee = burnFee.mul(gFees.referralPercent).div(1000);
TransferHelper.safeApprove(address(gFees.secondaryFeeToken), _referral, referralFee);
TransferHelper.safeTransfer(address(gFees.secondaryFeeToken), _referral, referralFee);
burnFee = burnFee.sub(referralFee);
}
gFees.secondaryFeeToken.burn(burnFee);
}
} else if (msg.value > 0){
// refund eth if a whitelisted member sent it by mistake
msg.sender.transfer(msg.value);
}
// percent fee
uint256 liquidityFee = _amount.mul(gFees.liquidityFee).div(1000);
if (!_fee_in_eth && !feeWhitelist.contains(msg.sender)) { // fee discount for large lockers using secondary token
liquidityFee = liquidityFee.mul(1000 - gFees.secondaryTokenDiscount).div(1000);
}
TransferHelper.safeTransfer(_lpToken, devaddr, liquidityFee);
uint256 amountLocked = _amount.sub(liquidityFee);
TokenLock memory token_lock;
token_lock.lockDate = block.timestamp;
token_lock.amount = amountLocked;
token_lock.initialAmount = amountLocked;
token_lock.unlockDate = _unlock_date;
token_lock.lockID = tokenLocks[_lpToken].length;
token_lock.owner = _withdrawer;
// record the lock for the univ2pair
tokenLocks[_lpToken].push(token_lock);
lockedTokens.add(_lpToken);
// record the lock for the user
UserInfo storage user = users[_withdrawer];
user.lockedTokens.add(_lpToken);
uint256[] storage user_locks = user.locksForToken[_lpToken];
user_locks.push(token_lock.lockID);
emit onDeposit(_lpToken, msg.sender, token_lock.amount, token_lock.lockDate, token_lock.unlockDate);
}
/**
* @notice extend a lock with a new unlock date, _index and _lockID ensure the correct lock is changed
* this prevents errors when a user performs multiple tx per block possibly with varying gas prices
*/
function relock (address _lpToken, uint256 _index, uint256 _lockID, uint256 _unlock_date) external nonReentrant {
require(_unlock_date < 10000000000, 'TIMESTAMP INVALID'); // prevents errors when timestamp entered in milliseconds
uint256 lockID = users[msg.sender].locksForToken[_lpToken][_index];
TokenLock storage userLock = tokenLocks[_lpToken][lockID];
require(lockID == _lockID && userLock.owner == msg.sender, 'LOCK MISMATCH'); // ensures correct lock is affected
require(userLock.unlockDate < _unlock_date, 'UNLOCK BEFORE');
uint256 liquidityFee = userLock.amount.mul(gFees.liquidityFee).div(1000);
uint256 amountLocked = userLock.amount.sub(liquidityFee);
userLock.amount = amountLocked;
userLock.unlockDate = _unlock_date;
// send univ2 fee to dev address
TransferHelper.safeTransfer(_lpToken, devaddr, liquidityFee);
}
/**
* @notice withdraw a specified amount from a lock. _index and _lockID ensure the correct lock is changed
* this prevents errors when a user performs multiple tx per block possibly with varying gas prices
*/
function withdraw (address _lpToken, uint256 _index, uint256 _lockID, uint256 _amount) external nonReentrant {
require(_amount > 0, 'ZERO WITHDRAWL');
uint256 lockID = users[msg.sender].locksForToken[_lpToken][_index];
TokenLock storage userLock = tokenLocks[_lpToken][lockID];
require(lockID == _lockID && userLock.owner == msg.sender, 'LOCK MISMATCH'); // ensures correct lock is affected
require(userLock.unlockDate < block.timestamp, 'NOT YET');
userLock.amount = userLock.amount.sub(_amount);
// clean user storage
if (userLock.amount == 0) {
uint256[] storage userLocks = users[msg.sender].locksForToken[_lpToken];
userLocks[_index] = userLocks[userLocks.length-1];
userLocks.pop();
if (userLocks.length == 0) {
users[msg.sender].lockedTokens.remove(_lpToken);
}
}
TransferHelper.safeTransfer(_lpToken, msg.sender, _amount);
emit onWithdraw(_lpToken, _amount);
}
/**
* @notice increase the amount of tokens per a specific lock, this is preferable to creating a new lock, less fees, and faster loading on our live block explorer
*/
function incrementLock (address _lpToken, uint256 _index, uint256 _lockID, uint256 _amount) external nonReentrant {
require(_amount > 0, 'ZERO AMOUNT');
uint256 lockID = users[msg.sender].locksForToken[_lpToken][_index];
TokenLock storage userLock = tokenLocks[_lpToken][lockID];
require(lockID == _lockID && userLock.owner == msg.sender, 'LOCK MISMATCH'); // ensures correct lock is affected
TransferHelper.safeTransferFrom(_lpToken, address(msg.sender), address(this), _amount);
// send univ2 fee to dev address
uint256 liquidityFee = _amount.mul(gFees.liquidityFee).div(1000);
TransferHelper.safeTransfer(_lpToken, devaddr, liquidityFee);
uint256 amountLocked = _amount.sub(liquidityFee);
userLock.amount = userLock.amount.add(amountLocked);
emit onDeposit(_lpToken, msg.sender, amountLocked, userLock.lockDate, userLock.unlockDate);
}
/**
* @notice split a lock into two seperate locks, useful when a lock is about to expire and youd like to relock a portion
* and withdraw a smaller portion
*/
function splitLock (address _lpToken, uint256 _index, uint256 _lockID, uint256 _amount) external payable nonReentrant {
require(_amount > 0, 'ZERO AMOUNT');
uint256 lockID = users[msg.sender].locksForToken[_lpToken][_index];
TokenLock storage userLock = tokenLocks[_lpToken][lockID];
require(lockID == _lockID && userLock.owner == msg.sender, 'LOCK MISMATCH'); // ensures correct lock is affected
require(msg.value == gFees.ethFee, 'FEE NOT MET');
devaddr.transfer(gFees.ethFee);
userLock.amount = userLock.amount.sub(_amount);
TokenLock memory token_lock;
token_lock.lockDate = userLock.lockDate;
token_lock.amount = _amount;
token_lock.initialAmount = _amount;
token_lock.unlockDate = userLock.unlockDate;
token_lock.lockID = tokenLocks[_lpToken].length;
token_lock.owner = msg.sender;
// record the lock for the univ2pair
tokenLocks[_lpToken].push(token_lock);
// record the lock for the user
UserInfo storage user = users[msg.sender];
uint256[] storage user_locks = user.locksForToken[_lpToken];
user_locks.push(token_lock.lockID);
}
/**
* @notice transfer a lock to a new owner, e.g. presale project -> project owner
*/
function transferLockOwnership (address _lpToken, uint256 _index, uint256 _lockID, address payable _newOwner) external {
require(msg.sender != _newOwner, 'OWNER');
uint256 lockID = users[msg.sender].locksForToken[_lpToken][_index];
TokenLock storage transferredLock = tokenLocks[_lpToken][lockID];
require(lockID == _lockID && transferredLock.owner == msg.sender, 'LOCK MISMATCH'); // ensures correct lock is affected
// record the lock for the new Owner
UserInfo storage user = users[_newOwner];
user.lockedTokens.add(_lpToken);
uint256[] storage user_locks = user.locksForToken[_lpToken];
user_locks.push(transferredLock.lockID);
// remove the lock from the old owner
uint256[] storage userLocks = users[msg.sender].locksForToken[_lpToken];
userLocks[_index] = userLocks[userLocks.length-1];
userLocks.pop();
if (userLocks.length == 0) {
users[msg.sender].lockedTokens.remove(_lpToken);
}
transferredLock.owner = _newOwner;
}
/**
* @notice migrates liquidity to uniswap v3
*/
function migrate (address _lpToken, uint256 _index, uint256 _lockID, uint256 _amount) external nonReentrant {
require(address(migrator) != address(0), "NOT SET");
require(_amount > 0, 'ZERO MIGRATION');
uint256 lockID = users[msg.sender].locksForToken[_lpToken][_index];
TokenLock storage userLock = tokenLocks[_lpToken][lockID];
require(lockID == _lockID && userLock.owner == msg.sender, 'LOCK MISMATCH'); // ensures correct lock is affected
userLock.amount = userLock.amount.sub(_amount);
// clean user storage
if (userLock.amount == 0) {
uint256[] storage userLocks = users[msg.sender].locksForToken[_lpToken];
userLocks[_index] = userLocks[userLocks.length-1];
userLocks.pop();
if (userLocks.length == 0) {
users[msg.sender].lockedTokens.remove(_lpToken);
}
}
TransferHelper.safeApprove(_lpToken, address(migrator), _amount);
migrator.migrate(_lpToken, _amount, userLock.unlockDate, msg.sender);
}
function getNumLocksForToken (address _lpToken) external view returns (uint256) {
return tokenLocks[_lpToken].length;
}
function getNumLockedTokens () external view returns (uint256) {
return lockedTokens.length();
}
function getLockedTokenAtIndex (uint256 _index) external view returns (address) {
return lockedTokens.at(_index);
}
// user functions
function getUserNumLockedTokens (address _user) external view returns (uint256) {
UserInfo storage user = users[_user];
return user.lockedTokens.length();
}
function getUserLockedTokenAtIndex (address _user, uint256 _index) external view returns (address) {
UserInfo storage user = users[_user];
return user.lockedTokens.at(_index);
}
function getUserNumLocksForToken (address _user, address _lpToken) external view returns (uint256) {
UserInfo storage user = users[_user];
return user.locksForToken[_lpToken].length;
}
function getUserLockForTokenAtIndex (address _user, address _lpToken, uint256 _index) external view
returns (uint256, uint256, uint256, uint256, uint256, address) {
uint256 lockID = users[_user].locksForToken[_lpToken][_index];
TokenLock storage tokenLock = tokenLocks[_lpToken][lockID];
return (tokenLock.lockDate, tokenLock.amount, tokenLock.initialAmount, tokenLock.unlockDate, tokenLock.lockID, tokenLock.owner);
}
// whitelist
function getWhitelistedUsersLength () external view returns (uint256) {
return feeWhitelist.length();
}
function getWhitelistedUserAtIndex (uint256 _index) external view returns (address) {
return feeWhitelist.at(_index);
}
function getUserWhitelistStatus (address _user) external view returns (bool) {
return feeWhitelist.contains(_user);
}
}

TransferHelper.sol

pragma solidity 0.6.12;
// helper methods for interacting with ERC20 tokens that do not consistently return true/false
library TransferHelper {
function safeApprove(address token, address to, uint value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
}
function safeTransfer(address token, address to, uint value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
}
function safeTransferFrom(address token, address from, address to, uint value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
}
}

SafeMath.sol

// SPDX-License-Identifier: MIT
// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/SafeMath.sol
// Subject to the MIT license.
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}

ReentrancyGuard.sol

// SPDX-License-Identifier: MIT
// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol
// Subject to the MIT license.
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor () internal {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}

Ownable.sol

// SPDX-License-Identifier: MIT
// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol
// Subject to the MIT license.
pragma solidity >=0.6.0 <0.8.0;
import "./Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () internal {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(_owner == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}

EnumerableSet.sol

// SPDX-License-Identifier: MIT
// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/EnumerableSet.sol
// Subject to the MIT license.
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping (bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) { // Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
// When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
// so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.
bytes32 lastvalue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastvalue;
// Update the index for the moved value
set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
require(set._values.length > index, "EnumerableSet: index out of bounds");
return set._values[index];
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(value)));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(value)));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(value)));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint256(_at(set._inner, index)));
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
}

Context.sol

// SPDX-License-Identifier: MIT
// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/GSN/Context.sol
// Subject to the MIT license.
pragma solidity >=0.6.0 <0.8.0;
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_uniswapFactory","internalType":"contract IUniFactory"}]},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"onDeposit","inputs":[{"type":"address","name":"lpToken","internalType":"address","indexed":false},{"type":"address","name":"user","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"lockDate","internalType":"uint256","indexed":false},{"type":"uint256","name":"unlockDate","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"onWithdraw","inputs":[{"type":"address","name":"lpToken","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"ethFee","internalType":"uint256"},{"type":"address","name":"secondaryFeeToken","internalType":"contract IERCBurn"},{"type":"uint256","name":"secondaryTokenFee","internalType":"uint256"},{"type":"uint256","name":"secondaryTokenDiscount","internalType":"uint256"},{"type":"uint256","name":"liquidityFee","internalType":"uint256"},{"type":"uint256","name":"referralPercent","internalType":"uint256"},{"type":"address","name":"referralToken","internalType":"contract IERCBurn"},{"type":"uint256","name":"referralHold","internalType":"uint256"},{"type":"uint256","name":"referralDiscount","internalType":"uint256"}],"name":"gFees","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"getLockedTokenAtIndex","inputs":[{"type":"uint256","name":"_index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getNumLockedTokens","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getNumLocksForToken","inputs":[{"type":"address","name":"_lpToken","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}],"name":"getUserLockForTokenAtIndex","inputs":[{"type":"address","name":"_user","internalType":"address"},{"type":"address","name":"_lpToken","internalType":"address"},{"type":"uint256","name":"_index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"getUserLockedTokenAtIndex","inputs":[{"type":"address","name":"_user","internalType":"address"},{"type":"uint256","name":"_index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getUserNumLockedTokens","inputs":[{"type":"address","name":"_user","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getUserNumLocksForToken","inputs":[{"type":"address","name":"_user","internalType":"address"},{"type":"address","name":"_lpToken","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"getUserWhitelistStatus","inputs":[{"type":"address","name":"_user","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"getWhitelistedUserAtIndex","inputs":[{"type":"uint256","name":"_index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getWhitelistedUsersLength","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"incrementLock","inputs":[{"type":"address","name":"_lpToken","internalType":"address"},{"type":"uint256","name":"_index","internalType":"uint256"},{"type":"uint256","name":"_lockID","internalType":"uint256"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"lockLPToken","inputs":[{"type":"address","name":"_lpToken","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"},{"type":"uint256","name":"_unlock_date","internalType":"uint256"},{"type":"address","name":"_referral","internalType":"address payable"},{"type":"bool","name":"_fee_in_eth","internalType":"bool"},{"type":"address","name":"_withdrawer","internalType":"address payable"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"migrate","inputs":[{"type":"address","name":"_lpToken","internalType":"address"},{"type":"uint256","name":"_index","internalType":"uint256"},{"type":"uint256","name":"_lockID","internalType":"uint256"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"relock","inputs":[{"type":"address","name":"_lpToken","internalType":"address"},{"type":"uint256","name":"_index","internalType":"uint256"},{"type":"uint256","name":"_lockID","internalType":"uint256"},{"type":"uint256","name":"_unlock_date","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setDev","inputs":[{"type":"address","name":"_devaddr","internalType":"address payable"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFees","inputs":[{"type":"uint256","name":"_referralPercent","internalType":"uint256"},{"type":"uint256","name":"_referralDiscount","internalType":"uint256"},{"type":"uint256","name":"_ethFee","internalType":"uint256"},{"type":"uint256","name":"_secondaryTokenFee","internalType":"uint256"},{"type":"uint256","name":"_secondaryTokenDiscount","internalType":"uint256"},{"type":"uint256","name":"_liquidityFee","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMigrator","inputs":[{"type":"address","name":"_migrator","internalType":"contract IMigrator"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setReferralTokenAndHold","inputs":[{"type":"address","name":"_referralToken","internalType":"contract IERCBurn"},{"type":"uint256","name":"_hold","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setSecondaryFeeToken","inputs":[{"type":"address","name":"_secondaryFeeToken","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"splitLock","inputs":[{"type":"address","name":"_lpToken","internalType":"address"},{"type":"uint256","name":"_index","internalType":"uint256"},{"type":"uint256","name":"_lockID","internalType":"uint256"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"lockDate","internalType":"uint256"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"initialAmount","internalType":"uint256"},{"type":"uint256","name":"unlockDate","internalType":"uint256"},{"type":"uint256","name":"lockID","internalType":"uint256"},{"type":"address","name":"owner","internalType":"address"}],"name":"tokenLocks","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferLockOwnership","inputs":[{"type":"address","name":"_lpToken","internalType":"address"},{"type":"uint256","name":"_index","internalType":"uint256"},{"type":"uint256","name":"_lockID","internalType":"uint256"},{"type":"address","name":"_newOwner","internalType":"address payable"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IUniFactory"}],"name":"uniswapFactory","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"whitelistFeeAccount","inputs":[{"type":"address","name":"_user","internalType":"address"},{"type":"bool","name":"_add","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw","inputs":[{"type":"address","name":"_lpToken","internalType":"address"},{"type":"uint256","name":"_index","internalType":"uint256"},{"type":"uint256","name":"_lockID","internalType":"uint256"},{"type":"uint256","name":"_amount","internalType":"uint256"}]}]
            

Deployed ByteCode

0x6080604052600436106101c25760003560e01c80638da5cb5b116100f7578063b9863a4411610095578063d4ff493f11610064578063d4ff493f14610b87578063ee42427814610c4f578063f02c264314610cbe578063f2fde38b14610d19576101c2565b8063b9863a44146109a2578063bef497fd14610a09578063ccebfa3f14610a8e578063d477f05f14610b36576101c2565b806391ff1eb1116100d157806391ff1eb1146107ec578063a396981514610849578063a69d9c4f146108ae578063a9b07cea14610933576101c2565b80638da5cb5b14610697578063903df806146106d857806390e1a0031461075d576101c2565b8063715018a6116101645780638931a4be1161013e5780638931a4be146104fc5780638af416f61461054d5780638bdb2afa146105f15780638c301df814610632576101c2565b8063715018a61461044d578063783451e81461046457806386f6c3c11461048f576101c2565b80634532d776116101a05780634532d776146102e25780634bb18e3f14610351578063582d5adc1461037c57806360491d24146103de576101c2565b806314dd79a3146101c75780631f2a1d2f1461022c57806323cf311814610291575b600080fd5b3480156101d357600080fd5b50610200600480360360208110156101ea57600080fd5b8101908080359060200190929190505050610d6a565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561023857600080fd5b5061027b6004803603602081101561024f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610d87565b6040518082815260200191505060405180910390f35b34801561029d57600080fd5b506102e0600480360360208110156102b457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610dd3565b005b3480156102ee57600080fd5b5061034f6004803603608081101561030557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190929190505050610edf565b005b34801561035d57600080fd5b506103666113ef565b6040518082815260200191505060405180910390f35b6103dc6004803603608081101561039257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190929190505050611400565b005b3480156103ea57600080fd5b5061044b6004803603608081101561040157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190929190505050611a29565b005b34801561045957600080fd5b50610462611e01565b005b34801561047057600080fd5b50610479611f87565b6040518082815260200191505060405180910390f35b34801561049b57600080fd5b506104fa600480360360c08110156104b257600080fd5b81019080803590602001909291908035906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190929190505050611f98565b005b34801561050857600080fd5b5061054b6004803603602081101561051f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506120a4565b005b6105ef600480360360c081101561056357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803515159060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506121b3565b005b3480156105fd57600080fd5b5061060661303d565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561063e57600080fd5b5061066b6004803603602081101561065557600080fd5b8101908080359060200190929190505050613063565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156106a357600080fd5b506106ac613080565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156106e457600080fd5b50610731600480360360408110156106fb57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506130a9565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561076957600080fd5b5061077261310c565b604051808a81526020018973ffffffffffffffffffffffffffffffffffffffff1681526020018881526020018781526020018681526020018581526020018473ffffffffffffffffffffffffffffffffffffffff168152602001838152602001828152602001995050505050505050505060405180910390f35b3480156107f857600080fd5b506108476004803603604081101561080f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803515159060200190929190505050613188565b005b34801561085557600080fd5b506108986004803603602081101561086c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061328a565b6040518082815260200191505060405180910390f35b3480156108ba57600080fd5b5061091d600480360360408110156108d157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506132e2565b6040518082815260200191505060405180910390f35b34801561093f57600080fd5b506109a06004803603608081101561095657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190929190505050613374565b005b3480156109ae57600080fd5b506109f1600480360360208110156109c557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061376b565b60405180821515815260200191505060405180910390f35b348015610a1557600080fd5b50610a8c60048036036080811015610a2c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613788565b005b348015610a9a57600080fd5b50610ae760048036036040811015610ab157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050613c46565b604051808781526020018681526020018581526020018481526020018381526020018273ffffffffffffffffffffffffffffffffffffffff168152602001965050505050505060405180910390f35b348015610b4257600080fd5b50610b8560048036036020811015610b5957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613cbc565b005b348015610b9357600080fd5b50610c0060048036036060811015610baa57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050613dc8565b604051808781526020018681526020018581526020018481526020018381526020018273ffffffffffffffffffffffffffffffffffffffff168152602001965050505050505060405180910390f35b348015610c5b57600080fd5b50610cbc60048036036080811015610c7257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190929190505050613f1e565b005b348015610cca57600080fd5b50610d1760048036036040811015610ce157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050614540565b005b348015610d2557600080fd5b50610d6860048036036020811015610d3c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050614659565b005b6000610d8082600461486490919063ffffffff16565b9050919050565b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490509050919050565b610ddb61487e565b73ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610e9b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b80601360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60026001541415610f58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0081525060200191505060405180910390fd5b600260018190555060008111610fd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f5a45524f2057495448445241574c00000000000000000000000000000000000081525060200191505060405180910390fd5b6000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020848154811061106257fe5b906000526020600020015490506000600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002082815481106110bb57fe5b90600052602060002090600602019050838214801561112957503373ffffffffffffffffffffffffffffffffffffffff168160050160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b61119b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f4c4f434b204d49534d415443480000000000000000000000000000000000000081525060200191505060405180910390fd5b42816003015410611214576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260078152602001807f4e4f54205945540000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b61122b83826001015461488690919063ffffffff16565b8160010181905550600081600101541415611380576000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050806001828054905003815481106112d657fe5b90600052602060002001548187815481106112ed57fe5b90600052602060002001819055508080548061130557fe5b6001900381819060005260206000200160009055905560008180549050141561137e5761137c87600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000016148d090919063ffffffff16565b505b505b61138b863385614900565b7fccad973dcd043c7d680389db4378bd6b9775db7124092e9e0422c9e46d7985dc8684604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a150506001808190555050505050565b60006113fb6010614ae3565b905090565b60026001541415611479576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0081525060200191505060405180910390fd5b6002600181905550600081116114f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600b8152602001807f5a45524f20414d4f554e5400000000000000000000000000000000000000000081525060200191505060405180910390fd5b6000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020848154811061158357fe5b906000526020600020015490506000600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002082815481106115dc57fe5b90600052602060002090600602019050838214801561164a57503373ffffffffffffffffffffffffffffffffffffffff168160050160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b6116bc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f4c4f434b204d49534d415443480000000000000000000000000000000000000081525060200191505060405180910390fd5b6007600001543414611736576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600b8152602001807f464545204e4f54204d455400000000000000000000000000000000000000000081525060200191505060405180910390fd5b601260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc6007600001549081150290604051600060405180830381858888f193505050501580156117a3573d6000803e3d6000fd5b506117bb83826001015461488690919063ffffffff16565b81600101819055506117cb61540d565b816000015481600001818152505083816020018181525050838160400181815250508160030154816060018181525050600660008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050816080018181525050338160a0019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600660008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819080600181540180825580915050600190039060005260206000209060060201600090919091909150600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015560a08201518160050160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050506000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008160020160008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050808360800151908060018154018082558091505060019003906000526020600020016000909190919091505550505050506001808190555050505050565b60026001541415611aa2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0081525060200191505060405180910390fd5b60026001819055506402540be4008110611b24576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f54494d455354414d5020494e56414c494400000000000000000000000000000081525060200191505060405180910390fd5b6000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208481548110611bb057fe5b906000526020600020015490506000600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208281548110611c0957fe5b906000526020600020906006020190508382148015611c7757503373ffffffffffffffffffffffffffffffffffffffff168160050160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b611ce9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f4c4f434b204d49534d415443480000000000000000000000000000000000000081525060200191505060405180910390fd5b82816003015410611d62576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f554e4c4f434b204245464f52450000000000000000000000000000000000000081525060200191505060405180910390fd5b6000611d946103e8611d866007600401548560010154614af890919063ffffffff16565b614b7e90919063ffffffff16565b90506000611daf82846001015461488690919063ffffffff16565b9050808360010181905550848360030181905550611df088601260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1684614900565b505050506001808190555050505050565b611e0961487e565b73ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611ec9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b6000611f936004614ae3565b905090565b611fa061487e565b73ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614612060576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b856007600501819055508460076008018190555083600760000181905550826007600201819055508160076003018190555080600760040181905550505050505050565b6120ac61487e565b73ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461216c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b80600760010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6002600154141561222c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0081525060200191505060405180910390fd5b60026001819055506402540be40084106122ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f54494d455354414d5020494e56414c494400000000000000000000000000000081525060200191505060405180910390fd5b60008511612324576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600c8152602001807f494e53554646494349454e54000000000000000000000000000000000000000081525060200191505060405180910390fd5b60008690506000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e6a439058373ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b1580156123af57600080fd5b505afa1580156123c3573d6000803e3d6000fd5b505050506040513d60208110156123d957600080fd5b81019080805190602001909291905050508473ffffffffffffffffffffffffffffffffffffffff1663d21220a76040518163ffffffff1660e01b815260040160206040518083038186803b15801561243057600080fd5b505afa158015612444573d6000803e3d6000fd5b505050506040513d602081101561245a57600080fd5b81019080805190602001909291905050506040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b1580156124d257600080fd5b505afa1580156124e6573d6000803e3d6000fd5b505050506040513d60208110156124fc57600080fd5b810190808051906020019092919050505090508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146125b0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260098152602001807f4e4f5420554e495632000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6125bc8833308a614bc8565b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161415801561264b5750600073ffffffffffffffffffffffffffffffffffffffff16600760060160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b15612791576007800154600760060160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231876040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156126e157600080fd5b505afa1580156126f5573d6000803e3d6000fd5b505050506040513d602081101561270b57600080fd5b81019080805190602001909291905050501015612790576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f494e41444551554154452042414c414e4345000000000000000000000000000081525060200191505060405180910390fd5b5b6127a5336010614dad90919063ffffffff16565b612c035783156129db5760006007600001549050600073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16146128205761281d6103e861280f6007600801546103e80384614af890919063ffffffff16565b614b7e90919063ffffffff16565b90505b803414612895576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600b8152602001807f464545204e4f54204d455400000000000000000000000000000000000000000081525060200191505060405180910390fd5b6000819050600082141580156128d85750600073ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614155b1561296b57600061290b6103e86128fd60076005015485614af890919063ffffffff16565b614b7e90919063ffffffff16565b90508773ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015612953573d6000803e3d6000fd5b50612967818361488690919063ffffffff16565b9150505b601260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501580156129d3573d6000803e3d6000fd5b505050612bfe565b60006007600201549050600073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614612a4c57612a496103e8612a3b6007600801546103e80384614af890919063ffffffff16565b614b7e90919063ffffffff16565b90505b612a7d600760010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16333084614bc8565b600060076005015414158015612ac05750600073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614155b15612b6c576000612af36103e8612ae560076005015485614af890919063ffffffff16565b614b7e90919063ffffffff16565b9050612b25600760010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168883614ddd565b612b55600760010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168883614900565b612b68818361488690919063ffffffff16565b9150505b600760010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166342966c68826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015612be457600080fd5b505af1158015612bf8573d6000803e3d6000fd5b50505050505b612c55565b6000341115612c54573373ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015612c52573d6000803e3d6000fd5b505b5b6000612c836103e8612c756007600401548b614af890919063ffffffff16565b614b7e90919063ffffffff16565b905084158015612ca45750612ca2336010614dad90919063ffffffff16565b155b15612cdc57612cd96103e8612ccb6007600301546103e80384614af890919063ffffffff16565b614b7e90919063ffffffff16565b90505b612d0989601260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683614900565b6000612d1e828a61488690919063ffffffff16565b9050612d2861540d565b42816000018181525050818160200181815250508181604001818152505088816060018181525050600660008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050816080018181525050858160a0019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600660008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819080600181540180825580915050600190039060005260206000209060060201600090919091909150600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015560a08201518160050160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050612ecc8b6004614fc090919063ffffffff16565b506000600360008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050612f268c82600001614fc090919063ffffffff16565b5060008160020160008e73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905080836080015190806001815401808255809150506001900390600052602060002001600090919091909150557f830357565da6ecfc26d8d9f69df488ed6f70361af9a07e570544aeb5c5e765e58d33856020015186600001518760600151604051808673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018381526020018281526020019550505050505060405180910390a15050505050505060018081905550505050505050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600061307982601061486490919063ffffffff16565b9050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600080600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050613103838260000161486490919063ffffffff16565b91505092915050565b60078060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020154908060030154908060040154908060050154908060060160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060070154908060080154905089565b61319061487e565b73ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614613250576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b80156132705761326a826010614fc090919063ffffffff16565b50613286565b6132848260106148d090919063ffffffff16565b505b5050565b600080600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506132da81600001614ae3565b915050919050565b600080600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060020160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054905091505092915050565b600260015414156133ed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0081525060200191505060405180910390fd5b60026001819055506000811161346b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600b8152602001807f5a45524f20414d4f554e5400000000000000000000000000000000000000000081525060200191505060405180910390fd5b6000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002084815481106134f757fe5b906000526020600020015490506000600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020828154811061355057fe5b9060005260206000209060060201905083821480156135be57503373ffffffffffffffffffffffffffffffffffffffff168160050160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b613630576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f4c4f434b204d49534d415443480000000000000000000000000000000000000081525060200191505060405180910390fd5b61363c86333086614bc8565b600061366a6103e861365c60076004015487614af890919063ffffffff16565b614b7e90919063ffffffff16565b905061369987601260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683614900565b60006136ae828661488690919063ffffffff16565b90506136c7818460010154614ff090919063ffffffff16565b83600101819055507f830357565da6ecfc26d8d9f69df488ed6f70361af9a07e570544aeb5c5e765e588338386600001548760030154604051808673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018381526020018281526020019550505050505060405180910390a1505050506001808190555050505050565b6000613781826010614dad90919063ffffffff16565b9050919050565b8073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561382a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f4f574e455200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002084815481106138b657fe5b906000526020600020015490506000600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020828154811061390f57fe5b90600052602060002090600602019050838214801561397d57503373ffffffffffffffffffffffffffffffffffffffff168160050160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b6139ef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f4c4f434b204d49534d415443480000000000000000000000000000000000000081525060200191505060405180910390fd5b6000600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050613a488782600001614fc090919063ffffffff16565b5060008160020160008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905080836004015490806001815401808255809150506001900390600052602060002001600090919091909150556000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905080600182805490500381548110613b5057fe5b9060005260206000200154818981548110613b6757fe5b906000526020600020018190555080805480613b7f57fe5b60019003818190600052602060002001600090559055600081805490501415613bf857613bf689600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000016148d090919063ffffffff16565b505b858460050160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505050505050505050565b60066020528160005260406000208181548110613c5f57fe5b9060005260206000209060060201600091509150508060000154908060010154908060020154908060030154908060040154908060050160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905086565b613cc461487e565b73ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614613d84576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b80601260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000806000806000806000600360008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208881548110613e5d57fe5b906000526020600020015490506000600660008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208281548110613eb657fe5b90600052602060002090600602019050806000015481600101548260020154836003015484600401548560050160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16975097509750975097509750505093975093979195509350565b60026001541415613f97576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0081525060200191505060405180910390fd5b6002600181905550600073ffffffffffffffffffffffffffffffffffffffff16601360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415614064576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260078152602001807f4e4f54205345540000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600081116140da576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f5a45524f204d4947524154494f4e00000000000000000000000000000000000081525060200191505060405180910390fd5b6000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020848154811061416657fe5b906000526020600020015490506000600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002082815481106141bf57fe5b90600052602060002090600602019050838214801561422d57503373ffffffffffffffffffffffffffffffffffffffff168160050160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b61429f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f4c4f434b204d49534d415443480000000000000000000000000000000000000081525060200191505060405180910390fd5b6142b683826001015461488690919063ffffffff16565b816001018190555060008160010154141561440b576000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060018280549050038154811061436157fe5b906000526020600020015481878154811061437857fe5b90600052602060002001819055508080548061439057fe5b600190038181906000526020600020016000905590556000818054905014156144095761440787600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000016148d090919063ffffffff16565b505b505b61443886601360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1685614ddd565b601360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663db5ecd3f87858460030154336040518563ffffffff1660e01b8152600401808573ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018381526020018273ffffffffffffffffffffffffffffffffffffffff168152602001945050505050602060405180830381600087803b1580156144f557600080fd5b505af1158015614509573d6000803e3d6000fd5b505050506040513d602081101561451f57600080fd5b81019080805190602001909291905050505050506001808190555050505050565b61454861487e565b73ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614614608576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b81600760060160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060078001819055505050565b61466161487e565b73ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614614721576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156147a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602681526020018061547c6026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60006148738360000183615078565b60001c905092915050565b600033905090565b60006148c883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506150fb565b905092915050565b60006148f8836000018373ffffffffffffffffffffffffffffffffffffffff1660001b6151bb565b905092915050565b600060608473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8585604051602401808373ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506040516020818303038152906040529060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040518082805190602001908083835b602083106149c357805182526020820191506020810190506020830392506149a0565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614a25576040519150601f19603f3d011682016040523d82523d6000602084013e614a2a565b606091505b5091509150818015614a6a5750600081511480614a695750808060200190516020811015614a5757600080fd5b81019080805190602001909291905050505b5b614adc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f5472616e7366657248656c7065723a205452414e534645525f4641494c45440081525060200191505060405180910390fd5b5050505050565b6000614af1826000016152a3565b9050919050565b600080831415614b0b5760009050614b78565b6000828402905082848281614b1c57fe5b0414614b73576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806154a26021913960400191505060405180910390fd5b809150505b92915050565b6000614bc083836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506152b4565b905092915050565b600060608573ffffffffffffffffffffffffffffffffffffffff166323b872dd868686604051602401808473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200193505050506040516020818303038152906040529060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040518082805190602001908083835b60208310614ca95780518252602082019150602081019050602083039250614c86565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614d0b576040519150601f19603f3d011682016040523d82523d6000602084013e614d10565b606091505b5091509150818015614d505750600081511480614d4f5750808060200190516020811015614d3d57600080fd5b81019080805190602001909291905050505b5b614da5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001806154c36024913960400191505060405180910390fd5b505050505050565b6000614dd5836000018373ffffffffffffffffffffffffffffffffffffffff1660001b61537a565b905092915050565b600060608473ffffffffffffffffffffffffffffffffffffffff1663095ea7b38585604051602401808373ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506040516020818303038152906040529060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040518082805190602001908083835b60208310614ea05780518252602082019150602081019050602083039250614e7d565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614f02576040519150601f19603f3d011682016040523d82523d6000602084013e614f07565b606091505b5091509150818015614f475750600081511480614f465750808060200190516020811015614f3457600080fd5b81019080805190602001909291905050505b5b614fb9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f5472616e7366657248656c7065723a20415050524f56455f4641494c4544000081525060200191505060405180910390fd5b5050505050565b6000614fe8836000018373ffffffffffffffffffffffffffffffffffffffff1660001b61539d565b905092915050565b60008082840190508381101561506e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b6000818360000180549050116150d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602281526020018061545a6022913960400191505060405180910390fd5b8260000182815481106150e857fe5b9060005260206000200154905092915050565b60008383111582906151a8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561516d578082015181840152602081019050615152565b50505050905090810190601f16801561519a5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b60008083600101600084815260200190815260200160002054905060008114615297576000600182039050600060018660000180549050039050600086600001828154811061520657fe5b906000526020600020015490508087600001848154811061522357fe5b906000526020600020018190555060018301876001016000838152602001908152602001600020819055508660000180548061525b57fe5b6001900381819060005260206000200160009055905586600101600087815260200190815260200160002060009055600194505050505061529d565b60009150505b92915050565b600081600001805490509050919050565b60008083118290615360576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561532557808201518184015260208101905061530a565b50505050905090810190601f1680156153525780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600083858161536c57fe5b049050809150509392505050565b600080836001016000848152602001908152602001600020541415905092915050565b60006153a9838361537a565b615402578260000182908060018154018082558091505060019003906000526020600020016000909190919091505582600001805490508360010160008481526020019081526020016000208190555060019050615407565b600090505b92915050565b6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff168152509056fe456e756d657261626c655365743a20696e646578206f7574206f6620626f756e64734f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775472616e7366657248656c7065723a205452414e534645525f46524f4d5f4641494c4544a26469706673582212206e7797fe9d91fff6eef3dec445458b6f840142582f72f4753506389937a9de4064736f6c634300060c0033