Transactions
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Read Proxy
Write Contract
Write Proxy
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- EtnyStakingImplementation
- Optimization enabled
- true
- Compiler version
- v0.8.30+commit.73712a01
- Optimization runs
- 200
- EVM Version
- istanbul
- Verified at
- 2025-08-06T15:02:36.876945Z
Contract source code
// File: ethernity-staking-smartcontract/Enums.sol
pragma solidity ^0.8.0;
library Enums {
enum BaseStakeStatus {
PENDING,
APPROVED,
DECLINED,
CANCELED,
TERMINATED
}
enum ExtendedStakeStatus {
PENDING,
APPROVED,
DECLINED,
CANCELED,
TERMINATED
}
enum StakeContractStatus {
PENDING,
APPROVED,
DECLINED,
CANCELED,
TERMINATED
}
enum EntityType{
STAKER,
NODE_OPERATOR
}
enum StakeType{
BASE_STAKE,
EXTENDED_STAKE
}
}
// File: ethernity-staking-smartcontract/Models.sol
pragma solidity ^0.8.0;
library Models {
struct BaseStake {
address stakeHolderAddress;
address rewardAddress;
address nodeAddress;
uint256 timestamp;
uint64 amount;
uint16 period;
Enums.BaseStakeStatus status;
uint256 stakeContractId;
}
struct ExtendedStake {
address stakeHolderAddress;
address rewardAddress;
address nodeAddress;
uint256 timestamp;
uint64 amount;
uint64 amountBooked;
uint64 stakingContracts;
uint16 period; // in months
uint8 operatorRewardPercentage;
bool allowMultipleOp;
bool autoConfirm;
Enums.ExtendedStakeStatus status;
mapping(uint64 => uint256) stakingContractsMapping;
mapping(Enums.StakeContractStatus => uint64) stakingContractsStatuses;
}
struct StakeContract {
address stakeHolder;
address stakeRewardAddress;
address nodeAddress;
address nodeRewardAddress;
uint256 timestamp;
uint64 amount;
uint64 operatorRewardPercentage;
uint16 period; //in months
uint256 canceledOn;
uint256 approvedOn;
uint256 expiresOn;
Enums.StakeContractStatus status;
uint256 stakeId;
Enums.StakeType stakeType;
bool isOperatorPerformingBad;
}
}
// File: ethernity-staking-smartcontract/interfaces/IEtnyStaking.sol
pragma solidity ^0.8.0;
interface IEtnyStaking {
function addBaseStakeRequest(
address nodeAddress,
uint64 amount,
uint16 period
) external returns (uint256);
function addExtendedStakeRequest(
address nodeAddress,
uint64 amount,
address rewardAddress,
uint16 period,
uint8 opReward,
bool allowMultipleOp,
bool autoConfirm
) external returns (uint256);
function approveBaseStakeRequest(
uint256 baseStakeId,
address rewardAddress
) external returns (bool);
function cancelBaseStakeRequest(
uint256 baseStakeId
) external returns (bool);
function lockBaseStakeRequest(
uint256 baseStakeId
) external returns (bool);
function declineBaseStakeRequest(
uint256 baseStakeId
) external returns (bool);
// extended stake
function cancelExtendedStakeRequest(
uint256 extendedStakeId
) external returns (bool);
function applyExtendedStakeRequest(
uint256 extendedStakeID,
uint64 amount,
address rewardAddress
) external returns (bool);
function freeExtendedStakeRequest(
uint256 extendedStakeId
) external returns (bool);
function getLockedBalanceAtStakeInWei(
address wallet
) external returns (uint256);
}
// File: ethernity-staking-smartcontract/interfaces/IOwnable.sol
pragma solidity ^0.8.0;
interface IOwnable {
function owner() external view returns (address);
}
// File: ethernity-staking-smartcontract/Initializable.sol
pragma solidity ^0.8.0;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
*/
bool private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Modifier to protect an initializer function from being invoked twice.
*/
modifier initializer() {
require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized");
bool isTopLevelCall = !_initializing;
if (isTopLevelCall) {
_initializing = true;
_initialized = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
}
}
/// @dev Returns true if and only if the function is running in the constructor
function _isConstructor() private view returns (bool) {
// extcodesize checks the size of the code stored in an address, and
// address returns the current address. Since the code is still not
// deployed when running a constructor, any checks on its code size will
// yield zero, making it an effective way to detect if a contract is
// under construction or not.
address self = address(this);
uint256 cs;
// solhint-disable-next-line no-inline-assembly
assembly {cs := extcodesize(self)}
return cs == 0;
}
}
// File: ethernity-staking-smartcontract/Ownable.sol
pragma solidity ^0.8.0;
/**
* @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.
* @author crypto-pumpkin
*
* By initialization, the owner account will be the one that called initializeOwner. 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.
*/
contract Ownable is Initializable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor(){
initializeOwner();
}
/**
* @dev COVER : Initializes the contract setting the deployer as the initial owner.
*/
function initializeOwner() internal initializer {
_owner = msg.sender;
emit OwnershipTransferred(address(0), _owner);
}
/**
* @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 == msg.sender, "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;
}
}
// File: ethernity-staking-smartcontract/interfaces/ERC20Interface.sol
pragma solidity ^0.8.0;
interface ERC20Interface {
function totalSupply() external view returns (uint);
function balanceOf(address tokenOwner) external view returns (uint balance);
function allowance(address tokenOwner, address spender) external view returns (uint remaining);
function transfer(address to, uint tokens) external returns (bool success);
function approve(address spender, uint tokens) external returns (bool success);
function transferFrom(address from, address to, uint tokens) external returns (bool success);
event Transfer(address indexed from, address indexed to, uint tokens);
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}
// File: ethernity-staking-smartcontract/CompanyWallet.sol
pragma solidity ^0.8.0;
contract CompanyWallet is Ownable {
mapping(address => bool) companyAddresses;
constructor(){
companyAddresses[msg.sender] = true;
}
function addCompanyWallet(address companyAddress) public onlyOwner {
companyAddresses[companyAddress] = true;
}
function removeCompanyWallet(address oldCompanyAddress) public onlyOwner {
companyAddresses[oldCompanyAddress] = false;
}
/**
* @dev Throws if called by any account other than other of company wallets.
*/
modifier onlyCompanyWallet() {
require(
companyAddresses[msg.sender],
"CompanyWallet: caller is not a wallet from company"
);
_;
}
}
// File: ethernity-staking-smartcontract/Delegated.sol
pragma solidity ^0.8.0;
/**
* Copyright (C) 2018, 2019, 2020 Ethernity HODL UG
*
* This file is part of ETHERNITY PoX SC.
*
* ETHERNITY PoE SC is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
contract Delegated is Ownable {
address public callerAddress;
event ProxyTransferred(address indexed _from, address indexed _to);
/*constructor() {
callerAddress = msg.sender;
}*/
modifier onlyDelegate {
require(msg.sender == callerAddress);
_;
}
function transferProxy(address _newProxy) public onlyOwner {
callerAddress = _newProxy;
}
}
// File: ethernity-staking-smartcontract/EtnyStakingStorage.sol
pragma solidity ^0.8.0;
/**
* Copyright (C) 2018, 2019, 2020 Ethernity HODL UG
*
* This file is part of ETHERNITY PoX SC.
*
* ETHERNITY PoE SC is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
contract EtnyStakingStorage is Delegated, CompanyWallet {
constructor() {
_owner = msg.sender;
companyAddresses[msg.sender] = true;
}
address public implementation;
address[] internal versions;
address public _owner;
address internal _etnyPartnershipProgramSmartContractAddress;
address internal _etnyTokenSmartContractAddress;
address internal _etnyNFTIntegrationContractAddress;
// contracts and requests lists
Models.BaseStake[] internal _baseStakesList;
Models.ExtendedStake[] internal _extendedStakeList;
Models.StakeContract[] internal _stakingContractsList;
mapping(address => uint256[]) internal _stakerBaseStakeRequests;
mapping(address => uint256[]) internal _stakerExtendedStakeRequests;
mapping(address => uint256[]) internal _nodeBaseStakeRequests;
mapping(address => bool) internal _nodeActiveBaseStake;
mapping(address => uint256[]) internal _nodeExtendedStakeRequests;
mapping(address => uint256[]) internal _nodeExtendedContracts;
mapping(address => uint256) internal _nodeStakingTotal;
mapping(uint256 => uint256) internal _baseStakePenalty;
mapping(address => uint256) internal _tokensLockedInStaking;
mapping(address => bool) internal _canceledBaseStakeNodes;
//technical properties
uint256 maxTokens = 75000;
uint256 maxNFTTokens = 225000;
uint8 apyPercentage = 10;
uint8 minPeriodStakeContractInMonths = 6;
uint64 totalSupply = 15000000;
uint64 minBaseStakeAmount = 1976;
uint64 minBaseStakeNFTAmount = 700;
uint64 minExtendedStakeAmount = 3024;
uint64 maxBaseStakeAmount = 75000;
uint64 nodesStakeMinAmount = 5000;
}
// File: ethernity-staking-smartcontract/utils.sol
pragma solidity ^0.8.0;
library Utils {
function computeExpirationDate(uint16 period, uint256 approvedOn) public view returns (uint256){
uint256 diff = 1;
if (block.timestamp - approvedOn >= 1 days)
diff = (block.timestamp - approvedOn) / 1 days;
uint256 duration = period * 30;
uint256 quotient = diff / duration;
uint256 remainder = diff % duration;
uint256 computedExpectedExpiration = 0;
if (remainder <= (duration - 30))
computedExpectedExpiration = approvedOn + (duration * (quotient + 1)) * 1 days;
else
computedExpectedExpiration = approvedOn + (duration * (quotient + 2)) * 1 days;
return computedExpectedExpiration;
}
}
// File: ethernity-staking-smartcontract/EtnyStakingImplementation.sol
pragma solidity ^0.8.0;
// must exists a base stake when applying or creating extended stake
contract EtnyStakingImplementation is IEtnyStaking, EtnyStakingStorage {
// ---------------------------------------------------------------------------------------------
// CONSTANTS
// ---------------------------------------------------------------------------------------------
uint256 private constant ONEHUNDREDYEARS = 4850176343;
// ---------------------------------------------------------------------------------------------
// EVENTS
// ---------------------------------------------------------------------------------------------
/// Base Stake events
event NewBaseStake(address indexed staker, uint256 baseStakeId);
event BaseStakeApproved(uint256 baseStakeId, uint256 nodeStakingTotal);
event ApplyPenaltiesToBaseStakeByCompany(uint256 nodeStakingTotal);
/// Base Stake Contract events
event NewStakeContract(address indexed staker, address indexed node, uint256 contractId);
event BaseStakeContractTerminated(uint256 stakeContractId);
event BaseStakeContractCanceled(uint256 stakeContractId);
event BaseStakeContractExtendedForPenalties(uint256 contractId);
/// Extended Stake events
event NewExtendedStake(address indexed staker, uint256 baseStakeId);
event ExtendedStakeTerminated(uint256 extendedStakeId);
event ExtendedStakeCanceled(uint256 extendedStakeId);
event ExtendedStakeFreed(uint256 extendedStakeId, uint256 tokensLockedInStaking);
event NodeAppliedToExtendedStake(address indexed node, uint256 extendedStakeId, uint256 nodeStakingTotal);
event TokensAddedToExtendedStake(uint256 extendedStakeId, uint64 additionalAmount);
/// Extended Stake Contract events
event ExtendedStakeContractTerminated(uint256 contractId, uint256 extendedContractStakeId);
event ExtendedStakeContractCanceled(uint256 contractId, uint256 extendedContractStakeId);
event ExtendedStakeContractApproved(uint256 contractId, uint256 extendedContractStakeId);
event ExtendedStakeContractDeclined(uint256 contractId, uint256 extendedContractStakeId);
// ---------------------------------------------------------------------------------------------
// BASE STAKE MANAGEMENT FUNCTIONS
// ---------------------------------------------------------------------------------------------
/// @notice Add new Base Stake Request
/// @dev Creates a new base stake request for a node, locking tokens and emitting an event.
/// @param nodeAddress The address of the node to stake on.
/// @param amount The amount of tokens to stake.
/// @param period The staking period in months.
/// @return _rowNumber The ID of the new base stake request.
function addBaseStakeRequest(
address nodeAddress,
uint64 amount,
uint16 period
) public onlyDelegate override returns (uint256 _rowNumber) {
require(
_etnyTokenSmartContractAddress != address(0),
"EtnyStaking: Something went wrong. The Ethernity Cloud SmartContract address is not correctly setup!"
);
require(
nodeAddress != address(0),
"EtnyStaking: node address is the zero address"
);
require(
msg.sender != nodeAddress,
"EtnyStaking: The node address must be different than current one!"
);
require(
period >= minPeriodStakeContractInMonths,
"EtnyStaking: The staking period is too low!"
);
require(
amount >= minBaseStakeAmount && amount <= maxBaseStakeAmount,
"EtnyStaking: amount must be between minimum and maximum values!");
require(
_nodeStakingTotal[nodeAddress] == 0,
"EtnyStaking: Node already has an existing base stake!"
);
require(
_nodeActiveBaseStake[nodeAddress] == false,
"EtnyStaking: Node already has an existing base stake!"
);
uint nodeBalance = getEtnyTokens(nodeAddress);
require(
nodeBalance == 0,
"EtnyStaking: Node has ETNY tokens!"
);
uint etnyBalance = getEtnyTokens(msg.sender);
require(
etnyBalance - _tokensLockedInStaking[msg.sender] >= amount,
"EtnyStaking: The amount exceeds balance available for staking!"
);
_stakerBaseStakeRequests[payable(msg.sender)].push(_baseStakesList.length);
_rowNumber = _baseStakesList.length;
_nodeBaseStakeRequests[nodeAddress].push(_rowNumber);
emit NewBaseStake(msg.sender, _rowNumber);
(Models.StakeContract storage stakeContract, uint256 stakeContractID) = addStakeContract(msg.sender, nodeAddress, address(0), period, amount, _rowNumber, 100);
stakeContract.stakeType = Enums.StakeType.BASE_STAKE;
_baseStakesList.push(
Models.BaseStake({
stakeHolderAddress: msg.sender,
rewardAddress: address(0),
nodeAddress: nodeAddress,
timestamp: block.timestamp,
amount: amount,
period: period,
status: Enums.BaseStakeStatus.PENDING,
stakeContractId: stakeContractID
})
);
_tokensLockedInStaking[msg.sender] += amount;
_nodeActiveBaseStake[nodeAddress] = true;
return _rowNumber;
}
/// @notice Retrieves the total number of base stake requests.
/// @return count The total count of base stake requests.
function getBaseStakeRequestTotal() public onlyDelegate view returns (uint256 count){
return _baseStakesList.length;
}
/// @notice Retrieves details of a specific base stake by ID.
/// @param baseStakeId The ID of the base stake.
/// @return _baseStakeId The ID.
/// @return stakeHolderAddress The staker's address.
/// @return rewardAddress The reward address.
/// @return nodeAddress The node address.
/// @return timestamp The creation timestamp.
/// @return amount The staked amount.
/// @return period The staking period.
/// @return status The status of the stake.
/// @return stakeType The type of stake (BASE_STAKE).
function getBaseStake(uint256 baseStakeId)
external onlyDelegate
view
returns (
uint256 _baseStakeId,
address stakeHolderAddress,
address rewardAddress,
address nodeAddress,
uint256 timestamp,
uint64 amount,
uint64 period,
Enums.BaseStakeStatus status,
Enums.StakeType stakeType
)
{
require(
baseStakeId < _baseStakesList.length,
"EtnyStaking: Invalid Base Stake ID provided!"
);
Models.BaseStake memory _stake = _baseStakesList[baseStakeId];
return (
baseStakeId,
_stake.stakeHolderAddress,
_stake.rewardAddress,
_stake.nodeAddress,
_stake.timestamp,
_stake.amount,
_stake.period,
_stake.status,
Enums.StakeType.BASE_STAKE
);
}
/// @notice Approves a pending base stake request.
/// @param baseStakeId The ID of the base stake to approve.
/// @param rewardAddress The reward address for the node.
/// @return bool Success indicator.
function approveBaseStakeRequest(uint256 baseStakeId, address rewardAddress) public onlyDelegate override returns (bool){
require(
baseStakeId < _baseStakesList.length,
"EtnyStaking: Invalid Base Stake ID provided!"
);
require(
rewardAddress != address(0),
"EtnyStaking: Reward address is the zero address!"
);
require(
rewardAddress != msg.sender,
"EtnyStaking: The node address should be different than reward address!"
);
Models.BaseStake storage _stake = _baseStakesList[baseStakeId];
require(
msg.sender == _stake.nodeAddress,
"EtnyStaking: only node operator can approve base stake!"
);
require(
_stake.status == Enums.BaseStakeStatus.PENDING,
"EtnyStaking: stake must be new to be approved!"
);
_stake.status = Enums.BaseStakeStatus.APPROVED;
_stake.rewardAddress = rewardAddress;
Models.StakeContract storage _contract = _stakingContractsList[_stake.stakeContractId];
_contract.status = Enums.StakeContractStatus.APPROVED;
_contract.approvedOn = block.timestamp;
_contract.nodeRewardAddress = rewardAddress;
_nodeStakingTotal[msg.sender] += _contract.amount;
emit BaseStakeApproved(baseStakeId, _nodeStakingTotal[msg.sender]);
return true;
}
/// @notice Cancels a base stake request.
/// @param baseStakeId The ID of the base stake to cancel.
/// @return bool Success indicator.
function cancelBaseStakeRequest(uint256 baseStakeId) public onlyDelegate override returns (bool){
require(
baseStakeId < _baseStakesList.length,
"EtnyStaking: Invalid Base Stake ID provided!"
);
Models.BaseStake storage _stake = _baseStakesList[baseStakeId];
require(
msg.sender == _stake.stakeHolderAddress,
"EtnyStaking: Only staker can cancel this request!"
);
require(
_stake.status == Enums.BaseStakeStatus.PENDING || _stake.status == Enums.BaseStakeStatus.APPROVED,
"EtnyStaking: Stake is having different status!"
);
_stake.status = Enums.BaseStakeStatus.CANCELED;
Models.StakeContract storage _contract = _stakingContractsList[_stake.stakeContractId];
if (_contract.status == Enums.StakeContractStatus.PENDING)
{
_contract.status = Enums.StakeContractStatus.TERMINATED;
_contract.canceledOn = block.timestamp;
_contract.expiresOn = block.timestamp;
_subtractFromTokensLockedInStaking(_contract.stakeHolder, _contract.amount);
_nodeActiveBaseStake[_contract.nodeAddress] = false;
emit BaseStakeContractTerminated(_stake.stakeContractId);
}
else
{
_contract.status = Enums.StakeContractStatus.CANCELED;
_contract.canceledOn = block.timestamp;
_canceledBaseStakeNodes[_contract.nodeAddress] = true;
emit BaseStakeContractCanceled(_stake.stakeContractId);
for (uint256 i = 0; i < _nodeExtendedContracts[_contract.nodeAddress].length; i++) {
uint256 _contractId = _nodeExtendedContracts[_contract.nodeAddress][i];
Models.StakeContract storage _extendedContract = _stakingContractsList[_contractId];
Models.ExtendedStake storage _extendedStake = _extendedStakeList[_extendedContract.stakeId];
if (_extendedContract.status == Enums.StakeContractStatus.PENDING
|| _extendedContract.status == Enums.StakeContractStatus.APPROVED)
_extendedStake.stakingContractsStatuses[_extendedContract.status] -= 1;
if (_extendedContract.status == Enums.StakeContractStatus.PENDING)
{
_extendedContract.status = Enums.StakeContractStatus.TERMINATED;
_extendedContract.canceledOn = block.timestamp;
_extendedContract.expiresOn = block.timestamp;
emit ExtendedStakeContractTerminated(_contractId, _extendedContract.stakeId);
_subtractFromNodeStakingTotal(_extendedContract.nodeAddress, _extendedContract.amount);
_subtractFromTokensLockedInStaking(_extendedContract.stakeHolder, _extendedContract.amount);
_extendedStake.amountBooked -= _extendedContract.amount;
_extendedStake.stakingContractsStatuses[_extendedContract.status] += 1;
if (_extendedStake.nodeAddress != address(0)) {
_extendedStake.amount = 0;
_extendedStake.status = Enums.ExtendedStakeStatus.TERMINATED;
emit ExtendedStakeTerminated(_extendedContract.stakeId);
}
}
else if (_extendedContract.status == Enums.StakeContractStatus.APPROVED)
{
_extendedContract.status = Enums.StakeContractStatus.CANCELED;
_extendedContract.canceledOn = block.timestamp;
_extendedContract.expiresOn = Utils.computeExpirationDate(_extendedContract.period, _extendedContract.approvedOn);
_extendedStake.stakingContractsStatuses[_extendedContract.status] += 1;
emit ExtendedStakeContractCanceled(_contractId, _extendedContract.stakeId);
}
if (_contract.expiresOn < _extendedContract.expiresOn)
_contract.expiresOn = _extendedContract.expiresOn;
}
//no extended stake where made on the node
if (_contract.expiresOn == 0) {
if (_contract.amount < nodesStakeMinAmount)
{
_contract.status = Enums.StakeContractStatus.TERMINATED;
_contract.canceledOn = block.timestamp;
_contract.expiresOn = block.timestamp;
_subtractFromTokensLockedInStaking(_contract.stakeHolder, _contract.amount);
_nodeActiveBaseStake[_contract.nodeAddress] = false;
_canceledBaseStakeNodes[_contract.nodeAddress] = false;
_subtractFromNodeStakingTotal(_contract.nodeAddress, _contract.amount);
emit BaseStakeContractTerminated(_stake.stakeContractId);
} else
_contract.expiresOn = Utils.computeExpirationDate(_contract.period, _contract.approvedOn);
}
}
return true;
}
/// @notice Locks a base stake request by the company.
/// @param baseStakeId The ID of the base stake to lock.
/// @return bool Success indicator.
function lockBaseStakeRequest(uint256 baseStakeId) public onlyCompanyWallet override returns (bool){
require(
baseStakeId < _baseStakesList.length,
"EtnyStaking: Invalid Base Stake ID provided!"
);
Models.BaseStake storage _stake = _baseStakesList[baseStakeId];
require(
_stake.status == Enums.BaseStakeStatus.APPROVED,
"EtnyStaking: Stake is having different status!"
);
_stake.status = Enums.BaseStakeStatus.CANCELED;
Models.StakeContract storage _contract = _stakingContractsList[_stake.stakeContractId];
_contract.status = Enums.StakeContractStatus.CANCELED;
_contract.canceledOn = block.timestamp;
_contract.expiresOn = 4850176343; // 12.09.2123
return true;
}
/// @notice Declines a pending base stake request.
/// @param baseStakeId The ID of the base stake to decline.
/// @return bool Success indicator.
function declineBaseStakeRequest(uint256 baseStakeId) public onlyDelegate override returns (bool){
require(
baseStakeId < _baseStakesList.length,
"EtnyStaking: Invalid Base Stake ID provided!"
);
Models.BaseStake storage _stake = _baseStakesList[baseStakeId];
require(
msg.sender == _stake.nodeAddress,
"EtnyStaking: Only node operator can decline this request!"
);
require(
_stake.status == Enums.BaseStakeStatus.PENDING,
"EtnyStaking: Stake is having different status!"
);
_stake.status = Enums.BaseStakeStatus.DECLINED;
Models.StakeContract storage _contract = _stakingContractsList[_stake.stakeContractId];
_contract.status = Enums.StakeContractStatus.DECLINED;
_subtractFromTokensLockedInStaking(_contract.stakeHolder, _contract.amount);
_nodeStakingTotal[msg.sender] = 0;
_nodeActiveBaseStake[msg.sender] = false;
return true;
}
// ---------------------------------------------------------------------------------------------
// EXTENDED STAKE MANAGEMENT FUNCTIONS
// ---------------------------------------------------------------------------------------------
/// @notice Add new Extended Stake Request
/// @dev Creates a new extended stake request, optionally linked to a node.
/// @param nodeAddress The node address (optional).
/// @param amount The amount to stake.
/// @param rewardAddress The reward address.
/// @param period The staking period.
/// @param opReward The operator reward percentage.
/// @param allowMultipleOp Whether multiple operators are allowed.
/// @param autoConfirm Whether to auto-confirm.
/// @return _extendedStakeId The ID of the new extended stake.
function addExtendedStakeRequest(
address nodeAddress,
uint64 amount,
address rewardAddress,
uint16 period,
uint8 opReward,
bool allowMultipleOp,
bool autoConfirm
) public onlyDelegate override returns (uint256 _extendedStakeId) {
require(
_etnyTokenSmartContractAddress != address(0),
"EtnyStaking: Something went wrong. The Ethernity Cloud SmartContract address is not correctly setup!"
);
if (opReward != 100)
require(
rewardAddress != address(0),
"EtnyStaking: reward address is the zero address"
);
require(
amount >= minExtendedStakeAmount,
"EtnyStaking: The amount is too low!"
);
require(
period >= minPeriodStakeContractInMonths,
"EtnyStaking: The period is too low!"
);
require(
opReward < 101,
"EtnyStaking: The operator reward percentage is too high!"
);
require(
opReward >= 0,
"EtnyStaking: The operator reward percentage is too low!"
);
require(
rewardAddress != msg.sender,
"EtnyStaking: The current address should be different than reward address!"
);
if (nodeAddress != address(0)) {
require(
!_canceledBaseStakeNodes[nodeAddress],
"EtnyStaking: The base stake contract on the node was canceled!"
);
require(
_nodeStakingTotal[nodeAddress] > 0,
"EtnyStaking: The node doesn't have any base stake setup!"
);
require(
msg.sender != nodeAddress,
"EtnyStaking: The node address must be different!"
);
require(
rewardAddress != nodeAddress,
"EtnyStaking: The node address should be different than reward address!"
);
require(
_nodeStakingTotal[nodeAddress] + amount <= maxTokens,
"EtnyStaking: The amount exceeds the maximum allowed tokens on the node!"
);
uint nodeBalance = getEtnyTokens(nodeAddress);
require(
nodeBalance == 0,
"EtnyStaking: Node has ETNY tokens!"
);
}
uint etnyBalance = getEtnyTokens(msg.sender);
require(
etnyBalance - _tokensLockedInStaking[msg.sender] >= amount,
"EtnyStaking: The amount exceeds balance available for staking!"
);
Models.ExtendedStake storage newExtendedReq = _extendedStakeList.push();
newExtendedReq.stakeHolderAddress = msg.sender;
newExtendedReq.rewardAddress = rewardAddress;
newExtendedReq.nodeAddress = nodeAddress;
newExtendedReq.timestamp = block.timestamp;
newExtendedReq.amount = amount;
newExtendedReq.amountBooked = 0;
newExtendedReq.stakingContracts = 0;
newExtendedReq.period = period;
newExtendedReq.operatorRewardPercentage = opReward;
newExtendedReq.allowMultipleOp = allowMultipleOp;
newExtendedReq.autoConfirm = autoConfirm;
newExtendedReq.status = Enums.ExtendedStakeStatus.PENDING;
_extendedStakeId = _extendedStakeList.length - 1;
emit NewExtendedStake(msg.sender, _extendedStakeId);
_stakerExtendedStakeRequests[payable(msg.sender)].push(_extendedStakeId);
if (nodeAddress != address(0)) {
(Models.StakeContract storage stakeContract, uint256 stakeContractID) = addStakeContract(newExtendedReq.stakeHolderAddress, nodeAddress, rewardAddress, period, amount, _extendedStakeId, opReward);
newExtendedReq.stakingContractsStatuses[stakeContract.status] += 1;
newExtendedReq.stakingContractsMapping[newExtendedReq.stakingContracts] = stakeContractID;
newExtendedReq.stakingContracts += 1;
newExtendedReq.amountBooked = amount;
_nodeExtendedStakeRequests[nodeAddress].push(_extendedStakeId);
_nodeExtendedContracts[nodeAddress].push(stakeContractID);
_nodeStakingTotal[nodeAddress] += amount;
}
_tokensLockedInStaking[msg.sender] += amount;
return _extendedStakeId;
}
/// @notice Retrieves details of an extended stake by ID.
/// @param extendedStakeId The ID of the extended stake.
/// @return _baseStakeId The ID.
/// @return stakeHolderAddress The staker's address.
/// @return rewardAddress The reward address.
/// @return nodeAddress The node address.
/// @return timestamp The creation timestamp.
/// @return amount The staked amount.
/// @return amountBooked The booked amount.
/// @return period The staking period.
/// @return operatorReward The operator reward percentage.
/// @return allowMultipleOp Whether multiple operators are allowed.
/// @return autoConfirm Whether auto-confirm is enabled.
/// @return status The status of the stake.
/// @return stakingContracts The number of staking contracts.
function getExtendedStake(uint256 extendedStakeId)
external
view
returns (
uint256 _baseStakeId,
address stakeHolderAddress,
address rewardAddress,
address nodeAddress,
uint256 timestamp,
uint64 amount,
uint64 amountBooked,
uint64 period,
uint8 operatorReward,
bool allowMultipleOp,
bool autoConfirm,
Enums.ExtendedStakeStatus status,
uint64 stakingContracts
)
{
Models.ExtendedStake storage _stake = _extendedStakeList[
extendedStakeId
];
return (
extendedStakeId,
_stake.stakeHolderAddress,
_stake.rewardAddress,
_stake.nodeAddress,
_stake.timestamp,
_stake.amount,
_stake.amountBooked,
_stake.period,
_stake.operatorRewardPercentage,
_stake.allowMultipleOp,
_stake.autoConfirm,
_stake.status,
_stake.stakingContracts
);
}
/// @notice Retrieves contract statistics for an extended stake request.
/// @param extendedStakeId The ID of the extended stake.
/// @return _extendedStakeId The ID.
/// @return allContracts Total contracts.
/// @return pendingContracts Pending contracts.
/// @return approvedContracts Approved contracts.
/// @return declinedContracts Declined contracts.
/// @return canceledContracts Canceled contracts.
/// @return terminatedContracts Terminated contracts.
function getExtendedStakeRequestContractStats(uint256 extendedStakeId)
external
view
returns (
uint256 _extendedStakeId,
uint64 allContracts,
uint64 pendingContracts,
uint64 approvedContracts,
uint64 declinedContracts,
uint64 canceledContracts,
uint64 terminatedContracts
)
{
Models.ExtendedStake storage _stake = _extendedStakeList[
extendedStakeId
];
return (
extendedStakeId,
_stake.stakingContracts,
_stake.stakingContractsStatuses[Enums.StakeContractStatus.PENDING],
_stake.stakingContractsStatuses[Enums.StakeContractStatus.APPROVED],
_stake.stakingContractsStatuses[Enums.StakeContractStatus.DECLINED],
_stake.stakingContractsStatuses[Enums.StakeContractStatus.CANCELED],
_stake.stakingContractsStatuses[Enums.StakeContractStatus.TERMINATED]
);
}
/// @notice Retrieves the total number of extended stake requests.
/// @return count The total count.
function getExtendedStakeRequestTotal() public onlyDelegate view returns (uint256 count){
return _extendedStakeList.length;
}
/// @notice Approves an extended stake contract.
/// @param stakeId The extended stake ID.
/// @param stakeContract The contract index.
/// @param rewardAddress The reward address.
/// @return bool Success indicator.
function approveExtendedStakeContract(uint256 stakeId, uint64 stakeContract, address rewardAddress) public onlyDelegate returns (bool){
require(
stakeId < _extendedStakeList.length,
"EtnyStaking: Invalid Extended Stake ID provided!"
);
Models.ExtendedStake storage _stake = _extendedStakeList[stakeId];
require(
stakeContract < _stake.stakingContracts,
"EtnyStaking: Invalid Stake Contract provided!"
);
if (_stake.nodeAddress != address(0)) {
//if the node was provided only the node operator can approve it
require(
_stake.nodeAddress == msg.sender,
"EtnyStaking: Only operator can approve the contract!"
);
require(
rewardAddress != address(0),
"EtnyStaking: Reward address for operator was not provided!"
);
require(
rewardAddress != msg.sender,
"EtnyStaking: Reward address should be different than the node address!"
);
require(
!_canceledBaseStakeNodes[msg.sender],
"EtnyStaking: The base stake contract on this node was canceled!"
);
}
uint256 _contractId = _stake.stakingContractsMapping[stakeContract];
Models.StakeContract storage _contract = _stakingContractsList[_contractId];
require(
_contract.status == Enums.StakeContractStatus.PENDING,
"EtnyStaking: Only pending staking contracts can be approved!"
);
_stake.stakingContractsStatuses[_contract.status] -= 1;
_contract.status = Enums.StakeContractStatus.APPROVED;
_contract.approvedOn = block.timestamp;
_stake.stakingContractsStatuses[_contract.status] += 1;
if (_stake.nodeAddress != address(0))
{
_contract.nodeRewardAddress = rewardAddress;
_stake.amountBooked = _stake.amount;
_stake.status = Enums.ExtendedStakeStatus.APPROVED;
}
if (_stake.amountBooked == _stake.amount
&& _stake.stakingContractsStatuses[Enums.StakeContractStatus.PENDING] == 0) {
_stake.status = Enums.ExtendedStakeStatus.APPROVED;
}
emit ExtendedStakeContractApproved(_contractId, stakeId);
return true;
}
/// @notice Cancels an extended stake request.
/// @param extendedStakeID The ID of the extended stake to cancel.
/// @return bool Success indicator.
function cancelExtendedStakeRequest(uint256 extendedStakeID) public onlyDelegate override returns (bool){
require(
extendedStakeID < _extendedStakeList.length,
"EtnyStaking: Invalid Extended Stake ID provided!"
);
Models.ExtendedStake storage _stake = _extendedStakeList[extendedStakeID];
require(
msg.sender == _stake.stakeHolderAddress,
"EtnyStaking: Only staker can cancel this request!"
);
require(
_stake.status == Enums.ExtendedStakeStatus.PENDING ||
_stake.status == Enums.ExtendedStakeStatus.APPROVED,
"EtnyStaking: Extended stake pool cannot be canceled. It has different status!"
);
_stake.status = Enums.ExtendedStakeStatus.CANCELED;
emit ExtendedStakeCanceled(extendedStakeID);
for (uint64 stakeContract = 0; stakeContract < _stake.stakingContracts; stakeContract++) {
uint256 _contractId = _stake.stakingContractsMapping[stakeContract];
Models.StakeContract storage _contract = _stakingContractsList[_contractId];
_stake.stakingContractsStatuses[_contract.status] -= 1;
if (_contract.status == Enums.StakeContractStatus.PENDING)
{
_contract.status = Enums.StakeContractStatus.TERMINATED;
_contract.canceledOn = block.timestamp;
_contract.expiresOn = block.timestamp;
emit ExtendedStakeContractTerminated(_contractId, _contract.stakeId);
_stake.amountBooked -= _contract.amount;
_subtractFromNodeStakingTotal(_contract.nodeAddress, _contract.amount);
_subtractFromTokensLockedInStaking(_contract.stakeHolder, _contract.amount);
if (_stake.nodeAddress != address(0)) {
_stake.amount = 0;
emit ExtendedStakeTerminated(_contract.stakeId);
}
}
else if (_contract.status == Enums.StakeContractStatus.APPROVED)
{
_contract.status = Enums.StakeContractStatus.CANCELED;
_contract.canceledOn = block.timestamp;
_contract.expiresOn = Utils.computeExpirationDate(_contract.period, _contract.approvedOn);
emit ExtendedStakeContractCanceled(_contractId, _contract.stakeId);
}
_stake.stakingContractsStatuses[_contract.status] += 1;
}
if (_stake.amount - _stake.amountBooked > 0)
{
_subtractFromTokensLockedInStaking(msg.sender, (_stake.amount - _stake.amountBooked));
_stake.amount = _stake.amountBooked;
}
return true;
}
/// @notice Declines an extended stake contract.
/// @param stakeId The extended stake ID.
/// @param stakeContract The contract index.
/// @return bool Success indicator.
function declineExtendedStakeContract(uint256 stakeId, uint64 stakeContract) public onlyDelegate returns (bool){
require(
stakeId < _extendedStakeList.length,
"EtnyStaking: Invalid Extended Stake ID provided!"
);
Models.ExtendedStake storage _stake = _extendedStakeList[stakeId];
require(
stakeContract < _stake.stakingContracts,
"EtnyStaking: Invalid Stake Contract provided!"
);
uint256 _contractId = _stake.stakingContractsMapping[stakeContract];
Models.StakeContract storage _contract = _stakingContractsList[_contractId];
require(
_contract.status == Enums.StakeContractStatus.PENDING,
"EtnyStaking: Only pending staking contracts can be declined!"
);
_stake.stakingContractsStatuses[_contract.status] -= 1;
_contract.status = Enums.StakeContractStatus.DECLINED;
_stake.stakingContractsStatuses[_contract.status] += 1;
_stake.amountBooked -= _contract.amount;
_subtractFromNodeStakingTotal(_contract.nodeAddress, _contract.amount);
if (_stake.nodeAddress != address(0)) {
_stake.status = Enums.ExtendedStakeStatus.DECLINED;
_subtractFromTokensLockedInStaking(_contract.stakeHolder, _contract.amount);
}
emit ExtendedStakeContractDeclined(_contractId, stakeId);
return true;
}
/// @notice Cancels an extended stake contract.
/// @param stakeId The extended stake ID.
/// @param stakeContract The contract index.
/// @param isOperatorPerformingBad Whether the operator is performing bad.
/// @return bool Success indicator.
function cancelExtendedStakeContract(uint256 stakeId, uint64 stakeContract, bool isOperatorPerformingBad) public onlyDelegate returns (bool){
require(
stakeId < _extendedStakeList.length,
"EtnyStaking: Invalid Extended Stake ID provided!"
);
Models.ExtendedStake storage _stake = _extendedStakeList[stakeId];
require(
stakeContract < _stake.stakingContracts,
"EtnyStaking: Invalid Stake Contract provided!"
);
uint256 _contractId = _stake.stakingContractsMapping[stakeContract];
Models.StakeContract storage _contract = _stakingContractsList[_contractId];
return _cancelExtendedStakeContract(_stake, _contract, _contractId, isOperatorPerformingBad);
}
/// @notice Applies to an extended stake request as a node.
/// @param extendedStakeID The extended stake ID.
/// @param amount The amount to apply with.
/// @param rewardAddress The reward address.
/// @return bool Success indicator.
function applyExtendedStakeRequest(uint256 extendedStakeID, uint64 amount, address rewardAddress) public onlyDelegate override returns (bool){
require(
extendedStakeID < _extendedStakeList.length,
"EtnyStaking: Invalid Extended Stake ID provided!"
);
require(
rewardAddress != address(0),
"EtnyStaking: Reward address is the zero address!"
);
require(
rewardAddress != msg.sender,
"EtnyStaking: Reward address must be different than node address!"
);
require(
amount >= minExtendedStakeAmount,
"EtnyStaking: The amount is lower than min extended stake value!"
);
require(
!_canceledBaseStakeNodes[msg.sender],
"EtnyStaking: The base stake contract on this node was canceled!"
);
Models.ExtendedStake storage _stake = _extendedStakeList[extendedStakeID];
require(
_stake.status == Enums.ExtendedStakeStatus.PENDING,
"EtnyStaking: Stake is having different status!"
);
require(
msg.sender != _stake.nodeAddress,
"EtnyStaking: You cannot apply to this Stake Request!"
);
require(
amount + _stake.amountBooked <= _stake.amount,
"EtnyStaking: The amount exceeds the available amount in current stake!"
);
require(
(_stake.stakingContracts <= 1 && !_stake.allowMultipleOp) || _stake.allowMultipleOp,
"EtnyStaking: This stake can accept only 1 contract!"
);
require(
_nodeStakingTotal[msg.sender] > 0,
"EtnyStaking: Need to have at least one base stake setup!"
);
require(
_nodeStakingTotal[msg.sender] + amount <= maxTokens,
"EtnyStaking: The amount exceeds the total of 75000!"
);
if (_stake.allowMultipleOp == false) {
require(
_stake.amount == amount,
"EtnyStaking: This staking pool cannot be split!"
);
}
_stake.amountBooked += amount;
if (_stake.amountBooked == _stake.amount && _stake.autoConfirm)
_stake.status = Enums.ExtendedStakeStatus.APPROVED;
(Models.StakeContract storage stakeContract, uint256 stakeContractID) = addStakeContract(_stake.stakeHolderAddress, msg.sender, _stake.rewardAddress, _stake.period, amount, extendedStakeID, _stake.operatorRewardPercentage);
stakeContract.nodeRewardAddress = rewardAddress;
if (_stake.autoConfirm)
{
stakeContract.status = Enums.StakeContractStatus.APPROVED;
stakeContract.approvedOn = block.timestamp;
}
_stake.stakingContractsStatuses[stakeContract.status] += 1;
_stake.stakingContractsMapping[_stake.stakingContracts] = stakeContractID;
_stake.stakingContracts += 1;
_nodeExtendedContracts[msg.sender].push(stakeContractID);
_nodeExtendedStakeRequests[payable(msg.sender)].push(extendedStakeID);
_nodeStakingTotal[stakeContract.nodeAddress] += stakeContract.amount;
emit NodeAppliedToExtendedStake(stakeContract.nodeAddress, extendedStakeID, _nodeStakingTotal[stakeContract.nodeAddress]);
return true;
}
/// @notice Frees unbooked tokens from an extended stake request.
/// @param stakeId The extended stake ID.
/// @return bool Success indicator.
function freeExtendedStakeRequest(uint256 stakeId) public onlyDelegate override returns (bool){
require(
stakeId < _extendedStakeList.length,
"EtnyStaking: Invalid Extended Stake ID provided!"
);
Models.ExtendedStake storage _stake = _extendedStakeList[stakeId];
require(
msg.sender == _stake.stakeHolderAddress,
"EtnyStaking: Only staker can call this!"
);
require(
_stake.status == Enums.ExtendedStakeStatus.PENDING
|| _stake.status == Enums.ExtendedStakeStatus.CANCELED,
"EtnyStaking: Stake is having different status!"
);
if (_stake.status == Enums.ExtendedStakeStatus.CANCELED) {
require(
_stake.stakingContracts > 0,
"EtnyStaking: Stake has no tokens locked!"
);
}
require(
_stake.amount > _stake.amountBooked,
"EtnyStaking: There are no tokens to unlock!"
);
_subtractFromTokensLockedInStaking(msg.sender, (_stake.amount - _stake.amountBooked));
_stake.amount = _stake.amountBooked;
if (_stake.amount == 0 && _stake.status == Enums.ExtendedStakeStatus.PENDING) {
_stake.status = Enums.ExtendedStakeStatus.CANCELED;
} else {
_stake.status = Enums.ExtendedStakeStatus.APPROVED;
}
emit ExtendedStakeFreed(stakeId, _tokensLockedInStaking[msg.sender]);
return true;
}
/// @notice Adds additional tokens to an approved extended stake.
/// @param extendedStakeId The extended stake ID.
/// @param additionalAmount The additional amount to add.
/// @return bool Success indicator.
function addTokensToExtendedStake(uint256 extendedStakeId, uint64 additionalAmount) public onlyDelegate returns (bool) {
require(
extendedStakeId < _extendedStakeList.length,
"EtnyStaking: Invalid Extended Stake ID provided!"
);
require(
additionalAmount >= minExtendedStakeAmount,
"EtnyStaking: The additional amount is too low!"
);
Models.ExtendedStake storage _stake = _extendedStakeList[extendedStakeId];
require(
msg.sender == _stake.stakeHolderAddress,
"EtnyStaking: Only staker can add tokens to this pool!"
);
require(
_stake.status == Enums.ExtendedStakeStatus.APPROVED,
"EtnyStaking: Can only add to approved pools after freeing!"
);
require(
_stake.amount == _stake.amountBooked,
"EtnyStaking: Must free unbooked amounts before adding more!"
);
require(
_stake.nodeAddress == address(0),
"EtnyStaking: Can only add to pools, not delegated stakes!"
);
uint etnyBalance = getEtnyTokens(msg.sender);
require(
etnyBalance - _tokensLockedInStaking[msg.sender] >= additionalAmount,
"EtnyStaking: The additional amount exceeds balance available for staking!"
);
_stake.amount += additionalAmount;
_tokensLockedInStaking[msg.sender] += additionalAmount;
_stake.status = Enums.ExtendedStakeStatus.PENDING;
emit TokensAddedToExtendedStake(extendedStakeId, additionalAmount);
return true;
}
// ---------------------------------------------------------------------------------------------
// STAKE CONTRACT MANAGEMENT FUNCTIONS (COMMON FOR BASE AND EXTENDED)
// ---------------------------------------------------------------------------------------------
/// @dev Internal function to add a new stake contract.
/// @param stakeHolderAddress The staker's address.
/// @param nodeAddress The node address.
/// @param rewardAddress The reward address.
/// @param period The period.
/// @param amount The amount.
/// @param stakeId The stake ID.
/// @param opReward The operator reward percentage.
/// @return _contract The new stake contract.
/// @return stakeContractID The ID of the new contract.
function addStakeContract(address stakeHolderAddress, address nodeAddress, address rewardAddress, uint16 period, uint64 amount, uint256 stakeId, uint8 opReward) internal returns (Models.StakeContract storage _contract, uint256 stakeContractID){
stakeContractID = _stakingContractsList.length;
Models.StakeContract storage stakeContract = _stakingContractsList.push();
stakeContract.stakeHolder = stakeHolderAddress;
stakeContract.nodeAddress = nodeAddress;
stakeContract.stakeRewardAddress = rewardAddress;
stakeContract.nodeRewardAddress = address(0);
stakeContract.timestamp = block.timestamp;
stakeContract.amount = amount;
stakeContract.period = period;
stakeContract.canceledOn = 0;
stakeContract.expiresOn = 0;
stakeContract.approvedOn = 0;
stakeContract.stakeId = stakeId;
//for base stake should override this value;
stakeContract.status = Enums.StakeContractStatus.PENDING;
stakeContract.stakeType = Enums.StakeType.EXTENDED_STAKE;
stakeContract.operatorRewardPercentage = opReward;
return (
stakeContract,
stakeContractID
);
}
/// @notice Retrieves a stake contract for an extended stake.
/// @param stakeId The stake ID.
/// @param stakeContract The contract index.
/// @return _stakeId The stake ID.
/// @return _stakeContract The contract index.
/// @return stakeContractId The contract ID.
/// @return stakeHolderAddress The staker.
/// @return nodeAddress The node.
/// @return timestamp The timestamp.
/// @return amount The amount.
/// @return period The period.
/// @return status The status.
/// @return estimatedExpiration The estimated expiration.
function getStakeContractForStake(uint256 stakeId, uint64 stakeContract)
external
view
returns (
uint256 _stakeId,
uint64 _stakeContract,
uint256 stakeContractId,
address stakeHolderAddress,
address nodeAddress,
uint256 timestamp,
uint64 amount,
uint64 period,
Enums.StakeContractStatus status,
uint256 estimatedExpiration
)
{
require(
stakeId < _extendedStakeList.length,
"EtnyStaking: Invalid Extended Stake ID provided!"
);
Models.ExtendedStake storage _stake = _extendedStakeList[stakeId];
require(
stakeContract < _stake.stakingContracts,
"EtnyStaking: Invalid Stake Contract provided!"
);
uint256 _contractId = _stake.stakingContractsMapping[stakeContract];
Models.StakeContract storage _contract = _stakingContractsList[_contractId];
estimatedExpiration = 0;
if (_contract.status == Enums.StakeContractStatus.APPROVED)
estimatedExpiration = Utils.computeExpirationDate(_contract.period, _contract.approvedOn);
else
estimatedExpiration = _contract.expiresOn;
return (
stakeId,
stakeContract,
_contractId,
_stake.stakeHolderAddress,
_contract.nodeAddress,
_contract.timestamp,
_contract.amount,
_contract.period,
_contract.status,
estimatedExpiration
);
}
/// @notice Retrieves a stake contract for a base stake.
/// @param stakeId The stake ID.
/// @param stakeContract The contract index (must be 0 for base).
/// @return _stakeId The stake ID.
/// @return _stakeContract The contract index.
/// @return stakeContractId The contract ID.
/// @return stakeHolderAddress The staker.
/// @return nodeAddress The node.
/// @return nodeRewardAddress The node reward address.
/// @return timestamp The timestamp.
/// @return amount The amount.
/// @return period The period.
/// @return status The status.
/// @return expiresOn The expiration.
function getStakeContractForBaseStake(uint256 stakeId, uint64 stakeContract)
external
view
returns (
uint256 _stakeId,
uint64 _stakeContract,
uint256 stakeContractId,
address stakeHolderAddress,
address nodeAddress,
address nodeRewardAddress,
uint256 timestamp,
uint64 amount,
uint64 period,
Enums.StakeContractStatus status,
uint256 expiresOn
)
{
require(
stakeId < _baseStakesList.length,
"EtnyStaking: Invalid Base Stake ID provided!"
);
Models.BaseStake storage _stake = _baseStakesList[stakeId];
require(
stakeContract == 0,
"EtnyStaking: Invalid Stake Contract provided!"
);
uint256 _contractId = _stake.stakeContractId;
Models.StakeContract storage _contract = _stakingContractsList[_contractId];
return (
stakeId,
stakeContract,
_contractId,
_stake.stakeHolderAddress,
_contract.nodeAddress,
_contract.nodeRewardAddress,
_contract.timestamp,
_contract.amount,
_contract.period,
_contract.status,
_contract.expiresOn
);
}
/// @notice Retrieves the total number of stake contracts.
/// @return count The total count.
function getStakeContractsTotal() public onlyDelegate view returns (uint256 count){
return _stakingContractsList.length;
}
/// @notice Retrieves details of a stake contract by ID.
/// @param stakeContractId The contract ID.
/// @return estimatedExpiration The estimated expiration.
/// @return stakeHolderAddress The staker.
/// @return nodeAddress The node.
/// @return nodeRewardAddress The node reward.
/// @return stakeHolderRewardAddress The staker reward.
/// @return timestamp The timestamp.
/// @return amount The amount.
/// @return opReward The operator reward.
/// @return period The period.
/// @return status The status.
/// @return stakeType The stake type.
function getStakeContract(uint256 stakeContractId)
external
view
returns (
uint256 estimatedExpiration,
address stakeHolderAddress,
address nodeAddress,
address nodeRewardAddress,
address stakeHolderRewardAddress,
uint256 timestamp,
uint64 amount,
uint64 opReward,
uint64 period,
Enums.StakeContractStatus status,
Enums.StakeType stakeType
)
{
require(
stakeContractId < _stakingContractsList.length,
"EtnyStaking: Invalid Stake contract ID provided!"
);
Models.StakeContract storage _contract = _stakingContractsList[stakeContractId];
estimatedExpiration = 0;
if (_contract.status == Enums.StakeContractStatus.APPROVED)
estimatedExpiration = Utils.computeExpirationDate(_contract.period, _contract.approvedOn);
else
estimatedExpiration = _contract.expiresOn;
return (
estimatedExpiration,
_contract.stakeHolder,
_contract.nodeAddress,
_contract.nodeRewardAddress,
_contract.stakeRewardAddress,
_contract.timestamp,
_contract.amount,
_contract.operatorRewardPercentage,
_contract.period,
_contract.status,
_contract.stakeType
);
}
// ---------------------------------------------------------------------------------------------
// BALANCE AND TOKEN MANAGEMENT FUNCTIONS
// ---------------------------------------------------------------------------------------------
/// @notice Retrieves the locked balance in staking for the caller.
/// @return The locked balance.
function getLockedBalanceAtStake() external view returns (uint256){
return _tokensLockedInStaking[msg.sender];
}
/// @notice Sets the locked balance in staking for a wallet (company only).
/// @param wallet The wallet address.
/// @param amount The amount to set.
/// @return bool Success indicator.
function setLockedBalanceAtStake(address wallet, uint64 amount) external onlyDelegate returns (bool){
require(companyAddresses[msg.sender] == true, "EtnyStaking: Only a company address can perform this action!");
_tokensLockedInStaking[wallet] = amount;
return true;
}
/// @notice Retrieves the locked balance in staking in wei for a wallet.
/// @param wallet The wallet address.
/// @return The locked balance in wei.
function getLockedBalanceAtStakeInWei(address wallet) override external view returns (uint256){
uint decimals = 18;
uint value = 10 ** uint(decimals);
return _tokensLockedInStaking[wallet] * value;
}
/// @dev Internal function to get ETNY token balance.
/// @param adr The address to query.
/// @return The balance.
function getEtnyTokens(address adr) internal view returns (uint256){
uint decimals = 18;
uint value = 10 ** uint(decimals);
return ERC20Interface(_etnyTokenSmartContractAddress).balanceOf(adr) / value;
}
/// @notice Retrieves available tokens for staking for the caller.
/// @return The available tokens.
function getAvailableTokensForStake() public onlyDelegate view returns (uint256){
uint etnyTokens = getEtnyTokens(msg.sender);
return etnyTokens - _tokensLockedInStaking[msg.sender];
}
// ---------------------------------------------------------------------------------------------
// QUERY FUNCTIONS FOR STAKES AND NODES
// ---------------------------------------------------------------------------------------------
/// @notice Retrieves base stake requests for the caller's node.
/// @return The list of base stake IDs.
function getBaseStakeRequestsForNode() public onlyDelegate view returns (uint256[] memory){
return _nodeBaseStakeRequests[msg.sender];
}
/// @notice Retrieves extended stake requests for the caller's node.
/// @return The list of extended stake IDs.
function getExtendedStakeRequestsForNode() public onlyDelegate view returns (uint256[] memory){
return _nodeExtendedStakeRequests[msg.sender];
}
/// @notice Retrieves the total staked on the caller's node.
/// @return The total staked amount.
function getTotalStakedOnNode() public onlyDelegate view returns (uint256){
return _nodeStakingTotal[msg.sender];
}
/// @notice Checks if the caller is a node.
/// @return bool True if node.
function isNode() public onlyDelegate view returns (bool){
return _nodeStakingTotal[msg.sender] > 0;
}
/// @notice Retrieves the count of base stake requests for the staker.
/// @return The count.
function getBaseStakeRequestsForStakerCount() public onlyDelegate view returns (uint256){
return _stakerBaseStakeRequests[msg.sender].length;
}
/// @notice Retrieves a base stake ID for the staker by index.
/// @param stakeIndex The index.
/// @return The stake ID.
function getBaseStakeRequestIdForStaker(uint256 stakeIndex) public onlyDelegate view returns (uint256){
require(
stakeIndex < _stakerBaseStakeRequests[msg.sender].length,
"EtnyStaking: Invalid Index provided!"
);
return _stakerBaseStakeRequests[msg.sender][stakeIndex];
}
/// @notice Retrieves the count of extended stake requests for the staker.
/// @return The count.
function getExtendedStakeRequestsForStakerCount() public onlyDelegate view returns (uint256){
return _stakerExtendedStakeRequests[msg.sender].length;
}
/// @notice Retrieves an extended stake ID for the staker by index.
/// @param stakeIndex The index.
/// @return The stake ID.
function getExtendedStakeRequestIdForStaker(uint256 stakeIndex) public onlyDelegate view returns (uint256){
require(
stakeIndex < _stakerExtendedStakeRequests[msg.sender].length,
"EtnyStaking: Invalid Index provided!"
);
return _stakerExtendedStakeRequests[msg.sender][stakeIndex];
}
/// @notice Retrieves the count of base stake requests for the operator.
/// @return The count.
function getBaseStakeRequestsForOperatorCount() public onlyDelegate view returns (uint256){
return _nodeBaseStakeRequests[msg.sender].length;
}
/// @notice Retrieves a base stake ID for the operator by index.
/// @param stakeIndex The index.
/// @return The stake ID.
function getBaseStakeRequestIdForOperator(uint256 stakeIndex) public onlyDelegate view returns (uint256){
require(
stakeIndex < _nodeBaseStakeRequests[msg.sender].length,
"EtnyStaking: Invalid Index provided!"
);
return _nodeBaseStakeRequests[msg.sender][stakeIndex];
}
/// @notice Retrieves the count of extended stake requests for the operator.
/// @return The count.
function getExtendedStakeRequestsForOperatorCount() public onlyDelegate view returns (uint256){
return _nodeExtendedStakeRequests[msg.sender].length;
}
/// @notice Retrieves an extended stake ID for the operator by index.
/// @param stakeIndex The index.
/// @return The stake ID.
function getExtendedStakeRequestIdForOperator(uint256 stakeIndex) public onlyDelegate view returns (uint256){
require(
stakeIndex < _nodeExtendedStakeRequests[msg.sender].length,
"EtnyStaking: Invalid Index provided!"
);
return _nodeExtendedStakeRequests[msg.sender][stakeIndex];
}
/// @notice Retrieves base stakes for a node.
/// @param nodeAddress The node address.
/// @return The list of base stake IDs.
function getBaseStakesForNode(address nodeAddress) public view returns (uint256[] memory){
return _nodeBaseStakeRequests[nodeAddress];
}
/// @notice Retrieves node details.
/// @param nodeAddress The node address.
/// @return baseStakeRequestList The base stake requests.
/// @return activeBaseStake Whether active base stake.
/// @return totalStaking The total staking.
/// @return canceledBaseStake Whether base stake canceled.
function getNodeDetails(address nodeAddress) public view returns (uint256[] memory baseStakeRequestList, bool activeBaseStake, uint256 totalStaking, bool canceledBaseStake){
return (
_nodeBaseStakeRequests[nodeAddress],
_nodeActiveBaseStake[nodeAddress],
_nodeStakingTotal[nodeAddress],
_canceledBaseStakeNodes[nodeAddress]
);
}
// ---------------------------------------------------------------------------------------------
// TERMINATION AND EXPIRATION HANDLING FUNCTIONS
// ---------------------------------------------------------------------------------------------
/// @dev Internal function to terminate a base stake contract.
/// @param _contract The contract to terminate.
/// @return bool Success indicator.
function terminateBaseStakeContract(Models.StakeContract storage _contract) internal returns (bool){
if (_contract.status != Enums.StakeContractStatus.PENDING) {
_subtractFromNodeStakingTotal(_contract.nodeAddress, _contract.amount);
}
_contract.status = Enums.StakeContractStatus.TERMINATED;
_contract.canceledOn = block.timestamp;
_contract.expiresOn = block.timestamp;
_subtractFromTokensLockedInStaking(_contract.stakeHolder, _contract.amount);
_nodeActiveBaseStake[_contract.nodeAddress] = false;
_canceledBaseStakeNodes[_contract.nodeAddress] = false;
return true;
}
/// @dev Internal function to cancel an extended stake contract.
/// @param _stake The extended stake.
/// @param _contract The contract.
/// @param _contractId The contract ID.
/// @param isOperatorPerformingBad Whether operator is bad.
/// @return bool Success indicator.
function _cancelExtendedStakeContract(Models.ExtendedStake storage _stake, Models.StakeContract storage _contract, uint256 _contractId, bool isOperatorPerformingBad) internal onlyDelegate returns (bool){
require(
_contract.status == Enums.StakeContractStatus.PENDING || _contract.status == Enums.StakeContractStatus.APPROVED,
"EtnyStaking: Only pending or approved staking contracts can be canceled!"
);
require(
msg.sender == _contract.stakeHolder || msg.sender == _contract.nodeAddress || companyAddresses[msg.sender] == true,
"EtnyStaking: Only stakeholder, node operator or companyaddress can cancel the contract!"
);
_stake.stakingContractsStatuses[_contract.status] -= 1;
if (_contract.status == Enums.StakeContractStatus.PENDING)
{
_contract.status = Enums.StakeContractStatus.TERMINATED;
_contract.canceledOn = block.timestamp;
_contract.expiresOn = block.timestamp;
emit ExtendedStakeContractTerminated(_contractId, _contract.stakeId);
_stake.amountBooked -= _contract.amount;
_subtractFromNodeStakingTotal(_contract.nodeAddress, _contract.amount);
_subtractFromTokensLockedInStaking(_contract.stakeHolder, _contract.amount);
if (_stake.nodeAddress != address(0)) {
_stake.status = Enums.ExtendedStakeStatus.TERMINATED;
_stake.amountBooked = 0;
_stake.amount = 0;
emit ExtendedStakeTerminated(_contract.stakeId);
}
}
else if (_contract.status == Enums.StakeContractStatus.APPROVED)
{
if (companyAddresses[msg.sender] == true) {
_terminateExtendedStakeContractByCompany(_stake, _contract, _contractId);
}
else {
_contract.status = Enums.StakeContractStatus.CANCELED;
_contract.canceledOn = block.timestamp;
_contract.expiresOn = Utils.computeExpirationDate(_contract.period, _contract.approvedOn);
emit ExtendedStakeContractCanceled(_contractId, _contract.stakeId);
}
if (msg.sender == _contract.stakeHolder || companyAddresses[msg.sender] == true) {
_contract.isOperatorPerformingBad = isOperatorPerformingBad;
}
}
_stake.stakingContractsStatuses[_contract.status] += 1;
_recalculateExtendedStakeStatusOnContractChange(_stake);
return true;
}
/// @dev Internal function to terminate an extended stake contract by company.
/// @param _stake The extended stake.
/// @param _contract The contract.
/// @param _contractId The contract ID.
function _terminateExtendedStakeContractByCompany(Models.ExtendedStake storage _stake, Models.StakeContract storage _contract, uint256 _contractId) internal {
_contract.status = Enums.StakeContractStatus.TERMINATED;
_contract.canceledOn = block.timestamp;
_contract.expiresOn = block.timestamp;
_stake.amountBooked -= _contract.amount;
_subtractFromNodeStakingTotal(_contract.nodeAddress, _contract.amount);
_subtractFromTokensLockedInStaking(_contract.stakeHolder, _contract.amount);
emit ExtendedStakeContractTerminated(_contractId, _contract.stakeId);
if (_stake.nodeAddress != address(0)) {
_stake.status = Enums.ExtendedStakeStatus.TERMINATED;
_stake.amountBooked = 0;
_stake.amount = 0;
emit ExtendedStakeTerminated(_contract.stakeId);
}
}
/// @notice Terminates a contract (base or extended) if expired.
/// @param contractId The contract ID.
/// @param hasPenalties Whether penalties apply (for base).
/// @return bool Success indicator.
function terminateContract(uint256 contractId, bool hasPenalties) public onlyDelegate returns (bool){
require(companyAddresses[msg.sender] == true, "EtnyStaking: Only a company address can terminate a Base Stake Contract and apply penalties!");
require(contractId < _stakingContractsList.length, "EtnyStaking: Invalid Index provided!");
Models.StakeContract storage _contract = _stakingContractsList[contractId];
require(_contract.status == Enums.StakeContractStatus.CANCELED, "EtnyStaking: Only a canceled contract can be ended!");
require(_contract.expiresOn < block.timestamp, "EtnyStaking: The contract can be terminated after it expires.");
if (_contract.stakeType == Enums.StakeType.EXTENDED_STAKE) {
terminateExpiredExtendedStakeContractByJob(contractId);
} else {
terminateExpiredBaseStakeContractByJob(contractId, hasPenalties, true);
}
return true;
}
/// @notice Retrieves date details for a contract.
/// @param contractId The contract ID.
/// @return timestamp Creation timestamp.
/// @return approvedOn Approval timestamp.
/// @return expiresOn Expiration timestamp.
/// @return estimatedExpiration Estimated expiration.
/// @return canceledOn Cancellation timestamp.
function getContractDateDetails(uint256 contractId) public view onlyDelegate returns (
uint256 timestamp,
uint256 approvedOn,
uint256 expiresOn,
uint256 estimatedExpiration,
uint256 canceledOn){
require(
contractId < _stakingContractsList.length,
"EtnyStaking: Invalid Index provided!"
);
Models.StakeContract storage _contract = _stakingContractsList[contractId];
estimatedExpiration = 0;
if (_contract.status == Enums.StakeContractStatus.APPROVED)
estimatedExpiration = Utils.computeExpirationDate(_contract.period, _contract.approvedOn);
else
estimatedExpiration = _contract.expiresOn;
return (
_contract.timestamp,
_contract.approvedOn,
_contract.expiresOn,
estimatedExpiration,
_contract.canceledOn
);
}
/// @notice Terminates expired contracts in an extended pool.
/// @param extendPoolId The extended pool ID.
/// @return bool Success indicator.
function terminateExtendPoolContracts(uint256 extendPoolId) public onlyDelegate returns (bool){
require(
extendPoolId < _extendedStakeList.length,
"EtnyStaking: Invalid Index provided!"
);
Models.ExtendedStake storage _stake = _extendedStakeList[extendPoolId];
for (uint64 stakeContract = 0; stakeContract < _stake.stakingContracts; stakeContract++) {
Models.StakeContract storage _contract = _stakingContractsList[_stake.stakingContractsMapping[stakeContract]];
if (_contract.status == Enums.StakeContractStatus.CANCELED && _contract.expiresOn < block.timestamp) {
_stake.stakingContractsStatuses[_contract.status] -= 1;
_contract.status = Enums.StakeContractStatus.TERMINATED;
_stake.stakingContractsStatuses[_contract.status] += 1;
_subtractFromTokensLockedInStaking(_contract.stakeHolder, _contract.amount);
_subtractFromNodeStakingTotal(_contract.nodeAddress, _contract.amount);
}
}
if (_stake.stakingContractsStatuses[Enums.StakeContractStatus.CANCELED] == 0
&& _stake.stakingContractsStatuses[Enums.StakeContractStatus.APPROVED] == 0
&& _stake.stakingContractsStatuses[Enums.StakeContractStatus.PENDING] == 0
&& _stake.amount - _stake.amountBooked == 0)
_stake.status = Enums.ExtendedStakeStatus.TERMINATED;
return true;
}
/// @notice Retrieves the max expiration date for an extended pool.
/// @param extendPoolId The pool ID.
/// @return The max expiration date.
function getExtendPoolMaxExpirationdate(uint256 extendPoolId) public onlyDelegate view returns (uint256){
require(
extendPoolId < _extendedStakeList.length,
"EtnyStaking: Invalid Index provided!"
);
Models.ExtendedStake storage _stake = _extendedStakeList[extendPoolId];
uint256 result = 0;
for (uint64 stakeContract = 0; stakeContract < _stake.stakingContracts; stakeContract++) {
Models.StakeContract storage _contract = _stakingContractsList[_stake.stakingContractsMapping[stakeContract]];
uint256 estimatedExpiration = 0;
if (_contract.status == Enums.StakeContractStatus.APPROVED)
estimatedExpiration = Utils.computeExpirationDate(_contract.period, _contract.approvedOn);
else
estimatedExpiration = _contract.expiresOn;
if (result < estimatedExpiration)
result = estimatedExpiration;
}
return result;
}
/// @notice Terminates a base stake if expired.
/// @param baseStakePoolId The base stake ID.
/// @return bool Success indicator.
function terminateBaseStake(uint256 baseStakePoolId) public onlyDelegate returns (bool){
require(
baseStakePoolId < _baseStakesList.length,
"EtnyStaking: Invalid Base Stake ID provided!"
);
Models.BaseStake storage _stake = _baseStakesList[baseStakePoolId];
require(
_stake.status == Enums.BaseStakeStatus.CANCELED,
"EtnyStaking: Stake is having different status!"
);
Models.StakeContract storage _contract = _stakingContractsList[_stake.stakeContractId];
require(
_contract.expiresOn < block.timestamp,
"EtnyStaking: Stake is not expired yet!"
);
_stake.status = Enums.BaseStakeStatus.TERMINATED;
_contract.status = Enums.StakeContractStatus.TERMINATED;
_subtractFromTokensLockedInStaking(_contract.stakeHolder, _contract.amount);
_nodeActiveBaseStake[_contract.nodeAddress] = false;
_subtractFromNodeStakingTotal(_contract.nodeAddress, _contract.amount);
_canceledBaseStakeNodes[_contract.nodeAddress] = false;
return true;
}
/// @notice Applies penalties to a base stake by company, locking forever if needed.
/// @dev Forcefully cancels and prolongs the base stake, terminates extended contracts.
/// @param stakeContractId The base stake contract ID.
/// @return bool Success indicator.
function applyPenaltiesToBaseStakeByCompany(uint256 stakeContractId) public onlyDelegate returns (bool) {
require(companyAddresses[msg.sender] == true, "EtnyStaking: Only a company address can terminate a Base Stake and apply penalties!");
// Check if the provided baseStakeId is valid
require(stakeContractId < _stakingContractsList.length, "EtnyStaking: Invalid Base Stake Contract ID provided!");
// Get the associated stake contract
Models.StakeContract storage _contract = _stakingContractsList[stakeContractId];
// Get the base stake associated with the given ID
Models.BaseStake storage _stake = _baseStakesList[_contract.stakeId];
require(_contract.expiresOn < ONEHUNDREDYEARS, "EtnyStaking: The contract was already prolonged forever!");
_finalizeBaseStakeCancellation(_stake);
_cancelAndProlongForeverBaseStakeContract(_contract);
_terminateForcefullyNodeExtendedContracts(_contract);
emit ApplyPenaltiesToBaseStakeByCompany(_nodeStakingTotal[_contract.nodeAddress]);
return true;
}
/// @notice Terminates an expired base stake contract by job.
/// @param contractId The contract ID.
/// @param hasPenalties Whether penalties apply.
/// @param recalculateContractExpiresOn Whether to recalculate expiration.
/// @return bool Success indicator.
function terminateExpiredBaseStakeContractByJob(uint256 contractId, bool hasPenalties, bool recalculateContractExpiresOn) public onlyDelegate returns (bool) {
require(companyAddresses[msg.sender] == true, "EtnyStaking: Only a company address can terminate a Base Stake Contract and apply penalties!");
require(contractId < _stakingContractsList.length, "EtnyStaking: Invalid Index provided!");
Models.StakeContract storage _contract = _stakingContractsList[contractId];
require(_contract.stakeType == Enums.StakeType.BASE_STAKE, "EtnyStaking: A Base Stake Contract id is expected!");
require(_contract.status == Enums.StakeContractStatus.CANCELED, "EtnyStaking: Only a canceled contract can be ended!");
if (recalculateContractExpiresOn){
_recalculateExpiresOnForBaseStakeContract(_contract);
}
require(_contract.expiresOn < block.timestamp, "EtnyStaking: The contract can be terminated after it expires.");
Models.BaseStake storage _baseStake = _baseStakesList[_contract.stakeId];
_terminateNodeExtendedContracts(_contract);
if (!hasPenalties) {
// no penalties are present
_subtractFromNodeStakingTotal(_contract.nodeAddress, _contract.amount);
_finalizeBaseStakeContractTermination(_contract);
_subtractFromTokensLockedInStaking(_contract.stakeHolder, _baseStake.amount);
_finalizeBaseStakeTermination(_baseStake);
emit BaseStakeContractTerminated(contractId);
return true;
}
// undo-cancel
_contract.canceledOn = 0;
_canceledBaseStakeNodes[_contract.nodeAddress] = false;
// set as approved
_baseStake.status = Enums.BaseStakeStatus.APPROVED;
_contract.status = Enums.StakeContractStatus.APPROVED;
// extend the contract for an additional period from now
_contract.approvedOn = block.timestamp;
_contract.expiresOn = Utils.computeExpirationDate(_contract.period, _contract.approvedOn);
emit BaseStakeContractExtendedForPenalties(contractId);
return true;
}
/// @notice Terminates an expired extended stake contract by job.
/// @param contractId The contract ID.
function terminateExpiredExtendedStakeContractByJob(uint256 contractId) public onlyDelegate {
require(companyAddresses[msg.sender] == true, "EtnyStaking: Only a company address can terminate an Extended Stake Contract and apply penalties!");
require(contractId < _stakingContractsList.length, "EtnyStaking: Invalid Index provided!");
Models.StakeContract storage _contract = _stakingContractsList[contractId];
require(_contract.stakeType == Enums.StakeType.EXTENDED_STAKE, "EtnyStaking: An Extended Stake Contract id is expected!");
require(_contract.status == Enums.StakeContractStatus.CANCELED, "EtnyStaking: Only a canceled contract can be ended!");
require(_contract.expiresOn < block.timestamp, "EtnyStaking: The contract can be terminated after it expires.");
_subtractFromTokensLockedInStaking(_contract.stakeHolder, _contract.amount);
_subtractFromNodeStakingTotal(_contract.nodeAddress, _contract.amount);
Models.ExtendedStake storage _extendedStake = _extendedStakeList[_contract.stakeId];
_extendedStake.amountBooked -= _contract.amount;
_changeExtendedStakeContractStatus(_contract, _extendedStake, Enums.StakeContractStatus.TERMINATED);
_recalculateExtendedStakeStatusOnContractChange(_extendedStake);
emit ExtendedStakeContractTerminated(contractId, _contract.stakeId);
}
// ---------------------------------------------------------------------------------------------
// INTERNAL HELPER FUNCTIONS
// ---------------------------------------------------------------------------------------------
/// @dev Finalizes base stake termination.
/// @param _baseStake The base stake.
function _finalizeBaseStakeTermination(Models.BaseStake storage _baseStake) internal {
_baseStake.status = Enums.BaseStakeStatus.TERMINATED;
}
/// @dev Finalizes base stake cancellation.
/// @param _baseStake The base stake.
function _finalizeBaseStakeCancellation(Models.BaseStake storage _baseStake) internal {
_baseStake.status = Enums.BaseStakeStatus.CANCELED;
}
/// @dev Finalizes base stake contract termination.
/// @param _baseContract The contract.
function _finalizeBaseStakeContractTermination(Models.StakeContract storage _baseContract) internal {
_baseContract.status = Enums.StakeContractStatus.TERMINATED;
_baseContract.canceledOn = block.timestamp;
_baseContract.expiresOn = block.timestamp;
_canceledBaseStakeNodes[_baseContract.nodeAddress] = false;
_nodeActiveBaseStake[_baseContract.nodeAddress] = false;
}
/// @dev Cancels and prolongs base stake contract forever.
/// @param _baseContract The contract.
function _cancelAndProlongForeverBaseStakeContract(Models.StakeContract storage _baseContract) internal {
_baseContract.status = Enums.StakeContractStatus.CANCELED;
_baseContract.canceledOn = block.timestamp;
_baseContract.expiresOn = ONEHUNDREDYEARS; // 12.09.2123 TODO ANDREI why not now + one hundred years?
_canceledBaseStakeNodes[_baseContract.nodeAddress] = true;
_nodeActiveBaseStake[_baseContract.nodeAddress] = true;
}
/// @dev Forcefully terminates node extended contracts.
/// @param _baseContract The base contract.
function _terminateForcefullyNodeExtendedContracts(Models.StakeContract storage _baseContract) internal {
for (uint256 i = 0; i < _nodeExtendedContracts[_baseContract.nodeAddress].length; i++) {
uint256 _contractId = _nodeExtendedContracts[_baseContract.nodeAddress][i];
Models.StakeContract storage _extendedContract = _stakingContractsList[_contractId];
Models.ExtendedStake storage _extendedStake = _extendedStakeList[_extendedContract.stakeId];
if (_extendedContract.status == Enums.StakeContractStatus.CANCELED){
_terminateExtendedStakeContractByCompany(_extendedStake, _extendedContract, _contractId);
_extendedContract.isOperatorPerformingBad = true;
} else if (_extendedContract.status == Enums.StakeContractStatus.PENDING || _extendedContract.status == Enums.StakeContractStatus.APPROVED) {
_cancelExtendedStakeContract(_extendedStake, _extendedContract, _contractId, true);
}
}
}
/// @dev Terminates node extended contracts if expired.
/// @param _baseContract The base contract.
function _terminateNodeExtendedContracts(Models.StakeContract storage _baseContract) internal {
for (uint256 i = 0; i < _nodeExtendedContracts[_baseContract.nodeAddress].length; i++) {
uint256 _contractId = _nodeExtendedContracts[_baseContract.nodeAddress][i];
Models.StakeContract storage _extendedContract = _stakingContractsList[_contractId];
Models.ExtendedStake storage _extendedStake = _extendedStakeList[_extendedContract.stakeId];
if (_extendedContract.status == Enums.StakeContractStatus.CANCELED && _extendedContract.expiresOn < block.timestamp) {
_finalizeExtendedStakeContractTermination(_extendedContract, _extendedStake);
_subtractFromTokensLockedInStaking(_extendedContract.stakeHolder, _extendedContract.amount);
_subtractFromNodeStakingTotal(_extendedContract.nodeAddress, _extendedContract.amount);
_extendedStake.amountBooked -= _extendedContract.amount;
if (_extendedStake.nodeAddress != address(0)) {
// if delegated, we have only one contract and we terminate it
_extendedStake.status = Enums.ExtendedStakeStatus.TERMINATED;
emit ExtendedStakeTerminated(_extendedContract.stakeId);
}
}
_recalculateExtendedStakeStatusOnContractChange(_extendedStake);
}
}
/// @dev Finalizes extended stake contract termination.
/// @param _extendedContract The extended contract.
/// @param _extendedStake The extended stake.
function _finalizeExtendedStakeContractTermination(Models.StakeContract storage _extendedContract, Models.ExtendedStake storage _extendedStake) internal {
_changeExtendedStakeContractStatus(_extendedContract, _extendedStake, Enums.StakeContractStatus.TERMINATED);
_extendedContract.canceledOn = block.timestamp;
_extendedContract.expiresOn = block.timestamp;
}
/// @dev Subtracts from node staking total.
/// @param nodeAddress The node.
/// @param amount The amount.
function _subtractFromNodeStakingTotal(address nodeAddress, uint64 amount) internal {
require (_nodeStakingTotal[nodeAddress] >= amount, "Insufficient node staked tokens for subtraction.");
_nodeStakingTotal[nodeAddress] -= amount;
}
/// @dev Subtracts from tokens locked in staking.
/// @param stakeHolderAddress The stakeholder.
/// @param amount The amount.
function _subtractFromTokensLockedInStaking(address stakeHolderAddress, uint64 amount) internal {
require (_tokensLockedInStaking[stakeHolderAddress] >= amount, "Insufficient stake holder locked tokens in staking for subtraction.");
_tokensLockedInStaking[stakeHolderAddress] -= amount;
}
/// @dev Recalculates extended stake status on contract change.
/// @param _extendedStake The extended stake.
function _recalculateExtendedStakeStatusOnContractChange(Models.ExtendedStake storage _extendedStake) internal {
if (_extendedStake.status == Enums.ExtendedStakeStatus.APPROVED && _extendedStake.amountBooked != _extendedStake.amount) {
_extendedStake.status = Enums.ExtendedStakeStatus.PENDING;
}
}
/// @dev Changes the status of an extended stake contract.
/// @param _extendedContract The contract.
/// @param _extendedStake The stake.
/// @param status The new status.
function _changeExtendedStakeContractStatus(Models.StakeContract storage _extendedContract, Models.ExtendedStake storage _extendedStake, Enums.StakeContractStatus status) internal {
_extendedStake.stakingContractsStatuses[_extendedContract.status] -= 1;
_extendedContract.status = status;
_extendedStake.stakingContractsStatuses[_extendedContract.status] += 1;
}
/// @dev Recalculates expiration for base stake contract based on extended contracts.
/// @param _contract The base contract.
function _recalculateExpiresOnForBaseStakeContract(Models.StakeContract storage _contract) internal {
for (uint256 i = 0; i < _nodeExtendedContracts[_contract.nodeAddress].length; i++) {
uint256 _extContractIndex = _nodeExtendedContracts[_contract.nodeAddress][i];
uint256 _extContractExpiresOn = _stakingContractsList[_extContractIndex].expiresOn;
// Update the expiresOn date for the base stake contract
if (_contract.expiresOn < _extContractExpiresOn) {
_contract.expiresOn = _extContractExpiresOn;
}
}
}
// ---------------------------------------------------------------------------------------------
// ADMIN AND CONFIGURATION FUNCTIONS
// ---------------------------------------------------------------------------------------------
/// @notice Checks if ETNY contract is set up.
/// @return bool True if set up.
function isEtnyContractSetup() public onlyDelegate view returns (bool){
return _etnyTokenSmartContractAddress != address(0);
}
/// @notice Updates the node reward address in a stake contract.
/// @param contractId The contract ID.
/// @param oldRewardAddress The old reward address.
/// @param newRewardAddress The new reward address.
/// @return bool Success indicator.
function updateStakeContractNodeRewardAddress(uint256 contractId, address oldRewardAddress, address newRewardAddress) public onlyDelegate onlyCompanyWallet returns (bool){
require(
contractId < _stakingContractsList.length,
"EtnyStaking: Invalid Index provided!"
);
Models.StakeContract storage _contract = _stakingContractsList[contractId];
require(
oldRewardAddress == _contract.nodeRewardAddress,
"EtnyStaking: reward address provided!"
);
_contract.nodeRewardAddress = newRewardAddress;
return true;
}
/// @notice Sets the ETNY token smart contract address.
/// @param newValue The new address.
function setEtnyTokenSmartContractAddress(address newValue) public onlyDelegate onlyCompanyWallet {
_etnyTokenSmartContractAddress = newValue;
}
/// @notice Retrieves the ETNY token smart contract address.
/// @return The address.
function getEtnyTokenSmartContractAddress() public onlyDelegate view returns (address){
return _etnyTokenSmartContractAddress;
}
/// @notice Retrieves the minimum extended stake amount.
/// @return The amount.
function getMinExtendedStakeAmount() public onlyDelegate view returns (uint64){
return minExtendedStakeAmount;
}
/// @notice Sets the max tokens on a node.
/// @param newValue The new value.
function setMaxTokens(uint256 newValue) public onlyDelegate onlyCompanyWallet {
maxTokens = newValue;
}
/// @notice Retrieves the max tokens on a node.
/// @return The max tokens.
function getMaxTokensOnNode() public onlyDelegate view returns (uint256){
return maxTokens;
}
/// @notice Sets the max NFT tokens.
/// @param newValue The new value.
function setNFTMaxTokens(uint256 newValue) public onlyDelegate onlyCompanyWallet {
maxNFTTokens = newValue;
}
/// @notice Sets the min extended stake amount.
/// @param newValue The new value.
function setMinExtendedStakeAmount(uint64 newValue) public onlyDelegate onlyCompanyWallet {
minExtendedStakeAmount = newValue;
}
/// @notice Sets the minimum period for stake contracts in months.
/// @param value The new minimum period value.
function setMinPeriodStakeContractInMonths(uint8 value) public onlyDelegate onlyCompanyWallet {
minPeriodStakeContractInMonths = value;
}
/// @notice Retrieves the min period for stake.
/// @return The min period.
function getMinPeriodForStake() public onlyDelegate view returns (uint8) {
return minPeriodStakeContractInMonths;
}
/// @notice Sets the APY percentage.
/// @param value The new APY percentage value.
function setApyPercentage(uint8 value) public onlyDelegate onlyCompanyWallet {
apyPercentage = value;
}
/// @notice Retrieves the current APY percentage.
/// @return The APY.
function getCurrentApyPercentage() public onlyDelegate view returns (uint8) {
return apyPercentage;
}
/// @notice Retrieves the stake total supply.
/// @return The total supply.
function getStakeTotalSupply() public onlyDelegate view returns (uint64) {
return totalSupply;
}
/// @notice Retrieves the min base stake amount.
/// @return The amount.
function getMinBaseStakeAmount() public onlyDelegate view returns (uint64){
return minBaseStakeAmount;
}
/// @notice Sets the min amount for base stake.
/// @param value The value.
function setMinAmountForBaseStake(uint64 value) public onlyDelegate onlyCompanyWallet {
minBaseStakeAmount = value;
}
/// @notice Sets the min amount for base stake NFT.
/// @param value The value.
function setMinAmountForBaseStakeNFT(uint64 value) public onlyDelegate onlyCompanyWallet {
minBaseStakeNFTAmount = value;
}
/// @notice Retrieves the max base stake amount.
/// @return The amount.
function getMaxBaseStakeAmount() public onlyDelegate view returns (uint64){
return maxBaseStakeAmount;
}
/// @notice Sets the max amount for base stake.
/// @param value The value.
function setMaxAmountForBaseStake(uint64 value) public onlyDelegate onlyCompanyWallet {
maxBaseStakeAmount = value;
}
/// @notice Cleans up a canceled base stake.
/// @param nodeAddress The node address.
/// @return bool Success indicator.
function cleanCanceledBaseStake(address nodeAddress) public onlyDelegate returns (bool){
require(
_canceledBaseStakeNodes[nodeAddress],
"EtnyStaking: Node is not canceled!"
);
require(
_nodeBaseStakeRequests[nodeAddress].length > 0,
"EtnyStaking: Node is not having any base stakes requests!"
);
uint256 lastSakeIndex = _nodeBaseStakeRequests[nodeAddress].length - 1;
uint256 baseStakeId = _nodeBaseStakeRequests[nodeAddress][lastSakeIndex];
Models.BaseStake storage _stake = _baseStakesList[baseStakeId];
require(
_stake.status == Enums.BaseStakeStatus.APPROVED
|| _stake.status == Enums.BaseStakeStatus.TERMINATED,
"EtnyStaking: Cannot execute cleanup on this status!"
);
_canceledBaseStakeNodes[nodeAddress] = false;
return true;
}
/// @notice Sets expiration date and status for base stake contract.
/// @param stakeContractId The contract ID.
/// @param expiresOn The new expires on.
/// @param canceledOn The new canceled on.
/// @param status The new status.
/// @return bool Success indicator.
function setBaseStakeContractExpirationDateAndStatus(uint256 stakeContractId, uint256 expiresOn, uint256 canceledOn, uint status) public onlyDelegate returns (bool){
require(companyAddresses[msg.sender] == true, "EtnyStaking: Only a company address can perform this action!");
// Check if the provided baseStakeId is valid
require(stakeContractId < _stakingContractsList.length, "EtnyStaking: Invalid Base Stake Contract ID provided!");
// Get the associated stake contract
Models.StakeContract storage _contract = _stakingContractsList[stakeContractId];
_contract.status = Enums.StakeContractStatus(status);
_contract.expiresOn = expiresOn;
_contract.canceledOn = canceledOn;
// Get the base stake associated with the given ID
Models.BaseStake storage _stake = _baseStakesList[_contract.stakeId];
_stake.status = Enums.BaseStakeStatus(status);
_canceledBaseStakeNodes[_stake.nodeAddress] = _stake.status == Enums.BaseStakeStatus.CANCELED;
return true;
}
}
Contract ABI
[{"type":"event","name":"ApplyPenaltiesToBaseStakeByCompany","inputs":[{"type":"uint256","name":"nodeStakingTotal","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"BaseStakeApproved","inputs":[{"type":"uint256","name":"baseStakeId","internalType":"uint256","indexed":false},{"type":"uint256","name":"nodeStakingTotal","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"BaseStakeContractCanceled","inputs":[{"type":"uint256","name":"stakeContractId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"BaseStakeContractExtendedForPenalties","inputs":[{"type":"uint256","name":"contractId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"BaseStakeContractTerminated","inputs":[{"type":"uint256","name":"stakeContractId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ExtendedStakeCanceled","inputs":[{"type":"uint256","name":"extendedStakeId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ExtendedStakeContractApproved","inputs":[{"type":"uint256","name":"contractId","internalType":"uint256","indexed":false},{"type":"uint256","name":"extendedContractStakeId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ExtendedStakeContractCanceled","inputs":[{"type":"uint256","name":"contractId","internalType":"uint256","indexed":false},{"type":"uint256","name":"extendedContractStakeId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ExtendedStakeContractDeclined","inputs":[{"type":"uint256","name":"contractId","internalType":"uint256","indexed":false},{"type":"uint256","name":"extendedContractStakeId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ExtendedStakeContractTerminated","inputs":[{"type":"uint256","name":"contractId","internalType":"uint256","indexed":false},{"type":"uint256","name":"extendedContractStakeId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ExtendedStakeFreed","inputs":[{"type":"uint256","name":"extendedStakeId","internalType":"uint256","indexed":false},{"type":"uint256","name":"tokensLockedInStaking","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ExtendedStakeTerminated","inputs":[{"type":"uint256","name":"extendedStakeId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"NewBaseStake","inputs":[{"type":"address","name":"staker","internalType":"address","indexed":true},{"type":"uint256","name":"baseStakeId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"NewExtendedStake","inputs":[{"type":"address","name":"staker","internalType":"address","indexed":true},{"type":"uint256","name":"baseStakeId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"NewStakeContract","inputs":[{"type":"address","name":"staker","internalType":"address","indexed":true},{"type":"address","name":"node","internalType":"address","indexed":true},{"type":"uint256","name":"contractId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"NodeAppliedToExtendedStake","inputs":[{"type":"address","name":"node","internalType":"address","indexed":true},{"type":"uint256","name":"extendedStakeId","internalType":"uint256","indexed":false},{"type":"uint256","name":"nodeStakingTotal","internalType":"uint256","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":"ProxyTransferred","inputs":[{"type":"address","name":"_from","internalType":"address","indexed":true},{"type":"address","name":"_to","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"TokensAddedToExtendedStake","inputs":[{"type":"uint256","name":"extendedStakeId","internalType":"uint256","indexed":false},{"type":"uint64","name":"additionalAmount","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"_owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"_rowNumber","internalType":"uint256"}],"name":"addBaseStakeRequest","inputs":[{"type":"address","name":"nodeAddress","internalType":"address"},{"type":"uint64","name":"amount","internalType":"uint64"},{"type":"uint16","name":"period","internalType":"uint16"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addCompanyWallet","inputs":[{"type":"address","name":"companyAddress","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"_extendedStakeId","internalType":"uint256"}],"name":"addExtendedStakeRequest","inputs":[{"type":"address","name":"nodeAddress","internalType":"address"},{"type":"uint64","name":"amount","internalType":"uint64"},{"type":"address","name":"rewardAddress","internalType":"address"},{"type":"uint16","name":"period","internalType":"uint16"},{"type":"uint8","name":"opReward","internalType":"uint8"},{"type":"bool","name":"allowMultipleOp","internalType":"bool"},{"type":"bool","name":"autoConfirm","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"addTokensToExtendedStake","inputs":[{"type":"uint256","name":"extendedStakeId","internalType":"uint256"},{"type":"uint64","name":"additionalAmount","internalType":"uint64"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"applyExtendedStakeRequest","inputs":[{"type":"uint256","name":"extendedStakeID","internalType":"uint256"},{"type":"uint64","name":"amount","internalType":"uint64"},{"type":"address","name":"rewardAddress","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"applyPenaltiesToBaseStakeByCompany","inputs":[{"type":"uint256","name":"stakeContractId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approveBaseStakeRequest","inputs":[{"type":"uint256","name":"baseStakeId","internalType":"uint256"},{"type":"address","name":"rewardAddress","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approveExtendedStakeContract","inputs":[{"type":"uint256","name":"stakeId","internalType":"uint256"},{"type":"uint64","name":"stakeContract","internalType":"uint64"},{"type":"address","name":"rewardAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"callerAddress","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"cancelBaseStakeRequest","inputs":[{"type":"uint256","name":"baseStakeId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"cancelExtendedStakeContract","inputs":[{"type":"uint256","name":"stakeId","internalType":"uint256"},{"type":"uint64","name":"stakeContract","internalType":"uint64"},{"type":"bool","name":"isOperatorPerformingBad","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"cancelExtendedStakeRequest","inputs":[{"type":"uint256","name":"extendedStakeID","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"cleanCanceledBaseStake","inputs":[{"type":"address","name":"nodeAddress","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"declineBaseStakeRequest","inputs":[{"type":"uint256","name":"baseStakeId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"declineExtendedStakeContract","inputs":[{"type":"uint256","name":"stakeId","internalType":"uint256"},{"type":"uint64","name":"stakeContract","internalType":"uint64"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"freeExtendedStakeRequest","inputs":[{"type":"uint256","name":"stakeId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getAvailableTokensForStake","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_baseStakeId","internalType":"uint256"},{"type":"address","name":"stakeHolderAddress","internalType":"address"},{"type":"address","name":"rewardAddress","internalType":"address"},{"type":"address","name":"nodeAddress","internalType":"address"},{"type":"uint256","name":"timestamp","internalType":"uint256"},{"type":"uint64","name":"amount","internalType":"uint64"},{"type":"uint64","name":"period","internalType":"uint64"},{"type":"uint8","name":"status","internalType":"enum Enums.BaseStakeStatus"},{"type":"uint8","name":"stakeType","internalType":"enum Enums.StakeType"}],"name":"getBaseStake","inputs":[{"type":"uint256","name":"baseStakeId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getBaseStakeRequestIdForOperator","inputs":[{"type":"uint256","name":"stakeIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getBaseStakeRequestIdForStaker","inputs":[{"type":"uint256","name":"stakeIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"count","internalType":"uint256"}],"name":"getBaseStakeRequestTotal","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getBaseStakeRequestsForNode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getBaseStakeRequestsForOperatorCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getBaseStakeRequestsForStakerCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getBaseStakesForNode","inputs":[{"type":"address","name":"nodeAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"timestamp","internalType":"uint256"},{"type":"uint256","name":"approvedOn","internalType":"uint256"},{"type":"uint256","name":"expiresOn","internalType":"uint256"},{"type":"uint256","name":"estimatedExpiration","internalType":"uint256"},{"type":"uint256","name":"canceledOn","internalType":"uint256"}],"name":"getContractDateDetails","inputs":[{"type":"uint256","name":"contractId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"getCurrentApyPercentage","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"getEtnyTokenSmartContractAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getExtendPoolMaxExpirationdate","inputs":[{"type":"uint256","name":"extendPoolId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_baseStakeId","internalType":"uint256"},{"type":"address","name":"stakeHolderAddress","internalType":"address"},{"type":"address","name":"rewardAddress","internalType":"address"},{"type":"address","name":"nodeAddress","internalType":"address"},{"type":"uint256","name":"timestamp","internalType":"uint256"},{"type":"uint64","name":"amount","internalType":"uint64"},{"type":"uint64","name":"amountBooked","internalType":"uint64"},{"type":"uint64","name":"period","internalType":"uint64"},{"type":"uint8","name":"operatorReward","internalType":"uint8"},{"type":"bool","name":"allowMultipleOp","internalType":"bool"},{"type":"bool","name":"autoConfirm","internalType":"bool"},{"type":"uint8","name":"status","internalType":"enum Enums.ExtendedStakeStatus"},{"type":"uint64","name":"stakingContracts","internalType":"uint64"}],"name":"getExtendedStake","inputs":[{"type":"uint256","name":"extendedStakeId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_extendedStakeId","internalType":"uint256"},{"type":"uint64","name":"allContracts","internalType":"uint64"},{"type":"uint64","name":"pendingContracts","internalType":"uint64"},{"type":"uint64","name":"approvedContracts","internalType":"uint64"},{"type":"uint64","name":"declinedContracts","internalType":"uint64"},{"type":"uint64","name":"canceledContracts","internalType":"uint64"},{"type":"uint64","name":"terminatedContracts","internalType":"uint64"}],"name":"getExtendedStakeRequestContractStats","inputs":[{"type":"uint256","name":"extendedStakeId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getExtendedStakeRequestIdForOperator","inputs":[{"type":"uint256","name":"stakeIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getExtendedStakeRequestIdForStaker","inputs":[{"type":"uint256","name":"stakeIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"count","internalType":"uint256"}],"name":"getExtendedStakeRequestTotal","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getExtendedStakeRequestsForNode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getExtendedStakeRequestsForOperatorCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getExtendedStakeRequestsForStakerCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getLockedBalanceAtStake","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getLockedBalanceAtStakeInWei","inputs":[{"type":"address","name":"wallet","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"","internalType":"uint64"}],"name":"getMaxBaseStakeAmount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getMaxTokensOnNode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"","internalType":"uint64"}],"name":"getMinBaseStakeAmount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"","internalType":"uint64"}],"name":"getMinExtendedStakeAmount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"getMinPeriodForStake","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"baseStakeRequestList","internalType":"uint256[]"},{"type":"bool","name":"activeBaseStake","internalType":"bool"},{"type":"uint256","name":"totalStaking","internalType":"uint256"},{"type":"bool","name":"canceledBaseStake","internalType":"bool"}],"name":"getNodeDetails","inputs":[{"type":"address","name":"nodeAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"estimatedExpiration","internalType":"uint256"},{"type":"address","name":"stakeHolderAddress","internalType":"address"},{"type":"address","name":"nodeAddress","internalType":"address"},{"type":"address","name":"nodeRewardAddress","internalType":"address"},{"type":"address","name":"stakeHolderRewardAddress","internalType":"address"},{"type":"uint256","name":"timestamp","internalType":"uint256"},{"type":"uint64","name":"amount","internalType":"uint64"},{"type":"uint64","name":"opReward","internalType":"uint64"},{"type":"uint64","name":"period","internalType":"uint64"},{"type":"uint8","name":"status","internalType":"enum Enums.StakeContractStatus"},{"type":"uint8","name":"stakeType","internalType":"enum Enums.StakeType"}],"name":"getStakeContract","inputs":[{"type":"uint256","name":"stakeContractId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_stakeId","internalType":"uint256"},{"type":"uint64","name":"_stakeContract","internalType":"uint64"},{"type":"uint256","name":"stakeContractId","internalType":"uint256"},{"type":"address","name":"stakeHolderAddress","internalType":"address"},{"type":"address","name":"nodeAddress","internalType":"address"},{"type":"address","name":"nodeRewardAddress","internalType":"address"},{"type":"uint256","name":"timestamp","internalType":"uint256"},{"type":"uint64","name":"amount","internalType":"uint64"},{"type":"uint64","name":"period","internalType":"uint64"},{"type":"uint8","name":"status","internalType":"enum Enums.StakeContractStatus"},{"type":"uint256","name":"expiresOn","internalType":"uint256"}],"name":"getStakeContractForBaseStake","inputs":[{"type":"uint256","name":"stakeId","internalType":"uint256"},{"type":"uint64","name":"stakeContract","internalType":"uint64"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_stakeId","internalType":"uint256"},{"type":"uint64","name":"_stakeContract","internalType":"uint64"},{"type":"uint256","name":"stakeContractId","internalType":"uint256"},{"type":"address","name":"stakeHolderAddress","internalType":"address"},{"type":"address","name":"nodeAddress","internalType":"address"},{"type":"uint256","name":"timestamp","internalType":"uint256"},{"type":"uint64","name":"amount","internalType":"uint64"},{"type":"uint64","name":"period","internalType":"uint64"},{"type":"uint8","name":"status","internalType":"enum Enums.StakeContractStatus"},{"type":"uint256","name":"estimatedExpiration","internalType":"uint256"}],"name":"getStakeContractForStake","inputs":[{"type":"uint256","name":"stakeId","internalType":"uint256"},{"type":"uint64","name":"stakeContract","internalType":"uint64"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"count","internalType":"uint256"}],"name":"getStakeContractsTotal","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"","internalType":"uint64"}],"name":"getStakeTotalSupply","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTotalStakedOnNode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"implementation","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isEtnyContractSetup","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isNode","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"lockBaseStakeRequest","inputs":[{"type":"uint256","name":"baseStakeId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeCompanyWallet","inputs":[{"type":"address","name":"oldCompanyAddress","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setApyPercentage","inputs":[{"type":"uint8","name":"value","internalType":"uint8"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"setBaseStakeContractExpirationDateAndStatus","inputs":[{"type":"uint256","name":"stakeContractId","internalType":"uint256"},{"type":"uint256","name":"expiresOn","internalType":"uint256"},{"type":"uint256","name":"canceledOn","internalType":"uint256"},{"type":"uint256","name":"status","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setEtnyTokenSmartContractAddress","inputs":[{"type":"address","name":"newValue","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"setLockedBalanceAtStake","inputs":[{"type":"address","name":"wallet","internalType":"address"},{"type":"uint64","name":"amount","internalType":"uint64"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMaxAmountForBaseStake","inputs":[{"type":"uint64","name":"value","internalType":"uint64"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMaxTokens","inputs":[{"type":"uint256","name":"newValue","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMinAmountForBaseStake","inputs":[{"type":"uint64","name":"value","internalType":"uint64"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMinAmountForBaseStakeNFT","inputs":[{"type":"uint64","name":"value","internalType":"uint64"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMinExtendedStakeAmount","inputs":[{"type":"uint64","name":"newValue","internalType":"uint64"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMinPeriodStakeContractInMonths","inputs":[{"type":"uint8","name":"value","internalType":"uint8"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setNFTMaxTokens","inputs":[{"type":"uint256","name":"newValue","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"terminateBaseStake","inputs":[{"type":"uint256","name":"baseStakePoolId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"terminateContract","inputs":[{"type":"uint256","name":"contractId","internalType":"uint256"},{"type":"bool","name":"hasPenalties","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"terminateExpiredBaseStakeContractByJob","inputs":[{"type":"uint256","name":"contractId","internalType":"uint256"},{"type":"bool","name":"hasPenalties","internalType":"bool"},{"type":"bool","name":"recalculateContractExpiresOn","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"terminateExpiredExtendedStakeContractByJob","inputs":[{"type":"uint256","name":"contractId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"terminateExtendPoolContracts","inputs":[{"type":"uint256","name":"extendPoolId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferProxy","inputs":[{"type":"address","name":"_newProxy","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"updateStakeContractNodeRewardAddress","inputs":[{"type":"uint256","name":"contractId","internalType":"uint256"},{"type":"address","name":"oldRewardAddress","internalType":"address"},{"type":"address","name":"newRewardAddress","internalType":"address"}]}]
Contract Creation Code
0x6080604052620124f860165562036ee8601755601880546001600160d01b0319167302bc00000000000007b80000000000e4e1c0060a179055601980546001600160c01b03191671138800000000000124f80000000000000bd017905534801561006857600080fd5b506100716100af565b3360008181526002602052604090208054600160ff1991821681178355600580546001600160a01b03191690941790935581541690911790556101c6565b600054610100900460ff16806100c45750303b155b806100d2575060005460ff16155b6101395760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b600054610100900460ff1615801561015b576000805461ffff19166101011790555b600080546201000033810262010000600160b01b0319909216919091178083556040519190046001600160a01b031691907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a380156101c3576000805461ff00191690555b50565b6197e9806101d56000396000f3fe608060405234801561001057600080fd5b50600436106104695760003560e01c80638caafbff1161024c578063c6aa90ef11610146578063de7c8830116100c3578063eb050c0911610087578063eb050c0914610a5b578063f2fde38b14610a6e578063f3b5397414610a81578063f8a25c5614610a94578063faa8aab114610a9c57600080fd5b8063de7c8830146109ee578063e0768b1814610a01578063e8454f0714610a14578063e99edf4114610a27578063ea55e31914610a2f57600080fd5b8063cf3c32871161010a578063cf3c3287146109a3578063d53ce9a9146109ab578063d598ed98146109be578063da67129a146109c6578063db797e81146109d957600080fd5b8063c6aa90ef14610932578063c75602391461096d578063c8f00e7514610980578063c91951c714610993578063cd7f0bcc1461099b57600080fd5b8063ac870fe8116101d4578063b6b7b3cf11610198578063b6b7b3cf146108d2578063b6c4ab71146108da578063b6ecc1cc146108f4578063bafb358114610907578063c573a9b61461092a57600080fd5b8063ac870fe81461087e578063af68faae14610891578063b06ba626146108a4578063b2bdfa7b146108b7578063b3036c64146108ca57600080fd5b806390cadc5a1161021b57806390cadc5a1461081457806391a8c1c514610827578063946e203f14610850578063a4f8277314610863578063a6f958c81461086b57600080fd5b80638caafbff146107cf5780638cd03f77146107d75780638d2adf32146107ea5780638da5cb5b146107fd57600080fd5b8063458dcf6a1161036857806367e40097116102e55780638014522d116102a95780638014522d1461076457806380605c931461077757806383082bb21461078a57806383c8eed91461079d57806388b4ec28146107c757600080fd5b806367e400971461071b5780636b2963551461072e578063715018a614610741578063749490b8146107495780637c5045e81461075c57600080fd5b80635d0d71661161032c5780635d0d7166146106bd5780635eba1aa3146106e557806362647959146106f8578063676465401461070057806367a53be31461071357600080fd5b8063458dcf6a14610644578063488b8e8b146106575780634d263b611461066a578063512532891461067f5780635c60da1b1461069257600080fd5b806328d9228c116103f657806337daa815116103ba57806337daa815146105ab578063380ae6be146106035780633b7973ed146106165780633e1e32871461061e578063438787d01461063157600080fd5b806328d9228c1461054c57806329e0a52b1461055f57806329e7d373146105725780632e14edaa146105855780633348dccd1461059857600080fd5b806311e776fe1161043d57806311e776fe146104db5780631492794d146104f0578063194dc6c8146105115780631c4bc72914610519578063275fdda51461053957600080fd5b8062226faa1461046e578063033751a2146104965780630b0e33d0146104c05780630ef7ef77146104c8575b600080fd5b61048161047c36600461886f565b610aaf565b60405190151581526020015b60405180910390f35b6104a96104a436600461886f565b610bdc565b60405161048d9b9a999897969594939291906188cb565b610481610e37565b6104816104d6366004618974565b610e63565b6104ee6104e936600461886f565b610f66565b005b6105036104fe36600461886f565b610fb1565b60405190815260200161048d565b61050361102c565b61052161104d565b6040516001600160401b03909116815260200161048d565b6104816105473660046189b0565b61107d565b61048161055a3660046189f9565b611214565b61048161056d366004618a2c565b611290565b61048161058036600461886f565b6117c4565b6104ee610593366004618a5f565b611a99565b6104ee6105a6366004618a7a565b611aed565b6105be6105b936600461886f565b611b56565b604080519788526001600160401b03968716602089015294861694870194909452918416606086015283166080850152821660a08401521660c082015260e00161048d565b61048161061136600461886f565b611c2f565b610503612248565b6104ee61062c366004618aa6565b612276565b6104ee61063f366004618a5f565b6122d8565b610503610652366004618a5f565b61232a565b6104ee610665366004618a7a565b612369565b6106726123dc565b60405161048d9190618afd565b61050361068d36600461886f565b612455565b6003546106a5906001600160a01b031681565b6040516001600160a01b03909116815260200161048d565b6106d06106cb36600461886f565b6125f3565b60405161048d99989796959493929190618b10565b6104816106f336600461886f565b612772565b610503612957565b6104ee61070e36600461886f565b612985565b610481612c90565b61050361072936600461886f565b612cc0565b61048161073c366004618a5f565b612d29565b6104ee612fa5565b610481610757366004618a2c565b613026565b61050361384a565b61048161077236600461886f565b613878565b6104ee610785366004618aa6565b613bc0565b61048161079836600461886f565b613c1c565b6107b06107ab366004618b80565b614548565b60405161048d9b9a99989796959493929190618ba3565b6105036146bb565b6105216146e9565b6104816107e536600461886f565b614713565b6104ee6107f8366004618a7a565b6148dd565b6000546201000090046001600160a01b03166106a5565b6104ee610822366004618a5f565b614950565b61083a610835366004618b80565b6149a1565b60405161048d9a99989796959493929190618c1d565b61048161085e366004618b80565b614be4565b610503614f29565b610481610879366004618c8c565b614f4a565b6104ee61088c366004618a5f565b615080565b61050361089f366004618cc1565b6150e8565b6105036108b2366004618cfb565b615671565b6005546106a5906001600160a01b031681565b610672615ffa565b610521616071565b6108e26160a2565b60405160ff909116815260200161048d565b6104ee610902366004618a7a565b6160c6565b61091a610915366004618a5f565b616139565b60405161048d9493929190618d81565b6105036161d9565b61094561094036600461886f565b6161fa565b604080519586526020860194909452928401919091526060830152608082015260a00161048d565b61050361097b36600461886f565b616346565b61048161098e36600461886f565b6163af565b61050361661c565b6106a561663d565b6108e2616667565b6104816109b9366004618db2565b616690565b610503616a64565b6104816109d4366004618dd7565b616a92565b33600090815260146020526040902054610503565b6106726109fc366004618a5f565b616d65565b6104ee610a0f36600461886f565b616dd1565b610503610a2236600461886f565b616e1c565b610521616e85565b610a42610a3d36600461886f565b616eb6565b60405161048d9d9c9b9a99989796959493929190618dfa565b610481610a69366004618b80565b617012565b6104ee610a7c366004618a5f565b617491565b610481610a8f366004618e9a565b61758f565b6105036176b7565b6001546106a5906001600160a01b031681565b3360009081526002602052604081205460ff16610ae75760405162461bcd60e51b8152600401610ade90618ebf565b60405180910390fd5b6009548210610b085760405162461bcd60e51b8152600401610ade90618f11565b600060098381548110610b1d57610b1d618f5d565b6000918252602090912060069091020190506001600482810154600160501b900460ff1690811115610b5157610b51618888565b14610b6e5760405162461bcd60e51b8152600401610ade90618f73565b60048101805460ff60501b1916600360501b1790556005810154600b8054600092908110610b9e57610b9e618f5d565b600091825260209091206009600c90920201908101805460ff1916600317905542600682015564012117d1576008909101555060019150505b919050565b6000806000806000806000806000806000600b805490508c10610c5a5760405162461bcd60e51b815260206004820152603060248201527f45746e795374616b696e673a20496e76616c6964205374616b6520636f6e747260448201526f6163742049442070726f76696465642160801b6064820152608401610ade565b6000600b8d81548110610c6f57610c6f618f5d565b600091825260208220919d50600c020190506001600982015460ff166004811115610c9c57610c9c618888565b03610d35576005810154600782015460405163d83102cd60e01b8152600160801b90920461ffff16600483015260248201527342e7bf71a3b0302011dbbb98d65e8a49abdb107b9063d83102cd90604401602060405180830381865af4158015610d0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2e9190618fc1565b9b50610d3d565b80600801549b505b8b8160000160009054906101000a90046001600160a01b03168260020160009054906101000a90046001600160a01b03168360030160009054906101000a90046001600160a01b03168460010160009054906101000a90046001600160a01b031685600401548660050160009054906101000a90046001600160401b03168760050160089054906101000a90046001600160401b03168860050160109054906101000a900461ffff168960090160009054906101000a900460ff168a600b0160009054906101000a900460ff168261ffff1692509b509b509b509b509b509b509b509b509b509b509b505091939597999b90929496989a50565b6001546000906001600160a01b03163314610e5157600080fd5b506007546001600160a01b0316151590565b6001546000906001600160a01b03163314610e7d57600080fd5b600a548410610e9e5760405162461bcd60e51b8152600401610ade90618fda565b6000600a8581548110610eb357610eb3618f5d565b906000526020600020906007020190508060040160109054906101000a90046001600160401b03166001600160401b0316846001600160401b031610610f0b5760405162461bcd60e51b8152600401610ade9061902a565b6001600160401b0384166000908152600582016020526040812054600b805491929183908110610f3d57610f3d618f5d565b90600052602060002090600c02019050610f59838284886176ff565b93505050505b9392505050565b6001546001600160a01b03163314610f7d57600080fd5b3360009081526002602052604090205460ff16610fac5760405162461bcd60e51b8152600401610ade90618ebf565b601655565b6001546000906001600160a01b03163314610fcb57600080fd5b336000908152600c60205260409020548210610ff95760405162461bcd60e51b8152600401610ade90619077565b336000908152600c6020526040902080548390811061101a5761101a618f5d565b90600052602060002001549050919050565b6001546000906001600160a01b0316331461104657600080fd5b5060095490565b6001546000906001600160a01b0316331461106757600080fd5b506018546201000090046001600160401b031690565b6001546000906001600160a01b0316331461109757600080fd5b3360009081526002602052604090205460ff1615156001146110cb5760405162461bcd60e51b8152600401610ade906190bb565b600b5485106110ec5760405162461bcd60e51b8152600401610ade90619106565b6000600b868154811061110157611101618f5d565b90600052602060002090600c0201905082600481111561112357611123618888565b60098201805460ff1916600183600481111561114157611141618888565b02179055506008810185905560068101849055600a8101546009805460009290811061116f5761116f618f5d565b9060005260206000209060060201905083600481111561119157611191618888565b81600401600a6101000a81548160ff021916908360048111156111b6576111b6618888565b02179055506003600482810154600160501b900460ff16908111156111dd576111dd618888565b6002909201546001600160a01b03166000908152601560205260409020805460ff1916919092141790555060019050949350505050565b6001546000906001600160a01b0316331461122e57600080fd5b3360009081526002602052604090205460ff1615156001146112625760405162461bcd60e51b8152600401610ade906190bb565b506001600160a01b03821660009081526014602052604090206001600160401b038216905560015b92915050565b6001546000906001600160a01b031633146112aa57600080fd5b600a5484106112cb5760405162461bcd60e51b8152600401610ade90618fda565b6000600a85815481106112e0576112e0618f5d565b906000526020600020906007020190508060040160109054906101000a90046001600160401b03166001600160401b0316846001600160401b0316106113385760405162461bcd60e51b8152600401610ade9061902a565b60028101546001600160a01b0316156114fd5760028101546001600160a01b031633146113c45760405162461bcd60e51b815260206004820152603460248201527f45746e795374616b696e673a204f6e6c79206f70657261746f722063616e20616044820152737070726f76652074686520636f6e74726163742160601b6064820152608401610ade565b6001600160a01b0383166114405760405162461bcd60e51b815260206004820152603a60248201527f45746e795374616b696e673a20526577617264206164647265737320666f722060448201527f6f70657261746f7220776173206e6f742070726f7669646564210000000000006064820152608401610ade565b336001600160a01b038416036114cd5760405162461bcd60e51b815260206004820152604660248201527f45746e795374616b696e673a2052657761726420616464726573732073686f7560448201527f6c6420626520646966666572656e74207468616e20746865206e6f646520616460648201526564726573732160d01b608482015260a401610ade565b3360009081526015602052604090205460ff16156114fd5760405162461bcd60e51b8152600401610ade9061915b565b6001600160401b0384166000908152600582016020526040812054600b80549192918390811061152f5761152f618f5d565b600091825260208220600c909102019150600982015460ff16600481111561155957611559618888565b146115cc5760405162461bcd60e51b815260206004820152603c60248201527f45746e795374616b696e673a204f6e6c792070656e64696e67207374616b696e60448201527f6720636f6e7472616374732063616e20626520617070726f76656421000000006064820152608401610ade565b6009810154600190600685019060009060ff1660048111156115f0576115f0618888565b600481111561160157611601618888565b815260208101919091526040016000908120805490919061162c9084906001600160401b03166191ce565b82546101009290920a6001600160401b0381810219909316918316021790915560098301805460ff19166001908117909155426007850155600081815260068701602052604081208054929450929091611688918591166191ed565b82546001600160401b039182166101009390930a92830291909202199091161790555060028301546001600160a01b031615611726576003810180546001600160a01b0319166001600160a01b0387161790556004830180547fffff00ffffffffffffffffffffffffff0000000000000000ffffffffffffffff81166001600160401b03909116600160401b0260ff60e81b191617600160e81b1790555b6004830154600160401b81046001600160401b039081169116148015611763575060008080526006840160205260409020546001600160401b0316155b1561177e5760048301805460ff60e81b1916600160e81b1790555b60408051838152602081018990527f492b38fe904dd9e188eb84bf5c076c5ba8391de320e4cda50c11fbc4faa5107f910160405180910390a15060019695505050505050565b6001546000906001600160a01b031633146117de57600080fd5b600a5482106117ff5760405162461bcd60e51b8152600401610ade90619077565b6000600a838154811061181457611814618f5d565b9060005260206000209060070201905060005b60048201546001600160401b03600160801b909104811690821610156119dc576001600160401b0381166000908152600583016020526040812054600b8054909190811061187757611877618f5d565b60009182526020909120600c9091020190506003600982015460ff1660048111156118a4576118a4618888565b1480156118b45750428160080154105b156119d3576009810154600190600685019060009060ff1660048111156118dd576118dd618888565b60048111156118ee576118ee618888565b81526020810191909152604001600090812080549091906119199084906001600160401b03166191ce565b82546101009290920a6001600160401b0381810219909316918316021790915560098301805460ff1916600490811790915560009081526006860160205260408120805460019450909261196f918591166191ed565b82546101009290920a6001600160401b03818102199093169183160217909155825460058401546119ad93506001600160a01b039091169116617cb7565b600281015460058201546119d3916001600160a01b0316906001600160401b0316617d94565b50600101611827565b50600360009081526006820160205260409020546001600160401b0316158015611a1f5750600160009081526006820160205260409020546001600160401b0316155b8015611a42575060008080526006820160205260409020546001600160401b0316155b8015611a7557506004810154611a6a906001600160401b03600160401b8204811691166191ce565b6001600160401b0316155b15611a905760048101805460ff60e81b1916600160ea1b1790555b50600192915050565b6000546201000090046001600160a01b03163314611ac95760405162461bcd60e51b8152600401610ade9061920c565b6001600160a01b03166000908152600260205260409020805460ff19166001179055565b6001546001600160a01b03163314611b0457600080fd5b3360009081526002602052604090205460ff16611b335760405162461bcd60e51b8152600401610ade90618ebf565b6019805467ffffffffffffffff19166001600160401b0392909216919091179055565b600080600080600080600080600a8981548110611b7557611b75618f5d565b90600052602060002090600702019050888160040160109054906101000a90046001600160401b0316826006016000806004811115611bb657611bb6618888565b6004811115611bc757611bc7618888565b81526020808201929092526040908101600090812054600182526006969096019092528082205460028352818320546003845282842054600485529290932054949e939d506001600160401b039586169c5085169a5090841698508316965091169350915050565b6001546000906001600160a01b03163314611c4957600080fd5b600a548210611c6a5760405162461bcd60e51b8152600401610ade90618fda565b6000600a8381548110611c7f57611c7f618f5d565b6000918252602090912060079091020180549091506001600160a01b03163314611cbb5760405162461bcd60e51b8152600401610ade90619241565b6000600482810154600160e81b900460ff1690811115611cdd57611cdd618888565b1480611d0857506001600482810154600160e81b900460ff1690811115611d0657611d06618888565b145b611d905760405162461bcd60e51b815260206004820152604d60248201527f45746e795374616b696e673a20457874656e646564207374616b6520706f6f6c60448201527f2063616e6e6f742062652063616e63656c65642e20497420686173206469666660648201526c6572656e74207374617475732160981b608482015260a401610ade565b60048101805460ff60e81b1916600360e81b1790556040805184815290517fed2eddad45e3518d4213edaae6c788ba893dc504b673a7f55821b62adb85b4349181900360200190a160005b60048201546001600160401b03600160801b909104811690821610156121bb576001600160401b0381166000908152600583016020526040812054600b805491929183908110611e2d57611e2d618f5d565b6000918252602082206009600c9092020190810154909250600191600687019160ff166004811115611e6157611e61618888565b6004811115611e7257611e72618888565b8152602081019190915260400160009081208054909190611e9d9084906001600160401b03166191ce565b92506101000a8154816001600160401b0302191690836001600160401b0316021790555060006004811115611ed457611ed4618888565b600982015460ff166004811115611eed57611eed618888565b0361201e5760098101805460ff1916600417905542600682018190556008820155600a810154604080518481526020810192909252600080516020619774833981519152910160405180910390a160058101546004850180546001600160401b0392831692600891611f68918591600160401b9004166191ce565b82546101009290920a6001600160401b0381810219909316918316021790915560028301546005840154611fa993506001600160a01b039091169116617d94565b80546005820154611fcc916001600160a01b0316906001600160401b0316617cb7565b60028401546001600160a01b0316156120195760048401805467ffffffffffffffff19169055600a8101546040519081526000805160206197348339815191529060200160405180910390a15b612128565b6001600982015460ff16600481111561203957612039618888565b036121285760098101805460ff191660031790554260068201556005810154600782015460405163d83102cd60e01b815261ffff600160801b90930492909216600483015260248201527342e7bf71a3b0302011dbbb98d65e8a49abdb107b9063d83102cd90604401602060405180830381865af41580156120bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e39190618fc1565b6008820155600a8101546040805184815260208101929092527fb503cf14e3d55841fd2c9a549abd732f6898fde969da012639aa917173e3a006910160405180910390a15b6009810154600190600686019060009060ff16600481111561214c5761214c618888565b600481111561215d5761215d618888565b81526020810191909152604001600090812080549091906121889084906001600160401b03166191ed565b92506101000a8154816001600160401b0302191690836001600160401b0316021790555050508080600101915050611ddb565b5060048101546000906121e0906001600160401b03600160401b8204811691166191ce565b6001600160401b03161115611a9057600481015461221b903390612216906001600160401b03600160401b8204811691166191ce565b617cb7565b6004018054600160401b81046001600160401b031667ffffffffffffffff19909116179055506001919050565b6001546000906001600160a01b0316331461226257600080fd5b50336000908152600d602052604090205490565b6001546001600160a01b0316331461228d57600080fd5b3360009081526002602052604090205460ff166122bc5760405162461bcd60e51b8152600401610ade90618ebf565b6018805460ff9092166101000261ff0019909216919091179055565b6000546201000090046001600160a01b031633146123085760405162461bcd60e51b8152600401610ade9061920c565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b600060128161233a82600a619379565b6001600160a01b038516600090815260146020526040902054909150612361908290619385565b949350505050565b6001546001600160a01b0316331461238057600080fd5b3360009081526002602052604090205460ff166123af5760405162461bcd60e51b8152600401610ade90618ebf565b601880546001600160401b03909216600160901b0267ffffffffffffffff60901b19909216919091179055565b6001546060906001600160a01b031633146123f657600080fd5b336000908152600e60209081526040918290208054835181840281018401909452808452909183018282801561244b57602002820191906000526020600020905b815481526020019060010190808311612437575b5050505050905090565b6001546000906001600160a01b0316331461246f57600080fd5b600a5482106124905760405162461bcd60e51b8152600401610ade90619077565b6000600a83815481106124a5576124a5618f5d565b906000526020600020906007020190506000805b60048301546001600160401b03600160801b909104811690821610156125eb576001600160401b0381166000908152600584016020526040812054600b8054909190811061250957612509618f5d565b600091825260208220600c9091020191506001600983015460ff16600481111561253557612535618888565b036125ce576005820154600783015460405163d83102cd60e01b8152600160801b90920461ffff16600483015260248201527342e7bf71a3b0302011dbbb98d65e8a49abdb107b9063d83102cd90604401602060405180830381865af41580156125a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c79190618fc1565b90506125d5565b5060088101545b808410156125e1578093505b50506001016124b9565b509392505050565b6000806000806000806000806000600160009054906101000a90046001600160a01b03166001600160a01b0316336001600160a01b03161461263457600080fd5b6009548a106126555760405162461bcd60e51b8152600401610ade90618f11565b600060098b8154811061266a5761266a618f5d565b6000918252602091829020604080516101008101825260069390930290910180546001600160a01b0390811684526001820154811694840194909452600281015490931690820152600382015460608201526004808301546001600160401b0381166080840152600160401b810461ffff1660a084015291929160c0840191600160501b90910460ff169081111561270457612704618888565b600481111561271557612715618888565b815260200160058201548152505090508a816000015182602001518360400151846060015185608001518660a001518760c0015160008261ffff169250995099509950995099509950995099509950509193959799909294969850565b6001546000906001600160a01b0316331461278c57600080fd5b60095482106127ad5760405162461bcd60e51b8152600401610ade90618f11565b6000600983815481106127c2576127c2618f5d565b6000918252602090912060069091020190506003600482810154600160501b900460ff16908111156127f6576127f6618888565b146128135760405162461bcd60e51b8152600401610ade90618f73565b6000600b82600501548154811061282c5761282c618f5d565b90600052602060002090600c020190504281600801541061289e5760405162461bcd60e51b815260206004820152602660248201527f45746e795374616b696e673a205374616b65206973206e6f742065787069726560448201526564207965742160d01b6064820152608401610ade565b6004828101805460ff60501b1916600160521b17905560098201805460ff19169091179055805460058201546128e6916001600160a01b0316906001600160401b0316617cb7565b6002810180546001600160a01b039081166000908152600f60205260409020805460ff191690559054600583015461292b9291909116906001600160401b0316617d94565b600201546001600160a01b03166000908152601560205260409020805460ff1916905550600192915050565b6001546000906001600160a01b0316331461297157600080fd5b503360009081526012602052604090205490565b6001546001600160a01b0316331461299c57600080fd5b3360009081526002602052604090205460ff161515600114612a445760405162461bcd60e51b8152602060048201526061602482015260008051602061975483398151915260448201527f6573732063616e207465726d696e61746520616e20457874656e64656420537460648201527f616b6520436f6e747261637420616e64206170706c792070656e616c746965736084820152602160f81b60a482015260c401610ade565b600b548110612a655760405162461bcd60e51b8152600401610ade90619077565b6000600b8281548110612a7a57612a7a618f5d565b60009182526020909120600c9091020190506001600b82015460ff166001811115612aa757612aa7618888565b14612b1a5760405162461bcd60e51b815260206004820152603760248201527f45746e795374616b696e673a20416e20457874656e646564205374616b65204360448201527f6f6e7472616374206964206973206578706563746564210000000000000000006064820152608401610ade565b6003600982015460ff166004811115612b3557612b35618888565b14612b525760405162461bcd60e51b8152600401610ade9061939c565b42816008015410612b755760405162461bcd60e51b8152600401610ade906193ef565b80546005820154612b98916001600160a01b0316906001600160401b0316617cb7565b60028101546005820154612bbe916001600160a01b0316906001600160401b0316617d94565b6000600a82600a015481548110612bd757612bd7618f5d565b906000526020600020906007020190508160050160009054906101000a90046001600160401b03168160040160088282829054906101000a90046001600160401b0316612c2491906191ce565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550612c5482826004617e4f565b612c5d81617f87565b600a82015460408051858152602081019290925260008051602061977483398151915291015b60405180910390a1505050565b6001546000906001600160a01b03163314612caa57600080fd5b5033600090815260126020526040902054151590565b6001546000906001600160a01b03163314612cda57600080fd5b336000908152600d60205260409020548210612d085760405162461bcd60e51b8152600401610ade90619077565b336000908152600d6020526040902080548390811061101a5761101a618f5d565b6001546000906001600160a01b03163314612d4357600080fd5b6001600160a01b03821660009081526015602052604090205460ff16612db65760405162461bcd60e51b815260206004820152602260248201527f45746e795374616b696e673a204e6f6465206973206e6f742063616e63656c65604482015261642160f01b6064820152608401610ade565b6001600160a01b0382166000908152600e6020526040902054612e415760405162461bcd60e51b815260206004820152603960248201527f45746e795374616b696e673a204e6f6465206973206e6f7420686176696e672060448201527f616e792062617365207374616b657320726571756573747321000000000000006064820152608401610ade565b6001600160a01b0382166000908152600e6020526040812054612e669060019061944c565b6001600160a01b0384166000908152600e602052604081208054929350909183908110612e9557612e95618f5d565b90600052602060002001549050600060098281548110612eb757612eb7618f5d565b6000918252602090912060069091020190506001600482810154600160501b900460ff1690811115612eeb57612eeb618888565b1480612f15575060048082810154600160501b900460ff1690811115612f1357612f13618888565b145b612f7d5760405162461bcd60e51b815260206004820152603360248201527f45746e795374616b696e673a2043616e6e6f74206578656375746520636c65616044820152726e7570206f6e2074686973207374617475732160681b6064820152608401610ade565b505050506001600160a01b03166000908152601560205260409020805460ff19169055600190565b6000546201000090046001600160a01b03163314612fd55760405162461bcd60e51b8152600401610ade9061920c565b60008054604051620100009091046001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a36000805462010000600160b01b0319169055565b6001546000906001600160a01b0316331461304057600080fd5b600a5484106130615760405162461bcd60e51b8152600401610ade90618fda565b6001600160a01b0382166130875760405162461bcd60e51b8152600401610ade9061945f565b336001600160a01b03831603613107576040805162461bcd60e51b81526020600482015260248101919091527f45746e795374616b696e673a205265776172642061646472657373206d75737460448201527f20626520646966666572656e74207468616e206e6f64652061646472657373216064820152608401610ade565b6019546001600160401b03908116908416101561318c5760405162461bcd60e51b815260206004820152603f60248201527f45746e795374616b696e673a2054686520616d6f756e74206973206c6f77657260448201527f207468616e206d696e20657874656e646564207374616b652076616c756521006064820152608401610ade565b3360009081526015602052604090205460ff16156131bc5760405162461bcd60e51b8152600401610ade9061915b565b6000600a85815481106131d1576131d1618f5d565b6000918252602082206007909102019150600482810154600160e81b900460ff169081111561320257613202618888565b1461321f5760405162461bcd60e51b8152600401610ade90618f73565b60028101546001600160a01b031633036132985760405162461bcd60e51b815260206004820152603460248201527f45746e795374616b696e673a20596f752063616e6e6f74206170706c7920746f6044820152732074686973205374616b6520526571756573742160601b6064820152608401610ade565b60048101546001600160401b03808216916132bc91600160401b90910416866191ed565b6001600160401b031611156133365760405162461bcd60e51b8152602060048201526046602482015260008051602061979483398151915260448201527f74686520617661696c61626c6520616d6f756e7420696e2063757272656e74206064820152657374616b652160d01b608482015260a401610ade565b60048101546001600160801b9091046001600160401b03161180159061336857506004810154600160d81b900460ff16155b8061337e57506004810154600160d81b900460ff165b6133e65760405162461bcd60e51b815260206004820152603360248201527f45746e795374616b696e673a2054686973207374616b652063616e20616363656044820152727074206f6e6c79203120636f6e74726163742160681b6064820152608401610ade565b336000908152601260205260409020546134685760405162461bcd60e51b815260206004820152603860248201527f45746e795374616b696e673a204e65656420746f2068617665206174206c656160448201527f7374206f6e652062617365207374616b652073657475702100000000000000006064820152608401610ade565b6016543360009081526012602052604090205461348f906001600160401b038716906194af565b11156134e75760405162461bcd60e51b8152602060048201526033602482015260008051602061979483398151915260448201527274686520746f74616c206f662037353030302160681b6064820152608401610ade565b6004810154600160d81b900460ff1615156000036135765760048101546001600160401b038581169116146135765760405162461bcd60e51b815260206004820152602f60248201527f45746e795374616b696e673a2054686973207374616b696e6720706f6f6c206360448201526e616e6e6f742062652073706c69742160881b6064820152608401610ade565b838160040160088282829054906101000a90046001600160401b031661359c91906191ed565b82546001600160401b039182166101009390930a9283029282021916919091179091556004830154600160401b81048216911614905080156135e957506004810154600160e01b900460ff165b156136045760048101805460ff60e81b1916600160e81b1790555b8054600182015460048301546000928392613648926001600160a01b039283169233921690600160c01b810461ffff16908b908d90600160d01b900460ff16617ff3565b6003820180546001600160a01b0319166001600160a01b03891617905560048501549193509150600160e01b900460ff16156136945760098201805460ff191660011790554260078301555b6009820154600190600685019060009060ff1660048111156136b8576136b8618888565b60048111156136c9576136c9618888565b81526020810191909152604001600090812080549091906136f49084906001600160401b03166191ed565b82546101009290920a6001600160401b03818102199093169183160217909155600485018054600160801b9081900483166000908152600588016020526040902085905581546001945091926010926137519286929104166191ed565b82546101009290920a6001600160401b0381810219909316918316021790915533600081815260116020908152604080832080546001818101835591855283852001889055938352601082528083208054948501815583528183209093018c9055600587015460028801546001600160a01b0316835260129091529181208054929093169350906137e39084906194af565b909155505060028201546001600160a01b03166000818152601260209081526040918290205482518b8152918201527f859208af8cfda136750efa35f96dbecdddfae3cf3fe2242c8722870edee6ddde910160405180910390a25060019695505050505050565b6001546000906001600160a01b0316331461386457600080fd5b50336000908152600e602052604090205490565b6001546000906001600160a01b0316331461389257600080fd5b600a5482106138b35760405162461bcd60e51b8152600401610ade90618fda565b6000600a83815481106138c8576138c8618f5d565b6000918252602090912060079091020180549091506001600160a01b031633146139445760405162461bcd60e51b815260206004820152602760248201527f45746e795374616b696e673a204f6e6c79207374616b65722063616e2063616c6044820152666c20746869732160c81b6064820152608401610ade565b6000600482810154600160e81b900460ff169081111561396657613966618888565b148061399157506003600482810154600160e81b900460ff169081111561398f5761398f618888565b145b6139ad5760405162461bcd60e51b8152600401610ade90618f73565b6003600482810154600160e81b900460ff16908111156139cf576139cf618888565b03613a46576004810154600160801b90046001600160401b0316613a465760405162461bcd60e51b815260206004820152602860248201527f45746e795374616b696e673a205374616b6520686173206e6f20746f6b656e73604482015267206c6f636b65642160c01b6064820152608401610ade565b60048101546001600160401b03600160401b82048116911611613abf5760405162461bcd60e51b815260206004820152602b60248201527f45746e795374616b696e673a20546865726520617265206e6f20746f6b656e7360448201526a20746f20756e6c6f636b2160a81b6064820152608401610ade565b6004810154613ae6903390612216906001600160401b03600160401b8204811691166191ce565b600481018054600160401b81046001600160401b031667ffffffffffffffff199091168117909155158015613b3a57506000600482810154600160e81b900460ff1690811115613b3857613b38618888565b145b15613b595760048101805460ff60e81b1916600360e81b179055613b6f565b60048101805460ff60e81b1916600160e81b1790555b33600090815260146020908152604091829020548251868152918201527f1ecc5ef7074a468a8b94f3c0c74cd118529219ec2801efefe9351818a4a46bb2910160405180910390a150600192915050565b6001546001600160a01b03163314613bd757600080fd5b3360009081526002602052604090205460ff16613c065760405162461bcd60e51b8152600401610ade90618ebf565b6018805460ff191660ff92909216919091179055565b6001546000906001600160a01b03163314613c3657600080fd5b6009548210613c575760405162461bcd60e51b8152600401610ade90618f11565b600060098381548110613c6c57613c6c618f5d565b6000918252602090912060069091020180549091506001600160a01b03163314613ca85760405162461bcd60e51b8152600401610ade90619241565b6000600482810154600160501b900460ff1690811115613cca57613cca618888565b1480613cf557506001600482810154600160501b900460ff1690811115613cf357613cf3618888565b145b613d115760405162461bcd60e51b8152600401610ade90618f73565b60048101805460ff60501b1916600360501b1790556005810154600b8054600092908110613d4157613d41618f5d565b600091825260208220600c909102019150600982015460ff166004811115613d6b57613d6b618888565b03613e125760098101805460ff191660041790554260068201819055600882015580546005820154613daf916001600160a01b0316906001600160401b0316617cb7565b60028101546001600160a01b03166000908152600f6020908152604091829020805460ff19169055600584015491519182527f2b7d80106cf63960f0324ea49c2f7f872886bdfb6cab927918027dd6d0f314f691015b60405180910390a161453e565b60098101805460ff1990811660031790915542600683015560028201546001600160a01b03166000908152601560209081526040918290208054909316600117909255600584015490519081527fff4d02402ef330920f2f7bfb4a8a15a187a10f1d4f607e9f3d55e6611ef4afe3910160405180910390a160005b60028201546001600160a01b03166000908152601160205260409020548110156143a85760028201546001600160a01b03166000908152601160205260408120805483908110613edf57613edf618f5d565b906000526020600020015490506000600b8281548110613f0157613f01618f5d565b90600052602060002090600c020190506000600a82600a015481548110613f2a57613f2a618f5d565b6000918252602082206007909102019150600983015460ff166004811115613f5457613f54618888565b1480613f7857506001600983015460ff166004811115613f7657613f76618888565b145b15614002576009820154600190600683019060009060ff166004811115613fa157613fa1618888565b6004811115613fb257613fb2618888565b8152602081019190915260400160009081208054909190613fdd9084906001600160401b03166191ce565b92506101000a8154816001600160401b0302191690836001600160401b031602179055505b6000600983015460ff16600481111561401d5761401d618888565b036141ed5760098201805460ff1916600417905542600683018190556008830155600a820154604080518581526020810192909252600080516020619774833981519152910160405180910390a160028201546005830154614091916001600160a01b0316906001600160401b0316617d94565b815460058301546140b4916001600160a01b0316906001600160401b0316617cb7565b60058201546004820180546001600160401b03928316926008916140e1918591600160401b9004166191ce565b92506101000a8154816001600160401b0302191690836001600160401b0316021790555060018160060160008460090160009054906101000a900460ff16600481111561413057614130618888565b600481111561414157614141618888565b815260208101919091526040016000908120805490919061416c9084906001600160401b03166191ed565b82546001600160401b039182166101009390930a92830291909202199091161790555060028101546001600160a01b0316156141e85760048101805467ffffffffffffffff60ff60e81b011916600160ea1b179055600a8201546040519081526000805160206197348339815191529060200160405180910390a15b614382565b6001600983015460ff16600481111561420857614208618888565b036143825760098201805460ff191660031790554260068301556005820154600783015460405163d83102cd60e01b815261ffff600160801b90930492909216600483015260248201527342e7bf71a3b0302011dbbb98d65e8a49abdb107b9063d83102cd90604401602060405180830381865af415801561428e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142b29190618fc1565b60088301556009820154600190600683019060009060ff1660048111156142db576142db618888565b60048111156142ec576142ec618888565b81526020810191909152604001600090812080549091906143179084906001600160401b03166191ed565b92506101000a8154816001600160401b0302191690836001600160401b031602179055507fb503cf14e3d55841fd2c9a549abd732f6898fde969da012639aa917173e3a0068383600a0154604051614379929190918252602082015260400190565b60405180910390a15b81600801548560080154101561439d57600880830154908601555b505050600101613e8d565b50806008015460000361453e5760195460058201546001600160401b03600160801b9092048216911610156144ab5760098101805460ff191660041790554260068201819055600882015580546005820154614416916001600160a01b0316906001600160401b0316617cb7565b6002810180546001600160a01b039081166000908152600f60209081526040808320805460ff19908116909155855485168452601590925290912080549091169055905460058301546144769291909116906001600160401b0316617d94565b7f2b7d80106cf63960f0324ea49c2f7f872886bdfb6cab927918027dd6d0f314f68260050154604051613e0591815260200190565b6005810154600782015460405163d83102cd60e01b8152600160801b90920461ffff16600483015260248201527342e7bf71a3b0302011dbbb98d65e8a49abdb107b9063d83102cd90604401602060405180830381865af4158015614514573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145389190618fc1565b60088201555b5060019392505050565b60008060008060008060008060008060006009805490508d1061457d5760405162461bcd60e51b8152600401610ade90618f11565b600060098e8154811061459257614592618f5d565b906000526020600020906006020190508c6001600160401b03166000146145cb5760405162461bcd60e51b8152600401610ade9061902a565b6000816005015490506000600b82815481106145e9576145e9618f5d565b90600052602060002090600c020190508f8f838560000160009054906101000a90046001600160a01b03168460020160009054906101000a90046001600160a01b03168560030160009054906101000a90046001600160a01b031686600401548760050160009054906101000a90046001600160401b03168860050160109054906101000a900461ffff168960090160009054906101000a900460ff168a600801548261ffff1692509d509d509d509d509d509d509d509d509d509d509d505050509295989b509295989b9093969950565b6001546000906001600160a01b031633146146d557600080fd5b503360009081526010602052604090205490565b6001546000906001600160a01b0316331461470357600080fd5b506019546001600160401b031690565b6001546000906001600160a01b0316331461472d57600080fd5b600954821061474e5760405162461bcd60e51b8152600401610ade90618f11565b60006009838154811061476357614763618f5d565b6000918252602090912060069091020160028101549091506001600160a01b031633146147f85760405162461bcd60e51b815260206004820152603960248201527f45746e795374616b696e673a204f6e6c79206e6f6465206f70657261746f722060448201527f63616e206465636c696e652074686973207265717565737421000000000000006064820152608401610ade565b6000600482810154600160501b900460ff169081111561481a5761481a618888565b146148375760405162461bcd60e51b8152600401610ade90618f73565b60048101805460ff60501b1916600160511b1790556005810154600b805460009290811061486757614867618f5d565b600091825260209091206009600c90920201908101805460ff19166002179055805460058201549192506148af916001600160a01b03909116906001600160401b0316617cb7565b5050336000908152601260209081526040808320839055600f9091529020805460ff19169055506001919050565b6001546001600160a01b031633146148f457600080fd5b3360009081526002602052604090205460ff166149235760405162461bcd60e51b8152600401610ade90618ebf565b601880546001600160401b03909216600160501b0267ffffffffffffffff60501b19909216919091179055565b6000546201000090046001600160a01b031633146149805760405162461bcd60e51b8152600401610ade9061920c565b6001600160a01b03166000908152600260205260409020805460ff19169055565b600080600080600080600080600080600a805490508c106149d45760405162461bcd60e51b8152600401610ade90618fda565b6000600a8d815481106149e9576149e9618f5d565b906000526020600020906007020190508060040160109054906101000a90046001600160401b03166001600160401b03168c6001600160401b031610614a415760405162461bcd60e51b8152600401610ade9061902a565b6001600160401b038c166000908152600582016020526040812054600b805491929183908110614a7357614a73618f5d565b600091825260208220919550600c020190506001600982015460ff166004811115614aa057614aa0618888565b03614b39576005810154600782015460405163d83102cd60e01b8152600160801b90920461ffff16600483015260248201527342e7bf71a3b0302011dbbb98d65e8a49abdb107b9063d83102cd90604401602060405180830381865af4158015614b0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b329190618fc1565b9350614b41565b806008015493505b8e8e838560000160009054906101000a90046001600160a01b03168460020160009054906101000a90046001600160a01b031685600401548660050160009054906101000a90046001600160401b03168760050160109054906101000a900461ffff168860090160009054906101000a900460ff168c8261ffff1692509c509c509c509c509c509c509c509c509c509c505050509295989b9194979a5092959850565b6001546000906001600160a01b03163314614bfe57600080fd5b600a548310614c1f5760405162461bcd60e51b8152600401610ade90618fda565b6000600a8481548110614c3457614c34618f5d565b906000526020600020906007020190508060040160109054906101000a90046001600160401b03166001600160401b0316836001600160401b031610614c8c5760405162461bcd60e51b8152600401610ade9061902a565b6001600160401b0383166000908152600582016020526040812054600b805491929183908110614cbe57614cbe618f5d565b600091825260208220600c909102019150600982015460ff166004811115614ce857614ce8618888565b14614d5b5760405162461bcd60e51b815260206004820152603c60248201527f45746e795374616b696e673a204f6e6c792070656e64696e67207374616b696e60448201527f6720636f6e7472616374732063616e206265206465636c696e656421000000006064820152608401610ade565b6009810154600190600685019060009060ff166004811115614d7f57614d7f618888565b6004811115614d9057614d90618888565b8152602081019190915260400160009081208054909190614dbb9084906001600160401b03166191ce565b82546101009290920a6001600160401b0381810219909316918316021790915560098301805460ff19166002908117909155600090815260068601602052604081208054600194509092614e11918591166191ed565b82546101009290920a6001600160401b038181021990931691831602179091556005830154600486018054918316935091600891614e58918591600160401b9004166191ce565b82546101009290920a6001600160401b0381810219909316918316021790915560028301546005840154614e9993506001600160a01b039091169116617d94565b60028301546001600160a01b031615614ee45760048301805460ff60e81b1916600160e91b17905580546005820154614ee4916001600160a01b0316906001600160401b0316617cb7565b60408051838152602081018890527fa6d35207a3d1012ac29345fe2aeabf0b1dc6285e13a1dbca53d5738524323a54910160405180910390a150600195945050505050565b6001546000906001600160a01b03163314614f4357600080fd5b5060165490565b6001546000906001600160a01b03163314614f6457600080fd5b3360009081526002602052604090205460ff161515600114614f985760405162461bcd60e51b8152600401610ade906194c2565b600b548310614fb95760405162461bcd60e51b8152600401610ade90619077565b6000600b8481548110614fce57614fce618f5d565b60009182526020909120600c9091020190506003600982015460ff166004811115614ffb57614ffb618888565b146150185760405162461bcd60e51b8152600401610ade9061939c565b4281600801541061503b5760405162461bcd60e51b8152600401610ade906193ef565b6001600b82015460ff16600181111561505657615056618888565b036150695761506484612985565b61453e565b61507584846001616690565b505060019392505050565b6001546001600160a01b0316331461509757600080fd5b3360009081526002602052604090205460ff166150c65760405162461bcd60e51b8152600401610ade90618ebf565b600780546001600160a01b0319166001600160a01b0392909216919091179055565b6001546000906001600160a01b0316331461510257600080fd5b6007546001600160a01b031661512a5760405162461bcd60e51b8152600401610ade90619533565b6001600160a01b0384166151965760405162461bcd60e51b815260206004820152602d60248201527f45746e795374616b696e673a206e6f646520616464726573732069732074686560448201526c207a65726f206164647265737360981b6064820152608401610ade565b6001600160a01b038416330361521e5760405162461bcd60e51b815260206004820152604160248201527f45746e795374616b696e673a20546865206e6f64652061646472657373206d7560448201527f737420626520646966666572656e74207468616e2063757272656e74206f6e656064820152602160f81b608482015260a401610ade565b601854610100900460ff1661ffff831610156152905760405162461bcd60e51b815260206004820152602b60248201527f45746e795374616b696e673a20546865207374616b696e6720706572696f642060448201526a697320746f6f206c6f772160a81b6064820152608401610ade565b6018546001600160401b03600160501b9091048116908416108015906152cc57506019546001600160401b03600160401b909104811690841611155b61533e5760405162461bcd60e51b815260206004820152603f60248201527f45746e795374616b696e673a20616d6f756e74206d757374206265206265747760448201527f65656e206d696e696d756d20616e64206d6178696d756d2076616c75657321006064820152608401610ade565b6001600160a01b038416600090815260126020526040902054156153745760405162461bcd60e51b8152600401610ade906195c3565b6001600160a01b0384166000908152600f602052604090205460ff16156153ad5760405162461bcd60e51b8152600401610ade906195c3565b60006153b885618270565b905080156153d85760405162461bcd60e51b8152600401610ade90619618565b60006153e333618270565b336000908152601460205260409020549091506001600160401b0386169061540b908361944c565b10156154295760405162461bcd60e51b8152600401610ade9061965a565b336000818152600c60209081526040808320600980548254600180820185559387528587200155546001600160a01b038c168552600e84528285208054928301815585529383902001839055518281529195507fd7490e816438b23e3486aef50b4dfd914be81021d62b1db81226227291f6c85b910160405180910390a26000806154bb33896000898b8a6064617ff3565b600b8201805492945090925060009160ff1916600183021790555060408051610100810182523381526000602082018190526001600160a01b038b16928201929092524260608201526001600160401b038916608082015261ffff881660a082015260099160c082019081526020908101849052825460018082018555600094855293829020835160069092020180546001600160a01b03199081166001600160a01b03938416178255928401519481018054841695831695909517909455604083015160028501805490931691161790556060810151600383015560808101516004808401805460a08501516001600160401b0390941669ffffffffffffffffffff1990911617600160401b61ffff909416939093029290921780835560c0840151939493929160ff60501b1990911690600160501b90849081111561560457615604618888565b021790555060e0919091015160059091015533600090815260146020526040812080546001600160401b038a16929061563e9084906194af565b9091555050506001600160a01b0387166000908152600f60205260409020805460ff191660011790555050509392505050565b6001546000906001600160a01b0316331461568b57600080fd5b6007546001600160a01b03166156b35760405162461bcd60e51b8152600401610ade90619533565b8360ff1660641461572c576001600160a01b03861661572c5760405162461bcd60e51b815260206004820152602f60248201527f45746e795374616b696e673a207265776172642061646472657373206973207460448201526e6865207a65726f206164647265737360881b6064820152608401610ade565b6019546001600160401b0390811690881610156157975760405162461bcd60e51b815260206004820152602360248201527f45746e795374616b696e673a2054686520616d6f756e7420697320746f6f206c6044820152626f772160e81b6064820152608401610ade565b601854610100900460ff1661ffff861610156158015760405162461bcd60e51b815260206004820152602360248201527f45746e795374616b696e673a2054686520706572696f6420697320746f6f206c6044820152626f772160e81b6064820152608401610ade565b60658460ff161061587a5760405162461bcd60e51b815260206004820152603860248201527f45746e795374616b696e673a20546865206f70657261746f722072657761726460448201527f2070657263656e7461676520697320746f6f20686967682100000000000000006064820152608401610ade565b336001600160a01b0387160361590a5760405162461bcd60e51b815260206004820152604960248201527f45746e795374616b696e673a205468652063757272656e74206164647265737360448201527f2073686f756c6420626520646966666572656e74207468616e2072657761726460648201526820616464726573732160b81b608482015260a401610ade565b6001600160a01b03881615615ba4576001600160a01b03881660009081526015602052604090205460ff16156159a85760405162461bcd60e51b815260206004820152603e60248201527f45746e795374616b696e673a205468652062617365207374616b6520636f6e7460448201527f72616374206f6e20746865206e6f6465207761732063616e63656c65642100006064820152608401610ade565b6001600160a01b038816600090815260126020526040902054615a335760405162461bcd60e51b815260206004820152603860248201527f45746e795374616b696e673a20546865206e6f646520646f65736e277420686160448201527f766520616e792062617365207374616b652073657475702100000000000000006064820152608401610ade565b6001600160a01b0388163303615aa45760405162461bcd60e51b815260206004820152603060248201527f45746e795374616b696e673a20546865206e6f64652061646472657373206d7560448201526f737420626520646966666572656e742160801b6064820152608401610ade565b876001600160a01b0316866001600160a01b031603615ad55760405162461bcd60e51b8152600401610ade906196a5565b6016546001600160a01b038916600090815260126020526040902054615b05906001600160401b038a16906194af565b1115615b775760405162461bcd60e51b8152602060048201526047602482015260008051602061979483398151915260448201527f746865206d6178696d756d20616c6c6f77656420746f6b656e73206f6e20746860648201526665206e6f64652160c81b608482015260a401610ade565b6000615b8289618270565b90508015615ba25760405162461bcd60e51b8152600401610ade90619618565b505b6000615baf33618270565b336000908152601460205260409020549091506001600160401b03891690615bd7908361944c565b1015615bf55760405162461bcd60e51b8152600401610ade9061965a565b6000600a6001816001815401808255809150500390600052602060002090600702019050338160000160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550878160010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550898160020160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550428160030181905550888160040160006101000a8154816001600160401b0302191690836001600160401b0316021790555060008160040160086101000a8154816001600160401b0302191690836001600160401b0316021790555060008160040160106101000a8154816001600160401b0302191690836001600160401b03160217905550868160040160186101000a81548161ffff021916908361ffff1602179055508581600401601a6101000a81548160ff021916908360ff1602179055508481600401601b6101000a81548160ff0219169083151502179055508381600401601c6101000a81548160ff021916908315150217905550600081600401601d6101000a81548160ff02191690836004811115615db557615db5618888565b0217905550600a54615dc99060019061944c565b60405181815290935033907ffb7b213a27fb2f9ada24dbc107b98a959d208d5a39fb37f481b80ff7cc4ec4b49060200160405180910390a2336000908152600d60209081526040822080546001810182559083529120018390556001600160a01b038a1615615fc05780546000908190615e51906001600160a01b03168d8c8c8f8a8e617ff3565b60098201549193509150600190600685019060009060ff166004811115615e7a57615e7a618888565b6004811115615e8b57615e8b618888565b8152602081019190915260400160009081208054909190615eb69084906001600160401b03166191ed565b82546101009290920a6001600160401b03818102199093169183160217909155600485018054600160801b908190048316600090815260058801602052604090208590558154600194509192601092615f139286929104166191ed565b82546101009290920a6001600160401b0381810219909316918316021790915560048501805467ffffffffffffffff60401b1916600160401b928f169283021790556001600160a01b038e166000818152601060209081526040808320805460018181018355918552838520018c9055848452601183528184208054918201815584528284200187905592825260129052908120805492935091615fb89084906194af565b909155505050505b33600090815260146020526040812080546001600160401b038c169290615fe89084906194af565b90915550505050979650505050505050565b6001546060906001600160a01b0316331461601457600080fd5b336000908152601060209081526040918290208054835181840281018401909452808452909183018282801561244b5760200282019190600052602060002090815481526020019060010190808311612437575050505050905090565b6001546000906001600160a01b0316331461608b57600080fd5b50601854600160501b90046001600160401b031690565b6001546000906001600160a01b031633146160bc57600080fd5b5060185460ff1690565b6001546001600160a01b031633146160dd57600080fd5b3360009081526002602052604090205460ff1661610c5760405162461bcd60e51b8152600401610ade90618ebf565b601980546001600160401b03909216600160401b0267ffffffffffffffff60401b19909216919091179055565b6001600160a01b0381166000908152600e60209081526040808320600f83528184205460128452828520546015855283862054835485518188028101880190965280865260609796879687969560ff9081169594169290918691908301828280156161c357602002820191906000526020600020905b8154815260200190600101908083116161af575b5050505050935093509350935093509193509193565b6001546000906001600160a01b031633146161f357600080fd5b50600a5490565b60015460009081908190819081906001600160a01b0316331461621c57600080fd5b600b54861061623d5760405162461bcd60e51b8152600401610ade90619077565b6000600b878154811061625257616252618f5d565b600091825260208220919450600c020190506001600982015460ff16600481111561627f5761627f618888565b03616318576005810154600782015460405163d83102cd60e01b8152600160801b90920461ffff16600483015260248201527342e7bf71a3b0302011dbbb98d65e8a49abdb107b9063d83102cd90604401602060405180830381865af41580156162ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906163119190618fc1565b9250616320565b806008015492505b600481015460078201546008830154600690930154919990985091965092945091925050565b6001546000906001600160a01b0316331461636057600080fd5b336000908152600e6020526040902054821061638e5760405162461bcd60e51b8152600401610ade90619077565b336000908152600e6020526040902080548390811061101a5761101a618f5d565b6001546000906001600160a01b031633146163c957600080fd5b3360009081526002602052604090205460ff16151560011461645d5760405162461bcd60e51b8152602060048201526053602482015260008051602061975483398151915260448201527f6573732063616e207465726d696e61746520612042617365205374616b6520616064820152726e64206170706c792070656e616c746965732160681b608482015260a401610ade565b600b54821061647e5760405162461bcd60e51b8152600401610ade90619106565b6000600b838154811061649357616493618f5d565b90600052602060002090600c020190506000600982600a0154815481106164bc576164bc618f5d565b9060005260206000209060060201905064012117d15782600801541061654a5760405162461bcd60e51b815260206004820152603860248201527f45746e795374616b696e673a2054686520636f6e74726163742077617320616c60448201527f72656164792070726f6c6f6e67656420666f72657665722100000000000000006064820152608401610ade565b616553816182fd565b600982018054600360ff199182161790915542600684015564012117d15760088401556002830180546001600160a01b03908116600090815260156020908152604080832080548716600190811790915594549093168252600f90522080549092161790556165c182618319565b60028201546001600160a01b03166000908152601260209081526040918290205491519182527f1fe3c8d9b22341d7ceb24f6a7806432c03c741b526bec20edf6a49bc22b20bc2910160405180910390a15060019392505050565b6001546000906001600160a01b0316331461663657600080fd5b50600b5490565b6001546000906001600160a01b0316331461665757600080fd5b506007546001600160a01b031690565b6001546000906001600160a01b0316331461668157600080fd5b50601854610100900460ff1690565b6001546000906001600160a01b031633146166aa57600080fd5b3360009081526002602052604090205460ff1615156001146166de5760405162461bcd60e51b8152600401610ade906194c2565b600b5484106166ff5760405162461bcd60e51b8152600401610ade90619077565b6000600b858154811061671457616714618f5d565b600091825260208220600c909102019150600b82015460ff16600181111561673e5761673e618888565b146167a65760405162461bcd60e51b815260206004820152603260248201527f45746e795374616b696e673a20412042617365205374616b6520436f6e74726160448201527163742069642069732065787065637465642160701b6064820152608401610ade565b6003600982015460ff1660048111156167c1576167c1618888565b146167de5760405162461bcd60e51b8152600401610ade9061939c565b82156167ed576167ed8161846e565b428160080154106168105760405162461bcd60e51b8152600401610ade906193ef565b6000600982600a01548154811061682957616829618f5d565b9060005260206000209060060201905061684282618517565b84616932576002820154600583015461686d916001600160a01b0316906001600160401b0316617d94565b600982018054600460ff1991821617909155426006840181905560088401556002830180546001600160a01b03908116600090815260156020908152604080832080548716905593549092168152600f9091522080549091169055815460048201546168eb916001600160a01b0316906001600160401b0316617cb7565b6168f4816186ff565b6040518681527f2b7d80106cf63960f0324ea49c2f7f872886bdfb6cab927918027dd6d0f314f69060200160405180910390a1600192505050610f5f565b60006006830181905560028301546001600160a01b03168152601560205260409020805460ff191690556004810180546001919060ff60501b1916600160501b8302179055506009820180546001919060ff1916828002179055504260078301819055600583015460405163d83102cd60e01b8152600160801b90910461ffff16600482015260248101919091527342e7bf71a3b0302011dbbb98d65e8a49abdb107b9063d83102cd90604401602060405180830381865af41580156169fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190616a209190618fc1565b60088301556040518681527f36e5b23050bb3a750f3648961be392c7f7ddad7be9d63439307a6381168b3a049060200160405180910390a150600195945050505050565b6001546000906001600160a01b03163314616a7e57600080fd5b50336000908152600c602052604090205490565b6001546000906001600160a01b03163314616aac57600080fd5b6009548310616acd5760405162461bcd60e51b8152600401610ade90618f11565b6001600160a01b038216616af35760405162461bcd60e51b8152600401610ade9061945f565b336001600160a01b03831603616b1b5760405162461bcd60e51b8152600401610ade906196a5565b600060098481548110616b3057616b30618f5d565b6000918252602090912060069091020160028101549091506001600160a01b03163314616bc55760405162461bcd60e51b815260206004820152603760248201527f45746e795374616b696e673a206f6e6c79206e6f6465206f70657261746f722060448201527f63616e20617070726f76652062617365207374616b65210000000000000000006064820152608401610ade565b6000600482810154600160501b900460ff1690811115616be757616be7618888565b14616c4b5760405162461bcd60e51b815260206004820152602e60248201527f45746e795374616b696e673a207374616b65206d757374206265206e6577207460448201526d6f20626520617070726f7665642160901b6064820152608401610ade565b60048101805460ff60501b1916600160501b1790556001810180546001600160a01b0319166001600160a01b0385161790556005810154600b8054600092908110616c9857616c98618f5d565b600091825260208083206009600c90930201918201805460ff191660011790554260078301556003820180546001600160a01b0389166001600160a01b0319909116179055600582015433845260129091526040832080549294506001600160401b03909116929091616d0c9084906194af565b909155505033600090815260126020908152604091829020548251888152918201527f1dbef83c751dbba35b43f07c7ba982ca00b3627cd0d733b6c55870a6ea4bce5691015b60405180910390a1506001949350505050565b6001600160a01b0381166000908152600e6020908152604091829020805483518184028101840190945280845260609392830182828015616dc557602002820191906000526020600020905b815481526020019060010190808311616db1575b50505050509050919050565b6001546001600160a01b03163314616de857600080fd5b3360009081526002602052604090205460ff16616e175760405162461bcd60e51b8152600401610ade90618ebf565b601755565b6001546000906001600160a01b03163314616e3657600080fd5b336000908152601060205260409020548210616e645760405162461bcd60e51b8152600401610ade90619077565b33600090815260106020526040902080548390811061101a5761101a618f5d565b6001546000906001600160a01b03163314616e9f57600080fd5b50601954600160401b90046001600160401b031690565b600080600080600080600080600080600080600080600a8f81548110616ede57616ede618f5d565b906000526020600020906007020190508e8160000160009054906101000a90046001600160a01b03168260010160009054906101000a90046001600160a01b03168360020160009054906101000a90046001600160a01b031684600301548560040160009054906101000a90046001600160401b03168660040160089054906101000a90046001600160401b03168760040160189054906101000a900461ffff1688600401601a9054906101000a900460ff1689600401601b9054906101000a900460ff168a600401601c9054906101000a900460ff168b600401601d9054906101000a900460ff168c60040160109054906101000a90046001600160401b03168561ffff1695509d509d509d509d509d509d509d509d509d509d509d509d509d505091939597999b9d90929496989a9c50565b6001546000906001600160a01b0316331461702c57600080fd5b600a54831061704d5760405162461bcd60e51b8152600401610ade90618fda565b6019546001600160401b0390811690831610156170c35760405162461bcd60e51b815260206004820152602e60248201527f45746e795374616b696e673a20546865206164646974696f6e616c20616d6f7560448201526d6e7420697320746f6f206c6f772160901b6064820152608401610ade565b6000600a84815481106170d8576170d8618f5d565b6000918252602090912060079091020180549091506001600160a01b031633146171625760405162461bcd60e51b815260206004820152603560248201527f45746e795374616b696e673a204f6e6c79207374616b65722063616e2061646460448201527420746f6b656e7320746f207468697320706f6f6c2160581b6064820152608401610ade565b6001600482810154600160e81b900460ff169081111561718457617184618888565b146171f75760405162461bcd60e51b815260206004820152603a60248201527f45746e795374616b696e673a2043616e206f6e6c792061646420746f2061707060448201527f726f76656420706f6f6c732061667465722066726565696e67210000000000006064820152608401610ade565b60048101546001600160401b03808216600160401b90920416146172835760405162461bcd60e51b815260206004820152603b60248201527f45746e795374616b696e673a204d757374206672656520756e626f6f6b65642060448201527f616d6f756e7473206265666f726520616464696e67206d6f72652100000000006064820152608401610ade565b60028101546001600160a01b0316156173045760405162461bcd60e51b815260206004820152603960248201527f45746e795374616b696e673a2043616e206f6e6c792061646420746f20706f6f60448201527f6c732c206e6f742064656c656761746564207374616b657321000000000000006064820152608401610ade565b600061730f33618270565b336000908152601460205260409020549091506001600160401b03851690617337908361944c565b10156173bd5760405162461bcd60e51b815260206004820152604960248201527f45746e795374616b696e673a20546865206164646974696f6e616c20616d6f7560448201527f6e7420657863656564732062616c616e636520617661696c61626c6520666f72606482015268207374616b696e672160b81b608482015260a401610ade565b6004820180548591906000906173dd9084906001600160401b03166191ed565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550836001600160401b031660146000336001600160a01b03166001600160a01b03168152602001908152602001600020600082825461743f91906194af565b909155505060048201805460ff60e81b19169055604080518681526001600160401b03861660208201527f62cbcd4fa152970bfc481d57c247601b3a7960fa04006e6f1382f42be25b96ca9101616d52565b6000546201000090046001600160a01b031633146174c15760405162461bcd60e51b8152600401610ade9061920c565b6001600160a01b0381166175265760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610ade565b600080546040516001600160a01b03808516936201000090930416917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b6001546000906001600160a01b031633146175a957600080fd5b3360009081526002602052604090205460ff166175d85760405162461bcd60e51b8152600401610ade90618ebf565b600b5484106175f95760405162461bcd60e51b8152600401610ade90619077565b6000600b858154811061760e5761760e618f5d565b600091825260209091206003600c90920201908101549091506001600160a01b0385811691161461768f5760405162461bcd60e51b815260206004820152602560248201527f45746e795374616b696e673a2072657761726420616464726573732070726f76604482015264696465642160d81b6064820152608401610ade565b60030180546001600160a01b0384166001600160a01b03199091161790555060019392505050565b6001546000906001600160a01b031633146176d157600080fd5b60006176dc33618270565b336000908152601460205260409020549091506176f9908261944c565b91505090565b6001546000906001600160a01b0316331461771957600080fd5b6000600985015460ff16600481111561773457617734618888565b148061775857506001600985015460ff16600481111561775657617756618888565b145b6177db5760405162461bcd60e51b815260206004820152604860248201527f45746e795374616b696e673a204f6e6c792070656e64696e67206f722061707060448201527f726f766564207374616b696e6720636f6e7472616374732063616e2062652063606482015267616e63656c65642160c01b608482015260a401610ade565b83546001600160a01b03163314806177ff575060028401546001600160a01b031633145b8061781e57503360009081526002602052604090205460ff1615156001145b6178b65760405162461bcd60e51b815260206004820152605760248201527f45746e795374616b696e673a204f6e6c79207374616b65686f6c6465722c206e60448201527f6f6465206f70657261746f72206f7220636f6d70616e7961646472657373206360648201527f616e2063616e63656c2074686520636f6e747261637421000000000000000000608482015260a401610ade565b6009840154600190600687019060009060ff1660048111156178da576178da618888565b60048111156178eb576178eb618888565b81526020810191909152604001600090812080549091906179169084906001600160401b03166191ce565b92506101000a8154816001600160401b0302191690836001600160401b031602179055506000600481111561794d5761794d618888565b600985015460ff16600481111561796657617966618888565b03617aa25760098401805460ff1916600417905542600685018190556008850155600a840154604080518581526020810192909252600080516020619774833981519152910160405180910390a160058401546004860180546001600160401b03928316926008916179e1918591600160401b9004166191ce565b82546101009290920a6001600160401b0381810219909316918316021790915560028601546005870154617a2293506001600160a01b039091169116617d94565b83546005850154617a45916001600160a01b0316906001600160401b0316617cb7565b60028501546001600160a01b031615617a9d576004850180546001600160801b0360ff60e81b011916600160ea1b179055600a8401546040519081526000805160206197348339815191529060200160405180910390a15b617c1f565b6001600985015460ff166004811115617abd57617abd618888565b03617c1f573360009081526002602052604090205460ff161515600103617aee57617ae9858585618718565b617bd8565b60098401805460ff191660031790554260068501556005840154600785015460405163d83102cd60e01b815261ffff600160801b90930492909216600483015260248201527342e7bf71a3b0302011dbbb98d65e8a49abdb107b9063d83102cd90604401602060405180830381865af4158015617b6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190617b939190618fc1565b6008850155600a8401546040805185815260208101929092527fb503cf14e3d55841fd2c9a549abd732f6898fde969da012639aa917173e3a006910160405180910390a15b83546001600160a01b0316331480617c0457503360009081526002602052604090205460ff1615156001145b15617c1f57600b8401805461ff001916610100841515021790555b6009840154600190600687019060009060ff166004811115617c4357617c43618888565b6004811115617c5457617c54618888565b8152602081019190915260400160009081208054909190617c7f9084906001600160401b03166191ed565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550617cac85617f87565b506001949350505050565b6001600160a01b0382166000908152601460205260409020546001600160401b0382161115617d5a5760405162461bcd60e51b815260206004820152604360248201527f496e73756666696369656e74207374616b6520686f6c646572206c6f636b656460448201527f20746f6b656e7320696e207374616b696e6720666f722073756274726163746960648201526237b71760e91b608482015260a401610ade565b6001600160a01b038216600090815260146020526040812080546001600160401b0384169290617d8b90849061944c565b90915550505050565b6001600160a01b0382166000908152601260205260409020546001600160401b0382161115617e1e5760405162461bcd60e51b815260206004820152603060248201527f496e73756666696369656e74206e6f6465207374616b656420746f6b656e732060448201526f3337b91039bab13a3930b1ba34b7b71760811b6064820152608401610ade565b6001600160a01b038216600090815260126020526040812080546001600160401b0384169290617d8b90849061944c565b6009830154600190600684019060009060ff166004811115617e7357617e73618888565b6004811115617e8457617e84618888565b8152602081019190915260400160009081208054909190617eaf9084906001600160401b03166191ce565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550808360090160006101000a81548160ff02191690836004811115617ef957617ef9618888565b02179055506009830154600190600684019060009060ff166004811115617f2257617f22618888565b6004811115617f3357617f33618888565b8152602081019190915260400160009081208054909190617f5e9084906001600160401b03166191ed565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550505050565b6001600482810154600160e81b900460ff1690811115617fa957617fa9618888565b148015617fcd57506004810154600160401b81046001600160401b03908116911614155b15617ff0576004810180546000919060ff60e81b1916600160e81b835b02179055505b50565b600b8054600180820183556000928352600c82027f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9810180546001600160a01b039c8d166001600160a01b03199182161782557f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbb830180549c8e169c82169c909c17909b557f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dba820180549a909c16998b1699909917909a557f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbc8a018054909916909855427f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbd8a01557f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbe890180547f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbf8b018490557f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dc18b018490557f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dc08b01939093557f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dc38a01949094557f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dc28901805460ff199081169091557f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dc49099018054909916909717909755600160401b60ff9091160261ffff93909316600160801b0271ffff0000000000000000ffffffffffffffff199096166001600160401b0392909216919091179490941767ffffffffffffffff60401b1916179092559091565b600060128161828082600a619379565b6007546040516370a0823160e01b81526001600160a01b0387811660048301529293508392909116906370a0823190602401602060405180830381865afa1580156182cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906182f39190618fc1565b6123619190619711565b6004810180546003919060ff60501b1916600160501b83617fea565b60005b60028201546001600160a01b031660009081526011602052604090205481101561846a5760028201546001600160a01b0316600090815260116020526040812080548390811061836e5761836e618f5d565b906000526020600020015490506000600b828154811061839057618390618f5d565b90600052602060002090600c020190506000600a82600a0154815481106183b9576183b9618f5d565b6000918252602090912060079091020190506003600983015460ff1660048111156183e6576183e6618888565b0361840c576183f6818385618718565b600b8201805461ff00191661010017905561845f565b6000600983015460ff16600481111561842757618427618888565b148061844b57506001600983015460ff16600481111561844957618449618888565b145b1561845f5761845d81838560016176ff565b505b50505060010161831c565b5050565b60005b60028201546001600160a01b031660009081526011602052604090205481101561846a5760028201546001600160a01b031660009081526011602052604081208054839081106184c3576184c3618f5d565b906000526020600020015490506000600b82815481106184e5576184e5618f5d565b90600052602060002090600c0201600801549050808460080154101561850d57600884018190555b5050600101618471565b60005b60028201546001600160a01b031660009081526011602052604090205481101561846a5760028201546001600160a01b0316600090815260116020526040812080548390811061856c5761856c618f5d565b906000526020600020015490506000600b828154811061858e5761858e618f5d565b90600052602060002090600c020190506000600a82600a0154815481106185b7576185b7618f5d565b6000918252602090912060079091020190506003600983015460ff1660048111156185e4576185e4618888565b1480156185f45750428260080154105b156186eb576186038282618852565b81546005830154618626916001600160a01b0316906001600160401b0316617cb7565b6002820154600583015461864c916001600160a01b0316906001600160401b0316617d94565b60058201546004820180546001600160401b0392831692600891618679918591600160401b9004166191ce565b82546001600160401b039182166101009390930a92830291909202199091161790555060028101546001600160a01b0316156186eb5760048101805460ff60e81b1916600160ea1b179055600a8201546040519081526000805160206197348339815191529060200160405180910390a15b6186f481617f87565b50505060010161851a565b6004818101805460ff60501b1916600160501b83617fea565b60098201805460ff191660049081179091554260068401819055600880850191909155600584015491850180546001600160401b0393841693919291618768918591600160401b909104166191ce565b82546101009290920a6001600160401b03818102199093169183160217909155600284015460058501546187a993506001600160a01b039091169116617d94565b815460058301546187cc916001600160a01b0316906001600160401b0316617cb7565b600a820154604080518381526020810192909252600080516020619774833981519152910160405180910390a160028301546001600160a01b03161561884d576004830180546001600160801b0360ff60e81b011916600160ea1b179055600a82015460405190815260008051602061973483398151915290602001612c83565b505050565b61885e82826004617e4f565b504260068201819055600890910155565b60006020828403121561888157600080fd5b5035919050565b634e487b7160e01b600052602160045260246000fd5b60058110617ff057617ff0618888565b6188b78161889e565b9052565b600281106188b7576188b7618888565b8b81526001600160a01b038b811660208301528a8116604083015289811660608301528816608082015260a081018790526001600160401b0386811660c083015285811660e08301528416610100820152610160810161892f6101208301856188ae565b61893d6101408301846188bb565b9c9b505050505050505050505050565b80356001600160401b0381168114610bd757600080fd5b80358015158114610bd757600080fd5b60008060006060848603121561898957600080fd5b833592506189996020850161894d565b91506189a760408501618964565b90509250925092565b600080600080608085870312156189c657600080fd5b5050823594602084013594506040840135936060013592509050565b80356001600160a01b0381168114610bd757600080fd5b60008060408385031215618a0c57600080fd5b618a15836189e2565b9150618a236020840161894d565b90509250929050565b600080600060608486031215618a4157600080fd5b83359250618a516020850161894d565b91506189a7604085016189e2565b600060208284031215618a7157600080fd5b610f5f826189e2565b600060208284031215618a8c57600080fd5b610f5f8261894d565b803560ff81168114610bd757600080fd5b600060208284031215618ab857600080fd5b610f5f82618a95565b600081518084526020840193506020830160005b82811015618af3578151865260209586019590910190600101618ad5565b5093949350505050565b602081526000610f5f6020830184618ac1565b8981526001600160a01b038981166020830152888116604083015287166060820152608081018690526001600160401b0385811660a0830152841660c08201526101208101618b5e8461889e565b8360e0830152618b726101008301846188bb565b9a9950505050505050505050565b60008060408385031215618b9357600080fd5b82359150618a236020840161894d565b8b81526001600160401b038b81166020830152604082018b90526001600160a01b038a811660608401528981166080840152881660a083015260c0820187905285811660e083015284166101008201526101608101618c066101208301856188ae565b826101408301529c9b505050505050505050505050565b8a81526001600160401b038a81166020830152604082018a90526001600160a01b0389811660608401528816608083015260a0820187905285811660c0830152841660e08201526101408101618c728461889e565b610100820193909352610120015298975050505050505050565b60008060408385031215618c9f57600080fd5b82359150618a2360208401618964565b803561ffff81168114610bd757600080fd5b600080600060608486031215618cd657600080fd5b618cdf846189e2565b9250618ced6020850161894d565b91506189a760408501618caf565b600080600080600080600060e0888a031215618d1657600080fd5b618d1f886189e2565b9650618d2d6020890161894d565b9550618d3b604089016189e2565b9450618d4960608901618caf565b9350618d5760808901618a95565b9250618d6560a08901618964565b9150618d7360c08901618964565b905092959891949750929550565b608081526000618d946080830187618ac1565b94151560208301525060408101929092521515606090910152919050565b600080600060608486031215618dc757600080fd5b8335925061899960208501618964565b60008060408385031215618dea57600080fd5b82359150618a23602084016189e2565b8d81526001600160a01b038d811660208301528c811660408301528b166060820152608081018a90526001600160401b0389811660a0830152881660c08201526101a081016001600160401b03881660e083015260ff8716610100830152851515610120830152841515610140830152618e786101608301856188ae565b6001600160401b0383166101808301529e9d5050505050505050505050505050565b600080600060608486031215618eaf57600080fd5b83359250618a51602085016189e2565b60208082526032908201527f436f6d70616e7957616c6c65743a2063616c6c6572206973206e6f7420612077604082015271616c6c65742066726f6d20636f6d70616e7960701b606082015260800190565b6020808252602c908201527f45746e795374616b696e673a20496e76616c69642042617365205374616b652060408201526b49442070726f76696465642160a01b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b6020808252602e908201527f45746e795374616b696e673a205374616b6520697320686176696e672064696660408201526d666572656e74207374617475732160901b606082015260800190565b600060208284031215618fd357600080fd5b5051919050565b60208082526030908201527f45746e795374616b696e673a20496e76616c696420457874656e64656420537460408201526f616b652049442070726f76696465642160801b606082015260800190565b6020808252602d908201527f45746e795374616b696e673a20496e76616c6964205374616b6520436f6e747260408201526c6163742070726f76696465642160981b606082015260800190565b60208082526024908201527f45746e795374616b696e673a20496e76616c696420496e6465782070726f76696040820152636465642160e01b606082015260800190565b6020808252603c9082015260008051602061975483398151915260408201527f6573732063616e20706572666f726d207468697320616374696f6e2100000000606082015260800190565b60208082526035908201527f45746e795374616b696e673a20496e76616c69642042617365205374616b6520604082015274436f6e74726163742049442070726f76696465642160581b606082015260800190565b6020808252603f908201527f45746e795374616b696e673a205468652062617365207374616b6520636f6e7460408201527f72616374206f6e2074686973206e6f6465207761732063616e63656c65642100606082015260800190565b634e487b7160e01b600052601160045260246000fd5b6001600160401b03828116828216039081111561128a5761128a6191b8565b6001600160401b03818116838216019081111561128a5761128a6191b8565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526031908201527f45746e795374616b696e673a204f6e6c79207374616b65722063616e2063616e60408201527063656c207468697320726571756573742160781b606082015260800190565b6001815b60018411156192cd578085048111156192b1576192b16191b8565b60018416156192bf57908102905b60019390931c928002619296565b935093915050565b6000826192e45750600161128a565b816192f15750600061128a565b816001811461930757600281146193115761932d565b600191505061128a565b60ff841115619322576193226191b8565b50506001821b61128a565b5060208310610133831016604e8410600b8410161715619350575081810a61128a565b61935d6000198484619292565b8060001904821115619371576193716191b8565b029392505050565b6000610f5f83836192d5565b808202811582820484141761128a5761128a6191b8565b60208082526033908201527f45746e795374616b696e673a204f6e6c7920612063616e63656c656420636f6e60408201527274726163742063616e20626520656e6465642160681b606082015260800190565b6020808252603d908201527f45746e795374616b696e673a2054686520636f6e74726163742063616e20626560408201527f207465726d696e6174656420616674657220697420657870697265732e000000606082015260800190565b8181038181111561128a5761128a6191b8565b60208082526030908201527f45746e795374616b696e673a205265776172642061646472657373206973207460408201526f6865207a65726f20616464726573732160801b606082015260800190565b8082018082111561128a5761128a6191b8565b6020808252605c9082015260008051602061975483398151915260408201527f6573732063616e207465726d696e61746520612042617365205374616b65204360608201527f6f6e747261637420616e64206170706c792070656e616c746965732100000000608082015260a00190565b60208082526064908201527f45746e795374616b696e673a20536f6d657468696e672077656e742077726f6e60408201527f672e205468652045746865726e69747920436c6f756420536d617274436f6e7460608201527f726163742061646472657373206973206e6f7420636f72726563746c792073656080820152637475702160e01b60a082015260c00190565b60208082526035908201527f45746e795374616b696e673a204e6f646520616c72656164792068617320616e604082015274206578697374696e672062617365207374616b652160581b606082015260800190565b60208082526022908201527f45746e795374616b696e673a204e6f6465206861732045544e5920746f6b656e604082015261732160f01b606082015260800190565b6020808252603e9082015260008051602061979483398151915260408201527f62616c616e636520617661696c61626c6520666f72207374616b696e67210000606082015260800190565b60208082526046908201527f45746e795374616b696e673a20546865206e6f6465206164647265737320736860408201527f6f756c6420626520646966666572656e74207468616e2072657761726420616460608201526564726573732160d01b608082015260a00190565b60008261972e57634e487b7160e01b600052601260045260246000fd5b50049056fea002debc9839c20f8a9424b3c4bad3295abbb3676c3acf6ea94d869f6b4f54c045746e795374616b696e673a204f6e6c79206120636f6d70616e792061646472ee821fc4af1ea42a6c6174adb5fd292ad9e326c120629b92006d036545c3c66b45746e795374616b696e673a2054686520616d6f756e74206578636565647320a2646970667358221220acda4732641c120a3e505fd1d2c0bbbbf3f695e4bf306cf60bf1233221b0c80064736f6c634300081e0033
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106104695760003560e01c80638caafbff1161024c578063c6aa90ef11610146578063de7c8830116100c3578063eb050c0911610087578063eb050c0914610a5b578063f2fde38b14610a6e578063f3b5397414610a81578063f8a25c5614610a94578063faa8aab114610a9c57600080fd5b8063de7c8830146109ee578063e0768b1814610a01578063e8454f0714610a14578063e99edf4114610a27578063ea55e31914610a2f57600080fd5b8063cf3c32871161010a578063cf3c3287146109a3578063d53ce9a9146109ab578063d598ed98146109be578063da67129a146109c6578063db797e81146109d957600080fd5b8063c6aa90ef14610932578063c75602391461096d578063c8f00e7514610980578063c91951c714610993578063cd7f0bcc1461099b57600080fd5b8063ac870fe8116101d4578063b6b7b3cf11610198578063b6b7b3cf146108d2578063b6c4ab71146108da578063b6ecc1cc146108f4578063bafb358114610907578063c573a9b61461092a57600080fd5b8063ac870fe81461087e578063af68faae14610891578063b06ba626146108a4578063b2bdfa7b146108b7578063b3036c64146108ca57600080fd5b806390cadc5a1161021b57806390cadc5a1461081457806391a8c1c514610827578063946e203f14610850578063a4f8277314610863578063a6f958c81461086b57600080fd5b80638caafbff146107cf5780638cd03f77146107d75780638d2adf32146107ea5780638da5cb5b146107fd57600080fd5b8063458dcf6a1161036857806367e40097116102e55780638014522d116102a95780638014522d1461076457806380605c931461077757806383082bb21461078a57806383c8eed91461079d57806388b4ec28146107c757600080fd5b806367e400971461071b5780636b2963551461072e578063715018a614610741578063749490b8146107495780637c5045e81461075c57600080fd5b80635d0d71661161032c5780635d0d7166146106bd5780635eba1aa3146106e557806362647959146106f8578063676465401461070057806367a53be31461071357600080fd5b8063458dcf6a14610644578063488b8e8b146106575780634d263b611461066a578063512532891461067f5780635c60da1b1461069257600080fd5b806328d9228c116103f657806337daa815116103ba57806337daa815146105ab578063380ae6be146106035780633b7973ed146106165780633e1e32871461061e578063438787d01461063157600080fd5b806328d9228c1461054c57806329e0a52b1461055f57806329e7d373146105725780632e14edaa146105855780633348dccd1461059857600080fd5b806311e776fe1161043d57806311e776fe146104db5780631492794d146104f0578063194dc6c8146105115780631c4bc72914610519578063275fdda51461053957600080fd5b8062226faa1461046e578063033751a2146104965780630b0e33d0146104c05780630ef7ef77146104c8575b600080fd5b61048161047c36600461886f565b610aaf565b60405190151581526020015b60405180910390f35b6104a96104a436600461886f565b610bdc565b60405161048d9b9a999897969594939291906188cb565b610481610e37565b6104816104d6366004618974565b610e63565b6104ee6104e936600461886f565b610f66565b005b6105036104fe36600461886f565b610fb1565b60405190815260200161048d565b61050361102c565b61052161104d565b6040516001600160401b03909116815260200161048d565b6104816105473660046189b0565b61107d565b61048161055a3660046189f9565b611214565b61048161056d366004618a2c565b611290565b61048161058036600461886f565b6117c4565b6104ee610593366004618a5f565b611a99565b6104ee6105a6366004618a7a565b611aed565b6105be6105b936600461886f565b611b56565b604080519788526001600160401b03968716602089015294861694870194909452918416606086015283166080850152821660a08401521660c082015260e00161048d565b61048161061136600461886f565b611c2f565b610503612248565b6104ee61062c366004618aa6565b612276565b6104ee61063f366004618a5f565b6122d8565b610503610652366004618a5f565b61232a565b6104ee610665366004618a7a565b612369565b6106726123dc565b60405161048d9190618afd565b61050361068d36600461886f565b612455565b6003546106a5906001600160a01b031681565b6040516001600160a01b03909116815260200161048d565b6106d06106cb36600461886f565b6125f3565b60405161048d99989796959493929190618b10565b6104816106f336600461886f565b612772565b610503612957565b6104ee61070e36600461886f565b612985565b610481612c90565b61050361072936600461886f565b612cc0565b61048161073c366004618a5f565b612d29565b6104ee612fa5565b610481610757366004618a2c565b613026565b61050361384a565b61048161077236600461886f565b613878565b6104ee610785366004618aa6565b613bc0565b61048161079836600461886f565b613c1c565b6107b06107ab366004618b80565b614548565b60405161048d9b9a99989796959493929190618ba3565b6105036146bb565b6105216146e9565b6104816107e536600461886f565b614713565b6104ee6107f8366004618a7a565b6148dd565b6000546201000090046001600160a01b03166106a5565b6104ee610822366004618a5f565b614950565b61083a610835366004618b80565b6149a1565b60405161048d9a99989796959493929190618c1d565b61048161085e366004618b80565b614be4565b610503614f29565b610481610879366004618c8c565b614f4a565b6104ee61088c366004618a5f565b615080565b61050361089f366004618cc1565b6150e8565b6105036108b2366004618cfb565b615671565b6005546106a5906001600160a01b031681565b610672615ffa565b610521616071565b6108e26160a2565b60405160ff909116815260200161048d565b6104ee610902366004618a7a565b6160c6565b61091a610915366004618a5f565b616139565b60405161048d9493929190618d81565b6105036161d9565b61094561094036600461886f565b6161fa565b604080519586526020860194909452928401919091526060830152608082015260a00161048d565b61050361097b36600461886f565b616346565b61048161098e36600461886f565b6163af565b61050361661c565b6106a561663d565b6108e2616667565b6104816109b9366004618db2565b616690565b610503616a64565b6104816109d4366004618dd7565b616a92565b33600090815260146020526040902054610503565b6106726109fc366004618a5f565b616d65565b6104ee610a0f36600461886f565b616dd1565b610503610a2236600461886f565b616e1c565b610521616e85565b610a42610a3d36600461886f565b616eb6565b60405161048d9d9c9b9a99989796959493929190618dfa565b610481610a69366004618b80565b617012565b6104ee610a7c366004618a5f565b617491565b610481610a8f366004618e9a565b61758f565b6105036176b7565b6001546106a5906001600160a01b031681565b3360009081526002602052604081205460ff16610ae75760405162461bcd60e51b8152600401610ade90618ebf565b60405180910390fd5b6009548210610b085760405162461bcd60e51b8152600401610ade90618f11565b600060098381548110610b1d57610b1d618f5d565b6000918252602090912060069091020190506001600482810154600160501b900460ff1690811115610b5157610b51618888565b14610b6e5760405162461bcd60e51b8152600401610ade90618f73565b60048101805460ff60501b1916600360501b1790556005810154600b8054600092908110610b9e57610b9e618f5d565b600091825260209091206009600c90920201908101805460ff1916600317905542600682015564012117d1576008909101555060019150505b919050565b6000806000806000806000806000806000600b805490508c10610c5a5760405162461bcd60e51b815260206004820152603060248201527f45746e795374616b696e673a20496e76616c6964205374616b6520636f6e747260448201526f6163742049442070726f76696465642160801b6064820152608401610ade565b6000600b8d81548110610c6f57610c6f618f5d565b600091825260208220919d50600c020190506001600982015460ff166004811115610c9c57610c9c618888565b03610d35576005810154600782015460405163d83102cd60e01b8152600160801b90920461ffff16600483015260248201527342e7bf71a3b0302011dbbb98d65e8a49abdb107b9063d83102cd90604401602060405180830381865af4158015610d0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2e9190618fc1565b9b50610d3d565b80600801549b505b8b8160000160009054906101000a90046001600160a01b03168260020160009054906101000a90046001600160a01b03168360030160009054906101000a90046001600160a01b03168460010160009054906101000a90046001600160a01b031685600401548660050160009054906101000a90046001600160401b03168760050160089054906101000a90046001600160401b03168860050160109054906101000a900461ffff168960090160009054906101000a900460ff168a600b0160009054906101000a900460ff168261ffff1692509b509b509b509b509b509b509b509b509b509b509b505091939597999b90929496989a50565b6001546000906001600160a01b03163314610e5157600080fd5b506007546001600160a01b0316151590565b6001546000906001600160a01b03163314610e7d57600080fd5b600a548410610e9e5760405162461bcd60e51b8152600401610ade90618fda565b6000600a8581548110610eb357610eb3618f5d565b906000526020600020906007020190508060040160109054906101000a90046001600160401b03166001600160401b0316846001600160401b031610610f0b5760405162461bcd60e51b8152600401610ade9061902a565b6001600160401b0384166000908152600582016020526040812054600b805491929183908110610f3d57610f3d618f5d565b90600052602060002090600c02019050610f59838284886176ff565b93505050505b9392505050565b6001546001600160a01b03163314610f7d57600080fd5b3360009081526002602052604090205460ff16610fac5760405162461bcd60e51b8152600401610ade90618ebf565b601655565b6001546000906001600160a01b03163314610fcb57600080fd5b336000908152600c60205260409020548210610ff95760405162461bcd60e51b8152600401610ade90619077565b336000908152600c6020526040902080548390811061101a5761101a618f5d565b90600052602060002001549050919050565b6001546000906001600160a01b0316331461104657600080fd5b5060095490565b6001546000906001600160a01b0316331461106757600080fd5b506018546201000090046001600160401b031690565b6001546000906001600160a01b0316331461109757600080fd5b3360009081526002602052604090205460ff1615156001146110cb5760405162461bcd60e51b8152600401610ade906190bb565b600b5485106110ec5760405162461bcd60e51b8152600401610ade90619106565b6000600b868154811061110157611101618f5d565b90600052602060002090600c0201905082600481111561112357611123618888565b60098201805460ff1916600183600481111561114157611141618888565b02179055506008810185905560068101849055600a8101546009805460009290811061116f5761116f618f5d565b9060005260206000209060060201905083600481111561119157611191618888565b81600401600a6101000a81548160ff021916908360048111156111b6576111b6618888565b02179055506003600482810154600160501b900460ff16908111156111dd576111dd618888565b6002909201546001600160a01b03166000908152601560205260409020805460ff1916919092141790555060019050949350505050565b6001546000906001600160a01b0316331461122e57600080fd5b3360009081526002602052604090205460ff1615156001146112625760405162461bcd60e51b8152600401610ade906190bb565b506001600160a01b03821660009081526014602052604090206001600160401b038216905560015b92915050565b6001546000906001600160a01b031633146112aa57600080fd5b600a5484106112cb5760405162461bcd60e51b8152600401610ade90618fda565b6000600a85815481106112e0576112e0618f5d565b906000526020600020906007020190508060040160109054906101000a90046001600160401b03166001600160401b0316846001600160401b0316106113385760405162461bcd60e51b8152600401610ade9061902a565b60028101546001600160a01b0316156114fd5760028101546001600160a01b031633146113c45760405162461bcd60e51b815260206004820152603460248201527f45746e795374616b696e673a204f6e6c79206f70657261746f722063616e20616044820152737070726f76652074686520636f6e74726163742160601b6064820152608401610ade565b6001600160a01b0383166114405760405162461bcd60e51b815260206004820152603a60248201527f45746e795374616b696e673a20526577617264206164647265737320666f722060448201527f6f70657261746f7220776173206e6f742070726f7669646564210000000000006064820152608401610ade565b336001600160a01b038416036114cd5760405162461bcd60e51b815260206004820152604660248201527f45746e795374616b696e673a2052657761726420616464726573732073686f7560448201527f6c6420626520646966666572656e74207468616e20746865206e6f646520616460648201526564726573732160d01b608482015260a401610ade565b3360009081526015602052604090205460ff16156114fd5760405162461bcd60e51b8152600401610ade9061915b565b6001600160401b0384166000908152600582016020526040812054600b80549192918390811061152f5761152f618f5d565b600091825260208220600c909102019150600982015460ff16600481111561155957611559618888565b146115cc5760405162461bcd60e51b815260206004820152603c60248201527f45746e795374616b696e673a204f6e6c792070656e64696e67207374616b696e60448201527f6720636f6e7472616374732063616e20626520617070726f76656421000000006064820152608401610ade565b6009810154600190600685019060009060ff1660048111156115f0576115f0618888565b600481111561160157611601618888565b815260208101919091526040016000908120805490919061162c9084906001600160401b03166191ce565b82546101009290920a6001600160401b0381810219909316918316021790915560098301805460ff19166001908117909155426007850155600081815260068701602052604081208054929450929091611688918591166191ed565b82546001600160401b039182166101009390930a92830291909202199091161790555060028301546001600160a01b031615611726576003810180546001600160a01b0319166001600160a01b0387161790556004830180547fffff00ffffffffffffffffffffffffff0000000000000000ffffffffffffffff81166001600160401b03909116600160401b0260ff60e81b191617600160e81b1790555b6004830154600160401b81046001600160401b039081169116148015611763575060008080526006840160205260409020546001600160401b0316155b1561177e5760048301805460ff60e81b1916600160e81b1790555b60408051838152602081018990527f492b38fe904dd9e188eb84bf5c076c5ba8391de320e4cda50c11fbc4faa5107f910160405180910390a15060019695505050505050565b6001546000906001600160a01b031633146117de57600080fd5b600a5482106117ff5760405162461bcd60e51b8152600401610ade90619077565b6000600a838154811061181457611814618f5d565b9060005260206000209060070201905060005b60048201546001600160401b03600160801b909104811690821610156119dc576001600160401b0381166000908152600583016020526040812054600b8054909190811061187757611877618f5d565b60009182526020909120600c9091020190506003600982015460ff1660048111156118a4576118a4618888565b1480156118b45750428160080154105b156119d3576009810154600190600685019060009060ff1660048111156118dd576118dd618888565b60048111156118ee576118ee618888565b81526020810191909152604001600090812080549091906119199084906001600160401b03166191ce565b82546101009290920a6001600160401b0381810219909316918316021790915560098301805460ff1916600490811790915560009081526006860160205260408120805460019450909261196f918591166191ed565b82546101009290920a6001600160401b03818102199093169183160217909155825460058401546119ad93506001600160a01b039091169116617cb7565b600281015460058201546119d3916001600160a01b0316906001600160401b0316617d94565b50600101611827565b50600360009081526006820160205260409020546001600160401b0316158015611a1f5750600160009081526006820160205260409020546001600160401b0316155b8015611a42575060008080526006820160205260409020546001600160401b0316155b8015611a7557506004810154611a6a906001600160401b03600160401b8204811691166191ce565b6001600160401b0316155b15611a905760048101805460ff60e81b1916600160ea1b1790555b50600192915050565b6000546201000090046001600160a01b03163314611ac95760405162461bcd60e51b8152600401610ade9061920c565b6001600160a01b03166000908152600260205260409020805460ff19166001179055565b6001546001600160a01b03163314611b0457600080fd5b3360009081526002602052604090205460ff16611b335760405162461bcd60e51b8152600401610ade90618ebf565b6019805467ffffffffffffffff19166001600160401b0392909216919091179055565b600080600080600080600080600a8981548110611b7557611b75618f5d565b90600052602060002090600702019050888160040160109054906101000a90046001600160401b0316826006016000806004811115611bb657611bb6618888565b6004811115611bc757611bc7618888565b81526020808201929092526040908101600090812054600182526006969096019092528082205460028352818320546003845282842054600485529290932054949e939d506001600160401b039586169c5085169a5090841698508316965091169350915050565b6001546000906001600160a01b03163314611c4957600080fd5b600a548210611c6a5760405162461bcd60e51b8152600401610ade90618fda565b6000600a8381548110611c7f57611c7f618f5d565b6000918252602090912060079091020180549091506001600160a01b03163314611cbb5760405162461bcd60e51b8152600401610ade90619241565b6000600482810154600160e81b900460ff1690811115611cdd57611cdd618888565b1480611d0857506001600482810154600160e81b900460ff1690811115611d0657611d06618888565b145b611d905760405162461bcd60e51b815260206004820152604d60248201527f45746e795374616b696e673a20457874656e646564207374616b6520706f6f6c60448201527f2063616e6e6f742062652063616e63656c65642e20497420686173206469666660648201526c6572656e74207374617475732160981b608482015260a401610ade565b60048101805460ff60e81b1916600360e81b1790556040805184815290517fed2eddad45e3518d4213edaae6c788ba893dc504b673a7f55821b62adb85b4349181900360200190a160005b60048201546001600160401b03600160801b909104811690821610156121bb576001600160401b0381166000908152600583016020526040812054600b805491929183908110611e2d57611e2d618f5d565b6000918252602082206009600c9092020190810154909250600191600687019160ff166004811115611e6157611e61618888565b6004811115611e7257611e72618888565b8152602081019190915260400160009081208054909190611e9d9084906001600160401b03166191ce565b92506101000a8154816001600160401b0302191690836001600160401b0316021790555060006004811115611ed457611ed4618888565b600982015460ff166004811115611eed57611eed618888565b0361201e5760098101805460ff1916600417905542600682018190556008820155600a810154604080518481526020810192909252600080516020619774833981519152910160405180910390a160058101546004850180546001600160401b0392831692600891611f68918591600160401b9004166191ce565b82546101009290920a6001600160401b0381810219909316918316021790915560028301546005840154611fa993506001600160a01b039091169116617d94565b80546005820154611fcc916001600160a01b0316906001600160401b0316617cb7565b60028401546001600160a01b0316156120195760048401805467ffffffffffffffff19169055600a8101546040519081526000805160206197348339815191529060200160405180910390a15b612128565b6001600982015460ff16600481111561203957612039618888565b036121285760098101805460ff191660031790554260068201556005810154600782015460405163d83102cd60e01b815261ffff600160801b90930492909216600483015260248201527342e7bf71a3b0302011dbbb98d65e8a49abdb107b9063d83102cd90604401602060405180830381865af41580156120bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e39190618fc1565b6008820155600a8101546040805184815260208101929092527fb503cf14e3d55841fd2c9a549abd732f6898fde969da012639aa917173e3a006910160405180910390a15b6009810154600190600686019060009060ff16600481111561214c5761214c618888565b600481111561215d5761215d618888565b81526020810191909152604001600090812080549091906121889084906001600160401b03166191ed565b92506101000a8154816001600160401b0302191690836001600160401b0316021790555050508080600101915050611ddb565b5060048101546000906121e0906001600160401b03600160401b8204811691166191ce565b6001600160401b03161115611a9057600481015461221b903390612216906001600160401b03600160401b8204811691166191ce565b617cb7565b6004018054600160401b81046001600160401b031667ffffffffffffffff19909116179055506001919050565b6001546000906001600160a01b0316331461226257600080fd5b50336000908152600d602052604090205490565b6001546001600160a01b0316331461228d57600080fd5b3360009081526002602052604090205460ff166122bc5760405162461bcd60e51b8152600401610ade90618ebf565b6018805460ff9092166101000261ff0019909216919091179055565b6000546201000090046001600160a01b031633146123085760405162461bcd60e51b8152600401610ade9061920c565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b600060128161233a82600a619379565b6001600160a01b038516600090815260146020526040902054909150612361908290619385565b949350505050565b6001546001600160a01b0316331461238057600080fd5b3360009081526002602052604090205460ff166123af5760405162461bcd60e51b8152600401610ade90618ebf565b601880546001600160401b03909216600160901b0267ffffffffffffffff60901b19909216919091179055565b6001546060906001600160a01b031633146123f657600080fd5b336000908152600e60209081526040918290208054835181840281018401909452808452909183018282801561244b57602002820191906000526020600020905b815481526020019060010190808311612437575b5050505050905090565b6001546000906001600160a01b0316331461246f57600080fd5b600a5482106124905760405162461bcd60e51b8152600401610ade90619077565b6000600a83815481106124a5576124a5618f5d565b906000526020600020906007020190506000805b60048301546001600160401b03600160801b909104811690821610156125eb576001600160401b0381166000908152600584016020526040812054600b8054909190811061250957612509618f5d565b600091825260208220600c9091020191506001600983015460ff16600481111561253557612535618888565b036125ce576005820154600783015460405163d83102cd60e01b8152600160801b90920461ffff16600483015260248201527342e7bf71a3b0302011dbbb98d65e8a49abdb107b9063d83102cd90604401602060405180830381865af41580156125a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c79190618fc1565b90506125d5565b5060088101545b808410156125e1578093505b50506001016124b9565b509392505050565b6000806000806000806000806000600160009054906101000a90046001600160a01b03166001600160a01b0316336001600160a01b03161461263457600080fd5b6009548a106126555760405162461bcd60e51b8152600401610ade90618f11565b600060098b8154811061266a5761266a618f5d565b6000918252602091829020604080516101008101825260069390930290910180546001600160a01b0390811684526001820154811694840194909452600281015490931690820152600382015460608201526004808301546001600160401b0381166080840152600160401b810461ffff1660a084015291929160c0840191600160501b90910460ff169081111561270457612704618888565b600481111561271557612715618888565b815260200160058201548152505090508a816000015182602001518360400151846060015185608001518660a001518760c0015160008261ffff169250995099509950995099509950995099509950509193959799909294969850565b6001546000906001600160a01b0316331461278c57600080fd5b60095482106127ad5760405162461bcd60e51b8152600401610ade90618f11565b6000600983815481106127c2576127c2618f5d565b6000918252602090912060069091020190506003600482810154600160501b900460ff16908111156127f6576127f6618888565b146128135760405162461bcd60e51b8152600401610ade90618f73565b6000600b82600501548154811061282c5761282c618f5d565b90600052602060002090600c020190504281600801541061289e5760405162461bcd60e51b815260206004820152602660248201527f45746e795374616b696e673a205374616b65206973206e6f742065787069726560448201526564207965742160d01b6064820152608401610ade565b6004828101805460ff60501b1916600160521b17905560098201805460ff19169091179055805460058201546128e6916001600160a01b0316906001600160401b0316617cb7565b6002810180546001600160a01b039081166000908152600f60205260409020805460ff191690559054600583015461292b9291909116906001600160401b0316617d94565b600201546001600160a01b03166000908152601560205260409020805460ff1916905550600192915050565b6001546000906001600160a01b0316331461297157600080fd5b503360009081526012602052604090205490565b6001546001600160a01b0316331461299c57600080fd5b3360009081526002602052604090205460ff161515600114612a445760405162461bcd60e51b8152602060048201526061602482015260008051602061975483398151915260448201527f6573732063616e207465726d696e61746520616e20457874656e64656420537460648201527f616b6520436f6e747261637420616e64206170706c792070656e616c746965736084820152602160f81b60a482015260c401610ade565b600b548110612a655760405162461bcd60e51b8152600401610ade90619077565b6000600b8281548110612a7a57612a7a618f5d565b60009182526020909120600c9091020190506001600b82015460ff166001811115612aa757612aa7618888565b14612b1a5760405162461bcd60e51b815260206004820152603760248201527f45746e795374616b696e673a20416e20457874656e646564205374616b65204360448201527f6f6e7472616374206964206973206578706563746564210000000000000000006064820152608401610ade565b6003600982015460ff166004811115612b3557612b35618888565b14612b525760405162461bcd60e51b8152600401610ade9061939c565b42816008015410612b755760405162461bcd60e51b8152600401610ade906193ef565b80546005820154612b98916001600160a01b0316906001600160401b0316617cb7565b60028101546005820154612bbe916001600160a01b0316906001600160401b0316617d94565b6000600a82600a015481548110612bd757612bd7618f5d565b906000526020600020906007020190508160050160009054906101000a90046001600160401b03168160040160088282829054906101000a90046001600160401b0316612c2491906191ce565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550612c5482826004617e4f565b612c5d81617f87565b600a82015460408051858152602081019290925260008051602061977483398151915291015b60405180910390a1505050565b6001546000906001600160a01b03163314612caa57600080fd5b5033600090815260126020526040902054151590565b6001546000906001600160a01b03163314612cda57600080fd5b336000908152600d60205260409020548210612d085760405162461bcd60e51b8152600401610ade90619077565b336000908152600d6020526040902080548390811061101a5761101a618f5d565b6001546000906001600160a01b03163314612d4357600080fd5b6001600160a01b03821660009081526015602052604090205460ff16612db65760405162461bcd60e51b815260206004820152602260248201527f45746e795374616b696e673a204e6f6465206973206e6f742063616e63656c65604482015261642160f01b6064820152608401610ade565b6001600160a01b0382166000908152600e6020526040902054612e415760405162461bcd60e51b815260206004820152603960248201527f45746e795374616b696e673a204e6f6465206973206e6f7420686176696e672060448201527f616e792062617365207374616b657320726571756573747321000000000000006064820152608401610ade565b6001600160a01b0382166000908152600e6020526040812054612e669060019061944c565b6001600160a01b0384166000908152600e602052604081208054929350909183908110612e9557612e95618f5d565b90600052602060002001549050600060098281548110612eb757612eb7618f5d565b6000918252602090912060069091020190506001600482810154600160501b900460ff1690811115612eeb57612eeb618888565b1480612f15575060048082810154600160501b900460ff1690811115612f1357612f13618888565b145b612f7d5760405162461bcd60e51b815260206004820152603360248201527f45746e795374616b696e673a2043616e6e6f74206578656375746520636c65616044820152726e7570206f6e2074686973207374617475732160681b6064820152608401610ade565b505050506001600160a01b03166000908152601560205260409020805460ff19169055600190565b6000546201000090046001600160a01b03163314612fd55760405162461bcd60e51b8152600401610ade9061920c565b60008054604051620100009091046001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a36000805462010000600160b01b0319169055565b6001546000906001600160a01b0316331461304057600080fd5b600a5484106130615760405162461bcd60e51b8152600401610ade90618fda565b6001600160a01b0382166130875760405162461bcd60e51b8152600401610ade9061945f565b336001600160a01b03831603613107576040805162461bcd60e51b81526020600482015260248101919091527f45746e795374616b696e673a205265776172642061646472657373206d75737460448201527f20626520646966666572656e74207468616e206e6f64652061646472657373216064820152608401610ade565b6019546001600160401b03908116908416101561318c5760405162461bcd60e51b815260206004820152603f60248201527f45746e795374616b696e673a2054686520616d6f756e74206973206c6f77657260448201527f207468616e206d696e20657874656e646564207374616b652076616c756521006064820152608401610ade565b3360009081526015602052604090205460ff16156131bc5760405162461bcd60e51b8152600401610ade9061915b565b6000600a85815481106131d1576131d1618f5d565b6000918252602082206007909102019150600482810154600160e81b900460ff169081111561320257613202618888565b1461321f5760405162461bcd60e51b8152600401610ade90618f73565b60028101546001600160a01b031633036132985760405162461bcd60e51b815260206004820152603460248201527f45746e795374616b696e673a20596f752063616e6e6f74206170706c7920746f6044820152732074686973205374616b6520526571756573742160601b6064820152608401610ade565b60048101546001600160401b03808216916132bc91600160401b90910416866191ed565b6001600160401b031611156133365760405162461bcd60e51b8152602060048201526046602482015260008051602061979483398151915260448201527f74686520617661696c61626c6520616d6f756e7420696e2063757272656e74206064820152657374616b652160d01b608482015260a401610ade565b60048101546001600160801b9091046001600160401b03161180159061336857506004810154600160d81b900460ff16155b8061337e57506004810154600160d81b900460ff165b6133e65760405162461bcd60e51b815260206004820152603360248201527f45746e795374616b696e673a2054686973207374616b652063616e20616363656044820152727074206f6e6c79203120636f6e74726163742160681b6064820152608401610ade565b336000908152601260205260409020546134685760405162461bcd60e51b815260206004820152603860248201527f45746e795374616b696e673a204e65656420746f2068617665206174206c656160448201527f7374206f6e652062617365207374616b652073657475702100000000000000006064820152608401610ade565b6016543360009081526012602052604090205461348f906001600160401b038716906194af565b11156134e75760405162461bcd60e51b8152602060048201526033602482015260008051602061979483398151915260448201527274686520746f74616c206f662037353030302160681b6064820152608401610ade565b6004810154600160d81b900460ff1615156000036135765760048101546001600160401b038581169116146135765760405162461bcd60e51b815260206004820152602f60248201527f45746e795374616b696e673a2054686973207374616b696e6720706f6f6c206360448201526e616e6e6f742062652073706c69742160881b6064820152608401610ade565b838160040160088282829054906101000a90046001600160401b031661359c91906191ed565b82546001600160401b039182166101009390930a9283029282021916919091179091556004830154600160401b81048216911614905080156135e957506004810154600160e01b900460ff165b156136045760048101805460ff60e81b1916600160e81b1790555b8054600182015460048301546000928392613648926001600160a01b039283169233921690600160c01b810461ffff16908b908d90600160d01b900460ff16617ff3565b6003820180546001600160a01b0319166001600160a01b03891617905560048501549193509150600160e01b900460ff16156136945760098201805460ff191660011790554260078301555b6009820154600190600685019060009060ff1660048111156136b8576136b8618888565b60048111156136c9576136c9618888565b81526020810191909152604001600090812080549091906136f49084906001600160401b03166191ed565b82546101009290920a6001600160401b03818102199093169183160217909155600485018054600160801b9081900483166000908152600588016020526040902085905581546001945091926010926137519286929104166191ed565b82546101009290920a6001600160401b0381810219909316918316021790915533600081815260116020908152604080832080546001818101835591855283852001889055938352601082528083208054948501815583528183209093018c9055600587015460028801546001600160a01b0316835260129091529181208054929093169350906137e39084906194af565b909155505060028201546001600160a01b03166000818152601260209081526040918290205482518b8152918201527f859208af8cfda136750efa35f96dbecdddfae3cf3fe2242c8722870edee6ddde910160405180910390a25060019695505050505050565b6001546000906001600160a01b0316331461386457600080fd5b50336000908152600e602052604090205490565b6001546000906001600160a01b0316331461389257600080fd5b600a5482106138b35760405162461bcd60e51b8152600401610ade90618fda565b6000600a83815481106138c8576138c8618f5d565b6000918252602090912060079091020180549091506001600160a01b031633146139445760405162461bcd60e51b815260206004820152602760248201527f45746e795374616b696e673a204f6e6c79207374616b65722063616e2063616c6044820152666c20746869732160c81b6064820152608401610ade565b6000600482810154600160e81b900460ff169081111561396657613966618888565b148061399157506003600482810154600160e81b900460ff169081111561398f5761398f618888565b145b6139ad5760405162461bcd60e51b8152600401610ade90618f73565b6003600482810154600160e81b900460ff16908111156139cf576139cf618888565b03613a46576004810154600160801b90046001600160401b0316613a465760405162461bcd60e51b815260206004820152602860248201527f45746e795374616b696e673a205374616b6520686173206e6f20746f6b656e73604482015267206c6f636b65642160c01b6064820152608401610ade565b60048101546001600160401b03600160401b82048116911611613abf5760405162461bcd60e51b815260206004820152602b60248201527f45746e795374616b696e673a20546865726520617265206e6f20746f6b656e7360448201526a20746f20756e6c6f636b2160a81b6064820152608401610ade565b6004810154613ae6903390612216906001600160401b03600160401b8204811691166191ce565b600481018054600160401b81046001600160401b031667ffffffffffffffff199091168117909155158015613b3a57506000600482810154600160e81b900460ff1690811115613b3857613b38618888565b145b15613b595760048101805460ff60e81b1916600360e81b179055613b6f565b60048101805460ff60e81b1916600160e81b1790555b33600090815260146020908152604091829020548251868152918201527f1ecc5ef7074a468a8b94f3c0c74cd118529219ec2801efefe9351818a4a46bb2910160405180910390a150600192915050565b6001546001600160a01b03163314613bd757600080fd5b3360009081526002602052604090205460ff16613c065760405162461bcd60e51b8152600401610ade90618ebf565b6018805460ff191660ff92909216919091179055565b6001546000906001600160a01b03163314613c3657600080fd5b6009548210613c575760405162461bcd60e51b8152600401610ade90618f11565b600060098381548110613c6c57613c6c618f5d565b6000918252602090912060069091020180549091506001600160a01b03163314613ca85760405162461bcd60e51b8152600401610ade90619241565b6000600482810154600160501b900460ff1690811115613cca57613cca618888565b1480613cf557506001600482810154600160501b900460ff1690811115613cf357613cf3618888565b145b613d115760405162461bcd60e51b8152600401610ade90618f73565b60048101805460ff60501b1916600360501b1790556005810154600b8054600092908110613d4157613d41618f5d565b600091825260208220600c909102019150600982015460ff166004811115613d6b57613d6b618888565b03613e125760098101805460ff191660041790554260068201819055600882015580546005820154613daf916001600160a01b0316906001600160401b0316617cb7565b60028101546001600160a01b03166000908152600f6020908152604091829020805460ff19169055600584015491519182527f2b7d80106cf63960f0324ea49c2f7f872886bdfb6cab927918027dd6d0f314f691015b60405180910390a161453e565b60098101805460ff1990811660031790915542600683015560028201546001600160a01b03166000908152601560209081526040918290208054909316600117909255600584015490519081527fff4d02402ef330920f2f7bfb4a8a15a187a10f1d4f607e9f3d55e6611ef4afe3910160405180910390a160005b60028201546001600160a01b03166000908152601160205260409020548110156143a85760028201546001600160a01b03166000908152601160205260408120805483908110613edf57613edf618f5d565b906000526020600020015490506000600b8281548110613f0157613f01618f5d565b90600052602060002090600c020190506000600a82600a015481548110613f2a57613f2a618f5d565b6000918252602082206007909102019150600983015460ff166004811115613f5457613f54618888565b1480613f7857506001600983015460ff166004811115613f7657613f76618888565b145b15614002576009820154600190600683019060009060ff166004811115613fa157613fa1618888565b6004811115613fb257613fb2618888565b8152602081019190915260400160009081208054909190613fdd9084906001600160401b03166191ce565b92506101000a8154816001600160401b0302191690836001600160401b031602179055505b6000600983015460ff16600481111561401d5761401d618888565b036141ed5760098201805460ff1916600417905542600683018190556008830155600a820154604080518581526020810192909252600080516020619774833981519152910160405180910390a160028201546005830154614091916001600160a01b0316906001600160401b0316617d94565b815460058301546140b4916001600160a01b0316906001600160401b0316617cb7565b60058201546004820180546001600160401b03928316926008916140e1918591600160401b9004166191ce565b92506101000a8154816001600160401b0302191690836001600160401b0316021790555060018160060160008460090160009054906101000a900460ff16600481111561413057614130618888565b600481111561414157614141618888565b815260208101919091526040016000908120805490919061416c9084906001600160401b03166191ed565b82546001600160401b039182166101009390930a92830291909202199091161790555060028101546001600160a01b0316156141e85760048101805467ffffffffffffffff60ff60e81b011916600160ea1b179055600a8201546040519081526000805160206197348339815191529060200160405180910390a15b614382565b6001600983015460ff16600481111561420857614208618888565b036143825760098201805460ff191660031790554260068301556005820154600783015460405163d83102cd60e01b815261ffff600160801b90930492909216600483015260248201527342e7bf71a3b0302011dbbb98d65e8a49abdb107b9063d83102cd90604401602060405180830381865af415801561428e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142b29190618fc1565b60088301556009820154600190600683019060009060ff1660048111156142db576142db618888565b60048111156142ec576142ec618888565b81526020810191909152604001600090812080549091906143179084906001600160401b03166191ed565b92506101000a8154816001600160401b0302191690836001600160401b031602179055507fb503cf14e3d55841fd2c9a549abd732f6898fde969da012639aa917173e3a0068383600a0154604051614379929190918252602082015260400190565b60405180910390a15b81600801548560080154101561439d57600880830154908601555b505050600101613e8d565b50806008015460000361453e5760195460058201546001600160401b03600160801b9092048216911610156144ab5760098101805460ff191660041790554260068201819055600882015580546005820154614416916001600160a01b0316906001600160401b0316617cb7565b6002810180546001600160a01b039081166000908152600f60209081526040808320805460ff19908116909155855485168452601590925290912080549091169055905460058301546144769291909116906001600160401b0316617d94565b7f2b7d80106cf63960f0324ea49c2f7f872886bdfb6cab927918027dd6d0f314f68260050154604051613e0591815260200190565b6005810154600782015460405163d83102cd60e01b8152600160801b90920461ffff16600483015260248201527342e7bf71a3b0302011dbbb98d65e8a49abdb107b9063d83102cd90604401602060405180830381865af4158015614514573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145389190618fc1565b60088201555b5060019392505050565b60008060008060008060008060008060006009805490508d1061457d5760405162461bcd60e51b8152600401610ade90618f11565b600060098e8154811061459257614592618f5d565b906000526020600020906006020190508c6001600160401b03166000146145cb5760405162461bcd60e51b8152600401610ade9061902a565b6000816005015490506000600b82815481106145e9576145e9618f5d565b90600052602060002090600c020190508f8f838560000160009054906101000a90046001600160a01b03168460020160009054906101000a90046001600160a01b03168560030160009054906101000a90046001600160a01b031686600401548760050160009054906101000a90046001600160401b03168860050160109054906101000a900461ffff168960090160009054906101000a900460ff168a600801548261ffff1692509d509d509d509d509d509d509d509d509d509d509d505050509295989b509295989b9093969950565b6001546000906001600160a01b031633146146d557600080fd5b503360009081526010602052604090205490565b6001546000906001600160a01b0316331461470357600080fd5b506019546001600160401b031690565b6001546000906001600160a01b0316331461472d57600080fd5b600954821061474e5760405162461bcd60e51b8152600401610ade90618f11565b60006009838154811061476357614763618f5d565b6000918252602090912060069091020160028101549091506001600160a01b031633146147f85760405162461bcd60e51b815260206004820152603960248201527f45746e795374616b696e673a204f6e6c79206e6f6465206f70657261746f722060448201527f63616e206465636c696e652074686973207265717565737421000000000000006064820152608401610ade565b6000600482810154600160501b900460ff169081111561481a5761481a618888565b146148375760405162461bcd60e51b8152600401610ade90618f73565b60048101805460ff60501b1916600160511b1790556005810154600b805460009290811061486757614867618f5d565b600091825260209091206009600c90920201908101805460ff19166002179055805460058201549192506148af916001600160a01b03909116906001600160401b0316617cb7565b5050336000908152601260209081526040808320839055600f9091529020805460ff19169055506001919050565b6001546001600160a01b031633146148f457600080fd5b3360009081526002602052604090205460ff166149235760405162461bcd60e51b8152600401610ade90618ebf565b601880546001600160401b03909216600160501b0267ffffffffffffffff60501b19909216919091179055565b6000546201000090046001600160a01b031633146149805760405162461bcd60e51b8152600401610ade9061920c565b6001600160a01b03166000908152600260205260409020805460ff19169055565b600080600080600080600080600080600a805490508c106149d45760405162461bcd60e51b8152600401610ade90618fda565b6000600a8d815481106149e9576149e9618f5d565b906000526020600020906007020190508060040160109054906101000a90046001600160401b03166001600160401b03168c6001600160401b031610614a415760405162461bcd60e51b8152600401610ade9061902a565b6001600160401b038c166000908152600582016020526040812054600b805491929183908110614a7357614a73618f5d565b600091825260208220919550600c020190506001600982015460ff166004811115614aa057614aa0618888565b03614b39576005810154600782015460405163d83102cd60e01b8152600160801b90920461ffff16600483015260248201527342e7bf71a3b0302011dbbb98d65e8a49abdb107b9063d83102cd90604401602060405180830381865af4158015614b0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b329190618fc1565b9350614b41565b806008015493505b8e8e838560000160009054906101000a90046001600160a01b03168460020160009054906101000a90046001600160a01b031685600401548660050160009054906101000a90046001600160401b03168760050160109054906101000a900461ffff168860090160009054906101000a900460ff168c8261ffff1692509c509c509c509c509c509c509c509c509c509c505050509295989b9194979a5092959850565b6001546000906001600160a01b03163314614bfe57600080fd5b600a548310614c1f5760405162461bcd60e51b8152600401610ade90618fda565b6000600a8481548110614c3457614c34618f5d565b906000526020600020906007020190508060040160109054906101000a90046001600160401b03166001600160401b0316836001600160401b031610614c8c5760405162461bcd60e51b8152600401610ade9061902a565b6001600160401b0383166000908152600582016020526040812054600b805491929183908110614cbe57614cbe618f5d565b600091825260208220600c909102019150600982015460ff166004811115614ce857614ce8618888565b14614d5b5760405162461bcd60e51b815260206004820152603c60248201527f45746e795374616b696e673a204f6e6c792070656e64696e67207374616b696e60448201527f6720636f6e7472616374732063616e206265206465636c696e656421000000006064820152608401610ade565b6009810154600190600685019060009060ff166004811115614d7f57614d7f618888565b6004811115614d9057614d90618888565b8152602081019190915260400160009081208054909190614dbb9084906001600160401b03166191ce565b82546101009290920a6001600160401b0381810219909316918316021790915560098301805460ff19166002908117909155600090815260068601602052604081208054600194509092614e11918591166191ed565b82546101009290920a6001600160401b038181021990931691831602179091556005830154600486018054918316935091600891614e58918591600160401b9004166191ce565b82546101009290920a6001600160401b0381810219909316918316021790915560028301546005840154614e9993506001600160a01b039091169116617d94565b60028301546001600160a01b031615614ee45760048301805460ff60e81b1916600160e91b17905580546005820154614ee4916001600160a01b0316906001600160401b0316617cb7565b60408051838152602081018890527fa6d35207a3d1012ac29345fe2aeabf0b1dc6285e13a1dbca53d5738524323a54910160405180910390a150600195945050505050565b6001546000906001600160a01b03163314614f4357600080fd5b5060165490565b6001546000906001600160a01b03163314614f6457600080fd5b3360009081526002602052604090205460ff161515600114614f985760405162461bcd60e51b8152600401610ade906194c2565b600b548310614fb95760405162461bcd60e51b8152600401610ade90619077565b6000600b8481548110614fce57614fce618f5d565b60009182526020909120600c9091020190506003600982015460ff166004811115614ffb57614ffb618888565b146150185760405162461bcd60e51b8152600401610ade9061939c565b4281600801541061503b5760405162461bcd60e51b8152600401610ade906193ef565b6001600b82015460ff16600181111561505657615056618888565b036150695761506484612985565b61453e565b61507584846001616690565b505060019392505050565b6001546001600160a01b0316331461509757600080fd5b3360009081526002602052604090205460ff166150c65760405162461bcd60e51b8152600401610ade90618ebf565b600780546001600160a01b0319166001600160a01b0392909216919091179055565b6001546000906001600160a01b0316331461510257600080fd5b6007546001600160a01b031661512a5760405162461bcd60e51b8152600401610ade90619533565b6001600160a01b0384166151965760405162461bcd60e51b815260206004820152602d60248201527f45746e795374616b696e673a206e6f646520616464726573732069732074686560448201526c207a65726f206164647265737360981b6064820152608401610ade565b6001600160a01b038416330361521e5760405162461bcd60e51b815260206004820152604160248201527f45746e795374616b696e673a20546865206e6f64652061646472657373206d7560448201527f737420626520646966666572656e74207468616e2063757272656e74206f6e656064820152602160f81b608482015260a401610ade565b601854610100900460ff1661ffff831610156152905760405162461bcd60e51b815260206004820152602b60248201527f45746e795374616b696e673a20546865207374616b696e6720706572696f642060448201526a697320746f6f206c6f772160a81b6064820152608401610ade565b6018546001600160401b03600160501b9091048116908416108015906152cc57506019546001600160401b03600160401b909104811690841611155b61533e5760405162461bcd60e51b815260206004820152603f60248201527f45746e795374616b696e673a20616d6f756e74206d757374206265206265747760448201527f65656e206d696e696d756d20616e64206d6178696d756d2076616c75657321006064820152608401610ade565b6001600160a01b038416600090815260126020526040902054156153745760405162461bcd60e51b8152600401610ade906195c3565b6001600160a01b0384166000908152600f602052604090205460ff16156153ad5760405162461bcd60e51b8152600401610ade906195c3565b60006153b885618270565b905080156153d85760405162461bcd60e51b8152600401610ade90619618565b60006153e333618270565b336000908152601460205260409020549091506001600160401b0386169061540b908361944c565b10156154295760405162461bcd60e51b8152600401610ade9061965a565b336000818152600c60209081526040808320600980548254600180820185559387528587200155546001600160a01b038c168552600e84528285208054928301815585529383902001839055518281529195507fd7490e816438b23e3486aef50b4dfd914be81021d62b1db81226227291f6c85b910160405180910390a26000806154bb33896000898b8a6064617ff3565b600b8201805492945090925060009160ff1916600183021790555060408051610100810182523381526000602082018190526001600160a01b038b16928201929092524260608201526001600160401b038916608082015261ffff881660a082015260099160c082019081526020908101849052825460018082018555600094855293829020835160069092020180546001600160a01b03199081166001600160a01b03938416178255928401519481018054841695831695909517909455604083015160028501805490931691161790556060810151600383015560808101516004808401805460a08501516001600160401b0390941669ffffffffffffffffffff1990911617600160401b61ffff909416939093029290921780835560c0840151939493929160ff60501b1990911690600160501b90849081111561560457615604618888565b021790555060e0919091015160059091015533600090815260146020526040812080546001600160401b038a16929061563e9084906194af565b9091555050506001600160a01b0387166000908152600f60205260409020805460ff191660011790555050509392505050565b6001546000906001600160a01b0316331461568b57600080fd5b6007546001600160a01b03166156b35760405162461bcd60e51b8152600401610ade90619533565b8360ff1660641461572c576001600160a01b03861661572c5760405162461bcd60e51b815260206004820152602f60248201527f45746e795374616b696e673a207265776172642061646472657373206973207460448201526e6865207a65726f206164647265737360881b6064820152608401610ade565b6019546001600160401b0390811690881610156157975760405162461bcd60e51b815260206004820152602360248201527f45746e795374616b696e673a2054686520616d6f756e7420697320746f6f206c6044820152626f772160e81b6064820152608401610ade565b601854610100900460ff1661ffff861610156158015760405162461bcd60e51b815260206004820152602360248201527f45746e795374616b696e673a2054686520706572696f6420697320746f6f206c6044820152626f772160e81b6064820152608401610ade565b60658460ff161061587a5760405162461bcd60e51b815260206004820152603860248201527f45746e795374616b696e673a20546865206f70657261746f722072657761726460448201527f2070657263656e7461676520697320746f6f20686967682100000000000000006064820152608401610ade565b336001600160a01b0387160361590a5760405162461bcd60e51b815260206004820152604960248201527f45746e795374616b696e673a205468652063757272656e74206164647265737360448201527f2073686f756c6420626520646966666572656e74207468616e2072657761726460648201526820616464726573732160b81b608482015260a401610ade565b6001600160a01b03881615615ba4576001600160a01b03881660009081526015602052604090205460ff16156159a85760405162461bcd60e51b815260206004820152603e60248201527f45746e795374616b696e673a205468652062617365207374616b6520636f6e7460448201527f72616374206f6e20746865206e6f6465207761732063616e63656c65642100006064820152608401610ade565b6001600160a01b038816600090815260126020526040902054615a335760405162461bcd60e51b815260206004820152603860248201527f45746e795374616b696e673a20546865206e6f646520646f65736e277420686160448201527f766520616e792062617365207374616b652073657475702100000000000000006064820152608401610ade565b6001600160a01b0388163303615aa45760405162461bcd60e51b815260206004820152603060248201527f45746e795374616b696e673a20546865206e6f64652061646472657373206d7560448201526f737420626520646966666572656e742160801b6064820152608401610ade565b876001600160a01b0316866001600160a01b031603615ad55760405162461bcd60e51b8152600401610ade906196a5565b6016546001600160a01b038916600090815260126020526040902054615b05906001600160401b038a16906194af565b1115615b775760405162461bcd60e51b8152602060048201526047602482015260008051602061979483398151915260448201527f746865206d6178696d756d20616c6c6f77656420746f6b656e73206f6e20746860648201526665206e6f64652160c81b608482015260a401610ade565b6000615b8289618270565b90508015615ba25760405162461bcd60e51b8152600401610ade90619618565b505b6000615baf33618270565b336000908152601460205260409020549091506001600160401b03891690615bd7908361944c565b1015615bf55760405162461bcd60e51b8152600401610ade9061965a565b6000600a6001816001815401808255809150500390600052602060002090600702019050338160000160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550878160010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550898160020160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550428160030181905550888160040160006101000a8154816001600160401b0302191690836001600160401b0316021790555060008160040160086101000a8154816001600160401b0302191690836001600160401b0316021790555060008160040160106101000a8154816001600160401b0302191690836001600160401b03160217905550868160040160186101000a81548161ffff021916908361ffff1602179055508581600401601a6101000a81548160ff021916908360ff1602179055508481600401601b6101000a81548160ff0219169083151502179055508381600401601c6101000a81548160ff021916908315150217905550600081600401601d6101000a81548160ff02191690836004811115615db557615db5618888565b0217905550600a54615dc99060019061944c565b60405181815290935033907ffb7b213a27fb2f9ada24dbc107b98a959d208d5a39fb37f481b80ff7cc4ec4b49060200160405180910390a2336000908152600d60209081526040822080546001810182559083529120018390556001600160a01b038a1615615fc05780546000908190615e51906001600160a01b03168d8c8c8f8a8e617ff3565b60098201549193509150600190600685019060009060ff166004811115615e7a57615e7a618888565b6004811115615e8b57615e8b618888565b8152602081019190915260400160009081208054909190615eb69084906001600160401b03166191ed565b82546101009290920a6001600160401b03818102199093169183160217909155600485018054600160801b908190048316600090815260058801602052604090208590558154600194509192601092615f139286929104166191ed565b82546101009290920a6001600160401b0381810219909316918316021790915560048501805467ffffffffffffffff60401b1916600160401b928f169283021790556001600160a01b038e166000818152601060209081526040808320805460018181018355918552838520018c9055848452601183528184208054918201815584528284200187905592825260129052908120805492935091615fb89084906194af565b909155505050505b33600090815260146020526040812080546001600160401b038c169290615fe89084906194af565b90915550505050979650505050505050565b6001546060906001600160a01b0316331461601457600080fd5b336000908152601060209081526040918290208054835181840281018401909452808452909183018282801561244b5760200282019190600052602060002090815481526020019060010190808311612437575050505050905090565b6001546000906001600160a01b0316331461608b57600080fd5b50601854600160501b90046001600160401b031690565b6001546000906001600160a01b031633146160bc57600080fd5b5060185460ff1690565b6001546001600160a01b031633146160dd57600080fd5b3360009081526002602052604090205460ff1661610c5760405162461bcd60e51b8152600401610ade90618ebf565b601980546001600160401b03909216600160401b0267ffffffffffffffff60401b19909216919091179055565b6001600160a01b0381166000908152600e60209081526040808320600f83528184205460128452828520546015855283862054835485518188028101880190965280865260609796879687969560ff9081169594169290918691908301828280156161c357602002820191906000526020600020905b8154815260200190600101908083116161af575b5050505050935093509350935093509193509193565b6001546000906001600160a01b031633146161f357600080fd5b50600a5490565b60015460009081908190819081906001600160a01b0316331461621c57600080fd5b600b54861061623d5760405162461bcd60e51b8152600401610ade90619077565b6000600b878154811061625257616252618f5d565b600091825260208220919450600c020190506001600982015460ff16600481111561627f5761627f618888565b03616318576005810154600782015460405163d83102cd60e01b8152600160801b90920461ffff16600483015260248201527342e7bf71a3b0302011dbbb98d65e8a49abdb107b9063d83102cd90604401602060405180830381865af41580156162ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906163119190618fc1565b9250616320565b806008015492505b600481015460078201546008830154600690930154919990985091965092945091925050565b6001546000906001600160a01b0316331461636057600080fd5b336000908152600e6020526040902054821061638e5760405162461bcd60e51b8152600401610ade90619077565b336000908152600e6020526040902080548390811061101a5761101a618f5d565b6001546000906001600160a01b031633146163c957600080fd5b3360009081526002602052604090205460ff16151560011461645d5760405162461bcd60e51b8152602060048201526053602482015260008051602061975483398151915260448201527f6573732063616e207465726d696e61746520612042617365205374616b6520616064820152726e64206170706c792070656e616c746965732160681b608482015260a401610ade565b600b54821061647e5760405162461bcd60e51b8152600401610ade90619106565b6000600b838154811061649357616493618f5d565b90600052602060002090600c020190506000600982600a0154815481106164bc576164bc618f5d565b9060005260206000209060060201905064012117d15782600801541061654a5760405162461bcd60e51b815260206004820152603860248201527f45746e795374616b696e673a2054686520636f6e74726163742077617320616c60448201527f72656164792070726f6c6f6e67656420666f72657665722100000000000000006064820152608401610ade565b616553816182fd565b600982018054600360ff199182161790915542600684015564012117d15760088401556002830180546001600160a01b03908116600090815260156020908152604080832080548716600190811790915594549093168252600f90522080549092161790556165c182618319565b60028201546001600160a01b03166000908152601260209081526040918290205491519182527f1fe3c8d9b22341d7ceb24f6a7806432c03c741b526bec20edf6a49bc22b20bc2910160405180910390a15060019392505050565b6001546000906001600160a01b0316331461663657600080fd5b50600b5490565b6001546000906001600160a01b0316331461665757600080fd5b506007546001600160a01b031690565b6001546000906001600160a01b0316331461668157600080fd5b50601854610100900460ff1690565b6001546000906001600160a01b031633146166aa57600080fd5b3360009081526002602052604090205460ff1615156001146166de5760405162461bcd60e51b8152600401610ade906194c2565b600b5484106166ff5760405162461bcd60e51b8152600401610ade90619077565b6000600b858154811061671457616714618f5d565b600091825260208220600c909102019150600b82015460ff16600181111561673e5761673e618888565b146167a65760405162461bcd60e51b815260206004820152603260248201527f45746e795374616b696e673a20412042617365205374616b6520436f6e74726160448201527163742069642069732065787065637465642160701b6064820152608401610ade565b6003600982015460ff1660048111156167c1576167c1618888565b146167de5760405162461bcd60e51b8152600401610ade9061939c565b82156167ed576167ed8161846e565b428160080154106168105760405162461bcd60e51b8152600401610ade906193ef565b6000600982600a01548154811061682957616829618f5d565b9060005260206000209060060201905061684282618517565b84616932576002820154600583015461686d916001600160a01b0316906001600160401b0316617d94565b600982018054600460ff1991821617909155426006840181905560088401556002830180546001600160a01b03908116600090815260156020908152604080832080548716905593549092168152600f9091522080549091169055815460048201546168eb916001600160a01b0316906001600160401b0316617cb7565b6168f4816186ff565b6040518681527f2b7d80106cf63960f0324ea49c2f7f872886bdfb6cab927918027dd6d0f314f69060200160405180910390a1600192505050610f5f565b60006006830181905560028301546001600160a01b03168152601560205260409020805460ff191690556004810180546001919060ff60501b1916600160501b8302179055506009820180546001919060ff1916828002179055504260078301819055600583015460405163d83102cd60e01b8152600160801b90910461ffff16600482015260248101919091527342e7bf71a3b0302011dbbb98d65e8a49abdb107b9063d83102cd90604401602060405180830381865af41580156169fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190616a209190618fc1565b60088301556040518681527f36e5b23050bb3a750f3648961be392c7f7ddad7be9d63439307a6381168b3a049060200160405180910390a150600195945050505050565b6001546000906001600160a01b03163314616a7e57600080fd5b50336000908152600c602052604090205490565b6001546000906001600160a01b03163314616aac57600080fd5b6009548310616acd5760405162461bcd60e51b8152600401610ade90618f11565b6001600160a01b038216616af35760405162461bcd60e51b8152600401610ade9061945f565b336001600160a01b03831603616b1b5760405162461bcd60e51b8152600401610ade906196a5565b600060098481548110616b3057616b30618f5d565b6000918252602090912060069091020160028101549091506001600160a01b03163314616bc55760405162461bcd60e51b815260206004820152603760248201527f45746e795374616b696e673a206f6e6c79206e6f6465206f70657261746f722060448201527f63616e20617070726f76652062617365207374616b65210000000000000000006064820152608401610ade565b6000600482810154600160501b900460ff1690811115616be757616be7618888565b14616c4b5760405162461bcd60e51b815260206004820152602e60248201527f45746e795374616b696e673a207374616b65206d757374206265206e6577207460448201526d6f20626520617070726f7665642160901b6064820152608401610ade565b60048101805460ff60501b1916600160501b1790556001810180546001600160a01b0319166001600160a01b0385161790556005810154600b8054600092908110616c9857616c98618f5d565b600091825260208083206009600c90930201918201805460ff191660011790554260078301556003820180546001600160a01b0389166001600160a01b0319909116179055600582015433845260129091526040832080549294506001600160401b03909116929091616d0c9084906194af565b909155505033600090815260126020908152604091829020548251888152918201527f1dbef83c751dbba35b43f07c7ba982ca00b3627cd0d733b6c55870a6ea4bce5691015b60405180910390a1506001949350505050565b6001600160a01b0381166000908152600e6020908152604091829020805483518184028101840190945280845260609392830182828015616dc557602002820191906000526020600020905b815481526020019060010190808311616db1575b50505050509050919050565b6001546001600160a01b03163314616de857600080fd5b3360009081526002602052604090205460ff16616e175760405162461bcd60e51b8152600401610ade90618ebf565b601755565b6001546000906001600160a01b03163314616e3657600080fd5b336000908152601060205260409020548210616e645760405162461bcd60e51b8152600401610ade90619077565b33600090815260106020526040902080548390811061101a5761101a618f5d565b6001546000906001600160a01b03163314616e9f57600080fd5b50601954600160401b90046001600160401b031690565b600080600080600080600080600080600080600080600a8f81548110616ede57616ede618f5d565b906000526020600020906007020190508e8160000160009054906101000a90046001600160a01b03168260010160009054906101000a90046001600160a01b03168360020160009054906101000a90046001600160a01b031684600301548560040160009054906101000a90046001600160401b03168660040160089054906101000a90046001600160401b03168760040160189054906101000a900461ffff1688600401601a9054906101000a900460ff1689600401601b9054906101000a900460ff168a600401601c9054906101000a900460ff168b600401601d9054906101000a900460ff168c60040160109054906101000a90046001600160401b03168561ffff1695509d509d509d509d509d509d509d509d509d509d509d509d509d505091939597999b9d90929496989a9c50565b6001546000906001600160a01b0316331461702c57600080fd5b600a54831061704d5760405162461bcd60e51b8152600401610ade90618fda565b6019546001600160401b0390811690831610156170c35760405162461bcd60e51b815260206004820152602e60248201527f45746e795374616b696e673a20546865206164646974696f6e616c20616d6f7560448201526d6e7420697320746f6f206c6f772160901b6064820152608401610ade565b6000600a84815481106170d8576170d8618f5d565b6000918252602090912060079091020180549091506001600160a01b031633146171625760405162461bcd60e51b815260206004820152603560248201527f45746e795374616b696e673a204f6e6c79207374616b65722063616e2061646460448201527420746f6b656e7320746f207468697320706f6f6c2160581b6064820152608401610ade565b6001600482810154600160e81b900460ff169081111561718457617184618888565b146171f75760405162461bcd60e51b815260206004820152603a60248201527f45746e795374616b696e673a2043616e206f6e6c792061646420746f2061707060448201527f726f76656420706f6f6c732061667465722066726565696e67210000000000006064820152608401610ade565b60048101546001600160401b03808216600160401b90920416146172835760405162461bcd60e51b815260206004820152603b60248201527f45746e795374616b696e673a204d757374206672656520756e626f6f6b65642060448201527f616d6f756e7473206265666f726520616464696e67206d6f72652100000000006064820152608401610ade565b60028101546001600160a01b0316156173045760405162461bcd60e51b815260206004820152603960248201527f45746e795374616b696e673a2043616e206f6e6c792061646420746f20706f6f60448201527f6c732c206e6f742064656c656761746564207374616b657321000000000000006064820152608401610ade565b600061730f33618270565b336000908152601460205260409020549091506001600160401b03851690617337908361944c565b10156173bd5760405162461bcd60e51b815260206004820152604960248201527f45746e795374616b696e673a20546865206164646974696f6e616c20616d6f7560448201527f6e7420657863656564732062616c616e636520617661696c61626c6520666f72606482015268207374616b696e672160b81b608482015260a401610ade565b6004820180548591906000906173dd9084906001600160401b03166191ed565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550836001600160401b031660146000336001600160a01b03166001600160a01b03168152602001908152602001600020600082825461743f91906194af565b909155505060048201805460ff60e81b19169055604080518681526001600160401b03861660208201527f62cbcd4fa152970bfc481d57c247601b3a7960fa04006e6f1382f42be25b96ca9101616d52565b6000546201000090046001600160a01b031633146174c15760405162461bcd60e51b8152600401610ade9061920c565b6001600160a01b0381166175265760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610ade565b600080546040516001600160a01b03808516936201000090930416917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b6001546000906001600160a01b031633146175a957600080fd5b3360009081526002602052604090205460ff166175d85760405162461bcd60e51b8152600401610ade90618ebf565b600b5484106175f95760405162461bcd60e51b8152600401610ade90619077565b6000600b858154811061760e5761760e618f5d565b600091825260209091206003600c90920201908101549091506001600160a01b0385811691161461768f5760405162461bcd60e51b815260206004820152602560248201527f45746e795374616b696e673a2072657761726420616464726573732070726f76604482015264696465642160d81b6064820152608401610ade565b60030180546001600160a01b0384166001600160a01b03199091161790555060019392505050565b6001546000906001600160a01b031633146176d157600080fd5b60006176dc33618270565b336000908152601460205260409020549091506176f9908261944c565b91505090565b6001546000906001600160a01b0316331461771957600080fd5b6000600985015460ff16600481111561773457617734618888565b148061775857506001600985015460ff16600481111561775657617756618888565b145b6177db5760405162461bcd60e51b815260206004820152604860248201527f45746e795374616b696e673a204f6e6c792070656e64696e67206f722061707060448201527f726f766564207374616b696e6720636f6e7472616374732063616e2062652063606482015267616e63656c65642160c01b608482015260a401610ade565b83546001600160a01b03163314806177ff575060028401546001600160a01b031633145b8061781e57503360009081526002602052604090205460ff1615156001145b6178b65760405162461bcd60e51b815260206004820152605760248201527f45746e795374616b696e673a204f6e6c79207374616b65686f6c6465722c206e60448201527f6f6465206f70657261746f72206f7220636f6d70616e7961646472657373206360648201527f616e2063616e63656c2074686520636f6e747261637421000000000000000000608482015260a401610ade565b6009840154600190600687019060009060ff1660048111156178da576178da618888565b60048111156178eb576178eb618888565b81526020810191909152604001600090812080549091906179169084906001600160401b03166191ce565b92506101000a8154816001600160401b0302191690836001600160401b031602179055506000600481111561794d5761794d618888565b600985015460ff16600481111561796657617966618888565b03617aa25760098401805460ff1916600417905542600685018190556008850155600a840154604080518581526020810192909252600080516020619774833981519152910160405180910390a160058401546004860180546001600160401b03928316926008916179e1918591600160401b9004166191ce565b82546101009290920a6001600160401b0381810219909316918316021790915560028601546005870154617a2293506001600160a01b039091169116617d94565b83546005850154617a45916001600160a01b0316906001600160401b0316617cb7565b60028501546001600160a01b031615617a9d576004850180546001600160801b0360ff60e81b011916600160ea1b179055600a8401546040519081526000805160206197348339815191529060200160405180910390a15b617c1f565b6001600985015460ff166004811115617abd57617abd618888565b03617c1f573360009081526002602052604090205460ff161515600103617aee57617ae9858585618718565b617bd8565b60098401805460ff191660031790554260068501556005840154600785015460405163d83102cd60e01b815261ffff600160801b90930492909216600483015260248201527342e7bf71a3b0302011dbbb98d65e8a49abdb107b9063d83102cd90604401602060405180830381865af4158015617b6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190617b939190618fc1565b6008850155600a8401546040805185815260208101929092527fb503cf14e3d55841fd2c9a549abd732f6898fde969da012639aa917173e3a006910160405180910390a15b83546001600160a01b0316331480617c0457503360009081526002602052604090205460ff1615156001145b15617c1f57600b8401805461ff001916610100841515021790555b6009840154600190600687019060009060ff166004811115617c4357617c43618888565b6004811115617c5457617c54618888565b8152602081019190915260400160009081208054909190617c7f9084906001600160401b03166191ed565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550617cac85617f87565b506001949350505050565b6001600160a01b0382166000908152601460205260409020546001600160401b0382161115617d5a5760405162461bcd60e51b815260206004820152604360248201527f496e73756666696369656e74207374616b6520686f6c646572206c6f636b656460448201527f20746f6b656e7320696e207374616b696e6720666f722073756274726163746960648201526237b71760e91b608482015260a401610ade565b6001600160a01b038216600090815260146020526040812080546001600160401b0384169290617d8b90849061944c565b90915550505050565b6001600160a01b0382166000908152601260205260409020546001600160401b0382161115617e1e5760405162461bcd60e51b815260206004820152603060248201527f496e73756666696369656e74206e6f6465207374616b656420746f6b656e732060448201526f3337b91039bab13a3930b1ba34b7b71760811b6064820152608401610ade565b6001600160a01b038216600090815260126020526040812080546001600160401b0384169290617d8b90849061944c565b6009830154600190600684019060009060ff166004811115617e7357617e73618888565b6004811115617e8457617e84618888565b8152602081019190915260400160009081208054909190617eaf9084906001600160401b03166191ce565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550808360090160006101000a81548160ff02191690836004811115617ef957617ef9618888565b02179055506009830154600190600684019060009060ff166004811115617f2257617f22618888565b6004811115617f3357617f33618888565b8152602081019190915260400160009081208054909190617f5e9084906001600160401b03166191ed565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550505050565b6001600482810154600160e81b900460ff1690811115617fa957617fa9618888565b148015617fcd57506004810154600160401b81046001600160401b03908116911614155b15617ff0576004810180546000919060ff60e81b1916600160e81b835b02179055505b50565b600b8054600180820183556000928352600c82027f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9810180546001600160a01b039c8d166001600160a01b03199182161782557f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbb830180549c8e169c82169c909c17909b557f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dba820180549a909c16998b1699909917909a557f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbc8a018054909916909855427f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbd8a01557f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbe890180547f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbf8b018490557f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dc18b018490557f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dc08b01939093557f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dc38a01949094557f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dc28901805460ff199081169091557f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dc49099018054909916909717909755600160401b60ff9091160261ffff93909316600160801b0271ffff0000000000000000ffffffffffffffff199096166001600160401b0392909216919091179490941767ffffffffffffffff60401b1916179092559091565b600060128161828082600a619379565b6007546040516370a0823160e01b81526001600160a01b0387811660048301529293508392909116906370a0823190602401602060405180830381865afa1580156182cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906182f39190618fc1565b6123619190619711565b6004810180546003919060ff60501b1916600160501b83617fea565b60005b60028201546001600160a01b031660009081526011602052604090205481101561846a5760028201546001600160a01b0316600090815260116020526040812080548390811061836e5761836e618f5d565b906000526020600020015490506000600b828154811061839057618390618f5d565b90600052602060002090600c020190506000600a82600a0154815481106183b9576183b9618f5d565b6000918252602090912060079091020190506003600983015460ff1660048111156183e6576183e6618888565b0361840c576183f6818385618718565b600b8201805461ff00191661010017905561845f565b6000600983015460ff16600481111561842757618427618888565b148061844b57506001600983015460ff16600481111561844957618449618888565b145b1561845f5761845d81838560016176ff565b505b50505060010161831c565b5050565b60005b60028201546001600160a01b031660009081526011602052604090205481101561846a5760028201546001600160a01b031660009081526011602052604081208054839081106184c3576184c3618f5d565b906000526020600020015490506000600b82815481106184e5576184e5618f5d565b90600052602060002090600c0201600801549050808460080154101561850d57600884018190555b5050600101618471565b60005b60028201546001600160a01b031660009081526011602052604090205481101561846a5760028201546001600160a01b0316600090815260116020526040812080548390811061856c5761856c618f5d565b906000526020600020015490506000600b828154811061858e5761858e618f5d565b90600052602060002090600c020190506000600a82600a0154815481106185b7576185b7618f5d565b6000918252602090912060079091020190506003600983015460ff1660048111156185e4576185e4618888565b1480156185f45750428260080154105b156186eb576186038282618852565b81546005830154618626916001600160a01b0316906001600160401b0316617cb7565b6002820154600583015461864c916001600160a01b0316906001600160401b0316617d94565b60058201546004820180546001600160401b0392831692600891618679918591600160401b9004166191ce565b82546001600160401b039182166101009390930a92830291909202199091161790555060028101546001600160a01b0316156186eb5760048101805460ff60e81b1916600160ea1b179055600a8201546040519081526000805160206197348339815191529060200160405180910390a15b6186f481617f87565b50505060010161851a565b6004818101805460ff60501b1916600160501b83617fea565b60098201805460ff191660049081179091554260068401819055600880850191909155600584015491850180546001600160401b0393841693919291618768918591600160401b909104166191ce565b82546101009290920a6001600160401b03818102199093169183160217909155600284015460058501546187a993506001600160a01b039091169116617d94565b815460058301546187cc916001600160a01b0316906001600160401b0316617cb7565b600a820154604080518381526020810192909252600080516020619774833981519152910160405180910390a160028301546001600160a01b03161561884d576004830180546001600160801b0360ff60e81b011916600160ea1b179055600a82015460405190815260008051602061973483398151915290602001612c83565b505050565b61885e82826004617e4f565b504260068201819055600890910155565b60006020828403121561888157600080fd5b5035919050565b634e487b7160e01b600052602160045260246000fd5b60058110617ff057617ff0618888565b6188b78161889e565b9052565b600281106188b7576188b7618888565b8b81526001600160a01b038b811660208301528a8116604083015289811660608301528816608082015260a081018790526001600160401b0386811660c083015285811660e08301528416610100820152610160810161892f6101208301856188ae565b61893d6101408301846188bb565b9c9b505050505050505050505050565b80356001600160401b0381168114610bd757600080fd5b80358015158114610bd757600080fd5b60008060006060848603121561898957600080fd5b833592506189996020850161894d565b91506189a760408501618964565b90509250925092565b600080600080608085870312156189c657600080fd5b5050823594602084013594506040840135936060013592509050565b80356001600160a01b0381168114610bd757600080fd5b60008060408385031215618a0c57600080fd5b618a15836189e2565b9150618a236020840161894d565b90509250929050565b600080600060608486031215618a4157600080fd5b83359250618a516020850161894d565b91506189a7604085016189e2565b600060208284031215618a7157600080fd5b610f5f826189e2565b600060208284031215618a8c57600080fd5b610f5f8261894d565b803560ff81168114610bd757600080fd5b600060208284031215618ab857600080fd5b610f5f82618a95565b600081518084526020840193506020830160005b82811015618af3578151865260209586019590910190600101618ad5565b5093949350505050565b602081526000610f5f6020830184618ac1565b8981526001600160a01b038981166020830152888116604083015287166060820152608081018690526001600160401b0385811660a0830152841660c08201526101208101618b5e8461889e565b8360e0830152618b726101008301846188bb565b9a9950505050505050505050565b60008060408385031215618b9357600080fd5b82359150618a236020840161894d565b8b81526001600160401b038b81166020830152604082018b90526001600160a01b038a811660608401528981166080840152881660a083015260c0820187905285811660e083015284166101008201526101608101618c066101208301856188ae565b826101408301529c9b505050505050505050505050565b8a81526001600160401b038a81166020830152604082018a90526001600160a01b0389811660608401528816608083015260a0820187905285811660c0830152841660e08201526101408101618c728461889e565b610100820193909352610120015298975050505050505050565b60008060408385031215618c9f57600080fd5b82359150618a2360208401618964565b803561ffff81168114610bd757600080fd5b600080600060608486031215618cd657600080fd5b618cdf846189e2565b9250618ced6020850161894d565b91506189a760408501618caf565b600080600080600080600060e0888a031215618d1657600080fd5b618d1f886189e2565b9650618d2d6020890161894d565b9550618d3b604089016189e2565b9450618d4960608901618caf565b9350618d5760808901618a95565b9250618d6560a08901618964565b9150618d7360c08901618964565b905092959891949750929550565b608081526000618d946080830187618ac1565b94151560208301525060408101929092521515606090910152919050565b600080600060608486031215618dc757600080fd5b8335925061899960208501618964565b60008060408385031215618dea57600080fd5b82359150618a23602084016189e2565b8d81526001600160a01b038d811660208301528c811660408301528b166060820152608081018a90526001600160401b0389811660a0830152881660c08201526101a081016001600160401b03881660e083015260ff8716610100830152851515610120830152841515610140830152618e786101608301856188ae565b6001600160401b0383166101808301529e9d5050505050505050505050505050565b600080600060608486031215618eaf57600080fd5b83359250618a51602085016189e2565b60208082526032908201527f436f6d70616e7957616c6c65743a2063616c6c6572206973206e6f7420612077604082015271616c6c65742066726f6d20636f6d70616e7960701b606082015260800190565b6020808252602c908201527f45746e795374616b696e673a20496e76616c69642042617365205374616b652060408201526b49442070726f76696465642160a01b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b6020808252602e908201527f45746e795374616b696e673a205374616b6520697320686176696e672064696660408201526d666572656e74207374617475732160901b606082015260800190565b600060208284031215618fd357600080fd5b5051919050565b60208082526030908201527f45746e795374616b696e673a20496e76616c696420457874656e64656420537460408201526f616b652049442070726f76696465642160801b606082015260800190565b6020808252602d908201527f45746e795374616b696e673a20496e76616c6964205374616b6520436f6e747260408201526c6163742070726f76696465642160981b606082015260800190565b60208082526024908201527f45746e795374616b696e673a20496e76616c696420496e6465782070726f76696040820152636465642160e01b606082015260800190565b6020808252603c9082015260008051602061975483398151915260408201527f6573732063616e20706572666f726d207468697320616374696f6e2100000000606082015260800190565b60208082526035908201527f45746e795374616b696e673a20496e76616c69642042617365205374616b6520604082015274436f6e74726163742049442070726f76696465642160581b606082015260800190565b6020808252603f908201527f45746e795374616b696e673a205468652062617365207374616b6520636f6e7460408201527f72616374206f6e2074686973206e6f6465207761732063616e63656c65642100606082015260800190565b634e487b7160e01b600052601160045260246000fd5b6001600160401b03828116828216039081111561128a5761128a6191b8565b6001600160401b03818116838216019081111561128a5761128a6191b8565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526031908201527f45746e795374616b696e673a204f6e6c79207374616b65722063616e2063616e60408201527063656c207468697320726571756573742160781b606082015260800190565b6001815b60018411156192cd578085048111156192b1576192b16191b8565b60018416156192bf57908102905b60019390931c928002619296565b935093915050565b6000826192e45750600161128a565b816192f15750600061128a565b816001811461930757600281146193115761932d565b600191505061128a565b60ff841115619322576193226191b8565b50506001821b61128a565b5060208310610133831016604e8410600b8410161715619350575081810a61128a565b61935d6000198484619292565b8060001904821115619371576193716191b8565b029392505050565b6000610f5f83836192d5565b808202811582820484141761128a5761128a6191b8565b60208082526033908201527f45746e795374616b696e673a204f6e6c7920612063616e63656c656420636f6e60408201527274726163742063616e20626520656e6465642160681b606082015260800190565b6020808252603d908201527f45746e795374616b696e673a2054686520636f6e74726163742063616e20626560408201527f207465726d696e6174656420616674657220697420657870697265732e000000606082015260800190565b8181038181111561128a5761128a6191b8565b60208082526030908201527f45746e795374616b696e673a205265776172642061646472657373206973207460408201526f6865207a65726f20616464726573732160801b606082015260800190565b8082018082111561128a5761128a6191b8565b6020808252605c9082015260008051602061975483398151915260408201527f6573732063616e207465726d696e61746520612042617365205374616b65204360608201527f6f6e747261637420616e64206170706c792070656e616c746965732100000000608082015260a00190565b60208082526064908201527f45746e795374616b696e673a20536f6d657468696e672077656e742077726f6e60408201527f672e205468652045746865726e69747920436c6f756420536d617274436f6e7460608201527f726163742061646472657373206973206e6f7420636f72726563746c792073656080820152637475702160e01b60a082015260c00190565b60208082526035908201527f45746e795374616b696e673a204e6f646520616c72656164792068617320616e604082015274206578697374696e672062617365207374616b652160581b606082015260800190565b60208082526022908201527f45746e795374616b696e673a204e6f6465206861732045544e5920746f6b656e604082015261732160f01b606082015260800190565b6020808252603e9082015260008051602061979483398151915260408201527f62616c616e636520617661696c61626c6520666f72207374616b696e67210000606082015260800190565b60208082526046908201527f45746e795374616b696e673a20546865206e6f6465206164647265737320736860408201527f6f756c6420626520646966666572656e74207468616e2072657761726420616460608201526564726573732160d01b608082015260a00190565b60008261972e57634e487b7160e01b600052601260045260246000fd5b50049056fea002debc9839c20f8a9424b3c4bad3295abbb3676c3acf6ea94d869f6b4f54c045746e795374616b696e673a204f6e6c79206120636f6d70616e792061646472ee821fc4af1ea42a6c6174adb5fd292ad9e326c120629b92006d036545c3c66b45746e795374616b696e673a2054686520616d6f756e74206578636565647320a2646970667358221220acda4732641c120a3e505fd1d2c0bbbbf3f695e4bf306cf60bf1233221b0c80064736f6c634300081e0033