Address Details
contract

0x618F20672f0C2F1789465551d5A28872F38De1B8

Contract Name
DoubleSigningSlasher
Creator
0x0cc59e–f1502d at 0x6d2405–e836fe
Balance
0 CELO
Locked CELO Balance
0.00 CELO
Voting CELO Balance
0.00 CELO
Pending Unlocked Gold
0.00 CELO
Tokens
Fetching tokens...
Transactions
Fetching transactions...
Transfers
Fetching transfers...
Gas Used
Fetching gas used...
Last Balance Update
1077
Contract name:
DoubleSigningSlasher




Optimization enabled
false
Compiler version
v0.5.8+commit.23d335f2




Verified at
2020-08-11T19:06:58.977369Z

Contract source code

pragma solidity ^0.5.3;


library SafeMath {
    
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        
        
        
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        
        require(b > 0, errorMessage);
        uint256 c = a / b;
        

        return c;
    }

    
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

contract Context {
    
    
    constructor () internal { }
    

    function _msgSender() internal view returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view returns (bytes memory) {
        this; 
        return msg.data;
    }
}

contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

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

    
    modifier onlyOwner() {
        require(isOwner(), "Ownable: caller is not the owner");
        _;
    }

    
    function isOwner() public view returns (bool) {
        return _msgSender() == _owner;
    }

    
    function renounceOwnership() public onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    
    function transferOwnership(address newOwner) public onlyOwner {
        _transferOwnership(newOwner);
    }

    
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

contract Initializable {
  bool public initialized;

  modifier initializer() {
    require(!initialized, "contract already initialized");
    initialized = true;
    _;
  }
}

interface IERC20 {
    
    function totalSupply() external view returns (uint256);

    
    function balanceOf(address account) external view returns (uint256);

    
    function transfer(address recipient, uint256 amount) external returns (bool);

    
    function allowance(address owner, address spender) external view returns (uint256);

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

    
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    
    event Transfer(address indexed from, address indexed to, uint256 value);

    
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

interface IAccounts {
  function isAccount(address) external view returns (bool);
  function voteSignerToAccount(address) external view returns (address);
  function validatorSignerToAccount(address) external view returns (address);
  function attestationSignerToAccount(address) external view returns (address);
  function signerToAccount(address) external view returns (address);
  function getAttestationSigner(address) external view returns (address);
  function getValidatorSigner(address) external view returns (address);
  function getVoteSigner(address) external view returns (address);
  function hasAuthorizedVoteSigner(address) external view returns (bool);
  function hasAuthorizedValidatorSigner(address) external view returns (bool);
  function hasAuthorizedAttestationSigner(address) external view returns (bool);

  function setAccountDataEncryptionKey(bytes calldata) external;
  function setMetadataURL(string calldata) external;
  function setName(string calldata) external;
  function setWalletAddress(address, uint8, bytes32, bytes32) external;
  function setAccount(string calldata, bytes calldata, address, uint8, bytes32, bytes32) external;

  function getDataEncryptionKey(address) external view returns (bytes memory);
  function getWalletAddress(address) external view returns (address);
  function getMetadataURL(address) external view returns (string memory);
  function batchGetMetadataURL(address[] calldata)
    external
    view
    returns (uint256[] memory, bytes memory);
  function getName(address) external view returns (string memory);

  function authorizeVoteSigner(address, uint8, bytes32, bytes32) external;
  function authorizeValidatorSigner(address, uint8, bytes32, bytes32) external;
  function authorizeValidatorSignerWithPublicKey(address, uint8, bytes32, bytes32, bytes calldata)
    external;
  function authorizeValidatorSignerWithKeys(
    address,
    uint8,
    bytes32,
    bytes32,
    bytes calldata,
    bytes calldata,
    bytes calldata
  ) external;
  function authorizeAttestationSigner(address, uint8, bytes32, bytes32) external;
  function createAccount() external returns (bool);
}

interface IFeeCurrencyWhitelist {
  function addToken(address) external;
  function getWhitelist() external view returns (address[] memory);
}

interface IFreezer {
  function isFrozen(address) external view returns (bool);
}

interface IRegistry {
  function setAddressFor(string calldata, address) external;
  function getAddressForOrDie(bytes32) external view returns (address);
  function getAddressFor(bytes32) external view returns (address);
  function isOneOf(bytes32[] calldata, address) external view returns (bool);
}

interface IElection {
  function getTotalVotes() external view returns (uint256);
  function getActiveVotes() external view returns (uint256);
  function getTotalVotesByAccount(address) external view returns (uint256);
  function markGroupIneligible(address) external;
  function markGroupEligible(address, address, address) external;
  function electValidatorSigners() external view returns (address[] memory);
  function vote(address, uint256, address, address) external returns (bool);
  function activate(address) external returns (bool);
  function revokeActive(address, uint256, address, address, uint256) external returns (bool);
  function revokeAllActive(address, address, address, uint256) external returns (bool);
  function revokePending(address, uint256, address, address, uint256) external returns (bool);
  function forceDecrementVotes(
    address,
    uint256,
    address[] calldata,
    address[] calldata,
    uint256[] calldata
  ) external returns (uint256);
}

interface IGovernance {
  function isVoting(address) external view returns (bool);
}

interface ILockedGold {
  function incrementNonvotingAccountBalance(address, uint256) external;
  function decrementNonvotingAccountBalance(address, uint256) external;
  function getAccountTotalLockedGold(address) external view returns (uint256);
  function getTotalLockedGold() external view returns (uint256);
  function getPendingWithdrawals(address)
    external
    view
    returns (uint256[] memory, uint256[] memory);
  function getTotalPendingWithdrawals(address) external view returns (uint256);
  function lock() external payable;
  function unlock(uint256) external;
  function relock(uint256, uint256) external;
  function withdraw(uint256) external;
  function slash(
    address account,
    uint256 penalty,
    address reporter,
    uint256 reward,
    address[] calldata lessers,
    address[] calldata greaters,
    uint256[] calldata indices
  ) external;
  function isSlasher(address) external view returns (bool);
}

interface IValidators {
  function getAccountLockedGoldRequirement(address) external view returns (uint256);
  function meetsAccountLockedGoldRequirements(address) external view returns (bool);
  function getGroupNumMembers(address) external view returns (uint256);
  function getGroupsNumMembers(address[] calldata) external view returns (uint256[] memory);
  function getNumRegisteredValidators() external view returns (uint256);
  function getTopGroupValidators(address, uint256) external view returns (address[] memory);
  function updateEcdsaPublicKey(address, address, bytes calldata) external returns (bool);
  function updatePublicKeys(address, address, bytes calldata, bytes calldata, bytes calldata)
    external
    returns (bool);
  function isValidator(address) external view returns (bool);
  function isValidatorGroup(address) external view returns (bool);
  function calculateGroupEpochScore(uint256[] calldata uptimes) external view returns (uint256);
  function groupMembershipInEpoch(address account, uint256 epochNumber, uint256 index)
    external
    view
    returns (address);
  function halveSlashingMultiplier(address group) external;
  function forceDeaffiliateIfValidator(address validator) external;
  function getValidatorGroupSlashingMultiplier(address) external view returns (uint256);
  function affiliate(address group) external returns (bool);
}

interface IRandom {
  function revealAndCommit(bytes32, bytes32, address) external;
  function randomnessBlockRetentionWindow() external view returns (uint256);
  function random() external view returns (bytes32);
  function getBlockRandomness(uint256) external view returns (bytes32);
}

interface IAttestations {
  function setAttestationRequestFee(address, uint256) external;
  function request(bytes32, uint256, address) external;
  function selectIssuers(bytes32) external;
  function complete(bytes32, uint8, bytes32, bytes32) external;
  function revoke(bytes32, uint256) external;
  function withdraw(address) external;

  function setAttestationExpiryBlocks(uint256) external;

  function getMaxAttestations() external view returns (uint256);

  function getUnselectedRequest(bytes32, address) external view returns (uint32, uint32, address);
  function getAttestationRequestFee(address) external view returns (uint256);

  function lookupAccountsForIdentifier(bytes32) external view returns (address[] memory);

  function getAttestationStats(bytes32, address) external view returns (uint32, uint32);

  function getAttestationState(bytes32, address, address)
    external
    view
    returns (uint8, uint32, address);
  function getCompletableAttestations(bytes32, address)
    external
    view
    returns (uint32[] memory, address[] memory, uint256[] memory, bytes memory);
}

interface IExchange {
  function exchange(uint256, uint256, bool) external returns (uint256);
  function setUpdateFrequency(uint256) external;
  function getBuyTokenAmount(uint256, bool) external view returns (uint256);
  function getSellTokenAmount(uint256, bool) external view returns (uint256);
  function getBuyAndSellBuckets(bool) external view returns (uint256, uint256);
}

interface IReserve {
  function setTobinTaxStalenessThreshold(uint256) external;
  function addToken(address) external returns (bool);
  function removeToken(address, uint256) external returns (bool);
  function transferGold(address payable, uint256) external returns (bool);
  function transferExchangeGold(address payable, uint256) external returns (bool);
  function getReserveGoldBalance() external view returns (uint256);
  function getUnfrozenReserveGoldBalance() external view returns (uint256);
  function getOrComputeTobinTax() external returns (uint256, uint256);
  function getTokens() external view returns (address[] memory);
  function getReserveRatio() external view returns (uint256);
}

interface ISortedOracles {
  function addOracle(address, address) external;
  function removeOracle(address, address, uint256) external;
  function report(address, uint256, address, address) external;
  function removeExpiredReports(address, uint256) external;
  function isOldestReportExpired(address token) external view returns (bool, address);
  function numRates(address) external view returns (uint256);
  function medianRate(address) external view returns (uint256, uint256);
  function numTimestamps(address) external view returns (uint256);
  function medianTimestamp(address) external view returns (uint256);
}

interface IStableToken {
  function mint(address, uint256) external returns (bool);
  function burn(uint256) external returns (bool);
  function setInflationParameters(uint256, uint256) external;
  function valueToUnits(uint256) external view returns (uint256);
  function unitsToValue(uint256) external view returns (uint256);
  function getInflationParameters() external view returns (uint256, uint256, uint256, uint256);

  
  function balanceOf(address) external view returns (uint256);
}

contract UsingRegistry is Ownable {
  event RegistrySet(address indexed registryAddress);

  
  bytes32 constant ACCOUNTS_REGISTRY_ID = keccak256(abi.encodePacked("Accounts"));
  bytes32 constant ATTESTATIONS_REGISTRY_ID = keccak256(abi.encodePacked("Attestations"));
  bytes32 constant DOWNTIME_SLASHER_REGISTRY_ID = keccak256(abi.encodePacked("DowntimeSlasher"));
  bytes32 constant DOUBLE_SIGNING_SLASHER_REGISTRY_ID = keccak256(
    abi.encodePacked("DoubleSigningSlasher")
  );
  bytes32 constant ELECTION_REGISTRY_ID = keccak256(abi.encodePacked("Election"));
  bytes32 constant EXCHANGE_REGISTRY_ID = keccak256(abi.encodePacked("Exchange"));
  bytes32 constant FEE_CURRENCY_WHITELIST_REGISTRY_ID = keccak256(
    abi.encodePacked("FeeCurrencyWhitelist")
  );
  bytes32 constant FREEZER_REGISTRY_ID = keccak256(abi.encodePacked("Freezer"));
  bytes32 constant GOLD_TOKEN_REGISTRY_ID = keccak256(abi.encodePacked("GoldToken"));
  bytes32 constant GOVERNANCE_REGISTRY_ID = keccak256(abi.encodePacked("Governance"));
  bytes32 constant GOVERNANCE_SLASHER_REGISTRY_ID = keccak256(
    abi.encodePacked("GovernanceSlasher")
  );
  bytes32 constant LOCKED_GOLD_REGISTRY_ID = keccak256(abi.encodePacked("LockedGold"));
  bytes32 constant RESERVE_REGISTRY_ID = keccak256(abi.encodePacked("Reserve"));
  bytes32 constant RANDOM_REGISTRY_ID = keccak256(abi.encodePacked("Random"));
  bytes32 constant SORTED_ORACLES_REGISTRY_ID = keccak256(abi.encodePacked("SortedOracles"));
  bytes32 constant STABLE_TOKEN_REGISTRY_ID = keccak256(abi.encodePacked("StableToken"));
  bytes32 constant VALIDATORS_REGISTRY_ID = keccak256(abi.encodePacked("Validators"));
  

  IRegistry public registry;

  modifier onlyRegisteredContract(bytes32 identifierHash) {
    require(registry.getAddressForOrDie(identifierHash) == msg.sender, "only registered contract");
    _;
  }

  modifier onlyRegisteredContracts(bytes32[] memory identifierHashes) {
    require(registry.isOneOf(identifierHashes, msg.sender), "only registered contracts");
    _;
  }

  
  function setRegistry(address registryAddress) public onlyOwner {
    require(registryAddress != address(0), "Cannot register the null address");
    registry = IRegistry(registryAddress);
    emit RegistrySet(registryAddress);
  }

  function getAccounts() internal view returns (IAccounts) {
    return IAccounts(registry.getAddressForOrDie(ACCOUNTS_REGISTRY_ID));
  }

  function getAttestations() internal view returns (IAttestations) {
    return IAttestations(registry.getAddressForOrDie(ATTESTATIONS_REGISTRY_ID));
  }

  function getElection() internal view returns (IElection) {
    return IElection(registry.getAddressForOrDie(ELECTION_REGISTRY_ID));
  }

  function getExchange() internal view returns (IExchange) {
    return IExchange(registry.getAddressForOrDie(EXCHANGE_REGISTRY_ID));
  }

  function getFeeCurrencyWhitelistRegistry() internal view returns (IFeeCurrencyWhitelist) {
    return IFeeCurrencyWhitelist(registry.getAddressForOrDie(FEE_CURRENCY_WHITELIST_REGISTRY_ID));
  }

  function getFreezer() internal view returns (IFreezer) {
    return IFreezer(registry.getAddressForOrDie(FREEZER_REGISTRY_ID));
  }

  function getGoldToken() internal view returns (IERC20) {
    return IERC20(registry.getAddressForOrDie(GOLD_TOKEN_REGISTRY_ID));
  }

  function getGovernance() internal view returns (IGovernance) {
    return IGovernance(registry.getAddressForOrDie(GOVERNANCE_REGISTRY_ID));
  }

  function getLockedGold() internal view returns (ILockedGold) {
    return ILockedGold(registry.getAddressForOrDie(LOCKED_GOLD_REGISTRY_ID));
  }

  function getRandom() internal view returns (IRandom) {
    return IRandom(registry.getAddressForOrDie(RANDOM_REGISTRY_ID));
  }

  function getReserve() internal view returns (IReserve) {
    return IReserve(registry.getAddressForOrDie(RESERVE_REGISTRY_ID));
  }

  function getSortedOracles() internal view returns (ISortedOracles) {
    return ISortedOracles(registry.getAddressForOrDie(SORTED_ORACLES_REGISTRY_ID));
  }

  function getStableToken() internal view returns (IStableToken) {
    return IStableToken(registry.getAddressForOrDie(STABLE_TOKEN_REGISTRY_ID));
  }

  function getValidators() internal view returns (IValidators) {
    return IValidators(registry.getAddressForOrDie(VALIDATORS_REGISTRY_ID));
  }
}

contract UsingPrecompiles {
  using SafeMath for uint256;

  address constant TRANSFER = address(0xff - 2);
  address constant FRACTION_MUL = address(0xff - 3);
  address constant PROOF_OF_POSSESSION = address(0xff - 4);
  address constant GET_VALIDATOR = address(0xff - 5);
  address constant NUMBER_VALIDATORS = address(0xff - 6);
  address constant EPOCH_SIZE = address(0xff - 7);
  address constant BLOCK_NUMBER_FROM_HEADER = address(0xff - 8);
  address constant HASH_HEADER = address(0xff - 9);
  address constant GET_PARENT_SEAL_BITMAP = address(0xff - 10);
  address constant GET_VERIFIED_SEAL_BITMAP = address(0xff - 11);

  
  function fractionMulExp(
    uint256 aNumerator,
    uint256 aDenominator,
    uint256 bNumerator,
    uint256 bDenominator,
    uint256 exponent,
    uint256 _decimals
  ) public view returns (uint256, uint256) {
    require(aDenominator != 0 && bDenominator != 0, "a denominator is zero");
    uint256 returnNumerator;
    uint256 returnDenominator;
    bool success;
    bytes memory out;
    (success, out) = FRACTION_MUL.staticcall(
      abi.encodePacked(aNumerator, aDenominator, bNumerator, bDenominator, exponent, _decimals)
    );
    require(success, "error calling fractionMulExp precompile");
    returnNumerator = getUint256FromBytes(out, 0);
    returnDenominator = getUint256FromBytes(out, 32);
    return (returnNumerator, returnDenominator);
  }

  
  function getEpochSize() public view returns (uint256) {
    bytes memory out;
    bool success;
    (success, out) = EPOCH_SIZE.staticcall(abi.encodePacked());
    require(success, "error calling getEpochSize precompile");
    return getUint256FromBytes(out, 0);
  }

  
  function getEpochNumberOfBlock(uint256 blockNumber) public view returns (uint256) {
    return epochNumberOfBlock(blockNumber, getEpochSize());
  }

  
  function getEpochNumber() public view returns (uint256) {
    return getEpochNumberOfBlock(block.number);
  }

  
  function epochNumberOfBlock(uint256 blockNumber, uint256 epochSize)
    internal
    pure
    returns (uint256)
  {
    
    uint256 epochNumber = blockNumber / epochSize;
    if (blockNumber % epochSize == 0) {
      return epochNumber;
    } else {
      return epochNumber + 1;
    }
  }

  
  function validatorSignerAddressFromCurrentSet(uint256 index) public view returns (address) {
    bytes memory out;
    bool success;
    (success, out) = GET_VALIDATOR.staticcall(abi.encodePacked(index, uint256(block.number)));
    require(success, "error calling validatorSignerAddressFromCurrentSet precompile");
    return address(getUint256FromBytes(out, 0));
  }

  
  function validatorSignerAddressFromSet(uint256 index, uint256 blockNumber)
    public
    view
    returns (address)
  {
    bytes memory out;
    bool success;
    (success, out) = GET_VALIDATOR.staticcall(abi.encodePacked(index, blockNumber));
    require(success, "error calling validatorSignerAddressFromSet precompile");
    return address(getUint256FromBytes(out, 0));
  }

  
  function numberValidatorsInCurrentSet() public view returns (uint256) {
    bytes memory out;
    bool success;
    (success, out) = NUMBER_VALIDATORS.staticcall(abi.encodePacked(uint256(block.number)));
    require(success, "error calling numberValidatorsInCurrentSet precompile");
    return getUint256FromBytes(out, 0);
  }

  
  function numberValidatorsInSet(uint256 blockNumber) public view returns (uint256) {
    bytes memory out;
    bool success;
    (success, out) = NUMBER_VALIDATORS.staticcall(abi.encodePacked(blockNumber));
    require(success, "error calling numberValidatorsInSet precompile");
    return getUint256FromBytes(out, 0);
  }

  
  function checkProofOfPossession(address sender, bytes memory blsKey, bytes memory blsPop)
    public
    view
    returns (bool)
  {
    bool success;
    (success, ) = PROOF_OF_POSSESSION.staticcall(abi.encodePacked(sender, blsKey, blsPop));
    return success;
  }

  
  function getBlockNumberFromHeader(bytes memory header) public view returns (uint256) {
    bytes memory out;
    bool success;
    (success, out) = BLOCK_NUMBER_FROM_HEADER.staticcall(abi.encodePacked(header));
    require(success, "error calling getBlockNumberFromHeader precompile");
    return getUint256FromBytes(out, 0);
  }

  
  function hashHeader(bytes memory header) public view returns (bytes32) {
    bytes memory out;
    bool success;
    (success, out) = HASH_HEADER.staticcall(abi.encodePacked(header));
    require(success, "error calling hashHeader precompile");
    return getBytes32FromBytes(out, 0);
  }

  
  function getParentSealBitmap(uint256 blockNumber) public view returns (bytes32) {
    bytes memory out;
    bool success;
    (success, out) = GET_PARENT_SEAL_BITMAP.staticcall(abi.encodePacked(blockNumber));
    require(success, "error calling getParentSealBitmap precompile");
    return getBytes32FromBytes(out, 0);
  }

  
  function getVerifiedSealBitmapFromHeader(bytes memory header) public view returns (bytes32) {
    bytes memory out;
    bool success;
    (success, out) = GET_VERIFIED_SEAL_BITMAP.staticcall(abi.encodePacked(header));
    require(success, "error calling getVerifiedSealBitmapFromHeader precompile");
    return getBytes32FromBytes(out, 0);
  }

  
  function getUint256FromBytes(bytes memory bs, uint256 start) internal pure returns (uint256) {
    return uint256(getBytes32FromBytes(bs, start));
  }

  
  function getBytes32FromBytes(bytes memory bs, uint256 start) internal pure returns (bytes32) {
    require(bs.length >= start + 32, "slicing out of range");
    bytes32 x;
    assembly {
      x := mload(add(bs, add(start, 32)))
    }
    return x;
  }

  
  function minQuorumSize(uint256 blockNumber) public view returns (uint256) {
    return numberValidatorsInSet(blockNumber).mul(2).add(2).div(3);
  }

  
  function minQuorumSizeInCurrentSet() public view returns (uint256) {
    return minQuorumSize(block.number);
  }

}

contract SlasherUtil is Ownable, Initializable, UsingRegistry, UsingPrecompiles {
  using SafeMath for uint256;

  struct SlashingIncentives {
    
    uint256 penalty;
    
    uint256 reward;
  }

  SlashingIncentives public slashingIncentives;

  event SlashingIncentivesSet(uint256 penalty, uint256 reward);

  
  function setSlashingIncentives(uint256 penalty, uint256 reward) public onlyOwner {
    require(penalty > reward, "Penalty has to be larger than reward");
    slashingIncentives.penalty = penalty;
    slashingIncentives.reward = reward;
    emit SlashingIncentivesSet(penalty, reward);
  }

  
  function groupMembershipAtBlock(
    address validator,
    uint256 blockNumber,
    uint256 groupMembershipHistoryIndex
  ) public view returns (address) {
    uint256 epoch = getEpochNumberOfBlock(blockNumber);
    require(epoch != 0, "Cannot slash on epoch 0");
    
    return
      getValidators().groupMembershipInEpoch(validator, epoch.sub(1), groupMembershipHistoryIndex);
  }

  function performSlashing(
    address validator,
    address recipient,
    uint256 startBlock,
    uint256 groupMembershipHistoryIndex,
    address[] memory validatorElectionLessers,
    address[] memory validatorElectionGreaters,
    uint256[] memory validatorElectionIndices,
    address[] memory groupElectionLessers,
    address[] memory groupElectionGreaters,
    uint256[] memory groupElectionIndices
  ) internal {
    ILockedGold lockedGold = getLockedGold();
    lockedGold.slash(
      validator,
      slashingIncentives.penalty,
      recipient,
      slashingIncentives.reward,
      validatorElectionLessers,
      validatorElectionGreaters,
      validatorElectionIndices
    );
    address group = groupMembershipAtBlock(validator, startBlock, groupMembershipHistoryIndex);
    assert(group != address(0));
    lockedGold.slash(
      group,
      slashingIncentives.penalty,
      recipient,
      slashingIncentives.reward,
      groupElectionLessers,
      groupElectionGreaters,
      groupElectionIndices
    );
    IValidators validators = getValidators();
    validators.forceDeaffiliateIfValidator(validator);
    validators.halveSlashingMultiplier(group);
  }

}

contract DoubleSigningSlasher is SlasherUtil {
  using SafeMath for uint256;

  
  mapping(address => mapping(bytes32 => bool)) isSlashed;

  event SlashingIncentivesSet(uint256 penalty, uint256 reward);
  event DoubleSigningSlashPerformed(address indexed validator, uint256 indexed blockNumber);

  
  function initialize(address registryAddress, uint256 _penalty, uint256 _reward)
    external
    initializer
  {
    _transferOwnership(msg.sender);
    setRegistry(registryAddress);
    setSlashingIncentives(_penalty, _reward);
  }

  
  function countSetBits(uint256 v) internal pure returns (uint256) {
    uint256 res = 0;
    uint256 acc = v;
    for (uint256 i = 0; i < 256; i = i.add(1)) {
      if (acc & 1 == 1) res = res.add(1);
      acc = acc >> 1;
    }
    return res;
  }

  
  function checkForDoubleSigning(
    address signer,
    uint256 index,
    bytes memory headerA,
    bytes memory headerB
  ) public view returns (uint256) {
    require(hashHeader(headerA) != hashHeader(headerB), "Block hashes have to be different");
    uint256 blockNumber = getBlockNumberFromHeader(headerA);
    require(
      blockNumber == getBlockNumberFromHeader(headerB),
      "Block headers are from different height"
    );
    require(index < numberValidatorsInSet(blockNumber), "Bad validator index");
    require(
      signer == validatorSignerAddressFromSet(index, blockNumber),
      "Wasn't a signer with given index"
    );
    uint256 mapA = uint256(getVerifiedSealBitmapFromHeader(headerA));
    uint256 mapB = uint256(getVerifiedSealBitmapFromHeader(headerB));
    require(mapA & (1 << index) != 0, "Didn't sign first block");
    require(mapB & (1 << index) != 0, "Didn't sign second block");
    require(
      countSetBits(mapA) >= minQuorumSize(blockNumber),
      "Not enough signers in the first block"
    );
    require(
      countSetBits(mapB) >= minQuorumSize(blockNumber),
      "Not enough signers in the second block"
    );
    return blockNumber;
  }

  function checkIfAlreadySlashed(address signer, bytes memory header) internal {
    bytes32 bhash = hashHeader(header);
    require(!isSlashed[signer][bhash], "Already slashed");
    isSlashed[signer][bhash] = true;
  }

  
  function slash(
    address signer,
    uint256 index,
    bytes memory headerA,
    bytes memory headerB,
    uint256 groupMembershipHistoryIndex,
    address[] memory validatorElectionLessers,
    address[] memory validatorElectionGreaters,
    uint256[] memory validatorElectionIndices,
    address[] memory groupElectionLessers,
    address[] memory groupElectionGreaters,
    uint256[] memory groupElectionIndices
  ) public {
    checkIfAlreadySlashed(signer, headerA);
    checkIfAlreadySlashed(signer, headerB);
    uint256 blockNumber = checkForDoubleSigning(signer, index, headerA, headerB);
    address validator = getAccounts().signerToAccount(signer);
    performSlashing(
      validator,
      msg.sender,
      blockNumber,
      groupMembershipHistoryIndex,
      validatorElectionLessers,
      validatorElectionGreaters,
      validatorElectionIndices,
      groupElectionLessers,
      groupElectionGreaters,
      groupElectionIndices
    );
    emit DoubleSigningSlashPerformed(validator, blockNumber);
  }
}
        

Contract ABI

[{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"checkForDoubleSigning","inputs":[{"type":"address","name":"signer"},{"type":"uint256","name":"index"},{"type":"bytes","name":"headerA"},{"type":"bytes","name":"headerB"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"penalty"},{"type":"uint256","name":"reward"}],"name":"slashingIncentives","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"validatorSignerAddressFromCurrentSet","inputs":[{"type":"uint256","name":"index"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"initialized","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"checkProofOfPossession","inputs":[{"type":"address","name":"sender"},{"type":"bytes","name":"blsKey"},{"type":"bytes","name":"blsPop"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getEpochNumberOfBlock","inputs":[{"type":"uint256","name":"blockNumber"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"getVerifiedSealBitmapFromHeader","inputs":[{"type":"bytes","name":"header"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"validatorSignerAddressFromSet","inputs":[{"type":"uint256","name":"index"},{"type":"uint256","name":"blockNumber"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"hashHeader","inputs":[{"type":"bytes","name":"header"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"renounceOwnership","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"minQuorumSizeInCurrentSet","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"initialize","inputs":[{"type":"address","name":"registryAddress"},{"type":"uint256","name":"_penalty"},{"type":"uint256","name":"_reward"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"registry","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"numberValidatorsInCurrentSet","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"groupMembershipAtBlock","inputs":[{"type":"address","name":"validator"},{"type":"uint256","name":"blockNumber"},{"type":"uint256","name":"groupMembershipHistoryIndex"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getBlockNumberFromHeader","inputs":[{"type":"bytes","name":"header"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"slash","inputs":[{"type":"address","name":"signer"},{"type":"uint256","name":"index"},{"type":"bytes","name":"headerA"},{"type":"bytes","name":"headerB"},{"type":"uint256","name":"groupMembershipHistoryIndex"},{"type":"address[]","name":"validatorElectionLessers"},{"type":"address[]","name":"validatorElectionGreaters"},{"type":"uint256[]","name":"validatorElectionIndices"},{"type":"address[]","name":"groupElectionLessers"},{"type":"address[]","name":"groupElectionGreaters"},{"type":"uint256[]","name":"groupElectionIndices"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"owner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isOwner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getEpochNumber","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"numberValidatorsInSet","inputs":[{"type":"uint256","name":"blockNumber"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setRegistry","inputs":[{"type":"address","name":"registryAddress"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setSlashingIncentives","inputs":[{"type":"uint256","name":"penalty"},{"type":"uint256","name":"reward"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getEpochSize","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"minQuorumSize","inputs":[{"type":"uint256","name":"blockNumber"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""},{"type":"uint256","name":""}],"name":"fractionMulExp","inputs":[{"type":"uint256","name":"aNumerator"},{"type":"uint256","name":"aDenominator"},{"type":"uint256","name":"bNumerator"},{"type":"uint256","name":"bDenominator"},{"type":"uint256","name":"exponent"},{"type":"uint256","name":"_decimals"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"getParentSealBitmap","inputs":[{"type":"uint256","name":"blockNumber"}],"constant":true},{"type":"event","name":"SlashingIncentivesSet","inputs":[{"type":"uint256","name":"penalty","indexed":false},{"type":"uint256","name":"reward","indexed":false}],"anonymous":false},{"type":"event","name":"DoubleSigningSlashPerformed","inputs":[{"type":"address","name":"validator","indexed":true},{"type":"uint256","name":"blockNumber","indexed":true}],"anonymous":false},{"type":"event","name":"RegistrySet","inputs":[{"type":"address","name":"registryAddress","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","indexed":true},{"type":"address","name":"newOwner","indexed":true}],"anonymous":false}]
              

Contract Creation Code

0x608060405260006100146100b760201b60201c565b9050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3506100bf565b600033905090565b61419b80620000cf6000396000f3fe608060405234801561001057600080fd5b50600436106101c45760003560e01c806388498aaf116100f9578063a91ee0dc11610097578063e50e652d11610071578063e50e652d146110a4578063ec683072146110e6578063f2fde38b14611161578063fae8db0a146111a5576101c4565b8063a91ee0dc1461100a578063bd0d99791461104e578063df4da46114611086576101c4565b80638da5cb5b116100d35780638da5cb5b14610f3e5780638f32d59b14610f885780639a7b3be714610faa5780639b2b592f14610fc8576101c4565b806388498aaf146108d85780638a883626146109705780638cc2691014610a3f576101c4565b80635d180adb116101665780637385e5da116101405780637385e5da146107fa5780637a1ac61e146108185780637b1039991461087057806387ee8a0f146108ba576101c4565b80635d180adb146106a957806367960e9114610721578063715018a6146107f0576101c4565b8063158ef93e116101a2578063158ef93e146103ec57806323f0ab651461040e5780633b1eb4bf146105985780634b2c2f44146105da576101c4565b806309f99447146101c95780630a05cd8414610359578063123633ea1461037e575b600080fd5b610343600480360360808110156101df57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561022657600080fd5b82018360208201111561023857600080fd5b8035906020019184600183028401116401000000008311171561025a57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803590602001906401000000008111156102bd57600080fd5b8201836020820111156102cf57600080fd5b803590602001918460018302840111640100000000831117156102f157600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506111e7565b6040518082815260200191505060405180910390f35b6103616115e0565b604051808381526020018281526020019250505060405180910390f35b6103aa6004803603602081101561039457600080fd5b81019080803590602001909291905050506115f2565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103f4611743565b604051808215151515815260200191505060405180910390f35b61057e6004803603606081101561042457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561046157600080fd5b82018360208201111561047357600080fd5b8035906020019184600183028401116401000000008311171561049557600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803590602001906401000000008111156104f857600080fd5b82018360208201111561050a57600080fd5b8035906020019184600183028401116401000000008311171561052c57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050611756565b604051808215151515815260200191505060405180910390f35b6105c4600480360360208110156105ae57600080fd5b810190808035906020019092919050505061190f565b6040518082815260200191505060405180910390f35b610693600480360360208110156105f057600080fd5b810190808035906020019064010000000081111561060d57600080fd5b82018360208201111561061f57600080fd5b8035906020019184600183028401116401000000008311171561064157600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050611929565b6040518082815260200191505060405180910390f35b6106df600480360360408110156106bf57600080fd5b810190808035906020019092919080359060200190929190505050611abd565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6107da6004803603602081101561073757600080fd5b810190808035906020019064010000000081111561075457600080fd5b82018360208201111561076657600080fd5b8035906020019184600183028401116401000000008311171561078857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050611c0f565b6040518082815260200191505060405180910390f35b6107f8611da3565b005b610802611edc565b6040518082815260200191505060405180910390f35b61086e6004803603606081101561082e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190929190505050611eec565b005b610878611fab565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6108c2611fd1565b6040518082815260200191505060405180910390f35b61092e600480360360608110156108ee57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190929190505050612118565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610a296004803603602081101561098657600080fd5b81019080803590602001906401000000008111156109a357600080fd5b8201836020820111156109b557600080fd5b803590602001918460018302840111640100000000831117156109d757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050612289565b6040518082815260200191505060405180910390f35b610f3c6004803603610160811015610a5657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190640100000000811115610a9d57600080fd5b820183602082011115610aaf57600080fd5b80359060200191846001830284011164010000000083111715610ad157600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610b3457600080fd5b820183602082011115610b4657600080fd5b80359060200191846001830284011164010000000083111715610b6857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019092919080359060200190640100000000811115610bd557600080fd5b820183602082011115610be757600080fd5b80359060200191846020830284011164010000000083111715610c0957600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610c6957600080fd5b820183602082011115610c7b57600080fd5b80359060200191846020830284011164010000000083111715610c9d57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610cfd57600080fd5b820183602082011115610d0f57600080fd5b80359060200191846020830284011164010000000083111715610d3157600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610d9157600080fd5b820183602082011115610da357600080fd5b80359060200191846020830284011164010000000083111715610dc557600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610e2557600080fd5b820183602082011115610e3757600080fd5b80359060200191846020830284011164010000000083111715610e5957600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610eb957600080fd5b820183602082011115610ecb57600080fd5b80359060200191846020830284011164010000000083111715610eed57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050919291929050505061241d565b005b610f46612569565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610f90612592565b604051808215151515815260200191505060405180910390f35b610fb26125f0565b6040518082815260200191505060405180910390f35b610ff460048036036020811015610fde57600080fd5b8101908080359060200190929190505050612600565b6040518082815260200191505060405180910390f35b61104c6004803603602081101561102057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612749565b005b6110846004803603604081101561106457600080fd5b8101908080359060200190929190803590602001909291905050506128ed565b005b61108e612a16565b6040518082815260200191505060405180910390f35b6110d0600480360360208110156110ba57600080fd5b8101908080359060200190929190505050612b52565b6040518082815260200191505060405180910390f35b611144600480360360c08110156110fc57600080fd5b81019080803590602001909291908035906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190929190505050612b9d565b604051808381526020018281526020019250505060405180910390f35b6111a36004803603602081101561117757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612db1565b005b6111d1600480360360208110156111bb57600080fd5b8101908080359060200190929190505050612e37565b6040518082815260200191505060405180910390f35b60006111f282611c0f565b6111fb84611c0f565b1415611252576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806140156021913960400191505060405180910390fd5b600061125d84612289565b905061126883612289565b81146112bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806140576027913960400191505060405180910390fd5b6112c881612600565b851061133c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f4261642076616c696461746f7220696e6465780000000000000000000000000081525060200191505060405180910390fd5b6113468582611abd565b73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16146113e6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f5761736e27742061207369676e6572207769746820676976656e20696e64657881525060200191505060405180910390fd5b60006113f185611929565b60001c9050600061140185611929565b60001c90506000876001901b83161415611483576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f4469646e2774207369676e20666972737420626c6f636b00000000000000000081525060200191505060405180910390fd5b6000876001901b82161415611500576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f4469646e2774207369676e207365636f6e6420626c6f636b000000000000000081525060200191505060405180910390fd5b61150983612b52565b61151283612f80565b1015611569576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180613e986025913960400191505060405180910390fd5b61157283612b52565b61157b82612f80565b10156115d2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806140f66026913960400191505060405180910390fd5b829350505050949350505050565b60028060000154908060010154905082565b60006060600060fa73ffffffffffffffffffffffffffffffffffffffff16844360405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061166b5780518252602082019150602081019050602083039250611648565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146116cb576040519150601f19603f3d011682016040523d82523d6000602084013e6116d0565b606091505b5080935081925050508061172f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603d815260200180613f6d603d913960400191505060405180910390fd5b61173a826000612feb565b92505050919050565b600060149054906101000a900460ff1681565b60008060fb73ffffffffffffffffffffffffffffffffffffffff16858585604051602001808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b815260140183805190602001908083835b602083106117df57805182526020820191506020810190506020830392506117bc565b6001836020036101000a03801982511681845116808217855250505050505090500182805190602001908083835b60208310611830578051825260208201915060208101905060208303925061180d565b6001836020036101000a03801982511681845116808217855250505050505090500193505050506040516020818303038152906040526040518082805190602001908083835b602083106118995780518252602082019150602081019050602083039250611876565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146118f9576040519150601f19603f3d011682016040523d82523d6000602084013e6118fe565b606091505b505080915050809150509392505050565b60006119228261191d612a16565b613002565b9050919050565b60006060600060f473ffffffffffffffffffffffffffffffffffffffff16846040516020018082805190602001908083835b6020831061197e578051825260208201915060208101905060208303925061195b565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b602083106119e557805182526020820191506020810190506020830392506119c2565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114611a45576040519150601f19603f3d011682016040523d82523d6000602084013e611a4a565b606091505b50809350819250505080611aa9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526038815260200180613f356038913960400191505060405180910390fd5b611ab482600061303a565b92505050919050565b60006060600060fa73ffffffffffffffffffffffffffffffffffffffff16858560405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310611b365780518252602082019150602081019050602083039250611b13565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114611b96576040519150601f19603f3d011682016040523d82523d6000602084013e611b9b565b606091505b50809350819250505080611bfa576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526036815260200180613fdf6036913960400191505060405180910390fd5b611c05826000612feb565b9250505092915050565b60006060600060f673ffffffffffffffffffffffffffffffffffffffff16846040516020018082805190602001908083835b60208310611c645780518252602082019150602081019050602083039250611c41565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b60208310611ccb5780518252602082019150602081019050602083039250611ca8565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114611d2b576040519150601f19603f3d011682016040523d82523d6000602084013e611d30565b606091505b50809350819250505080611d8f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602381526020018061414d6023913960400191505060405180910390fd5b611d9a82600061303a565b92505050919050565b611dab612592565b611e1d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b6000611ee743612b52565b905090565b600060149054906101000a900460ff1615611f6f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f636f6e747261637420616c726561647920696e697469616c697a65640000000081525060200191505060405180910390fd5b6001600060146101000a81548160ff021916908315150217905550611f93336130cb565b611f9c83612749565b611fa682826128ed565b505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006060600060f973ffffffffffffffffffffffffffffffffffffffff1643604051602001808281526020019150506040516020818303038152906040526040518082805190602001908083835b60208310612042578051825260208201915060208101905060208303925061201f565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146120a2576040519150601f19603f3d011682016040523d82523d6000602084013e6120a7565b606091505b50809350819250505080612106576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526035815260200180613faa6035913960400191505060405180910390fd5b612111826000612feb565b9250505090565b6000806121248461190f565b9050600081141561219d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f43616e6e6f7420736c617368206f6e2065706f6368203000000000000000000081525060200191505060405180910390fd5b6121a561320f565b73ffffffffffffffffffffffffffffffffffffffff1663eb1d0b42866121d560018561330a90919063ffffffff16565b866040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001838152602001828152602001935050505060206040518083038186803b15801561224457600080fd5b505afa158015612258573d6000803e3d6000fd5b505050506040513d602081101561226e57600080fd5b81019080805190602001909291905050509150509392505050565b60006060600060f773ffffffffffffffffffffffffffffffffffffffff16846040516020018082805190602001908083835b602083106122de57805182526020820191506020810190506020830392506122bb565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b602083106123455780518252602082019150602081019050602083039250612322565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146123a5576040519150601f19603f3d011682016040523d82523d6000602084013e6123aa565b606091505b50809350819250505080612409576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603181526020018061411c6031913960400191505060405180910390fd5b612414826000612feb565b92505050919050565b6124278b8a613354565b6124318b89613354565b600061243f8c8c8c8c6111e7565b9050600061244b6134a0565b73ffffffffffffffffffffffffffffffffffffffff166393c5c4878e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156124c757600080fd5b505afa1580156124db573d6000803e3d6000fd5b505050506040513d60208110156124f157600080fd5b810190808051906020019092919050505090506125168133848c8c8c8c8c8c8c61359b565b818173ffffffffffffffffffffffffffffffffffffffff167fca7992de940988854714f90c0236621d5b6b850313f03eeea47f7028aaecea4060405160405180910390a350505050505050505050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166125d4613ab6565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60006125fb4361190f565b905090565b60006060600060f973ffffffffffffffffffffffffffffffffffffffff1684604051602001808281526020019150506040516020818303038152906040526040518082805190602001908083835b60208310612671578051825260208201915060208101905060208303925061264e565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146126d1576040519150601f19603f3d011682016040523d82523d6000602084013e6126d6565b606091505b50809350819250505080612735576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e815260200180613ebd602e913960400191505060405180910390fd5b612740826000612feb565b92505050919050565b612751612592565b6127c3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415612866576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f43616e6e6f7420726567697374657220746865206e756c6c206164647265737381525060200191505060405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167f27fe5f0c1c3b1ed427cc63d0f05759ffdecf9aec9e18d31ef366fc8a6cb5dc3b60405160405180910390a250565b6128f5612592565b612967576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b8082116129bf576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180613eeb6024913960400191505060405180910390fd5b81600260000181905550806002600101819055507f716dc7c34384df36c6ccc5a2949f2ce9b019f5d4075ef39139a80038a4fdd1c38282604051808381526020018281526020019250505060405180910390a15050565b60006060600060f873ffffffffffffffffffffffffffffffffffffffff166040516020016040516020818303038152906040526040518082805190602001908083835b60208310612a7c5780518252602082019150602081019050602083039250612a59565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114612adc576040519150601f19603f3d011682016040523d82523d6000602084013e612ae1565b606091505b50809350819250505080612b40576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806140a56025913960400191505060405180910390fd5b612b4b826000612feb565b9250505090565b6000612b966003612b886002612b7a6002612b6c88612600565b613abe90919063ffffffff16565b613b4490919063ffffffff16565b613bcc90919063ffffffff16565b9050919050565b60008060008714158015612bb2575060008514155b612c24576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f612064656e6f6d696e61746f72206973207a65726f000000000000000000000081525060200191505060405180910390fd5b6000806000606060fc73ffffffffffffffffffffffffffffffffffffffff168c8c8c8c8c8c6040516020018087815260200186815260200185815260200184815260200183815260200182815260200196505050505050506040516020818303038152906040526040518082805190602001908083835b60208310612cbe5780518252602082019150602081019050602083039250612c9b565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114612d1e576040519150601f19603f3d011682016040523d82523d6000602084013e612d23565b606091505b50809250819350505081612d82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061407e6027913960400191505060405180910390fd5b612d8d816000612feb565b9350612d9a816020612feb565b925083839550955050505050965096945050505050565b612db9612592565b612e2b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b612e34816130cb565b50565b60006060600060f573ffffffffffffffffffffffffffffffffffffffff1684604051602001808281526020019150506040516020818303038152906040526040518082805190602001908083835b60208310612ea85780518252602082019150602081019050602083039250612e85565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114612f08576040519150601f19603f3d011682016040523d82523d6000602084013e612f0d565b606091505b50809350819250505080612f6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c8152602001806140ca602c913960400191505060405180910390fd5b612f7782600061303a565b92505050919050565b60008060009050600083905060008090505b610100811015612fe05760018083161415612fbe57612fbb600184613b4490919063ffffffff16565b92505b600182901c9150612fd9600182613b4490919063ffffffff16565b9050612f92565b508192505050919050565b6000612ff7838361303a565b60001c905092915050565b60008082848161300e57fe5b049050600083858161301c57fe5b06141561302c5780915050613034565b600181019150505b92915050565b600060208201835110156130b6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f736c6963696e67206f7574206f662072616e676500000000000000000000000081525060200191505060405180910390fd5b60006020830184015190508091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415613151576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180613f0f6026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f56616c696461746f727300000000000000000000000000000000000000000000815250600a019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156132ca57600080fd5b505afa1580156132de573d6000803e3d6000fd5b505050506040513d60208110156132f457600080fd5b8101908080519060200190929190505050905090565b600061334c83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613c16565b905092915050565b600061335f82611c0f565b9050600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082815260200190815260200160002060009054906101000a900460ff1615613432576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f416c726561647920736c6173686564000000000000000000000000000000000081525060200191505060405180910390fd5b6001600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600083815260200190815260200160002060006101000a81548160ff021916908315150217905550505050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f4163636f756e74730000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561355b57600080fd5b505afa15801561356f573d6000803e3d6000fd5b505050506040513d602081101561358557600080fd5b8101908080519060200190929190505050905090565b60006135a5613cd6565b90508073ffffffffffffffffffffffffffffffffffffffff166331993fc98c6002600001548d6002600101548c8c8c6040518863ffffffff1660e01b8152600401808873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018781526020018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b8381101561369e578082015181840152602081019050613683565b50505050905001848103835286818151815260200191508051906020019060200280838360005b838110156136e05780820151818401526020810190506136c5565b50505050905001848103825285818151815260200191508051906020019060200280838360005b83811015613722578082015181840152602081019050613707565b505050509050019a5050505050505050505050600060405180830381600087803b15801561374f57600080fd5b505af1158015613763573d6000803e3d6000fd5b5050505060006137748c8b8b612118565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156137ad57fe5b8173ffffffffffffffffffffffffffffffffffffffff166331993fc9826002600001548e6002600101548a8a8a6040518863ffffffff1660e01b8152600401808873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018781526020018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b838110156138a4578082015181840152602081019050613889565b50505050905001848103835286818151815260200191508051906020019060200280838360005b838110156138e65780820151818401526020810190506138cb565b50505050905001848103825285818151815260200191508051906020019060200280838360005b8381101561392857808201518184015260208101905061390d565b505050509050019a5050505050505050505050600060405180830381600087803b15801561395557600080fd5b505af1158015613969573d6000803e3d6000fd5b50505050600061397761320f565b90508073ffffffffffffffffffffffffffffffffffffffff1663e33301aa8e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b1580156139f857600080fd5b505af1158015613a0c573d6000803e3d6000fd5b505050508073ffffffffffffffffffffffffffffffffffffffff1663c22d3bba836040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b158015613a8f57600080fd5b505af1158015613aa3573d6000803e3d6000fd5b5050505050505050505050505050505050565b600033905090565b600080831415613ad15760009050613b3e565b6000828402905082848281613ae257fe5b0414613b39576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806140366021913960400191505060405180910390fd5b809150505b92915050565b600080828401905083811015613bc2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b6000613c0e83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613dd1565b905092915050565b6000838311158290613cc3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613c88578082015181840152602081019050613c6d565b50505050905090810190601f168015613cb55780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f4c6f636b6564476f6c6400000000000000000000000000000000000000000000815250600a019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015613d9157600080fd5b505afa158015613da5573d6000803e3d6000fd5b505050506040513d6020811015613dbb57600080fd5b8101908080519060200190929190505050905090565b60008083118290613e7d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613e42578082015181840152602081019050613e27565b50505050905090810190601f168015613e6f5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000838581613e8957fe5b04905080915050939250505056fe4e6f7420656e6f756768207369676e65727320696e2074686520666972737420626c6f636b6572726f722063616c6c696e67206e756d62657256616c696461746f7273496e53657420707265636f6d70696c6550656e616c74792068617320746f206265206c6172676572207468616e207265776172644f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573736572726f722063616c6c696e672067657456657269666965645365616c4269746d617046726f6d48656164657220707265636f6d70696c656572726f722063616c6c696e672076616c696461746f725369676e65724164647265737346726f6d43757272656e7453657420707265636f6d70696c656572726f722063616c6c696e67206e756d62657256616c696461746f7273496e43757272656e7453657420707265636f6d70696c656572726f722063616c6c696e672076616c696461746f725369676e65724164647265737346726f6d53657420707265636f6d70696c65426c6f636b20686173686573206861766520746f20626520646966666572656e74536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77426c6f636b2068656164657273206172652066726f6d20646966666572656e74206865696768746572726f722063616c6c696e67206672616374696f6e4d756c45787020707265636f6d70696c656572726f722063616c6c696e672067657445706f636853697a6520707265636f6d70696c656572726f722063616c6c696e6720676574506172656e745365616c4269746d617020707265636f6d70696c654e6f7420656e6f756768207369676e65727320696e20746865207365636f6e6420626c6f636b6572726f722063616c6c696e6720676574426c6f636b4e756d62657246726f6d48656164657220707265636f6d70696c656572726f722063616c6c696e67206861736848656164657220707265636f6d70696c65a165627a7a72305820a175d1f562d81b0bba1400ef58430ea393a96c96054c09f9ee1db18f80b44f9d0029

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106101c45760003560e01c806388498aaf116100f9578063a91ee0dc11610097578063e50e652d11610071578063e50e652d146110a4578063ec683072146110e6578063f2fde38b14611161578063fae8db0a146111a5576101c4565b8063a91ee0dc1461100a578063bd0d99791461104e578063df4da46114611086576101c4565b80638da5cb5b116100d35780638da5cb5b14610f3e5780638f32d59b14610f885780639a7b3be714610faa5780639b2b592f14610fc8576101c4565b806388498aaf146108d85780638a883626146109705780638cc2691014610a3f576101c4565b80635d180adb116101665780637385e5da116101405780637385e5da146107fa5780637a1ac61e146108185780637b1039991461087057806387ee8a0f146108ba576101c4565b80635d180adb146106a957806367960e9114610721578063715018a6146107f0576101c4565b8063158ef93e116101a2578063158ef93e146103ec57806323f0ab651461040e5780633b1eb4bf146105985780634b2c2f44146105da576101c4565b806309f99447146101c95780630a05cd8414610359578063123633ea1461037e575b600080fd5b610343600480360360808110156101df57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561022657600080fd5b82018360208201111561023857600080fd5b8035906020019184600183028401116401000000008311171561025a57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803590602001906401000000008111156102bd57600080fd5b8201836020820111156102cf57600080fd5b803590602001918460018302840111640100000000831117156102f157600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506111e7565b6040518082815260200191505060405180910390f35b6103616115e0565b604051808381526020018281526020019250505060405180910390f35b6103aa6004803603602081101561039457600080fd5b81019080803590602001909291905050506115f2565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103f4611743565b604051808215151515815260200191505060405180910390f35b61057e6004803603606081101561042457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561046157600080fd5b82018360208201111561047357600080fd5b8035906020019184600183028401116401000000008311171561049557600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803590602001906401000000008111156104f857600080fd5b82018360208201111561050a57600080fd5b8035906020019184600183028401116401000000008311171561052c57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050611756565b604051808215151515815260200191505060405180910390f35b6105c4600480360360208110156105ae57600080fd5b810190808035906020019092919050505061190f565b6040518082815260200191505060405180910390f35b610693600480360360208110156105f057600080fd5b810190808035906020019064010000000081111561060d57600080fd5b82018360208201111561061f57600080fd5b8035906020019184600183028401116401000000008311171561064157600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050611929565b6040518082815260200191505060405180910390f35b6106df600480360360408110156106bf57600080fd5b810190808035906020019092919080359060200190929190505050611abd565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6107da6004803603602081101561073757600080fd5b810190808035906020019064010000000081111561075457600080fd5b82018360208201111561076657600080fd5b8035906020019184600183028401116401000000008311171561078857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050611c0f565b6040518082815260200191505060405180910390f35b6107f8611da3565b005b610802611edc565b6040518082815260200191505060405180910390f35b61086e6004803603606081101561082e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190929190505050611eec565b005b610878611fab565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6108c2611fd1565b6040518082815260200191505060405180910390f35b61092e600480360360608110156108ee57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190929190505050612118565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610a296004803603602081101561098657600080fd5b81019080803590602001906401000000008111156109a357600080fd5b8201836020820111156109b557600080fd5b803590602001918460018302840111640100000000831117156109d757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050612289565b6040518082815260200191505060405180910390f35b610f3c6004803603610160811015610a5657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190640100000000811115610a9d57600080fd5b820183602082011115610aaf57600080fd5b80359060200191846001830284011164010000000083111715610ad157600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610b3457600080fd5b820183602082011115610b4657600080fd5b80359060200191846001830284011164010000000083111715610b6857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019092919080359060200190640100000000811115610bd557600080fd5b820183602082011115610be757600080fd5b80359060200191846020830284011164010000000083111715610c0957600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610c6957600080fd5b820183602082011115610c7b57600080fd5b80359060200191846020830284011164010000000083111715610c9d57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610cfd57600080fd5b820183602082011115610d0f57600080fd5b80359060200191846020830284011164010000000083111715610d3157600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610d9157600080fd5b820183602082011115610da357600080fd5b80359060200191846020830284011164010000000083111715610dc557600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610e2557600080fd5b820183602082011115610e3757600080fd5b80359060200191846020830284011164010000000083111715610e5957600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610eb957600080fd5b820183602082011115610ecb57600080fd5b80359060200191846020830284011164010000000083111715610eed57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050919291929050505061241d565b005b610f46612569565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610f90612592565b604051808215151515815260200191505060405180910390f35b610fb26125f0565b6040518082815260200191505060405180910390f35b610ff460048036036020811015610fde57600080fd5b8101908080359060200190929190505050612600565b6040518082815260200191505060405180910390f35b61104c6004803603602081101561102057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612749565b005b6110846004803603604081101561106457600080fd5b8101908080359060200190929190803590602001909291905050506128ed565b005b61108e612a16565b6040518082815260200191505060405180910390f35b6110d0600480360360208110156110ba57600080fd5b8101908080359060200190929190505050612b52565b6040518082815260200191505060405180910390f35b611144600480360360c08110156110fc57600080fd5b81019080803590602001909291908035906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190929190505050612b9d565b604051808381526020018281526020019250505060405180910390f35b6111a36004803603602081101561117757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612db1565b005b6111d1600480360360208110156111bb57600080fd5b8101908080359060200190929190505050612e37565b6040518082815260200191505060405180910390f35b60006111f282611c0f565b6111fb84611c0f565b1415611252576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806140156021913960400191505060405180910390fd5b600061125d84612289565b905061126883612289565b81146112bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806140576027913960400191505060405180910390fd5b6112c881612600565b851061133c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f4261642076616c696461746f7220696e6465780000000000000000000000000081525060200191505060405180910390fd5b6113468582611abd565b73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16146113e6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f5761736e27742061207369676e6572207769746820676976656e20696e64657881525060200191505060405180910390fd5b60006113f185611929565b60001c9050600061140185611929565b60001c90506000876001901b83161415611483576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f4469646e2774207369676e20666972737420626c6f636b00000000000000000081525060200191505060405180910390fd5b6000876001901b82161415611500576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f4469646e2774207369676e207365636f6e6420626c6f636b000000000000000081525060200191505060405180910390fd5b61150983612b52565b61151283612f80565b1015611569576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180613e986025913960400191505060405180910390fd5b61157283612b52565b61157b82612f80565b10156115d2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806140f66026913960400191505060405180910390fd5b829350505050949350505050565b60028060000154908060010154905082565b60006060600060fa73ffffffffffffffffffffffffffffffffffffffff16844360405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061166b5780518252602082019150602081019050602083039250611648565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146116cb576040519150601f19603f3d011682016040523d82523d6000602084013e6116d0565b606091505b5080935081925050508061172f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603d815260200180613f6d603d913960400191505060405180910390fd5b61173a826000612feb565b92505050919050565b600060149054906101000a900460ff1681565b60008060fb73ffffffffffffffffffffffffffffffffffffffff16858585604051602001808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b815260140183805190602001908083835b602083106117df57805182526020820191506020810190506020830392506117bc565b6001836020036101000a03801982511681845116808217855250505050505090500182805190602001908083835b60208310611830578051825260208201915060208101905060208303925061180d565b6001836020036101000a03801982511681845116808217855250505050505090500193505050506040516020818303038152906040526040518082805190602001908083835b602083106118995780518252602082019150602081019050602083039250611876565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146118f9576040519150601f19603f3d011682016040523d82523d6000602084013e6118fe565b606091505b505080915050809150509392505050565b60006119228261191d612a16565b613002565b9050919050565b60006060600060f473ffffffffffffffffffffffffffffffffffffffff16846040516020018082805190602001908083835b6020831061197e578051825260208201915060208101905060208303925061195b565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b602083106119e557805182526020820191506020810190506020830392506119c2565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114611a45576040519150601f19603f3d011682016040523d82523d6000602084013e611a4a565b606091505b50809350819250505080611aa9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526038815260200180613f356038913960400191505060405180910390fd5b611ab482600061303a565b92505050919050565b60006060600060fa73ffffffffffffffffffffffffffffffffffffffff16858560405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310611b365780518252602082019150602081019050602083039250611b13565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114611b96576040519150601f19603f3d011682016040523d82523d6000602084013e611b9b565b606091505b50809350819250505080611bfa576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526036815260200180613fdf6036913960400191505060405180910390fd5b611c05826000612feb565b9250505092915050565b60006060600060f673ffffffffffffffffffffffffffffffffffffffff16846040516020018082805190602001908083835b60208310611c645780518252602082019150602081019050602083039250611c41565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b60208310611ccb5780518252602082019150602081019050602083039250611ca8565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114611d2b576040519150601f19603f3d011682016040523d82523d6000602084013e611d30565b606091505b50809350819250505080611d8f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602381526020018061414d6023913960400191505060405180910390fd5b611d9a82600061303a565b92505050919050565b611dab612592565b611e1d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b6000611ee743612b52565b905090565b600060149054906101000a900460ff1615611f6f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f636f6e747261637420616c726561647920696e697469616c697a65640000000081525060200191505060405180910390fd5b6001600060146101000a81548160ff021916908315150217905550611f93336130cb565b611f9c83612749565b611fa682826128ed565b505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006060600060f973ffffffffffffffffffffffffffffffffffffffff1643604051602001808281526020019150506040516020818303038152906040526040518082805190602001908083835b60208310612042578051825260208201915060208101905060208303925061201f565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146120a2576040519150601f19603f3d011682016040523d82523d6000602084013e6120a7565b606091505b50809350819250505080612106576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526035815260200180613faa6035913960400191505060405180910390fd5b612111826000612feb565b9250505090565b6000806121248461190f565b9050600081141561219d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f43616e6e6f7420736c617368206f6e2065706f6368203000000000000000000081525060200191505060405180910390fd5b6121a561320f565b73ffffffffffffffffffffffffffffffffffffffff1663eb1d0b42866121d560018561330a90919063ffffffff16565b866040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001838152602001828152602001935050505060206040518083038186803b15801561224457600080fd5b505afa158015612258573d6000803e3d6000fd5b505050506040513d602081101561226e57600080fd5b81019080805190602001909291905050509150509392505050565b60006060600060f773ffffffffffffffffffffffffffffffffffffffff16846040516020018082805190602001908083835b602083106122de57805182526020820191506020810190506020830392506122bb565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b602083106123455780518252602082019150602081019050602083039250612322565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146123a5576040519150601f19603f3d011682016040523d82523d6000602084013e6123aa565b606091505b50809350819250505080612409576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603181526020018061411c6031913960400191505060405180910390fd5b612414826000612feb565b92505050919050565b6124278b8a613354565b6124318b89613354565b600061243f8c8c8c8c6111e7565b9050600061244b6134a0565b73ffffffffffffffffffffffffffffffffffffffff166393c5c4878e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156124c757600080fd5b505afa1580156124db573d6000803e3d6000fd5b505050506040513d60208110156124f157600080fd5b810190808051906020019092919050505090506125168133848c8c8c8c8c8c8c61359b565b818173ffffffffffffffffffffffffffffffffffffffff167fca7992de940988854714f90c0236621d5b6b850313f03eeea47f7028aaecea4060405160405180910390a350505050505050505050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166125d4613ab6565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60006125fb4361190f565b905090565b60006060600060f973ffffffffffffffffffffffffffffffffffffffff1684604051602001808281526020019150506040516020818303038152906040526040518082805190602001908083835b60208310612671578051825260208201915060208101905060208303925061264e565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146126d1576040519150601f19603f3d011682016040523d82523d6000602084013e6126d6565b606091505b50809350819250505080612735576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e815260200180613ebd602e913960400191505060405180910390fd5b612740826000612feb565b92505050919050565b612751612592565b6127c3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415612866576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f43616e6e6f7420726567697374657220746865206e756c6c206164647265737381525060200191505060405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167f27fe5f0c1c3b1ed427cc63d0f05759ffdecf9aec9e18d31ef366fc8a6cb5dc3b60405160405180910390a250565b6128f5612592565b612967576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b8082116129bf576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180613eeb6024913960400191505060405180910390fd5b81600260000181905550806002600101819055507f716dc7c34384df36c6ccc5a2949f2ce9b019f5d4075ef39139a80038a4fdd1c38282604051808381526020018281526020019250505060405180910390a15050565b60006060600060f873ffffffffffffffffffffffffffffffffffffffff166040516020016040516020818303038152906040526040518082805190602001908083835b60208310612a7c5780518252602082019150602081019050602083039250612a59565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114612adc576040519150601f19603f3d011682016040523d82523d6000602084013e612ae1565b606091505b50809350819250505080612b40576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806140a56025913960400191505060405180910390fd5b612b4b826000612feb565b9250505090565b6000612b966003612b886002612b7a6002612b6c88612600565b613abe90919063ffffffff16565b613b4490919063ffffffff16565b613bcc90919063ffffffff16565b9050919050565b60008060008714158015612bb2575060008514155b612c24576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f612064656e6f6d696e61746f72206973207a65726f000000000000000000000081525060200191505060405180910390fd5b6000806000606060fc73ffffffffffffffffffffffffffffffffffffffff168c8c8c8c8c8c6040516020018087815260200186815260200185815260200184815260200183815260200182815260200196505050505050506040516020818303038152906040526040518082805190602001908083835b60208310612cbe5780518252602082019150602081019050602083039250612c9b565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114612d1e576040519150601f19603f3d011682016040523d82523d6000602084013e612d23565b606091505b50809250819350505081612d82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061407e6027913960400191505060405180910390fd5b612d8d816000612feb565b9350612d9a816020612feb565b925083839550955050505050965096945050505050565b612db9612592565b612e2b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b612e34816130cb565b50565b60006060600060f573ffffffffffffffffffffffffffffffffffffffff1684604051602001808281526020019150506040516020818303038152906040526040518082805190602001908083835b60208310612ea85780518252602082019150602081019050602083039250612e85565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114612f08576040519150601f19603f3d011682016040523d82523d6000602084013e612f0d565b606091505b50809350819250505080612f6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c8152602001806140ca602c913960400191505060405180910390fd5b612f7782600061303a565b92505050919050565b60008060009050600083905060008090505b610100811015612fe05760018083161415612fbe57612fbb600184613b4490919063ffffffff16565b92505b600182901c9150612fd9600182613b4490919063ffffffff16565b9050612f92565b508192505050919050565b6000612ff7838361303a565b60001c905092915050565b60008082848161300e57fe5b049050600083858161301c57fe5b06141561302c5780915050613034565b600181019150505b92915050565b600060208201835110156130b6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f736c6963696e67206f7574206f662072616e676500000000000000000000000081525060200191505060405180910390fd5b60006020830184015190508091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415613151576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180613f0f6026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f56616c696461746f727300000000000000000000000000000000000000000000815250600a019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156132ca57600080fd5b505afa1580156132de573d6000803e3d6000fd5b505050506040513d60208110156132f457600080fd5b8101908080519060200190929190505050905090565b600061334c83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613c16565b905092915050565b600061335f82611c0f565b9050600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082815260200190815260200160002060009054906101000a900460ff1615613432576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f416c726561647920736c6173686564000000000000000000000000000000000081525060200191505060405180910390fd5b6001600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600083815260200190815260200160002060006101000a81548160ff021916908315150217905550505050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f4163636f756e74730000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561355b57600080fd5b505afa15801561356f573d6000803e3d6000fd5b505050506040513d602081101561358557600080fd5b8101908080519060200190929190505050905090565b60006135a5613cd6565b90508073ffffffffffffffffffffffffffffffffffffffff166331993fc98c6002600001548d6002600101548c8c8c6040518863ffffffff1660e01b8152600401808873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018781526020018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b8381101561369e578082015181840152602081019050613683565b50505050905001848103835286818151815260200191508051906020019060200280838360005b838110156136e05780820151818401526020810190506136c5565b50505050905001848103825285818151815260200191508051906020019060200280838360005b83811015613722578082015181840152602081019050613707565b505050509050019a5050505050505050505050600060405180830381600087803b15801561374f57600080fd5b505af1158015613763573d6000803e3d6000fd5b5050505060006137748c8b8b612118565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156137ad57fe5b8173ffffffffffffffffffffffffffffffffffffffff166331993fc9826002600001548e6002600101548a8a8a6040518863ffffffff1660e01b8152600401808873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018781526020018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b838110156138a4578082015181840152602081019050613889565b50505050905001848103835286818151815260200191508051906020019060200280838360005b838110156138e65780820151818401526020810190506138cb565b50505050905001848103825285818151815260200191508051906020019060200280838360005b8381101561392857808201518184015260208101905061390d565b505050509050019a5050505050505050505050600060405180830381600087803b15801561395557600080fd5b505af1158015613969573d6000803e3d6000fd5b50505050600061397761320f565b90508073ffffffffffffffffffffffffffffffffffffffff1663e33301aa8e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b1580156139f857600080fd5b505af1158015613a0c573d6000803e3d6000fd5b505050508073ffffffffffffffffffffffffffffffffffffffff1663c22d3bba836040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b158015613a8f57600080fd5b505af1158015613aa3573d6000803e3d6000fd5b5050505050505050505050505050505050565b600033905090565b600080831415613ad15760009050613b3e565b6000828402905082848281613ae257fe5b0414613b39576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806140366021913960400191505060405180910390fd5b809150505b92915050565b600080828401905083811015613bc2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b6000613c0e83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613dd1565b905092915050565b6000838311158290613cc3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613c88578082015181840152602081019050613c6d565b50505050905090810190601f168015613cb55780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f4c6f636b6564476f6c6400000000000000000000000000000000000000000000815250600a019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015613d9157600080fd5b505afa158015613da5573d6000803e3d6000fd5b505050506040513d6020811015613dbb57600080fd5b8101908080519060200190929190505050905090565b60008083118290613e7d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613e42578082015181840152602081019050613e27565b50505050905090810190601f168015613e6f5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000838581613e8957fe5b04905080915050939250505056fe4e6f7420656e6f756768207369676e65727320696e2074686520666972737420626c6f636b6572726f722063616c6c696e67206e756d62657256616c696461746f7273496e53657420707265636f6d70696c6550656e616c74792068617320746f206265206c6172676572207468616e207265776172644f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573736572726f722063616c6c696e672067657456657269666965645365616c4269746d617046726f6d48656164657220707265636f6d70696c656572726f722063616c6c696e672076616c696461746f725369676e65724164647265737346726f6d43757272656e7453657420707265636f6d70696c656572726f722063616c6c696e67206e756d62657256616c696461746f7273496e43757272656e7453657420707265636f6d70696c656572726f722063616c6c696e672076616c696461746f725369676e65724164647265737346726f6d53657420707265636f6d70696c65426c6f636b20686173686573206861766520746f20626520646966666572656e74536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77426c6f636b2068656164657273206172652066726f6d20646966666572656e74206865696768746572726f722063616c6c696e67206672616374696f6e4d756c45787020707265636f6d70696c656572726f722063616c6c696e672067657445706f636853697a6520707265636f6d70696c656572726f722063616c6c696e6720676574506172656e745365616c4269746d617020707265636f6d70696c654e6f7420656e6f756768207369676e65727320696e20746865207365636f6e6420626c6f636b6572726f722063616c6c696e6720676574426c6f636b4e756d62657246726f6d48656164657220707265636f6d70696c656572726f722063616c6c696e67206861736848656164657220707265636f6d70696c65a165627a7a72305820a175d1f562d81b0bba1400ef58430ea393a96c96054c09f9ee1db18f80b44f9d0029