Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- Staking
- Optimization enabled
- true
- Compiler version
- v0.8.4+commit.c7e474f2
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2024-09-26T15:34:40.210114Z
Contract source code
// File: contracts/EnumerableSet.sol
pragma solidity ^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.0.0, only sets of type `address` (`AddressSet`) and `uint256`
* (`UintSet`) are supported.
*/
library EnumerableSet {
struct AddressSet {
// Storage of set values
address[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping (address => 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(AddressSet storage set, address value) internal 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(AddressSet storage set, address value) internal 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.
address 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(AddressSet storage set, address value) internal view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function length(AddressSet storage set) internal 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(AddressSet storage set, uint256 index) internal view returns (address) {
require(set._values.length > index, "EnumerableSet: index out of bounds");
return set._values[index];
}
}
// File: contracts/StakingBIC.sol
pragma solidity ^0.8.0;
interface IBEP20 {
function transfer(address recipient, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function mint(address user, uint256 amount) external;
function balanceOf(address account) external view returns (uint256);
}
abstract contract Ownable {
address internal _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
/* we use proxy, so owner will be set in initialize() function
constructor () {
_owner = msg.sender;
emit OwnershipTransferred(address(0), msg.sender);
}
*/
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == msg.sender, "Ownable: caller is not the owner");
_;
}
/**
* @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;
}
}
contract Staking is Ownable {
using EnumerableSet for EnumerableSet.AddressSet;
address public token; // BIC token
EnumerableSet.AddressSet usersList; // list of users with stake
struct User {
uint256 amount; // amount of deposit
uint256 weightedTokens; // the user's weighted tokens balance. (weighted tokens = token amount * staked days)
uint256 previousWeightedTokens; // the user's weighted tokens balance for previous month.
uint256 reward; // amount of reward that user may withdraw before ends of staking.
uint64 unlockTime; // when can be unstake
uint64 updated; // day when updated
uint64 multiplier; // multiplier (with 2 decimals) applied to deposit ([0.25 .. 1])
uint8 status; // 0 - active, 1 - ended (weightedTokens > 0), 2 - ended (previousWeightedTokens > 0), 3 - ended, but not withdrawn
}
mapping(address => User[]) public users; // users deposits array
mapping(uint256 => uint256) public multiplier; // staking days => multiplier (with 2 decimals)
uint256 public withdrawWindow; // user may withdraw during this time when previous lock period ends.
uint256 public prolongate; // if user did not withdraw, money locked on next 30 days.
uint256 public minimumAmount; // minimum amount for staking
// for TEST
/*
uint256 public withdrawWindow = 1 days; // user may withdraw during this time when previous lock period ends.
uint256 public prolongate = 2 days; // if user user did not withdraw, money locked on next 30 days.
uint256 public minimumAmount = 1; // minimum amount for staking
*/
uint256 public totalStaked;
uint256 public totalStakedWeight;
uint256 public previousTotalStakedWeight; // the total staked weight for previous month.
int256 public amountPerWeightedToken; // amount (with 18 decimals) of profit/loss per weighted token for previous month.
int256 public monthResultAmount; // result for previous month
uint256 public processingStep; // 0 - processing complete, 1 - recalculate Weight, 2 - split result
uint256 public processedDay; // last day that was processed
uint256 public precessedMonth; // month when profit/loss was added. Admin can add profit/loss only once per month.
uint256 public nextProcessUser;
mapping (address => bool) public admins;
event SetAdmin(address admin, bool isActive);
event Stake(address user, uint256 amount, uint256 period, uint256 multiplier);
event Unstake(address user, uint256 amount);
event WithdrawUSD(address user, uint256 amount);
event Processed(uint256 number, uint256 total, uint256 step);
event RemoveUser(address user);
event RemoveDeposit(address user, uint256 depositId);
event MonthResult(int256 amount);
event SplitResult(address user, uint256 depositId, int256 amount);
// run only once from proxy
function initialize(address newOwner, address _token) external {
require(newOwner != address(0) && _owner == address(0)); // run only once
_owner = newOwner;
token = _token;
emit OwnershipTransferred(address(0), msg.sender);
withdrawWindow = 5 days; // user may withdraw during this time when previous lock period ends.
prolongate = 30 days; // if user did not withdraw, money locked on next 30 days.
minimumAmount = 200 ether; // minimum amount for staking
multiplier[90] = 25; // staking for 90 days = multiplier 0.25
multiplier[180] = 50; // staking for 180 days = multiplier 0.5
multiplier[270] = 75; // staking for 270 days = multiplier 0.75
multiplier[360] = 100; // staking for 180 days = multiplier 1
}
/**
* @dev Throws if called by any account other than the admin.
*/
modifier onlyAdmin() {
require(admins[msg.sender] || owner() == msg.sender, "Caller is not admin");
_;
}
function setAdmin(address admin, bool isActive) external onlyOwner {
admins[admin] = isActive;
emit SetAdmin(admin, isActive);
}
// set multiplier (with 2 decimals)
function setMultiplier(uint256 _days, uint256 _multiplier) external onlyOwner {
require(_multiplier <= 100, "Wrong multiplier");
multiplier[_days] = _multiplier;
}
// set minimumAmount
function setMinimumAmount(uint256 _minAmount) external onlyOwner {
minimumAmount = _minAmount;
}
// set withdrawWindow in seconds
function setWithdrawWindow(uint256 time) external onlyOwner {
withdrawWindow = time;
}
// set prolongate in seconds
function setProlongate(uint256 time) external onlyOwner {
prolongate = time;
}
// get total number of users
function getUsersNumber() external view returns(uint256) {
return usersList.length();
}
// get total number of deposits of user
function getUsersDepositsNumber(address user) external view returns(uint256) {
return users[user].length;
}
// get deposits of user
function getUsersDeposits(address user) external view returns(User[] memory) {
return users[user];
}
// Step 0. Call this function 1st day of each month
// Enter result for previous month
function monthResult(int256 amount) external onlyOwner {
require(processingStep == 0, "Previous result was not processed");
_updateWeight();
(,uint256 month,) = timestampToDate(block.timestamp);
//month = block.timestamp / 1 days; // for TEST
require(precessedMonth != month, "Result may be added only once per month");
precessedMonth = month;
monthResultAmount = amount;
require (int256(totalStaked) + amount >= 0, "totalStaked less then amount");
if (amount > 0) {
_safeTransferFrom(token, msg.sender, address(this), uint256(amount));
}
processingStep = 1;
nextProcessUser = 0;
emit MonthResult(amount);
}
// recalculate users weights and total weights to exclude expired staking.
// Step 1. Call this function 1st day of each month
// numberUsers - is number of users that will processed at one transaction. Repeat call this function until emit event with number == total.
function recalculateWeight(uint256 numberUsers) external onlyAdmin {
require(processingStep == 1, "Wrong step");
uint256 currentDay = block.timestamp / 1 days; // number of days that passed
//uint256 currentDay = block.timestamp / 1 hours; // for TEST
uint256 precessedUsers = nextProcessUser;
uint256 lastUser = usersList.length();
while (precessedUsers < lastUser) {
address user = usersList.at(precessedUsers);
uint256 deposits = users[user].length;
if (numberUsers >= deposits) {
numberUsers -= deposits;
} else {
nextProcessUser = precessedUsers;
emit Processed(precessedUsers, lastUser, processingStep);
return;
}
for (uint256 i = 0; i < deposits; i++) {
_updateUser(currentDay, users[user][i]);
}
precessedUsers++;
}
processingStep = 2;
nextProcessUser = 0;
emit Processed(precessedUsers, lastUser, 1);
}
// call this function 1st day of each month to split month's result among users.
// numberUsers - is number of users that will processed at one transaction. Repeat call this function until emit event with number == total.
function splitResult(uint256 numberUsers) external onlyAdmin {
require(processingStep == 2, "Wrong step");
int256 _monthResult = monthResultAmount;
uint256 lastUser = usersList.length();
if (_monthResult == 0) { // exit if no amount to split
processingStep = 0;
emit Processed(lastUser, lastUser, 2);
return;
}
int256 _previousTotalStakedWeight = int256(previousTotalStakedWeight);
int256 split;
uint256 precessedUsers = nextProcessUser;
while (precessedUsers < lastUser) {
address user = usersList.at(precessedUsers);
uint256 deposits = users[user].length;
if (numberUsers >= deposits) {
numberUsers -= deposits;
} else {
nextProcessUser = precessedUsers;
totalStaked = uint256(int256(totalStaked) + split); // add to totalStaked split amount
emit Processed(precessedUsers, lastUser, processingStep);
return;
}
for (uint256 i = 0; i < deposits; i++) {
int256 wight = int256(users[user][i].previousWeightedTokens);
if (wight != 0) {
int256 stakedAmount = int256(users[user][i].amount);
int256 reward = _monthResult * wight * int64(users[user][i].multiplier) / (_previousTotalStakedWeight * 100);
split += reward;
if (reward > 0) users[user][i].reward += uint256(reward);
stakedAmount = stakedAmount + reward;
if (stakedAmount < 0) {
split = split - stakedAmount; // unsplit negative values
stakedAmount = 0;
}
users[user][i].amount = uint256(stakedAmount);
users[user][i].previousWeightedTokens = 0;
emit SplitResult(user, i, reward);
}
}
precessedUsers++;
}
totalStaked = uint256(int256(totalStaked) + split); // add to totalStaked split amount
processingStep = 0;
nextProcessUser = 0;
if (_monthResult > 0) {
uint256 bal = IBEP20(token).balanceOf(address(this));
if (bal > totalStaked) // send rest of money to owner
_safeTransfer(token, owner(), bal - totalStaked);
}
emit Processed(precessedUsers, lastUser, 2);
}
// allow owner to unstake token's on user behalf without waiting unlock time.
// user's deposit will be deleted.
function unstakeAdmin(address user, uint256 depositId, bool withdrawUSD) external onlyOwner {
uint256 currentDay = _updateWeight(); // number of days that passed
User storage u = users[user][depositId];
_updateUser(currentDay, u);
uint256 totalAmount = u.amount;
if (totalAmount != 0) {
if (withdrawUSD) {
_safeTransfer(token, owner(), totalAmount);
emit WithdrawUSD(user, totalAmount);
}
else {
_safeTransfer(token, user, totalAmount);
emit Unstake(user, totalAmount);
}
}
if (u.status == 0) totalStaked -= totalAmount;
totalStakedWeight -= u.weightedTokens;
previousTotalStakedWeight -= u.previousWeightedTokens;
// delete deposit records
uint256 lastDepositId = users[user].length - 1;
if (lastDepositId == 0) {
users[user].pop(); // delete last deposit
usersList.remove(user); // remove user from list
emit RemoveUser(user);
} else {
if (depositId != lastDepositId) users[user][depositId] = users[user][lastDepositId];
users[user].pop();
emit RemoveDeposit(user, depositId);
}
}
// User stake amount of tokens.
// User can't withdraw tokens/USD at least 90 days after first deposit or 30 days after further deposits
function stake(uint256 amount, uint256 period) external {
require(amount >= minimumAmount, "Staked amount is less then minimum");
uint256 mp = multiplier[period];
require(mp != 0, "Wrong period");
_safeTransferFrom(token, msg.sender, address(this), amount);
_stake(msg.sender, amount, period, mp);
}
// Owner stake amount of tokens on user behalf.
// user - address of user's wallet
// amount - amount of token to transfer on stake
// period - number of days when tokens will be locked on stake
// multiplier_ - multiplier (with 2 decimals) applied to deposit ([0.25 .. 1]). I.e. 25 means 0.25
function stakeBehalf(address user, uint256 amount, uint256 period, uint256 multiplier_) external onlyOwner {
require(multiplier_ <= 100, "Wrong multiplier");
_safeTransferFrom(token, msg.sender, address(this), amount);
_stake(user, amount, period, multiplier_);
}
// Withdraw rewards during allowed window.
function withdrawRewards(uint256 depositId, uint256 amount, bool withdrawUSD) external {
User storage u = users[msg.sender][depositId];
uint256 unlockTime = u.unlockTime;
if (block.timestamp < unlockTime) {
uint256 _days = unlockTime - block.timestamp;
_days = _days % prolongate;
require(_days > prolongate - withdrawWindow || _days == 0, "Out of withdraw window");
uint256 reward = u.reward;
require(amount <= reward && amount <= u.amount, "Not enough rewards");
uint256 currentDay = _updateWeight(); // number of days that passed
_updateUser(currentDay, u);
u.reward = reward - amount;
u.amount -= amount;
if (u.status == 0) totalStaked -= amount;
if (withdrawUSD) {
_safeTransfer(token, owner(), amount);
emit WithdrawUSD(msg.sender, amount);
}
else {
_safeTransfer(token, msg.sender, amount);
emit Unstake(msg.sender, amount);
}
} else {
_unstake(msg.sender, depositId, withdrawUSD);
}
}
// unstake tokens to user wallet or withdraw USD (tokens will be send to owner())
// User can't unstake/withdraw at least 90 days after first deposit or 30 days after further deposits
function unstake(uint256 depositId, bool withdrawUSD) external {
require(block.timestamp >= users[msg.sender][depositId].unlockTime, "Account locked");
_unstake(msg.sender, depositId, withdrawUSD);
}
// Stake amount for selected period (in days)
function _stake(address user, uint256 amount, uint256 period, uint256 multiplier_) internal {
_updateWeight();
require(users[user].length < 10, "Allowed 10 deposits per wallet");
totalStaked += amount;
usersList.add(user);
users[user].push(
User({
amount: amount,
weightedTokens: 0,
previousWeightedTokens: 0,
reward: 0,
unlockTime: uint64(block.timestamp + (period * 1 days)),
updated: uint64(block.timestamp / 1 days),
//unlockTime: uint64(block.timestamp + (period * 1 hours)), // for TEST
//updated: uint64(block.timestamp / 1 hours), // for TEST
multiplier: uint64(multiplier_),
status: 0
})
);
emit Stake(user, amount, period, multiplier_);
}
function _unstake(address user, uint256 depositId, bool withdrawUSD) internal {
uint256 currentDay = _updateWeight(); // number of days that passed
User storage u = users[user][depositId];
_updateUser(currentDay, u);
uint256 totalAmount = u.amount;
u.amount = 0;
u.reward = 0;
if (totalAmount != 0) {
if (withdrawUSD) {
_safeTransfer(token, owner(), totalAmount);
emit WithdrawUSD(user, totalAmount);
}
else {
_safeTransfer(token, user, totalAmount);
emit Unstake(user, totalAmount);
}
}
if(u.previousWeightedTokens == 0 && u.weightedTokens == 0) {
// delete deposit records
uint256 lastDepositId = users[user].length - 1;
if (lastDepositId == 0) {
users[user].pop(); // delete last deposit
usersList.remove(user); // remove user from list
emit RemoveUser(user);
} else {
if (depositId != lastDepositId) users[user][depositId] = users[user][lastDepositId];
users[user].pop();
emit RemoveDeposit(user, depositId);
}
}
}
function _updateUser(uint256 currentDay, User storage u) internal {
uint8 status = u.status; // 0 - active, 1 - ended (weightedTokens > 0), 2 - ended (previousWeightedTokens > 0), 3 - ended, but not withdrawn
if (status == 0) {
uint256 amount = u.amount;
uint256 weightedTokens = u.weightedTokens;
uint256 unlockDay = u.unlockTime / 1 days;
if (unlockDay <= currentDay) {
// Stacking ends. Fix previous weight.
(uint256 previousStakedWeight, uint256 stakedWeight) =
_calculateWeight(currentDay, unlockDay, amount, weightedTokens);
totalStakedWeight -= stakedWeight;
if (previousStakedWeight != 0)
previousTotalStakedWeight -= previousStakedWeight;
(previousStakedWeight, stakedWeight) =
_calculateWeight(unlockDay, u.updated, amount, weightedTokens);
u.updated = uint64(currentDay);
u.weightedTokens = stakedWeight;
if (previousStakedWeight != 0)
u.previousWeightedTokens = previousStakedWeight;
if(stakedWeight != 0) {
u.status = 1; // no active staked amount
} else if (previousStakedWeight != 0) {
u.status = 2;
} else {
u.status = 3;
}
totalStaked -= amount;
} else {
(uint256 previousStakedWeight, uint256 stakedWeight) =
_calculateWeight(currentDay, u.updated, amount, weightedTokens);
u.updated = uint64(currentDay);
u.weightedTokens = stakedWeight;
if (previousStakedWeight != 0)
u.previousWeightedTokens = previousStakedWeight;
}
} else if (status == 1 && u.updated < currentDay && u.previousWeightedTokens == 0) {
u.previousWeightedTokens = u.weightedTokens;
u.weightedTokens = 0;
if (u.previousWeightedTokens != 0) {
u.status = 2;
} else {
u.status = 3;
}
}
}
function _updateWeight() internal returns(uint256 currentDay) {
currentDay = block.timestamp / 1 days; // number of days that passed
//currentDay = block.timestamp / 1 hours; // for TEST
if (currentDay > processedDay) {
(uint256 previousStakedWeight, uint256 stakedWeight) =
_calculateWeight(currentDay, processedDay, totalStaked, totalStakedWeight);
processedDay = currentDay;
totalStakedWeight = stakedWeight;
if (previousStakedWeight != 0)
previousTotalStakedWeight = previousStakedWeight;
}
}
function _calculateWeight(uint256 currentDay, uint256 lastUpdate, uint256 amount, uint256 currentStakedWeight) internal pure returns(uint256 previousStakedWeight, uint256 stakedWeight) {
stakedWeight = currentStakedWeight;
if (currentDay > lastUpdate) {
uint256 interval = currentDay - lastUpdate;
(,,uint day) = _daysToDate(currentDay);
if (day <= interval) { // new month starts
uint256 previousInterval = interval - day + 1;
previousStakedWeight = currentStakedWeight + (amount * previousInterval);
interval = interval - previousInterval; // number of days passed in current month
stakedWeight = amount * interval; // start total staked weight from zero
}
else {
stakedWeight = currentStakedWeight + (amount * interval);
}
}
}
// TEST ========================================================================================================
/*
function TEST_calculateWeight(uint256 currentDay, uint256 lastUpdate, uint256 amount, uint256 currentStakedWeight) public pure returns(uint256 previousStakedWeight, uint256 stakedWeight) {
stakedWeight = currentStakedWeight;
if (currentDay > lastUpdate) {
uint256 interval = currentDay - lastUpdate;
uint day = (currentDay % 24) + 1; // 1 hour = 1 day, 24 hours = 1 month
if (day <= interval) { // new month starts
uint256 previousInterval = interval - day + 1;
previousStakedWeight = currentStakedWeight + (amount * previousInterval);
interval = interval - previousInterval; // number of days passed in current month
stakedWeight = amount * interval; // start total staked weight from zero
}
else {
stakedWeight = currentStakedWeight + (amount * interval);
}
}
}
*/
// END TEST ====================================================================================================
function _safeTransfer(address _token, address to, uint value) internal {
// bytes4(keccak256(bytes('transfer(address,uint256)')));
(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 {
// bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
(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');
}
/**
* @dev Calculate number of days from 1/1/1970 to selected date.
* @param year The year number
* @param month The month number
* @param day The day number
* @return _days number of day.
*/
function _daysFromDate(uint year, uint month, uint day) internal pure returns (uint _days) {
require(year >= 1970);
int _year = int(year);
int _month = int(month);
int _day = int(day);
int __days = _day
- 32075
+ 1461 * (_year + 4800 + (_month - 14) / 12) / 4
+ 367 * (_month - 2 - (_month - 14) / 12 * 12) / 12
- 3 * ((_year + 4900 + (_month - 14) / 12) / 100) / 4
- 2440588;
_days = uint(__days);
}
/**
* @dev Calculate timestamp (UNIX time) of selected date and time.
* @param year The year number
* @param month The month number
* @param day The day number
* @param hour number of hours
* @param minute number of minutes
* @param second number of seconds
* @return timestamp UNIX time
*/
function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (uint timestamp) {
timestamp = _daysFromDate(year, month, day) * 86400 + hour * 3600 + minute * 60 + second;
}
function _daysToDate(uint _days) internal pure returns (uint year, uint month, uint day) {
int __days = int(_days);
int L = __days + 68569 + 2440588;
int N = 4 * L / 146097;
L = L - (146097 * N + 3) / 4;
int _year = 4000 * (L + 1) / 1461001;
L = L - 1461 * _year / 4 + 31;
int _month = 80 * L / 2447;
int _day = L - 2447 * _month / 80;
L = _month / 11;
_month = _month + 2 - 12 * L;
_year = 100 * (N - 49) + _year + L;
year = uint(_year);
month = uint(_month);
day = uint(_day);
}
/**
* @dev Calculate date from timestamp (UNIX time) .
* @param timestamp UNIX time
* @return year The year number
* @return month The month number
* @return day The day number
*/
function timestampToDate(uint timestamp) internal pure returns (uint year, uint month, uint day) {
(year, month, day) = _daysToDate(timestamp / 86400);
}
}
Contract ABI
[{"type":"event","name":"MonthResult","inputs":[{"type":"int256","name":"amount","internalType":"int256","indexed":false}],"anonymous":false},{"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":"Processed","inputs":[{"type":"uint256","name":"number","internalType":"uint256","indexed":false},{"type":"uint256","name":"total","internalType":"uint256","indexed":false},{"type":"uint256","name":"step","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RemoveDeposit","inputs":[{"type":"address","name":"user","internalType":"address","indexed":false},{"type":"uint256","name":"depositId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RemoveUser","inputs":[{"type":"address","name":"user","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"SetAdmin","inputs":[{"type":"address","name":"admin","internalType":"address","indexed":false},{"type":"bool","name":"isActive","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"SplitResult","inputs":[{"type":"address","name":"user","internalType":"address","indexed":false},{"type":"uint256","name":"depositId","internalType":"uint256","indexed":false},{"type":"int256","name":"amount","internalType":"int256","indexed":false}],"anonymous":false},{"type":"event","name":"Stake","inputs":[{"type":"address","name":"user","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"period","internalType":"uint256","indexed":false},{"type":"uint256","name":"multiplier","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Unstake","inputs":[{"type":"address","name":"user","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"WithdrawUSD","inputs":[{"type":"address","name":"user","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"admins","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"int256","name":"","internalType":"int256"}],"name":"amountPerWeightedToken","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct Staking.User[]","components":[{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"weightedTokens","internalType":"uint256"},{"type":"uint256","name":"previousWeightedTokens","internalType":"uint256"},{"type":"uint256","name":"reward","internalType":"uint256"},{"type":"uint64","name":"unlockTime","internalType":"uint64"},{"type":"uint64","name":"updated","internalType":"uint64"},{"type":"uint64","name":"multiplier","internalType":"uint64"},{"type":"uint8","name":"status","internalType":"uint8"}]}],"name":"getUsersDeposits","inputs":[{"type":"address","name":"user","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getUsersDepositsNumber","inputs":[{"type":"address","name":"user","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getUsersNumber","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"newOwner","internalType":"address"},{"type":"address","name":"_token","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"minimumAmount","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"monthResult","inputs":[{"type":"int256","name":"amount","internalType":"int256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"int256","name":"","internalType":"int256"}],"name":"monthResultAmount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"multiplier","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"nextProcessUser","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"precessedMonth","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"previousTotalStakedWeight","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"processedDay","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"processingStep","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"prolongate","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"recalculateWeight","inputs":[{"type":"uint256","name":"numberUsers","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setAdmin","inputs":[{"type":"address","name":"admin","internalType":"address"},{"type":"bool","name":"isActive","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMinimumAmount","inputs":[{"type":"uint256","name":"_minAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMultiplier","inputs":[{"type":"uint256","name":"_days","internalType":"uint256"},{"type":"uint256","name":"_multiplier","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setProlongate","inputs":[{"type":"uint256","name":"time","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setWithdrawWindow","inputs":[{"type":"uint256","name":"time","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"splitResult","inputs":[{"type":"uint256","name":"numberUsers","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"stake","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"period","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"stakeBehalf","inputs":[{"type":"address","name":"user","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"period","internalType":"uint256"},{"type":"uint256","name":"multiplier_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"token","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalStaked","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalStakedWeight","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unstake","inputs":[{"type":"uint256","name":"depositId","internalType":"uint256"},{"type":"bool","name":"withdrawUSD","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unstakeAdmin","inputs":[{"type":"address","name":"user","internalType":"address"},{"type":"uint256","name":"depositId","internalType":"uint256"},{"type":"bool","name":"withdrawUSD","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"weightedTokens","internalType":"uint256"},{"type":"uint256","name":"previousWeightedTokens","internalType":"uint256"},{"type":"uint256","name":"reward","internalType":"uint256"},{"type":"uint64","name":"unlockTime","internalType":"uint64"},{"type":"uint64","name":"updated","internalType":"uint64"},{"type":"uint64","name":"multiplier","internalType":"uint64"},{"type":"uint8","name":"status","internalType":"uint8"}],"name":"users","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawRewards","inputs":[{"type":"uint256","name":"depositId","internalType":"uint256"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"bool","name":"withdrawUSD","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"withdrawWindow","inputs":[]}]
Contract Creation Code
0x608060405234801561001057600080fd5b50613054806100206000396000f3fe608060405234801561001057600080fd5b50600436106102115760003560e01c80639ebea88c11610125578063ebda3b05116100ad578063eeb4a9c81161007c578063eeb4a9c814610485578063f2fde38b14610498578063f7cb8124146104ab578063fc0c546a146104b4578063ff293df3146104c757600080fd5b8063ebda3b051461044d578063ed47ab5b14610456578063edcb208b14610469578063ee79da191461047c57600080fd5b8063bbe0d9f6116100f4578063bbe0d9f61461040c578063bc10b1721461041f578063cb028a8314610428578063e03aabe614610431578063e6fc015e1461043a57600080fd5b80639ebea88c146103de578063aa8c5324146103f1578063ab2e58dd146103fa578063bb0c82981461040357600080fd5b80634b0bddd2116101a85780637b0472f0116101775780637b0472f01461038c5780637fe912391461039f578063817b1cd2146103a75780638da5cb5b146103b05780639652b121146103d557600080fd5b80634b0bddd2146102fd57806354a02f9e146103105780635c141991146103705780636696f3ff1461038357600080fd5b8063333271d0116101e4578063333271d01461029157806334553147146102a4578063429b62e5146102b7578063485cc955146102ea57600080fd5b806305e30f511461021657806313c028461461024957806320114ac21461025e57806328a6a2dd14610271575b600080fd5b610236610224366004612c29565b60056020526000908152604090205481565b6040519081526020015b60405180910390f35b61025c610257366004612c29565b6104f0565b005b61025c61026c366004612c29565b6106d2565b61028461027f366004612ae4565b6108fe565b6040516102409190612d04565b61025c61029f366004612c7d565b6109d5565b61025c6102b2366004612c9e565b610a64565b6102da6102c5366004612ae4565b60126020526000908152604090205460ff1681565b6040519015158152602001610240565b61025c6102f8366004612b05565b610cd1565b61025c61030b366004612b37565b610e0c565b61032361031e366004612b6d565b610ea1565b6040805198895260208901979097529587019490945260608601929092526001600160401b03908116608086015290811660a08501521660c083015260ff1660e082015261010001610240565b61025c61037e366004612c29565b610f18565b61023660105481565b61025c61039a366004612c7d565b610f56565b610236611027565b61023660095481565b6000546001600160a01b03165b6040516001600160a01b039091168152602001610240565b610236600d5481565b61025c6103ec366004612c59565b611037565b61023660075481565b61023660115481565b61023660085481565b61025c61041a366004612bd5565b6110d2565b610236600a5481565b61023660065481565b610236600f5481565b61025c610448366004612c29565b611179565b610236600e5481565b61025c610464366004612b96565b611713565b61025c610477366004612c29565b611bfb565b610236600c5481565b61025c610493366004612c29565b611c39565b61025c6104a6366004612ae4565b611c77565b610236600b5481565b6001546103bd906001600160a01b031681565b6102366104d5366004612ae4565b6001600160a01b031660009081526004602052604090205490565b336105036000546001600160a01b031690565b6001600160a01b0316146105325760405162461bcd60e51b815260040161052990612da7565b60405180910390fd5b600e541561058c5760405162461bcd60e51b815260206004820152602160248201527f50726576696f757320726573756c7420776173206e6f742070726f63657373656044820152601960fa1b6064820152608401610529565b610594611d70565b5060006105a042611dc1565b509150508060105414156106065760405162461bcd60e51b815260206004820152602760248201527f526573756c74206d6179206265206164646564206f6e6c79206f6e63652070656044820152660e440dadedce8d60cb1b6064820152608401610529565b6010819055600d829055600954600090610621908490612ddc565b121561066f5760405162461bcd60e51b815260206004820152601c60248201527f746f74616c5374616b6564206c657373207468656e20616d6f756e74000000006044820152606401610529565b600082131561069057600154610690906001600160a01b0316333085611de7565b6001600e5560006011556040518281527f7e378eda7a53c9c96fb609c656ea4cddfd3f364b2fd5a0338fed559471da4fbe906020015b60405180910390a15050565b3360009081526012602052604090205460ff16806107095750336106fe6000546001600160a01b031690565b6001600160a01b0316145b61074b5760405162461bcd60e51b815260206004820152601360248201527221b0b63632b91034b9903737ba1030b236b4b760691b6044820152606401610529565b600e5460011461078a5760405162461bcd60e51b815260206004820152600a602482015269057726f6e6720737465760b41b6044820152606401610529565b60006107996201518042612e63565b60115490915060006107aa60025490565b90505b808210156108ba5760006107c2600284611f17565b6001600160a01b0381166000908152600460205260409020549091508086106107f6576107ef8187612f7e565b9550610837565b6011849055600e54604080518681526020810186905290810191909152600080516020612fff833981519152906060015b60405180910390a1505050505050565b60005b818110156108a5576001600160a01b038316600090815260046020526040902080546108939188918490811061088057634e487b7160e01b600052603260045260246000fd5b9060005260206000209060050201611fb6565b8061089d81612f95565b91505061083a565b50836108b081612f95565b94505050506107ad565b6002600e5560006011556040805183815260208101839052600191810191909152600080516020612fff833981519152906060015b60405180910390a15050505b50565b6001600160a01b0381166000908152600460209081526040808320805482518185028101850190935280835260609492939192909184015b828210156109ca576000848152602090819020604080516101008101825260058602909201805483526001808201548486015260028201549284019290925260038101546060840152600401546001600160401b038082166080850152600160401b8204811660a0850152600160801b82041660c0840152600160c01b900460ff1660e08301529083529092019101610936565b505050509050919050565b336109e86000546001600160a01b031690565b6001600160a01b031614610a0e5760405162461bcd60e51b815260040161052990612da7565b6064811115610a525760405162461bcd60e51b815260206004820152601060248201526f2bb937b7339036bab63a34b83634b2b960811b6044820152606401610529565b60009182526005602052604090912055565b336000908152600460205260408120805485908110610a9357634e487b7160e01b600052603260045260246000fd5b6000918252602090912060059091020160048101549091506001600160401b031642811115610cbf576000610ac84283612f7e565b905060075481610ad89190612fb0565b9050600654600754610aea9190612f7e565b811180610af5575080155b610b3a5760405162461bcd60e51b81526020600482015260166024820152754f7574206f662077697468647261772077696e646f7760501b6044820152606401610529565b6003830154808611801590610b50575083548611155b610b915760405162461bcd60e51b81526020600482015260126024820152714e6f7420656e6f756768207265776172647360701b6044820152606401610529565b6000610b9b611d70565b9050610ba78186611fb6565b610bb18783612f7e565b6003860155845487908690600090610bca908490612f7e565b90915550506004850154600160c01b900460ff16610bfa578660096000828254610bf49190612f7e565b90915550505b8515610c6657600154610c28906001600160a01b0316610c226000546001600160a01b031690565b89612214565b60408051338152602081018990527fa859066e89895ffb9f2cdf2af7e7e84061fcb7ddd8657877c264737f25f8b655910160405180910390a1610cb7565b600154610c7d906001600160a01b03163389612214565b60408051338152602081018990527f85082129d87b2fe11527cb1b3b7a520aeb5aa6913f88a3d8757fe40d1db02fdd910160405180910390a15b505050610cca565b610cca338685612328565b5050505050565b6001600160a01b03821615801590610cf257506000546001600160a01b0316155b610cfb57600080fd5b600080546001600160a01b038085166001600160a01b031992831617835560018054918516919092161790556040513391907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350506206978060065562278d00600755680ad78ebc5ac6200000600855600560205260197faadf04b4a1bf84e121ab68e5c1cffab5aeb9be1a024ff9944a2a0bc1674866095560327fec79235ffe9302935718f9bddc23f2c5c6c950ae49f49d137c786213c361802755604b7fe78ea91a221fb67f10aba14ba22dc39f780130b5cf7d2295f57a7414e295968b5561016860005260647f5464d34515fb195718451914a9b5e2c4ac04dce5fd392ea5e3f190355ea2fb7e55565b33610e1f6000546001600160a01b031690565b6001600160a01b031614610e455760405162461bcd60e51b815260040161052990612da7565b6001600160a01b038216600081815260126020908152604091829020805460ff19168515159081179091558251938452908301527f55a5194bc0174fcaf12b2978bef43911466bf63b34db8d1dd1a0d5dcd5c41bea91016106c6565b60046020528160005260406000208181548110610ebd57600080fd5b60009182526020909120600590910201805460018201546002830154600384015460049094015492955090935091906001600160401b0380821691600160401b8104821691600160801b82041690600160c01b900460ff1688565b33610f2b6000546001600160a01b031690565b6001600160a01b031614610f515760405162461bcd60e51b815260040161052990612da7565b600755565b600854821015610fb35760405162461bcd60e51b815260206004820152602260248201527f5374616b656420616d6f756e74206973206c657373207468656e206d696e696d604482015261756d60f01b6064820152608401610529565b60008181526005602052604090205480610ffe5760405162461bcd60e51b815260206004820152600c60248201526b15dc9bdb99c81c195c9a5bd960a21b6044820152606401610529565b600154611016906001600160a01b0316333086611de7565b611022338484846124a2565b505050565b600061103260025490565b905090565b33600090815260046020526040902080548390811061106657634e487b7160e01b600052603260045260246000fd5b60009182526020909120600460059092020101546001600160401b03164210156110c35760405162461bcd60e51b815260206004820152600e60248201526d1058d8dbdd5b9d081b1bd8dad95960921b6044820152606401610529565b6110ce338383612328565b5050565b336110e56000546001600160a01b031690565b6001600160a01b03161461110b5760405162461bcd60e51b815260040161052990612da7565b606481111561114f5760405162461bcd60e51b815260206004820152601060248201526f2bb937b7339036bab63a34b83634b2b960811b6044820152606401610529565b600154611167906001600160a01b0316333086611de7565b611173848484846124a2565b50505050565b3360009081526012602052604090205460ff16806111b05750336111a56000546001600160a01b031690565b6001600160a01b0316145b6111f25760405162461bcd60e51b815260206004820152601360248201527221b0b63632b91034b9903737ba1030b236b4b760691b6044820152606401610529565b600e546002146112315760405162461bcd60e51b815260206004820152600a602482015269057726f6e6720737465760b41b6044820152606401610529565b600d54600061123f60025490565b90508161127e576000600e5560408051828152602081018390526002818301529051600080516020612fff8339815191529181900360600190a1505050565b600b546011546000905b8381101561160257600061129d600283611f17565b6001600160a01b0381166000908152600460205260409020549091508088106112d1576112ca8189612f7e565b9750611322565b60118390556009546112e4908590612ddc565b600955600e5460408051858152602081018990528082019290925251600080516020612fff8339815191529181900360600190a15050505050505050565b60005b818110156115ed576001600160a01b038316600090815260046020526040812080548390811061136557634e487b7160e01b600052603260045260246000fd5b9060005260206000209060050201600201549050806000146115da576001600160a01b03841660009081526004602052604081208054849081106113b957634e487b7160e01b600052603260045260246000fd5b6000918252602082206005909102015491506113d6896064612e9d565b6001600160a01b038716600090815260046020526040902080548690811061140e57634e487b7160e01b600052603260045260246000fd5b6000918252602090912060059091020160040154600160801b90046001600160401b031660070b61143f858e612e9d565b6114499190612e9d565b6114539190612e35565b905061145f8189612ddc565b975060008113156114cb576001600160a01b03861660009081526004602052604090208054829190869081106114a557634e487b7160e01b600052603260045260246000fd5b906000526020600020906005020160030160008282546114c59190612e1d565b90915550505b6114d58183612ddc565b915060008212156114f1576114ea8289612f3f565b9750600091505b6001600160a01b038616600090815260046020526040902080548391908690811061152c57634e487b7160e01b600052603260045260246000fd5b600091825260208083206005909202909101929092556001600160a01b038816815260049091526040812080548690811061157757634e487b7160e01b600052603260045260246000fd5b600091825260209182902060026005909202010191909155604080516001600160a01b038916815291820186905281018290527f4410f5289f71baff2baf30dad8844d6c4d5af1f55fd01dd890aec66584f1677c9060600160405180910390a150505b50806115e581612f95565b915050611325565b50826115f881612f95565b9350505050611288565b816009546116109190612ddc565b6009556000600e81905560118190558513156116e4576001546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b15801561166a57600080fd5b505afa15801561167e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a29190612c41565b90506009548111156116e2576001546116e2906001600160a01b03166116d06000546001600160a01b031690565b6009546116dd9085612f7e565b612214565b505b6040805182815260208101869052600291810191909152600080516020612fff83398151915290606001610827565b336117266000546001600160a01b031690565b6001600160a01b03161461174c5760405162461bcd60e51b815260040161052990612da7565b6000611756611d70565b6001600160a01b0385166000908152600460205260408120805492935090918590811061179357634e487b7160e01b600052603260045260246000fd5b906000526020600020906005020190506117ad8282611fb6565b8054801561188457831561182a576001546117e3906001600160a01b03166117dd6000546001600160a01b031690565b83612214565b604080516001600160a01b0388168152602081018390527fa859066e89895ffb9f2cdf2af7e7e84061fcb7ddd8657877c264737f25f8b655910160405180910390a1611884565b600154611841906001600160a01b03168783612214565b604080516001600160a01b0388168152602081018390527f85082129d87b2fe11527cb1b3b7a520aeb5aa6913f88a3d8757fe40d1db02fdd910160405180910390a15b6004820154600160c01b900460ff166118af5780600960008282546118a99190612f7e565b90915550505b8160010154600a60008282546118c59190612f7e565b90915550506002820154600b80546000906118e1908490612f7e565b90915550506001600160a01b03861660009081526004602052604081205461190b90600190612f7e565b9050806119d5576001600160a01b038716600090815260046020526040902080548061194757634e487b7160e01b600052603160045260246000fd5b600082815260208120600560001990930192830201818155600181018290556002808201839055600382019290925560040180546001600160c81b0319169055915561199390886126d8565b506040516001600160a01b03881681527f0ad8e54ac59bf2d8a7a1474c1af503b593553cf4fcaaffdef04ab5249f89762b9060200160405180910390a1611bf2565b808614611b36576001600160a01b0387166000908152600460205260409020805482908110611a1457634e487b7160e01b600052603260045260246000fd5b906000526020600020906005020160046000896001600160a01b03166001600160a01b031681526020019081526020016000208781548110611a6657634e487b7160e01b600052603260045260246000fd5b6000918252602090912082546005909202019081556001808301549082015560028083015490820155600380830154908201556004918201805492909101805467ffffffffffffffff1981166001600160401b0394851690811783558354600160401b908190048616026001600160801b031990921617178082558254600160801b9081900490941690930267ffffffffffffffff60801b19841681178255915460ff600160c01b91829004160260ff60c01b1990921668ffffffffffffffffff60801b19909316929092171790555b6001600160a01b0387166000908152600460205260409020805480611b6b57634e487b7160e01b600052603160045260246000fd5b600082815260208082206005600019949094019384020182815560018101839055600281018390556003810192909255600490910180546001600160c81b03191690559155604080516001600160a01b038a1681529182018890527f52da67f845146a7b07a837a7e32b5b74f6d3fafb17ec6c04f23acfc9e1aa9d1f910160405180910390a15b50505050505050565b33611c0e6000546001600160a01b031690565b6001600160a01b031614611c345760405162461bcd60e51b815260040161052990612da7565b600655565b33611c4c6000546001600160a01b031690565b6001600160a01b031614611c725760405162461bcd60e51b815260040161052990612da7565b600855565b33611c8a6000546001600160a01b031690565b6001600160a01b031614611cb05760405162461bcd60e51b815260040161052990612da7565b6001600160a01b038116611d155760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610529565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000611d7f6201518042612e63565b9050600f54811115611dbe57600080611da083600f54600954600a54612844565b600f859055600a81905590925090508115611dbb57600b8290555b50505b90565b60008080611dda611dd56201518086612e63565b6128e3565b9196909550909350915050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092839290881691611e4b9190612ccb565b6000604051808303816000865af19150503d8060008114611e88576040519150601f19603f3d011682016040523d82523d6000602084013e611e8d565b606091505b5091509150818015611eb7575080511580611eb7575080806020019051810190611eb79190612c0d565b611f0f5760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b6064820152608401610529565b505050505050565b81546000908210611f755760405162461bcd60e51b815260206004820152602260248201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604482015261647360f01b6064820152608401610529565b826000018281548110611f9857634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b031690505b92915050565b6004810154600160c01b900460ff168061219457815460018301546004840154600090611ff09062015180906001600160401b0316612e77565b6001600160401b031690508581116121225760008061201188848787612844565b9150915080600a60008282546120279190612f7e565b9091555050811561204a5781600b60008282546120449190612f7e565b90915550505b600487015461206c908490600160401b90046001600160401b03168787612844565b60048901805467ffffffffffffffff60401b1916600160401b6001600160401b038d160217905560018901819055909250905081156120ad57600287018290555b80156120cd5760048701805460ff60c01b1916600160c01b179055612103565b81156120ed5760048701805460ff60c01b1916600160c11b179055612103565b60048701805460ff60c01b1916600360c01b1790555b84600960008282546121159190612f7e565b90915550611f0f92505050565b60048501546000908190612149908990600160401b90046001600160401b03168787612844565b60048901805467ffffffffffffffff60401b1916600160401b6001600160401b038d1602179055600189018190559092509050811561218a57600287018290555b5050505050505050565b8060ff1660011480156121ba57506004820154600160401b90046001600160401b031683115b80156121c857506002820154155b1561102257600182018054600284018190556000909155156121fc5750600401805460ff60c01b1916600160c11b17905550565b50600401805460ff60c01b1916600360c01b17905550565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916122709190612ccb565b6000604051808303816000865af19150503d80600081146122ad576040519150601f19603f3d011682016040523d82523d6000602084013e6122b2565b606091505b50915091508180156122dc5750805115806122dc5750808060200190518101906122dc9190612c0d565b610cca5760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610529565b6000612332611d70565b6001600160a01b0385166000908152600460205260408120805492935090918590811061236f57634e487b7160e01b600052603260045260246000fd5b906000526020600020906005020190506123898282611fb6565b805460008083556003830155801561246457831561240a576001546123c3906001600160a01b03166117dd6000546001600160a01b031690565b604080516001600160a01b0388168152602081018390527fa859066e89895ffb9f2cdf2af7e7e84061fcb7ddd8657877c264737f25f8b655910160405180910390a1612464565b600154612421906001600160a01b03168783612214565b604080516001600160a01b0388168152602081018390527f85082129d87b2fe11527cb1b3b7a520aeb5aa6913f88a3d8757fe40d1db02fdd910160405180910390a15b600282015415801561247857506001820154155b15611f0f576001600160a01b03861660009081526004602052604081205461190b90600190612f7e565b6124aa611d70565b506001600160a01b038416600090815260046020526040902054600a116125135760405162461bcd60e51b815260206004820152601e60248201527f416c6c6f776564203130206465706f73697473207065722077616c6c657400006044820152606401610529565b82600960008282546125259190612e1d565b909155506125369050600285612a56565b5060046000856001600160a01b03166001600160a01b0316815260200190815260200160002060405180610100016040528085815260200160008152602001600081526020016000815260200184620151806125929190612f20565b61259c9042612e1d565b6001600160401b031681526020016125b76201518042612e63565b6001600160401b0390811682528481166020808401919091526000604093840181905285546001818101885596825290829020855160059092020190815590840151948101949094558282015160028501556060830151600385015560808301516004909401805460a085015160c086015160e09096015160ff16600160c01b0260ff60c01b19968516600160801b029690961668ffffffffffffffffff60801b19918516600160401b026001600160801b0319909316979094169690961717949094161791909117909155517ff556991011e831bcfac4f406d547e5e32cdd98267efab83935230d5f8d02c446906108ef9086908690869086906001600160a01b0394909416845260208401929092526040830152606082015260800190565b6001600160a01b0381166000908152600183016020526040812054801561283a576000612706600183612f7e565b855490915060009061271a90600190612f7e565b9050600086600001828154811061274157634e487b7160e01b600052603260045260246000fd5b60009182526020909120015487546001600160a01b039091169150819088908590811061277e57634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160a01b0319166001600160a01b03929092169190911790556127b2836001612e1d565b6001600160a01b038216600090815260018901602052604090205586548790806127ec57634e487b7160e01b600052603160045260246000fd5b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b0388168252600189810190915260408220919091559450611fb09350505050565b6000915050611fb0565b600081848611156128da57600061285b8688612f7e565b90506000612868886128e3565b925050508181116128c057600061287f8284612f7e565b61288a906001612e1d565b90506128968188612f20565b6128a09087612e1d565b94506128ac8184612f7e565b92506128b88388612f20565b9350506128d7565b6128ca8287612f20565b6128d49086612e1d565b92505b50505b94509492505050565b6000808083816128f68262010bd9612ddc565b6129039062253d8c612ddc565b9050600062023ab1612916836004612e9d565b6129209190612e35565b905060046129318262023ab1612e9d565b61293c906003612ddc565b6129469190612e35565b6129509083612f3f565b9150600062164b09612963846001612ddc565b61296f90610fa0612e9d565b6129799190612e35565b90506004612989826105b5612e9d565b6129939190612e35565b61299d9084612f3f565b6129a890601f612ddc565b9250600061098f6129ba856050612e9d565b6129c49190612e35565b9050600060506129d68361098f612e9d565b6129e09190612e35565b6129ea9086612f3f565b90506129f7600b83612e35565b9450612a0485600c612e9d565b612a0f836002612ddc565b612a199190612f3f565b91508483612a28603187612f3f565b612a33906064612e9d565b612a3d9190612ddc565b612a479190612ddc565b9a919950975095505050505050565b6001600160a01b0381166000908152600183016020526040812054612ac057508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b03861690811790915585549082528286019093526040902091909155611fb0565b506000611fb0565b80356001600160a01b0381168114612adf57600080fd5b919050565b600060208284031215612af5578081fd5b612afe82612ac8565b9392505050565b60008060408385031215612b17578081fd5b612b2083612ac8565b9150612b2e60208401612ac8565b90509250929050565b60008060408385031215612b49578182fd5b612b5283612ac8565b91506020830135612b6281612ff0565b809150509250929050565b60008060408385031215612b7f578182fd5b612b8883612ac8565b946020939093013593505050565b600080600060608486031215612baa578081fd5b612bb384612ac8565b9250602084013591506040840135612bca81612ff0565b809150509250925092565b60008060008060808587031215612bea578081fd5b612bf385612ac8565b966020860135965060408601359560600135945092505050565b600060208284031215612c1e578081fd5b8151612afe81612ff0565b600060208284031215612c3a578081fd5b5035919050565b600060208284031215612c52578081fd5b5051919050565b60008060408385031215612c6b578182fd5b823591506020830135612b6281612ff0565b60008060408385031215612c8f578182fd5b50508035926020909101359150565b600080600060608486031215612cb2578283fd5b83359250602084013591506040840135612bca81612ff0565b60008251815b81811015612ceb5760208186018101518583015201612cd1565b81811115612cf95782828501525b509190910192915050565b602080825282518282018190526000919060409081850190868401855b82811015612d9a5781518051855286810151878601528581015186860152606080820151908601526080808201516001600160401b039081169187019190915260a08083015182169087015260c0808301519091169086015260e09081015160ff16908501526101009093019290850190600101612d21565b5091979650505050505050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b600080821280156001600160ff1b0384900385131615612dfe57612dfe612fc4565b600160ff1b8390038412811615612e1757612e17612fc4565b50500190565b60008219821115612e3057612e30612fc4565b500190565b600082612e4457612e44612fda565b600160ff1b821460001984141615612e5e57612e5e612fc4565b500590565b600082612e7257612e72612fda565b500490565b60006001600160401b0380841680612e9157612e91612fda565b92169190910492915050565b60006001600160ff1b0381841382841380821686840486111615612ec357612ec3612fc4565b600160ff1b84871282811687830589121615612ee157612ee1612fc4565b858712925087820587128484161615612efc57612efc612fc4565b87850587128184161615612f1257612f12612fc4565b505050929093029392505050565b6000816000190483118215151615612f3a57612f3a612fc4565b500290565b60008083128015600160ff1b850184121615612f5d57612f5d612fc4565b6001600160ff1b0384018313811615612f7857612f78612fc4565b50500390565b600082821015612f9057612f90612fc4565b500390565b6000600019821415612fa957612fa9612fc4565b5060010190565b600082612fbf57612fbf612fda565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b80151581146108fb57600080fdfec534675d962a9c4b4a6eef4e934d46b14162000192fa31cf0c29cd81fdb8c2eea264697066735822122047a55bd19ac71dcd1a3095db5fce55b6bd983cb71d4b8cd5304175935d04552764736f6c63430008040033
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106102115760003560e01c80639ebea88c11610125578063ebda3b05116100ad578063eeb4a9c81161007c578063eeb4a9c814610485578063f2fde38b14610498578063f7cb8124146104ab578063fc0c546a146104b4578063ff293df3146104c757600080fd5b8063ebda3b051461044d578063ed47ab5b14610456578063edcb208b14610469578063ee79da191461047c57600080fd5b8063bbe0d9f6116100f4578063bbe0d9f61461040c578063bc10b1721461041f578063cb028a8314610428578063e03aabe614610431578063e6fc015e1461043a57600080fd5b80639ebea88c146103de578063aa8c5324146103f1578063ab2e58dd146103fa578063bb0c82981461040357600080fd5b80634b0bddd2116101a85780637b0472f0116101775780637b0472f01461038c5780637fe912391461039f578063817b1cd2146103a75780638da5cb5b146103b05780639652b121146103d557600080fd5b80634b0bddd2146102fd57806354a02f9e146103105780635c141991146103705780636696f3ff1461038357600080fd5b8063333271d0116101e4578063333271d01461029157806334553147146102a4578063429b62e5146102b7578063485cc955146102ea57600080fd5b806305e30f511461021657806313c028461461024957806320114ac21461025e57806328a6a2dd14610271575b600080fd5b610236610224366004612c29565b60056020526000908152604090205481565b6040519081526020015b60405180910390f35b61025c610257366004612c29565b6104f0565b005b61025c61026c366004612c29565b6106d2565b61028461027f366004612ae4565b6108fe565b6040516102409190612d04565b61025c61029f366004612c7d565b6109d5565b61025c6102b2366004612c9e565b610a64565b6102da6102c5366004612ae4565b60126020526000908152604090205460ff1681565b6040519015158152602001610240565b61025c6102f8366004612b05565b610cd1565b61025c61030b366004612b37565b610e0c565b61032361031e366004612b6d565b610ea1565b6040805198895260208901979097529587019490945260608601929092526001600160401b03908116608086015290811660a08501521660c083015260ff1660e082015261010001610240565b61025c61037e366004612c29565b610f18565b61023660105481565b61025c61039a366004612c7d565b610f56565b610236611027565b61023660095481565b6000546001600160a01b03165b6040516001600160a01b039091168152602001610240565b610236600d5481565b61025c6103ec366004612c59565b611037565b61023660075481565b61023660115481565b61023660085481565b61025c61041a366004612bd5565b6110d2565b610236600a5481565b61023660065481565b610236600f5481565b61025c610448366004612c29565b611179565b610236600e5481565b61025c610464366004612b96565b611713565b61025c610477366004612c29565b611bfb565b610236600c5481565b61025c610493366004612c29565b611c39565b61025c6104a6366004612ae4565b611c77565b610236600b5481565b6001546103bd906001600160a01b031681565b6102366104d5366004612ae4565b6001600160a01b031660009081526004602052604090205490565b336105036000546001600160a01b031690565b6001600160a01b0316146105325760405162461bcd60e51b815260040161052990612da7565b60405180910390fd5b600e541561058c5760405162461bcd60e51b815260206004820152602160248201527f50726576696f757320726573756c7420776173206e6f742070726f63657373656044820152601960fa1b6064820152608401610529565b610594611d70565b5060006105a042611dc1565b509150508060105414156106065760405162461bcd60e51b815260206004820152602760248201527f526573756c74206d6179206265206164646564206f6e6c79206f6e63652070656044820152660e440dadedce8d60cb1b6064820152608401610529565b6010819055600d829055600954600090610621908490612ddc565b121561066f5760405162461bcd60e51b815260206004820152601c60248201527f746f74616c5374616b6564206c657373207468656e20616d6f756e74000000006044820152606401610529565b600082131561069057600154610690906001600160a01b0316333085611de7565b6001600e5560006011556040518281527f7e378eda7a53c9c96fb609c656ea4cddfd3f364b2fd5a0338fed559471da4fbe906020015b60405180910390a15050565b3360009081526012602052604090205460ff16806107095750336106fe6000546001600160a01b031690565b6001600160a01b0316145b61074b5760405162461bcd60e51b815260206004820152601360248201527221b0b63632b91034b9903737ba1030b236b4b760691b6044820152606401610529565b600e5460011461078a5760405162461bcd60e51b815260206004820152600a602482015269057726f6e6720737465760b41b6044820152606401610529565b60006107996201518042612e63565b60115490915060006107aa60025490565b90505b808210156108ba5760006107c2600284611f17565b6001600160a01b0381166000908152600460205260409020549091508086106107f6576107ef8187612f7e565b9550610837565b6011849055600e54604080518681526020810186905290810191909152600080516020612fff833981519152906060015b60405180910390a1505050505050565b60005b818110156108a5576001600160a01b038316600090815260046020526040902080546108939188918490811061088057634e487b7160e01b600052603260045260246000fd5b9060005260206000209060050201611fb6565b8061089d81612f95565b91505061083a565b50836108b081612f95565b94505050506107ad565b6002600e5560006011556040805183815260208101839052600191810191909152600080516020612fff833981519152906060015b60405180910390a15050505b50565b6001600160a01b0381166000908152600460209081526040808320805482518185028101850190935280835260609492939192909184015b828210156109ca576000848152602090819020604080516101008101825260058602909201805483526001808201548486015260028201549284019290925260038101546060840152600401546001600160401b038082166080850152600160401b8204811660a0850152600160801b82041660c0840152600160c01b900460ff1660e08301529083529092019101610936565b505050509050919050565b336109e86000546001600160a01b031690565b6001600160a01b031614610a0e5760405162461bcd60e51b815260040161052990612da7565b6064811115610a525760405162461bcd60e51b815260206004820152601060248201526f2bb937b7339036bab63a34b83634b2b960811b6044820152606401610529565b60009182526005602052604090912055565b336000908152600460205260408120805485908110610a9357634e487b7160e01b600052603260045260246000fd5b6000918252602090912060059091020160048101549091506001600160401b031642811115610cbf576000610ac84283612f7e565b905060075481610ad89190612fb0565b9050600654600754610aea9190612f7e565b811180610af5575080155b610b3a5760405162461bcd60e51b81526020600482015260166024820152754f7574206f662077697468647261772077696e646f7760501b6044820152606401610529565b6003830154808611801590610b50575083548611155b610b915760405162461bcd60e51b81526020600482015260126024820152714e6f7420656e6f756768207265776172647360701b6044820152606401610529565b6000610b9b611d70565b9050610ba78186611fb6565b610bb18783612f7e565b6003860155845487908690600090610bca908490612f7e565b90915550506004850154600160c01b900460ff16610bfa578660096000828254610bf49190612f7e565b90915550505b8515610c6657600154610c28906001600160a01b0316610c226000546001600160a01b031690565b89612214565b60408051338152602081018990527fa859066e89895ffb9f2cdf2af7e7e84061fcb7ddd8657877c264737f25f8b655910160405180910390a1610cb7565b600154610c7d906001600160a01b03163389612214565b60408051338152602081018990527f85082129d87b2fe11527cb1b3b7a520aeb5aa6913f88a3d8757fe40d1db02fdd910160405180910390a15b505050610cca565b610cca338685612328565b5050505050565b6001600160a01b03821615801590610cf257506000546001600160a01b0316155b610cfb57600080fd5b600080546001600160a01b038085166001600160a01b031992831617835560018054918516919092161790556040513391907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350506206978060065562278d00600755680ad78ebc5ac6200000600855600560205260197faadf04b4a1bf84e121ab68e5c1cffab5aeb9be1a024ff9944a2a0bc1674866095560327fec79235ffe9302935718f9bddc23f2c5c6c950ae49f49d137c786213c361802755604b7fe78ea91a221fb67f10aba14ba22dc39f780130b5cf7d2295f57a7414e295968b5561016860005260647f5464d34515fb195718451914a9b5e2c4ac04dce5fd392ea5e3f190355ea2fb7e55565b33610e1f6000546001600160a01b031690565b6001600160a01b031614610e455760405162461bcd60e51b815260040161052990612da7565b6001600160a01b038216600081815260126020908152604091829020805460ff19168515159081179091558251938452908301527f55a5194bc0174fcaf12b2978bef43911466bf63b34db8d1dd1a0d5dcd5c41bea91016106c6565b60046020528160005260406000208181548110610ebd57600080fd5b60009182526020909120600590910201805460018201546002830154600384015460049094015492955090935091906001600160401b0380821691600160401b8104821691600160801b82041690600160c01b900460ff1688565b33610f2b6000546001600160a01b031690565b6001600160a01b031614610f515760405162461bcd60e51b815260040161052990612da7565b600755565b600854821015610fb35760405162461bcd60e51b815260206004820152602260248201527f5374616b656420616d6f756e74206973206c657373207468656e206d696e696d604482015261756d60f01b6064820152608401610529565b60008181526005602052604090205480610ffe5760405162461bcd60e51b815260206004820152600c60248201526b15dc9bdb99c81c195c9a5bd960a21b6044820152606401610529565b600154611016906001600160a01b0316333086611de7565b611022338484846124a2565b505050565b600061103260025490565b905090565b33600090815260046020526040902080548390811061106657634e487b7160e01b600052603260045260246000fd5b60009182526020909120600460059092020101546001600160401b03164210156110c35760405162461bcd60e51b815260206004820152600e60248201526d1058d8dbdd5b9d081b1bd8dad95960921b6044820152606401610529565b6110ce338383612328565b5050565b336110e56000546001600160a01b031690565b6001600160a01b03161461110b5760405162461bcd60e51b815260040161052990612da7565b606481111561114f5760405162461bcd60e51b815260206004820152601060248201526f2bb937b7339036bab63a34b83634b2b960811b6044820152606401610529565b600154611167906001600160a01b0316333086611de7565b611173848484846124a2565b50505050565b3360009081526012602052604090205460ff16806111b05750336111a56000546001600160a01b031690565b6001600160a01b0316145b6111f25760405162461bcd60e51b815260206004820152601360248201527221b0b63632b91034b9903737ba1030b236b4b760691b6044820152606401610529565b600e546002146112315760405162461bcd60e51b815260206004820152600a602482015269057726f6e6720737465760b41b6044820152606401610529565b600d54600061123f60025490565b90508161127e576000600e5560408051828152602081018390526002818301529051600080516020612fff8339815191529181900360600190a1505050565b600b546011546000905b8381101561160257600061129d600283611f17565b6001600160a01b0381166000908152600460205260409020549091508088106112d1576112ca8189612f7e565b9750611322565b60118390556009546112e4908590612ddc565b600955600e5460408051858152602081018990528082019290925251600080516020612fff8339815191529181900360600190a15050505050505050565b60005b818110156115ed576001600160a01b038316600090815260046020526040812080548390811061136557634e487b7160e01b600052603260045260246000fd5b9060005260206000209060050201600201549050806000146115da576001600160a01b03841660009081526004602052604081208054849081106113b957634e487b7160e01b600052603260045260246000fd5b6000918252602082206005909102015491506113d6896064612e9d565b6001600160a01b038716600090815260046020526040902080548690811061140e57634e487b7160e01b600052603260045260246000fd5b6000918252602090912060059091020160040154600160801b90046001600160401b031660070b61143f858e612e9d565b6114499190612e9d565b6114539190612e35565b905061145f8189612ddc565b975060008113156114cb576001600160a01b03861660009081526004602052604090208054829190869081106114a557634e487b7160e01b600052603260045260246000fd5b906000526020600020906005020160030160008282546114c59190612e1d565b90915550505b6114d58183612ddc565b915060008212156114f1576114ea8289612f3f565b9750600091505b6001600160a01b038616600090815260046020526040902080548391908690811061152c57634e487b7160e01b600052603260045260246000fd5b600091825260208083206005909202909101929092556001600160a01b038816815260049091526040812080548690811061157757634e487b7160e01b600052603260045260246000fd5b600091825260209182902060026005909202010191909155604080516001600160a01b038916815291820186905281018290527f4410f5289f71baff2baf30dad8844d6c4d5af1f55fd01dd890aec66584f1677c9060600160405180910390a150505b50806115e581612f95565b915050611325565b50826115f881612f95565b9350505050611288565b816009546116109190612ddc565b6009556000600e81905560118190558513156116e4576001546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b15801561166a57600080fd5b505afa15801561167e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a29190612c41565b90506009548111156116e2576001546116e2906001600160a01b03166116d06000546001600160a01b031690565b6009546116dd9085612f7e565b612214565b505b6040805182815260208101869052600291810191909152600080516020612fff83398151915290606001610827565b336117266000546001600160a01b031690565b6001600160a01b03161461174c5760405162461bcd60e51b815260040161052990612da7565b6000611756611d70565b6001600160a01b0385166000908152600460205260408120805492935090918590811061179357634e487b7160e01b600052603260045260246000fd5b906000526020600020906005020190506117ad8282611fb6565b8054801561188457831561182a576001546117e3906001600160a01b03166117dd6000546001600160a01b031690565b83612214565b604080516001600160a01b0388168152602081018390527fa859066e89895ffb9f2cdf2af7e7e84061fcb7ddd8657877c264737f25f8b655910160405180910390a1611884565b600154611841906001600160a01b03168783612214565b604080516001600160a01b0388168152602081018390527f85082129d87b2fe11527cb1b3b7a520aeb5aa6913f88a3d8757fe40d1db02fdd910160405180910390a15b6004820154600160c01b900460ff166118af5780600960008282546118a99190612f7e565b90915550505b8160010154600a60008282546118c59190612f7e565b90915550506002820154600b80546000906118e1908490612f7e565b90915550506001600160a01b03861660009081526004602052604081205461190b90600190612f7e565b9050806119d5576001600160a01b038716600090815260046020526040902080548061194757634e487b7160e01b600052603160045260246000fd5b600082815260208120600560001990930192830201818155600181018290556002808201839055600382019290925560040180546001600160c81b0319169055915561199390886126d8565b506040516001600160a01b03881681527f0ad8e54ac59bf2d8a7a1474c1af503b593553cf4fcaaffdef04ab5249f89762b9060200160405180910390a1611bf2565b808614611b36576001600160a01b0387166000908152600460205260409020805482908110611a1457634e487b7160e01b600052603260045260246000fd5b906000526020600020906005020160046000896001600160a01b03166001600160a01b031681526020019081526020016000208781548110611a6657634e487b7160e01b600052603260045260246000fd5b6000918252602090912082546005909202019081556001808301549082015560028083015490820155600380830154908201556004918201805492909101805467ffffffffffffffff1981166001600160401b0394851690811783558354600160401b908190048616026001600160801b031990921617178082558254600160801b9081900490941690930267ffffffffffffffff60801b19841681178255915460ff600160c01b91829004160260ff60c01b1990921668ffffffffffffffffff60801b19909316929092171790555b6001600160a01b0387166000908152600460205260409020805480611b6b57634e487b7160e01b600052603160045260246000fd5b600082815260208082206005600019949094019384020182815560018101839055600281018390556003810192909255600490910180546001600160c81b03191690559155604080516001600160a01b038a1681529182018890527f52da67f845146a7b07a837a7e32b5b74f6d3fafb17ec6c04f23acfc9e1aa9d1f910160405180910390a15b50505050505050565b33611c0e6000546001600160a01b031690565b6001600160a01b031614611c345760405162461bcd60e51b815260040161052990612da7565b600655565b33611c4c6000546001600160a01b031690565b6001600160a01b031614611c725760405162461bcd60e51b815260040161052990612da7565b600855565b33611c8a6000546001600160a01b031690565b6001600160a01b031614611cb05760405162461bcd60e51b815260040161052990612da7565b6001600160a01b038116611d155760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610529565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000611d7f6201518042612e63565b9050600f54811115611dbe57600080611da083600f54600954600a54612844565b600f859055600a81905590925090508115611dbb57600b8290555b50505b90565b60008080611dda611dd56201518086612e63565b6128e3565b9196909550909350915050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092839290881691611e4b9190612ccb565b6000604051808303816000865af19150503d8060008114611e88576040519150601f19603f3d011682016040523d82523d6000602084013e611e8d565b606091505b5091509150818015611eb7575080511580611eb7575080806020019051810190611eb79190612c0d565b611f0f5760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b6064820152608401610529565b505050505050565b81546000908210611f755760405162461bcd60e51b815260206004820152602260248201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604482015261647360f01b6064820152608401610529565b826000018281548110611f9857634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b031690505b92915050565b6004810154600160c01b900460ff168061219457815460018301546004840154600090611ff09062015180906001600160401b0316612e77565b6001600160401b031690508581116121225760008061201188848787612844565b9150915080600a60008282546120279190612f7e565b9091555050811561204a5781600b60008282546120449190612f7e565b90915550505b600487015461206c908490600160401b90046001600160401b03168787612844565b60048901805467ffffffffffffffff60401b1916600160401b6001600160401b038d160217905560018901819055909250905081156120ad57600287018290555b80156120cd5760048701805460ff60c01b1916600160c01b179055612103565b81156120ed5760048701805460ff60c01b1916600160c11b179055612103565b60048701805460ff60c01b1916600360c01b1790555b84600960008282546121159190612f7e565b90915550611f0f92505050565b60048501546000908190612149908990600160401b90046001600160401b03168787612844565b60048901805467ffffffffffffffff60401b1916600160401b6001600160401b038d1602179055600189018190559092509050811561218a57600287018290555b5050505050505050565b8060ff1660011480156121ba57506004820154600160401b90046001600160401b031683115b80156121c857506002820154155b1561102257600182018054600284018190556000909155156121fc5750600401805460ff60c01b1916600160c11b17905550565b50600401805460ff60c01b1916600360c01b17905550565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916122709190612ccb565b6000604051808303816000865af19150503d80600081146122ad576040519150601f19603f3d011682016040523d82523d6000602084013e6122b2565b606091505b50915091508180156122dc5750805115806122dc5750808060200190518101906122dc9190612c0d565b610cca5760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610529565b6000612332611d70565b6001600160a01b0385166000908152600460205260408120805492935090918590811061236f57634e487b7160e01b600052603260045260246000fd5b906000526020600020906005020190506123898282611fb6565b805460008083556003830155801561246457831561240a576001546123c3906001600160a01b03166117dd6000546001600160a01b031690565b604080516001600160a01b0388168152602081018390527fa859066e89895ffb9f2cdf2af7e7e84061fcb7ddd8657877c264737f25f8b655910160405180910390a1612464565b600154612421906001600160a01b03168783612214565b604080516001600160a01b0388168152602081018390527f85082129d87b2fe11527cb1b3b7a520aeb5aa6913f88a3d8757fe40d1db02fdd910160405180910390a15b600282015415801561247857506001820154155b15611f0f576001600160a01b03861660009081526004602052604081205461190b90600190612f7e565b6124aa611d70565b506001600160a01b038416600090815260046020526040902054600a116125135760405162461bcd60e51b815260206004820152601e60248201527f416c6c6f776564203130206465706f73697473207065722077616c6c657400006044820152606401610529565b82600960008282546125259190612e1d565b909155506125369050600285612a56565b5060046000856001600160a01b03166001600160a01b0316815260200190815260200160002060405180610100016040528085815260200160008152602001600081526020016000815260200184620151806125929190612f20565b61259c9042612e1d565b6001600160401b031681526020016125b76201518042612e63565b6001600160401b0390811682528481166020808401919091526000604093840181905285546001818101885596825290829020855160059092020190815590840151948101949094558282015160028501556060830151600385015560808301516004909401805460a085015160c086015160e09096015160ff16600160c01b0260ff60c01b19968516600160801b029690961668ffffffffffffffffff60801b19918516600160401b026001600160801b0319909316979094169690961717949094161791909117909155517ff556991011e831bcfac4f406d547e5e32cdd98267efab83935230d5f8d02c446906108ef9086908690869086906001600160a01b0394909416845260208401929092526040830152606082015260800190565b6001600160a01b0381166000908152600183016020526040812054801561283a576000612706600183612f7e565b855490915060009061271a90600190612f7e565b9050600086600001828154811061274157634e487b7160e01b600052603260045260246000fd5b60009182526020909120015487546001600160a01b039091169150819088908590811061277e57634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160a01b0319166001600160a01b03929092169190911790556127b2836001612e1d565b6001600160a01b038216600090815260018901602052604090205586548790806127ec57634e487b7160e01b600052603160045260246000fd5b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b0388168252600189810190915260408220919091559450611fb09350505050565b6000915050611fb0565b600081848611156128da57600061285b8688612f7e565b90506000612868886128e3565b925050508181116128c057600061287f8284612f7e565b61288a906001612e1d565b90506128968188612f20565b6128a09087612e1d565b94506128ac8184612f7e565b92506128b88388612f20565b9350506128d7565b6128ca8287612f20565b6128d49086612e1d565b92505b50505b94509492505050565b6000808083816128f68262010bd9612ddc565b6129039062253d8c612ddc565b9050600062023ab1612916836004612e9d565b6129209190612e35565b905060046129318262023ab1612e9d565b61293c906003612ddc565b6129469190612e35565b6129509083612f3f565b9150600062164b09612963846001612ddc565b61296f90610fa0612e9d565b6129799190612e35565b90506004612989826105b5612e9d565b6129939190612e35565b61299d9084612f3f565b6129a890601f612ddc565b9250600061098f6129ba856050612e9d565b6129c49190612e35565b9050600060506129d68361098f612e9d565b6129e09190612e35565b6129ea9086612f3f565b90506129f7600b83612e35565b9450612a0485600c612e9d565b612a0f836002612ddc565b612a199190612f3f565b91508483612a28603187612f3f565b612a33906064612e9d565b612a3d9190612ddc565b612a479190612ddc565b9a919950975095505050505050565b6001600160a01b0381166000908152600183016020526040812054612ac057508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b03861690811790915585549082528286019093526040902091909155611fb0565b506000611fb0565b80356001600160a01b0381168114612adf57600080fd5b919050565b600060208284031215612af5578081fd5b612afe82612ac8565b9392505050565b60008060408385031215612b17578081fd5b612b2083612ac8565b9150612b2e60208401612ac8565b90509250929050565b60008060408385031215612b49578182fd5b612b5283612ac8565b91506020830135612b6281612ff0565b809150509250929050565b60008060408385031215612b7f578182fd5b612b8883612ac8565b946020939093013593505050565b600080600060608486031215612baa578081fd5b612bb384612ac8565b9250602084013591506040840135612bca81612ff0565b809150509250925092565b60008060008060808587031215612bea578081fd5b612bf385612ac8565b966020860135965060408601359560600135945092505050565b600060208284031215612c1e578081fd5b8151612afe81612ff0565b600060208284031215612c3a578081fd5b5035919050565b600060208284031215612c52578081fd5b5051919050565b60008060408385031215612c6b578182fd5b823591506020830135612b6281612ff0565b60008060408385031215612c8f578182fd5b50508035926020909101359150565b600080600060608486031215612cb2578283fd5b83359250602084013591506040840135612bca81612ff0565b60008251815b81811015612ceb5760208186018101518583015201612cd1565b81811115612cf95782828501525b509190910192915050565b602080825282518282018190526000919060409081850190868401855b82811015612d9a5781518051855286810151878601528581015186860152606080820151908601526080808201516001600160401b039081169187019190915260a08083015182169087015260c0808301519091169086015260e09081015160ff16908501526101009093019290850190600101612d21565b5091979650505050505050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b600080821280156001600160ff1b0384900385131615612dfe57612dfe612fc4565b600160ff1b8390038412811615612e1757612e17612fc4565b50500190565b60008219821115612e3057612e30612fc4565b500190565b600082612e4457612e44612fda565b600160ff1b821460001984141615612e5e57612e5e612fc4565b500590565b600082612e7257612e72612fda565b500490565b60006001600160401b0380841680612e9157612e91612fda565b92169190910492915050565b60006001600160ff1b0381841382841380821686840486111615612ec357612ec3612fc4565b600160ff1b84871282811687830589121615612ee157612ee1612fc4565b858712925087820587128484161615612efc57612efc612fc4565b87850587128184161615612f1257612f12612fc4565b505050929093029392505050565b6000816000190483118215151615612f3a57612f3a612fc4565b500290565b60008083128015600160ff1b850184121615612f5d57612f5d612fc4565b6001600160ff1b0384018313811615612f7857612f78612fc4565b50500390565b600082821015612f9057612f90612fc4565b500390565b6000600019821415612fa957612fa9612fc4565b5060010190565b600082612fbf57612fbf612fda565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b80151581146108fb57600080fdfec534675d962a9c4b4a6eef4e934d46b14162000192fa31cf0c29cd81fdb8c2eea264697066735822122047a55bd19ac71dcd1a3095db5fce55b6bd983cb71d4b8cd5304175935d04552764736f6c63430008040033